/*
 * Notarium — the ⌘K command palette
 *
 * The trigger in the topbar and the palette dialog it opens.
 *
 * Split out of koncern.css so one agent can own this surface. The file is
 * named `koncern_*` ON PURPOSE: `stylesheet_link_tag :app` emits every
 * sheet in ALPHABETICAL order, and koncern.css currently loads BEFORE
 * notarium.css, so notarium.css wins ties against it. A file called
 * `palette.css` or `notifications.css` would sort AFTER notarium.css and
 * silently start winning ties this CSS has never won. `koncern_…` keeps it
 * between koncern.css and marketing.css — exactly where it has always been.
 *
 * Depends on section 0 of koncern.css (the --koncern-frist-* tone vars),
 * which still loads first.
 *
 * ── The design brief this file answers ────────────────────────────────────
 *
 * A palette is an instrument: it is opened blind, used at speed, and closed.
 * Four rules follow from that and every rule below serves one of them.
 *
 *   1. ONE accent. Bordeaux (--nt-seal*) marks the selection and nothing
 *      else. Green means "i orden", amber means an approaching frist and red
 *      means overdue — none of those states exist in here, so none of those
 *      colours appear in here.
 *   2. The selection is the loudest thing on screen. It is three signals at
 *      once (tinted plate + bordeaux edge bar + filled icon), because a
 *      keyboard user reads it in peripheral vision while typing, and because
 *      one signal alone dies in one of the two themes: the dark seal wash
 *      (#2c1a1d) sits four points off the dark overlay (#24211b) and is
 *      almost invisible on its own.
 *   3. Hover must never impersonate the selection. Enter acts on the
 *      keyboard row, so anything that looks selected under the mouse is a
 *      lie about what Enter will do. Hover gets a flat neutral tint; the
 *      selection gets the bordeaux.
 *   4. Nothing moves when the selection moves. The ↵ affordance on each row
 *      is always in the DOM and only changes opacity, so arrowing down a
 *      list never reflows it.
 */

/* ══════════════════════════════════════════════════════════════════════
   7. ⌘K TRIGGER + PALETTE
   ══════════════════════════════════════════════════════════════════════ */

/* — Keycaps — */

/* Sized, not just padded: ↑ ↓ ↵ esc are wildly different glyph widths and a
   row of keycaps that jitters between them reads as debris. The heavier
   bottom border is the whole illusion — it is what makes a box a key. */
.koncern-kbd {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.4rem;
  height: 1.4rem;
  padding: 0 0.32rem;
  font-family: var(--nt-font-mono);
  font-size: 0.66rem;
  line-height: 1;
  border: 1px solid var(--nt-border);
  border-bottom-width: 2px;
  border-radius: var(--nt-radius-xs);
  background: var(--nt-surface);
  color: var(--nt-text-tertiary);
  white-space: nowrap;
}

/* — The trigger in the navbar — */

/* Shaped like the field it opens, not like a button: a search affordance in
   a topbar is read as "type here", and the keycap parked on the right edge
   is the part that teaches the shortcut. Below 48rem it collapses to the
   icon alone (navbar.css drops the keycap under 30rem — a phone has no ⌘). */
.koncern-cmdk {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  height: 2.15rem;
  padding: 0 0.4rem 0 0.6rem;
  border-radius: var(--nt-radius);
  border: 1px solid var(--nt-border-subtle);
  background: var(--nt-surface-sunken);
  color: var(--nt-text-tertiary);
  font-family: var(--nt-font-body);
  font-size: var(--nt-text-sm);
  cursor: pointer;
  transition:
    border-color var(--nt-duration-fast) var(--nt-ease),
    background-color var(--nt-duration-fast) var(--nt-ease),
    color var(--nt-duration-fast) var(--nt-ease);
}

.koncern-cmdk:hover {
  border-color: var(--nt-border-strong);
  background: var(--nt-surface);
  color: var(--nt-text-secondary);
}

/* The keycap picks up the identity colour on hover — the one place the
   trigger admits it belongs to Notarium rather than to the browser. */
.koncern-cmdk:hover .koncern-kbd {
  border-color: var(--nt-seal-border);
  color: var(--nt-seal-text);
}

.koncern-cmdk:focus-visible {
  outline: none;
  border-color: var(--nt-seal);
  box-shadow: var(--nt-shadow-focus);
}

/* Parked against the right edge, which is what turns a pill into a field. */
.koncern-cmdk .koncern-kbd { margin-left: auto; }

.koncern-cmdk-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Two labels, one at a time: "Søg" is a control, "Søg og spring til" is an
   invitation, and only the wide navbar has room for the invitation. */
.koncern-cmdk-label-short,
.koncern-cmdk-label-long { display: none; }

@media (min-width: 48rem) {
  .koncern-cmdk { min-width: 11rem; }
  .koncern-cmdk-label-short { display: inline; }
}

@media (min-width: 64rem) {
  .koncern-cmdk { min-width: 14.5rem; }
  .koncern-cmdk-label-short { display: none; }
  .koncern-cmdk-label-long { display: inline; }
}

/* — The dialog — */

.koncern-palette-dialog {
  width: 100%;
  /* Not centred: a palette belongs under the hand, near the top of the
     screen, the way every editor's does. */
  margin: 8vh auto auto;
}

/* The scrim belongs to .nt-dialog::backdrop; only the fade is ours, so the
   palette does not punch a hole in the page in a single frame. */
.koncern-palette-dialog::backdrop {
  animation: koncern-palette-backdrop-in var(--nt-duration) var(--nt-ease) both;
}

@keyframes koncern-palette-backdrop-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

.koncern-palette {
  /* One knob for the left edge of everything: search icon, group rule and
     result text all start on the same vertical line (row inset + row padding
     is deliberately equal to the gutter — see .koncern-result). */
  --koncern-palette-gutter: 1.25rem;
  --koncern-palette-inset: 0.6rem;

  position: relative;
  width: min(40rem, calc(100vw - 2rem));
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  /* Capped in rem as well as viewport units: on a tall monitor 76vh is a
     column of thirty results, which is a list, not a palette. */
  max-height: min(78dvh, 36rem);
  background: var(--nt-surface-overlay);
  border: 1px solid var(--nt-border-subtle);
  border-radius: var(--nt-radius-lg);
  box-shadow: var(--nt-shadow-3);
  overflow: hidden;
  animation: koncern-palette-in var(--nt-duration-slow) var(--nt-ease) both;
}

@keyframes koncern-palette-in {
  from { opacity: 0; transform: translateY(-0.6rem) scale(0.99); }
  to { opacity: 1; transform: none; }
}

/* — Search — */

.koncern-palette-search {
  position: relative;
  display: flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.9rem var(--koncern-palette-gutter);
  border-bottom: 1px solid var(--nt-border-subtle);
}

.koncern-palette-search-icon {
  flex: none;
  display: flex;
  color: var(--nt-text-tertiary);
  transition: color var(--nt-duration-fast) var(--nt-ease);
}

/* The field is the headline of this surface — no border, no fill, no inner
   box. Type large enough to be the thing you look at when the dialog opens. */
.koncern-palette-input {
  flex: 1;
  min-width: 0;
  border: 0;
  background: transparent;
  color: var(--nt-text);
  font-family: var(--nt-font-body);
  font-size: var(--nt-text-lg);
  font-weight: 450;
  letter-spacing: -0.01em;
  line-height: 1.4;
  outline: none;
}

.koncern-palette-input::placeholder {
  color: var(--nt-text-disabled);
  font-weight: 400;
}

/* Caret in the identity colour: the smallest possible reminder of whose
   product this is, on the one pixel column the eye is already watching. */
.koncern-palette-input { caret-color: var(--nt-seal); }

/* No ring on the field. The dialog IS the focus context — the input is
   focused the instant it appears and never loses focus while the palette is
   open, so a 2px bordeaux rectangle around it says nothing and reinstates
   exactly the "form control in a box" look this surface is meant to shed.
   Focus is signalled by the caret and by the search glyph turning bordeaux.

   :focus-visible is required in the selector, not merely the bare class:
   notarium.css's global ring is written `:where(a, button, input, …):focus-visible`
   and the :focus-visible sits OUTSIDE the :where(), so that rule is 0,1,0 —
   not the zero its comment claims — and notarium.css sorts after this file. */
.koncern-palette-input:focus-visible { outline: none; }

.koncern-palette-search:focus-within .koncern-palette-search-icon { color: var(--nt-seal); }

.koncern-palette-esc {
  flex: none;
  display: inline-flex;
  align-items: center;
  border: 0;
  background: transparent;
  padding: 0;
  cursor: pointer;
  line-height: 0;
  color: var(--nt-text-tertiary);
  border-radius: var(--nt-radius-xs);
}

.koncern-palette-esc:hover .koncern-kbd { border-color: var(--nt-border-strong); color: var(--nt-text); }
.koncern-palette-esc:focus-visible { outline: 2px solid var(--nt-focus); outline-offset: 2px; }

/* The keycap IS the close button on a machine that has the key; a touch
   screen gets a real ✕ instead, because printing "esc" at someone holding a
   phone is a hint they cannot take. */
.koncern-palette-esc-touch { display: none; }

/* — Searching —

   Turbo stamps [busy] on the frame for the length of the request, so the
   whole indicator is CSS: a bordeaux sweep along the seam under the field.
   Delayed past 140ms so an answer that arrives instantly never flashes a
   loading state, and placed on the seam rather than over the results so the
   list you are already reading does not move or dim while it refreshes.

   :has() is load-bearing but not critical — where it is missing the rule is
   dropped whole and the palette simply has no busy bar. */
.koncern-palette:has(.koncern-palette-results[busy]) .koncern-palette-search::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 2px;
  background: linear-gradient(90deg, transparent, var(--nt-seal), transparent);
  animation: koncern-palette-busy 900ms var(--nt-ease-in-out) 140ms infinite both;
}

@keyframes koncern-palette-busy {
  from { transform: translateX(-100%); opacity: 0; }
  25% { opacity: 1; }
  to { transform: translateX(100%); opacity: 1; }
}

/* — Results — */

.koncern-palette-results {
  display: block;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding-bottom: var(--nt-space-2);
  /* A palette's scrollbar is chrome inside chrome; keep it hairline in both
     themes rather than letting the OS paint a slab down the edge. */
  scrollbar-width: thin;
  scrollbar-color: var(--nt-border) transparent;
}

/* — Groups —

   Up to five headings can be on screen at once, so they carry as little ink
   as a label can and still be found: mono, uppercase, wide-tracked, tertiary,
   with a hairline running out to the right edge. The rule is what makes them
   scannable — the eye follows it and lands on the group, instead of reading
   five shouted words.

   Sticky, because a 30-row list scrolled halfway is otherwise a list of rows
   with no idea what kind of thing they are. */
.koncern-palette-group { padding-bottom: var(--nt-space-1); }

.koncern-palette-group-head {
  position: sticky;
  top: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.7rem var(--koncern-palette-gutter) 0.35rem;
  background: var(--nt-surface-overlay);
  font-family: var(--nt-font-mono);
  font-size: 0.64rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--nt-text-tertiary);
}

.koncern-palette-group-head::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--nt-border-subtle);
}

/* — Rows — */

.koncern-result {
  position: relative;
  display: flex;
  align-items: center;
  gap: 0.7rem;
  /* inset + padding == the gutter above, so titles line up under the group
     label and under the search icon. */
  margin: 0 var(--koncern-palette-inset);
  padding: 0.5rem 0.65rem;
  border: 0;
  border-radius: var(--nt-radius);
  background: transparent;
  color: inherit;
  font-family: var(--nt-font-body);
  font-size: var(--nt-text-base);
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  /* scrollIntoView({block:"nearest"}) would otherwise park the row exactly
     under the sticky group heading it belongs to. */
  scroll-margin-top: 2.4rem;
  scroll-margin-bottom: 0.5rem;
}

/* Hover is feedback, not selection — see rule 3 in the header. Flat neutral,
   no bordeaux, no edge bar: it must be impossible to mistake for the row
   Enter will open. --nt-neutral-tint is the one soft fill that moves the
   right way in both themes (paper-200 down from white, night-600 up from
   night-700). */
.koncern-result:hover { background: var(--nt-neutral-tint); }

/* The selection is driven by the controller, not by :hover — a palette where
   the mouse position fights the arrow keys is unusable. */
.koncern-result-active,
.koncern-result-active:hover {
  background: var(--nt-seal-tint);
  box-shadow: inset 0 0 0 1px var(--nt-seal-border);
}

/* The edge bar. A pill rather than an inset shadow so the radius of the
   plate does not shear it into a crescent.

   Scoped to .koncern-result and not to .koncern-result-active alone: the
   example chips share the active class, they are not positioned, and an
   absolute ::before on them resolved against .koncern-palette instead —
   painting a bordeaux stripe down the entire dialog. */
.koncern-result.koncern-result-active::before {
  content: "";
  position: absolute;
  left: 0.3rem;
  top: 0.45rem;
  bottom: 0.45rem;
  width: 3px;
  border-radius: var(--nt-radius-full);
  background: var(--nt-seal);
}

.koncern-result-icon {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.9rem;
  height: 1.9rem;
  border-radius: var(--nt-radius-sm);
  background: var(--nt-neutral-soft);
  border: 1px solid var(--nt-neutral-border);
  color: var(--nt-neutral-text);
}

.koncern-result-icon-seal { background: var(--nt-seal-soft); border-color: var(--nt-seal-border); color: var(--nt-seal-text); }
.koncern-result-icon-info { background: var(--nt-info-soft); border-color: var(--nt-info-border); color: var(--nt-info-text); }

/* Selected: the tile fills. This is the signal that survives being read out
   of the corner of the eye, and it is the reason the row's own tint can stay
   quiet enough to sit under long text. */
.koncern-result-active .koncern-result-icon {
  background: var(--nt-seal);
  border-color: var(--nt-seal);
  color: var(--nt-on-seal);
}

.koncern-result-text {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.06rem;
  line-height: 1.3;
}

/* Danish company names and document titles are long and their distinguishing
   words are at the FRONT ("Wilstrup Holding ApS", "Referat af ordinær
   generalforsamling 2025"), so both lines truncate at the tail on one line.
   Wrapping would let a single result push the next one off the screen. */
.koncern-result-title {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 550;
  letter-spacing: -0.005em;
}

.koncern-result-subtitle {
  font-size: var(--nt-text-xs);
  color: var(--nt-text-tertiary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.koncern-result-active .koncern-result-title { color: var(--nt-seal-text); }
.koncern-result-active .koncern-result-subtitle { color: var(--nt-text-secondary); }

/* Right-hand zone: the contextual meta, then the ↵ affordance. Capped at
   40% so a long meta (a document's selskab) can never win the row against
   the title, which is what the user is actually reading. */
.koncern-result-aside {
  flex: 0 1 auto;
  min-width: 0;
  max-width: 40%;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.koncern-result-meta {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--nt-text-xs);
  color: var(--nt-text-tertiary);
}

/* A CVR number is a number: mono and tabular, like everywhere else in the
   product. (.nt-mono is not used here — its 0.85em would drop this to 0.6rem.) */
.koncern-result-meta-companies {
  font-family: var(--nt-font-mono);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
}

.koncern-result-active .koncern-result-meta { color: var(--nt-text-secondary); }

/* Always rendered, never conditional: opacity means the row is exactly as
   wide selected as unselected, so arrowing through the list never reflows a
   single pixel. */
.koncern-result-enter {
  flex: none;
  opacity: 0;
  transition: opacity var(--nt-duration-fast) var(--nt-ease);
}

.koncern-result-active .koncern-result-enter {
  opacity: 1;
  border-color: var(--nt-seal-border);
  color: var(--nt-seal-text);
}

/* — Empty, no-results — */

.koncern-palette-empty {
  padding: var(--nt-space-5) var(--koncern-palette-gutter) var(--nt-space-4);
}

/* Left-aligned on purpose: centred prose in a search surface reads as an
   error dialog. This is an invitation, and it starts on the same line the
   results will start on. */
.koncern-palette-empty-title {
  font-family: var(--nt-font-display);
  font-weight: 600;
  font-size: var(--nt-text-lg);
  letter-spacing: -0.01em;
}

.koncern-palette-empty-body {
  margin-top: 0.3rem;
  max-width: 32rem;
  font-size: var(--nt-text-sm);
  line-height: 1.5;
  color: var(--nt-text-secondary);
}

/* The query, quoted back inside the no-results headline. */
.koncern-palette-q {
  font-family: var(--nt-font-mono);
  font-size: 0.9em;
  color: var(--nt-seal-text);
}

/* — "Bestil hjælp": the fallback that is a product, not an error —

   Rendered with .koncern-result so it inherits the row geometry and the
   selected state wholesale: it is the first item in the list, it is what
   Enter does, and it should look like a thing you can do rather than like
   the consolation prize at the bottom of a failure. */
.koncern-palette-cta {
  margin-top: var(--nt-space-4);
  margin-inline: 0;
  padding: 0.6rem 0.7rem;
  border: 1px solid var(--nt-seal-border);
  background: var(--nt-seal-soft);
  /* It is selected the moment the frame loads, so the controller scrolls it
     into view — and on a short window that pushed the headline that explains
     WHY it is here off the top. The margin drags the two lines above it into
     the scroll target. */
  scroll-margin-top: 6rem;
}

.koncern-palette-cta .koncern-result-title { color: var(--nt-seal-text); }

/* — Example chips — */

.koncern-palette-examples { margin-top: var(--nt-space-5); }

.koncern-palette-examples-head {
  font-family: var(--nt-font-mono);
  font-size: 0.64rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--nt-text-tertiary);
}

.koncern-example-row {
  margin-top: var(--nt-space-3);
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}

/* The chips are real palette items (arrow keys reach them, Enter runs them),
   so they carry the same selected treatment as a result row — otherwise the
   resting state would be the one screen where the selection disappears. */
.koncern-example {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.32rem 0.7rem;
  border-radius: var(--nt-radius-full);
  border: 1px solid var(--nt-border-subtle);
  background: var(--nt-surface-raised);
  color: var(--nt-text-secondary);
  font-family: var(--nt-font-body);
  font-size: var(--nt-text-sm);
  text-decoration: none;
  cursor: pointer;
  transition:
    border-color var(--nt-duration-fast) var(--nt-ease),
    background-color var(--nt-duration-fast) var(--nt-ease),
    color var(--nt-duration-fast) var(--nt-ease);
}

.koncern-example svg { color: var(--nt-text-tertiary); }

.koncern-example:hover {
  border-color: var(--nt-border-strong);
  background: var(--nt-neutral-tint);
  color: var(--nt-text);
}

.koncern-example.koncern-result-active {
  border-color: var(--nt-seal);
  background: var(--nt-seal-tint);
  color: var(--nt-seal-text);
  box-shadow: none;
}

.koncern-example.koncern-result-active svg { color: var(--nt-seal-text); }

/* — Footer — */

.koncern-palette-foot {
  display: flex;
  align-items: center;
  gap: var(--nt-space-4);
  padding: 0.45rem var(--koncern-palette-gutter);
  border-top: 1px solid var(--nt-border-subtle);
  /* Sunken rather than raised: in dark, --nt-surface-raised is the same
     night-700 as the overlay, so a "raised" tray would be invisible. */
  background: var(--nt-surface-sunken);
  font-size: var(--nt-text-xs);
  color: var(--nt-text-tertiary);
}

.koncern-palette-foot span {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
}

.koncern-palette-foot-end { margin-left: auto; }

/* — Phone —

   The keyboard hints go away wholesale: every one of them describes a key
   that is not on the device, and the vertical space they cost is space the
   on-screen keyboard has already taken. The dialog moves to the top edge and
   drops to the smaller radius so it reads as part of the screen. */
@media (max-width: 40rem) {
  .koncern-palette-dialog { margin: 0.75rem auto auto; }

  .koncern-palette {
    --koncern-palette-gutter: 1rem;
    --koncern-palette-inset: 0.5rem;

    width: calc(100vw - 1.5rem);
    max-height: 86dvh;
    border-radius: var(--nt-radius);
  }

  .koncern-palette-search { padding: 0.75rem var(--koncern-palette-gutter); }
  .koncern-palette-input { font-size: var(--nt-text-md); }
  .koncern-result { padding: 0.5rem; }
  .koncern-palette-esc-kbd { display: none; }
  .koncern-palette-esc-touch { display: inline-flex; }
  .koncern-result-enter { display: none; }
  .koncern-palette-foot { display: none; }
}

/* ══════════════════════════════════════════════════════════════════════
   9. REDUCED MOTION
   ══════════════════════════════════════════════════════════════════════ */

@media (prefers-reduced-motion: reduce) {
  .koncern-palette,
  .koncern-palette-dialog::backdrop { animation: none; }

  .koncern-result-enter { transition: none; }

  /* The busy bar keeps its meaning but loses its travel: it fades in on the
     same 140ms delay and then holds still. */
  .koncern-palette:has(.koncern-palette-results[busy]) .koncern-palette-search::after {
    animation: koncern-palette-busy-static 1ms linear 140ms both;
  }

  @keyframes koncern-palette-busy-static {
    from { opacity: 0; }
    to { opacity: 0.9; }
  }
}
