@layer components {
  /* The command palette (D-15)

     The primary navigation surface, so it is the one thing in the product
     allowed to sit over everything else. A real <dialog>: the browser gives the
     top layer, the backdrop, the focus trap and Escape for free, and gives a
     screen reader something it already knows the shape of.

     High on the screen rather than centred — a list that grows downward from a
     field should grow into space, not push itself off both edges. */

  .palette {
    width: min(42rem, calc(100vw - var(--space-4)));
    max-height: min(32rem, calc(100vh - var(--space-10)));
    margin: 12vh auto auto;
    padding: 0;
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    background: var(--surface);
    box-shadow: var(--shadow-card);
    color: var(--ink);
    overflow: hidden;
  }

  /* The layout goes here and not above, and the distinction is not cosmetic: a
     closed <dialog> is hidden by the user agent's own `dialog:not([open]) {
     display: none }`, and any author `display` outranks a user agent one no
     matter how it is written. Setting it unconditionally left both sheets drawn
     into the page at all times — 12vh down an absolutely positioned document,
     which is to say half off the bottom of the screen, and still there after
     Escape. The menus above say the same thing under :popover-open. */
  .palette[open] {
    display: flex;
    flex-direction: column;
    opacity: 1;
    translate: none;
    scale: 1;
    transition: opacity var(--transition),
                translate var(--transition),
                scale var(--transition),
                overlay var(--transition) allow-discrete,
                display var(--transition) allow-discrete;

    @starting-style {
      opacity: 0;
      translate: 0 calc(var(--space) * -1);
      scale: 0.98;
    }
  }

  /* The way out, which it did not have. A dialog closes by having its `open`
     attribute removed, so the closed state is the bare element — the same
     allow-discrete pair the menus use holds it and its backdrop in the top
     layer long enough to be seen going. Two per cent of scale, because this
     one is large enough that fading alone reads as a light going off rather
     than as a panel closing. */
  .palette {
    opacity: 0;
    translate: 0 calc(var(--space) * -1);
    scale: 0.98;
    transition: opacity var(--transition-exit),
                translate var(--transition-exit),
                scale var(--transition-exit),
                overlay var(--transition-exit) allow-discrete,
                display var(--transition-exit) allow-discrete;
  }

  .palette::backdrop { background: light-dark(rgb(25 26 29 / 20%), rgb(0 0 0 / 55%)); }

  /* The backdrop travels with it, or the page behind goes dark in one frame
     and light again in another while the panel is still moving. */
  .palette::backdrop {
    opacity: 0;
    transition: opacity var(--transition-exit),
                overlay var(--transition-exit) allow-discrete,
                display var(--transition-exit) allow-discrete;
  }

  .palette[open]::backdrop {
    opacity: 1;
    transition: opacity var(--transition),
                overlay var(--transition) allow-discrete,
                display var(--transition) allow-discrete;

    @starting-style { opacity: 0; }
  }

  .palette__form {
    display: flex;
    align-items: center;
    margin: 0;
    padding-left: var(--space-3);
    border-bottom: 1px solid var(--line);
  }

  /* The reference prefix.
     
     Grows in front of what you are typing the moment the query is all digits,
     so 142 reads as ACME-142 — which is what the search is actually looking
     for. Mono, because the product sets everything the system assigned in mono
     and everything a person wrote in sans, and a task's number is the system's.
     
     max-width rather than width, because width cannot transition from nothing
     to the width of a word nobody has measured. Overflow hidden is what makes
     the letters arrive rather than appear. */
  .palette__prefix {
    flex: none;
    max-width: 0;
    overflow: hidden;
    font-family: var(--font-mono);
    font-size: var(--text-md);
    letter-spacing: var(--tracking-label);
    color: var(--ink-faint);
    white-space: nowrap;
    opacity: 0;
    transition: max-width var(--transition), opacity var(--transition);
  }

  .palette[data-reference] .palette__prefix { max-width: 8ch; opacity: 1; }

  /* The field is the whole top of the panel. No border of its own, no icon: at
     this size the only thing it could be is a search field. */
  .palette__input {
    font: inherit;
    font-size: var(--text-md);
    flex: 1;
    min-width: 0;
    height: var(--control-h);
    padding: 0 var(--space-3) 0 0;
    border: 0;
    background: none;
    color: var(--ink);
  }

  .palette__input:focus { outline: none; }
  .palette__input::placeholder { color: var(--ink-faint); }
  .palette__input::-webkit-search-cancel-button { display: none; }

  .palette__results { overflow-y: auto; }
  .palette__list { list-style: none; margin: 0; padding: var(--space); position: relative; }

  /* One cursor, moved. The keyboard's position in the list is a single object
     that travels rather than a background that appears somewhere else each
     time — which is the difference between a list you are moving through and a
     list that is redrawing itself under you.
     
     Behind the rows, so the reference and the title keep their own colour and
     the marks stay legible on top of it. Under reduced motion --transition is
     0s and it simply appears where it is needed, which is the same answer the
     rest of the product gives. */
  .palette__cursor {
    position: absolute;
    left: var(--space);
    right: var(--space);
    top: 0;
    height: 0;
    border-radius: var(--radius-sm);
    background: var(--accent-sunk);
    opacity: 0;
    pointer-events: none;
    transition: transform var(--transition), height var(--transition),
                opacity var(--transition);
  }

  .palette__cursor[data-at] { opacity: 1; }

  .palette__result {
    display: grid;
    grid-template-columns: var(--rail) minmax(0, 1fr) auto;
    align-items: center;
    gap: var(--space-2);
    min-height: var(--control-h-sm);
    padding: var(--space) var(--space-2);
    border-radius: var(--radius-sm);
    color: var(--ink);
    text-decoration: none;
  }

  /* One row is highlighted at all times, and it is the one Enter follows. A
     palette where Enter does nothing until you arrow down is a search box.
     That highlight is the cursor above; what is left here is the mouse, which
     is a different question — where the pointer is, not where Enter goes. */
  .palette__result { position: relative; }
  .palette__result:hover { background: var(--surface-hover); }

  .palette__title {
    font-size: var(--text-base);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .palette__state {
    display: flex;
    align-items: baseline;
    gap: var(--space);
    white-space: nowrap;
  }

  /* The letters you typed, found in the row. An underline in the accent rather
     than a highlighter: it marks without shouting, it reads the same on the
     cursor as off it, and it leaves the words their own colour. */
  .palette__match {
    background: none;
    color: inherit;
    text-decoration: underline;
    text-decoration-color: var(--accent);
    text-decoration-thickness: 2px;
    text-underline-offset: 3px;
  }

  .palette__project { font-size: var(--text-xs); color: var(--ink-faint); }

  .palette__empty {
    padding: var(--space-3);
    color: var(--ink-faint);
    font-size: var(--text-sm);
  }

  /* The palette's rows, when the row is a place rather than a task. "Go" sits in
     the reference rail, so the two kinds line up down the same column instead of
     each having their own left edge. */
  .palette__result--command .task__ref { color: var(--ink-faint); }

  /* Set as a label in base.css; only its place in the list is here. */
  .palette__group { padding: var(--space-2) var(--space-2) var(--space); }
}
