@layer lotek {
  .lt-select {
    /* The design system cannot assume the consumer has a CSS reset. Without
       border-box, padding and border are added outside the width, and the
       field becomes wider than the box it sits in. */
    box-sizing: border-box;

    display: block;
    width: var(--lt-select-width, 100%);
    padding: var(--lt-select-padding, var(--lt-spacing-2) var(--lt-spacing-3));
    /* The end side is the room for the arrow, and it is fixed: the arrow is
       drawn a fixed distance from the edge, so less room would put the text
       on top of it. So `--lt-select-padding` applies to everything except
       this side here. With `data-picker="styled"` the arrow takes real
       room, and there the variable applies to all four sides. */
    padding-inline-end: calc(var(--lt-spacing-4) + var(--lt-spacing-2));
    font-family: inherit;
    font-size: var(--lt-font-size-m);
    line-height: var(--lt-line-height-default);
    color: var(--lt-color-neutral-text-strong);
    background-color: var(--lt-color-neutral-canvas);
    border: 1px solid var(--lt-color-neutral-border);
    border-radius: var(--lt-select-radius, var(--lt-spacing-1));
    appearance: none;
    background-image:
      linear-gradient(
        45deg,
        transparent 50%,
        var(--lt-color-neutral-text-subtle) 50%
      ),
      linear-gradient(
        135deg,
        var(--lt-color-neutral-text-subtle) 50%,
        transparent 50%
      );
    background-position:
      calc(100% - 1rem) calc(50% - 0.1rem),
      calc(100% - 0.75rem) calc(50% - 0.1rem);
    background-size:
      0.35rem 0.35rem,
      0.35rem 0.35rem;
    background-repeat: no-repeat;
  }

  /* The arrow is two gradients, and `background-position` has no logical
     variant. The mirrored version is the same two pieces, moved to the left
     edge and swapped: the one that was outermost is now innermost. From the
     left the position is given to the piece's left edge, from the right with
     `calc(100% - ...)` to the same point on the other side, so the distances
     are the same numbers. With 0.35rem subtracted the arrow sat 6 pixels
     from the edge instead of 12. */
  .lt-select:dir(rtl) {
    background-position:
      0.75rem calc(50% - 0.1rem),
      1rem calc(50% - 0.1rem);
  }

  .lt-select:hover {
    border-color: var(--lt-color-neutral-border-strong);
  }

  .lt-select:focus-visible {
    outline: var(--lt-focus-ring);
    outline-offset: 2px;
    border-color: var(--lt-color-accent-border);
  }

  .lt-select:disabled,
  .lt-select[aria-disabled="true"] {
    background-color: var(--lt-color-disabled-surface);
    color: var(--lt-color-disabled-text);
    border-color: var(--lt-color-disabled-surface);
    /* No pointer-events: none here. The browser already blocks a disabled
       field, and pointer-events would only stop the cursor from showing. The
       element is then not hit by the mouse at all. */
    cursor: not-allowed;
  }

  /* aria-disabled is only information for screen readers; the element still
     works. Here pointer-events stops the mouse, at the cost of the cursor.
     If the field should really be off, use `disabled` or `readonly`. */
  .lt-select[aria-disabled="true"] {
    pointer-events: none;
  }

  .lt-select[data-state="invalid"] {
    border-color: var(--lt-color-danger-text);
    background-color: var(--lt-color-danger-surface);
  }

  .lt-select[data-state="invalid"]:focus-visible {
    outline-color: var(--lt-color-danger-text);
  }

  .lt-select[data-state="success"] {
    border-color: var(--lt-color-success-text);
    background-color: var(--lt-color-success-surface);
  }

  .lt-select[data-state="success"]:focus-visible {
    outline-color: var(--lt-color-success-text);
  }

  /* Disabled wins over a state. `[data-state]` used to come after
     `:disabled` with the same specificity, and an invalid field in a form
     that was disabled during submission looked red, not disabled. */
  .lt-select:is(:disabled, [aria-disabled="true"])[data-state] {
    background-color: var(--lt-color-disabled-surface);
    color: var(--lt-color-disabled-text);
    border-color: var(--lt-color-disabled-surface);
  }

  /*
   * The dropdown list is a window from the operating system, and no CSS
   * reaches into it. `appearance: base-select` asks the browser to draw it
   * inside the page instead: `::picker(select)` becomes a normal element,
   * and each `<option>` can get the design system's colours and spacing.
   *
   * It is optional, and turned on with `data-picker="styled"`. Firefox 150
   * does not have it, and there the field keeps the browser's own list. It
   * is the same component with two looks, not something that breaks.
   */
  @supports (appearance: base-select) {
    .lt-select[data-picker="styled"],
    .lt-select[data-picker="styled"]::picker(select) {
      appearance: base-select;
    }

    /* The button now draws its own arrow with `::picker-icon`, so the
       gradients must go. The arrow takes real room in the layout, and the
       room we kept for the drawn arrow would then be there twice. */
    .lt-select[data-picker="styled"] {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: var(--lt-spacing-2);
      background-image: none;
      padding: var(
        --lt-select-padding,
        var(--lt-spacing-2) var(--lt-spacing-3)
      );
    }

    /* The text in the button is the current choice. Long choices should be
       clipped, not push the arrow out of the field. Without
       `min-inline-size: 0` it does not shrink, because flex gives it the
       minimum width of its content.

       The browser does not create <selectedcontent> by itself. It only
       exists when the author writes
       `<button><selectedcontent></selectedcontent></button>` first in the
       select. Without it the choice is drawn in the browser's own shadow
       DOM, which no rule reaches, and a long choice wraps over several
       lines. `white-space: nowrap` on the select does not help: the text
       does not shrink there, and the arrow is pushed out of the field. */
    /* biome-ignore lint/correctness/noUnknownTypeSelector: <selectedcontent> is
       the element that shows the selected option in a customisable
       dropdown list. Biome does not know it yet. */
    .lt-select[data-picker="styled"] selectedcontent {
      min-inline-size: 0;
      overflow: hidden;
      white-space: nowrap;
      text-overflow: ellipsis;
    }

    .lt-select[data-picker="styled"]::picker-icon {
      color: var(--lt-color-neutral-text-subtle);
      transition: rotate 120ms ease;
    }

    .lt-select[data-picker="styled"]:open::picker-icon {
      rotate: 180deg;
    }

    .lt-select[data-picker="styled"]::picker(select) {
      box-sizing: border-box;
      min-inline-size: anchor-size(self-inline);
      /* The list should fill the room that is actually left down to the
         edge of the window, not stretch beyond it. `stretch` is exactly
         that room, and the margin is subtracted. */
      max-block-size: stretch;
      margin-block: var(--lt-select-viewport-margin, var(--lt-spacing-2));
      padding: 0;
      overflow-y: auto;
      background: var(--lt-color-neutral-canvas);
      border: 1px solid var(--lt-color-neutral-border);
      border-radius: var(--lt-select-radius, var(--lt-spacing-1));
      box-shadow: var(--lt-shadow-overlay);
      /* If there is no room below the field, the list goes above it. */
      position-try-fallbacks: flip-block;
      opacity: 0;
      transition:
        opacity 120ms ease,
        overlay 120ms allow-discrete,
        display 120ms allow-discrete;
    }

    .lt-select[data-picker="styled"]:open::picker(select) {
      opacity: 1;
    }

    @starting-style {
      .lt-select[data-picker="styled"]:open::picker(select) {
        opacity: 0;
      }
    }

    /* The height can only be animated where `calc-size` exists, since `auto`
       is otherwise not a value that can be transitioned to. Without support
       the height stays `auto`, and only the opacity fades. */
    @supports (block-size: calc-size(auto, size)) {
      .lt-select[data-picker="styled"]::picker(select) {
        block-size: 0;
        transition:
          opacity 120ms ease,
          block-size 120ms ease,
          overlay 120ms allow-discrete,
          display 120ms allow-discrete;
      }

      .lt-select[data-picker="styled"]:open::picker(select) {
        block-size: calc-size(auto, size);
      }

      @starting-style {
        .lt-select[data-picker="styled"]:open::picker(select) {
          block-size: 0;
        }
      }
    }

    /* The group heading is not an element we can target when it comes from
       `label=`, only from `<legend>`. So it is set on the group, and
       inherited down: the size and colour set it apart from the options,
       and `text-indent` gives it the same left edge as the text in an
       option. The options set those three back to their own values. */
    .lt-select[data-picker="styled"] optgroup {
      padding-block: var(--lt-spacing-2) var(--lt-spacing-1);
      font-size: var(--lt-font-size-s);
      color: var(--lt-color-neutral-text-subtle);
      text-indent: var(--lt-spacing-3);
    }

    .lt-select[data-picker="styled"] option {
      text-indent: 0;
      display: flex;
      align-items: center;
      gap: var(--lt-spacing-2);
      padding: var(
        --lt-select-option-padding,
        var(--lt-spacing-2) var(--lt-spacing-3)
      );
      font-family: inherit;
      font-size: var(--lt-font-size-m);
      line-height: var(--lt-line-height-default);
      color: var(--lt-color-neutral-text-strong);
      background: var(--lt-color-neutral-canvas);
      cursor: pointer;
    }

    /* The tick comes after the text, not before it, so all the options get
       the text in the same place. */
    .lt-select[data-picker="styled"] option::checkmark {
      order: 1;
      margin-inline-start: auto;
    }

    .lt-select[data-picker="styled"] option:hover {
      background: var(--lt-color-accent-surface);
    }

    .lt-select[data-picker="styled"] option:checked {
      background: var(--lt-color-accent-fill);
      color: var(--lt-color-accent-content);
    }

    /* Focus is shown with a border, not with a surface. The arrow keys move
       focus between the options, and the selected one already has its own
       surface. A different background colour would therefore disappear
       exactly where the user is. */
    .lt-select[data-picker="styled"] option:focus {
      outline: var(--lt-focus-ring);
      outline-offset: -2px;
    }

    .lt-select[data-picker="styled"] option:checked:focus {
      outline-color: var(--lt-color-accent-content);
    }

    .lt-select[data-picker="styled"] option:disabled {
      color: var(--lt-color-disabled-text);
      background: var(--lt-color-disabled-surface);
      cursor: not-allowed;
    }

    @media (prefers-reduced-motion: reduce) {
      .lt-select[data-picker="styled"]::picker(select),
      .lt-select[data-picker="styled"]::picker-icon {
        transition: none;
      }
    }
  }

  /* High contrast: the arrow is two gradients, and they are removed in the
     mode. The browser's own arrow is then better than none. The list drawn
     in the page falls back for the same reason: the browser's own list uses
     the system colours, and they are the only ones guaranteed to be
     readable in the mode. */
  @media (forced-colors: active) {
    .lt-select,
    .lt-select[data-picker="styled"] {
      display: block;
      appearance: auto;
      background-image: none;
      padding: var(
        --lt-select-padding,
        var(--lt-spacing-2) var(--lt-spacing-3)
      );
    }
  }
}
