/* ── design-system components ────────────────────────────────────────────────
   Custom controls that replace the browser's own. RULES.md §13: never ship a
   native dialog or a native <select> as app UI — they cannot be themed, cannot
   use the design tokens, and look different on every OS.

   Everything here is applied only once JavaScript has enhanced the native
   control, so with JavaScript off the real <select> still renders and still
   submits. The native element is kept in the DOM throughout: it holds the value,
   it is what the form posts, and it keeps the markup meaningful without CSS. */

/* ── custom select ───────────────────────────────────────────────────────── */
.cs { position:relative; }

/* the native control stays in the layout until JS is ready, then becomes the
   value holder. display:none still submits; `disabled` would not. */
.cs[data-cs-ready] > select {
  position:absolute; inline-size:1px; block-size:1px; opacity:0; pointer-events:none;
  margin:0; padding:0; border:0; overflow:hidden; clip-path:inset(50%);
}

.cs__btn {
  display:flex; align-items:center; gap:8px; inline-size:100%; box-sizing:border-box;
  /* the metrics of the .select this replaces — enhancing a control must not
     move anything on the page */
  min-block-size:var(--ctl-h); padding:0 var(--ctl-px);
  background:var(--surface-2); color:var(--ink-1);
  border:1px solid var(--line-control); border-radius:var(--r-sm);
  font:400 .875rem/1.3 var(--font-ui); text-align:left; cursor:pointer;
  transition:border-color var(--d-2), box-shadow var(--d-2), background var(--d-2);
}
/* ── the panel, and the search inside it ─────────────────────────────────────
   The panel is what gets positioned and hidden; the list scrolls inside it. The
   search row is `flex: none` so it never scrolls out of reach, and the list takes
   the remaining height — which is why the panel, not the list, carries the
   max-height cap. */
.cs__panel {
  display: flex;
  flex-direction: column;
  background: var(--surface-1);
  border: 1px solid var(--line-2);
  border-radius: var(--r-md);
  box-shadow: 0 12px 32px rgba(3, 8, 16, .16);
  overflow: hidden;

  /*
   * Above everything.
   *
   * `position: fixed` escapes a clipping ancestor, but it does NOT escape a
   * STACKING CONTEXT — an ancestor with its own z-index paints above a fixed
   * descendant regardless of how large that descendant's z-index is. This panel
   * carried no z-index at all while the stylesheets in use go up to 200, so on a
   * page whose cards are layered the options rendered underneath them: the
   * control opened and the list was invisible.
   *
   * The value is above the highest in the codebase (200) with room to spare, and
   * it is the only place a z-index this large is needed — a dropdown is the one
   * element that has to sit over whatever it was opened from.
   */
  z-index: 1000;
}

/*
 * `display: flex` beats the `hidden` attribute.
 *
 * The UA stylesheet hides `[hidden]` with `display: none`, and ANY author
 * `display` rule wins over it — so the moment this panel became a flex container
 * it stopped closing. The component toggles `panel.hidden`, so the loss was
 * silent: the list appeared not to open or close reliably, and the panel painted
 * an empty 2px strip under every closed control. Written explicitly, because the
 * alternative is remembering not to use `display` on anything toggleable.
 */
.cs__panel[hidden] { display: none; }
.cs__search {
  flex: none;
  padding: var(--s-2);
  border-bottom: 1px solid var(--line-1);
  background: var(--surface-2);
}
.cs__searchinput {
  inline-size: 100%;
  box-sizing: border-box;
  block-size: var(--ctl-h-sm);
  padding: 0 var(--s-3);
  font: 400 .875rem var(--font-ui);
  color: var(--ink-1);
  background: var(--surface-1);
  border: 1px solid var(--line-control);
  border-radius: var(--r-sm);
}
.cs__searchinput:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
/* Safari draws its own clear button; it sits over the text at this height */
.cs__searchinput::-webkit-search-cancel-button { margin-inline-end: 2px; }
.cs__empty {
  margin: 0;
  padding: var(--s-4);
  text-align: center;
  font: var(--t-xs);
  color: var(--ink-3);
}

/* The dense tier, matching `.select--sm` exactly. Enhancing a control must not
   change its size, and until this existed every small select grew from 36px to
   44px the moment JavaScript ran — beside 36px inputs and buttons. */
.cs--sm .cs__btn {
  min-block-size:var(--ctl-h-sm);
  font-size:.875rem; font-weight:500;
  padding:0 var(--s-7) 0 var(--ctl-px);
}
.cs--sm .cs__list { font-size:.875rem; }

/* ── password preview — hold to reveal ───────────────────────────────────────
   The wrapper is `position:relative` and the button is placed inside it, so the
   field keeps its own height and width: the layout is identical whether or not
   password.js has run.

   The drawn control is 30px because that is the size the field can hold without
   disturbing it, but 30px is BELOW this project's 44px minimum target. So the
   TARGET is 44px: `::after` extends the hit area by 7px on every side, which
   measures 30 + 7 + 7 = 44 in both axes without moving a single glyph or
   changing the field's height. Sizing the button itself to 44px was tried on
   paper and rejected — `.pw` wraps password fields on compact forms too, and an
   absolutely positioned 44px box overflows a field shorter than that.

   The button IS a tab stop, deliberately. password.js carries the reasoning:
   `tabIndex = -1` was traded away because the cost was a reveal control that no
   keyboard user could reach. */
.pw { position:relative; display:block; inline-size:100%; }
.pw > input { inline-size:100%; }
.pw__btn {
  position:absolute; inset-block-start:50%; inset-inline-end:6px;
  translate:0 -50%;
  display:grid; place-items:center;
  inline-size:30px; block-size:30px;
  padding:0; border:0; border-radius:var(--r-sm);
  background:none; color:var(--ink-4);
  cursor:pointer;
  /* a long press must not select text or raise the callout instead of holding */
  -webkit-touch-callout:none; -webkit-user-select:none; user-select:none;
  touch-action:manipulation;
  transition:color var(--d-2) var(--ease-standard), background var(--d-2) var(--ease-standard);
}
/* the 44px minimum target, without a 44px box in the layout */
.pw__btn::after { content:''; position:absolute; inset:-7px; }
.pw__btn:hover { color:var(--ink-1); background:var(--surface-3); }
.pw__btn:focus-visible { outline:2px solid var(--accent); outline-offset:1px; }
/* the value must not run underneath the button */
.pw > input[type="password"], .pw > input[type="text"] { padding-inline-end:40px; }

.cs__btn:hover { border-color:var(--ink-4); }
.cs__btn:focus-visible { outline:none; border-color:var(--accent); box-shadow:0 0 0 3px var(--accent-soft); }
.cs__btn[aria-expanded="true"] { border-color:var(--accent); box-shadow:0 0 0 3px var(--accent-soft); }
.cs__value { flex:1 1 auto; min-inline-size:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.cs__value--empty { color:var(--ink-4); }
.cs__caret { flex:none; inline-size:17px; block-size:17px; color:var(--ink-3); transition:transform var(--d-2); }
.cs__btn[aria-expanded="true"] .cs__caret { transform:rotate(180deg); }

/*
 * The list scrolls INSIDE the panel; it is no longer the positioned element.
 *
 * It used to be `position: absolute` with its own border, radius and shadow,
 * because it was the thing that opened. The panel took that job over — it is what
 * `place()` positions and what carries the chrome — and an absolutely-positioned
 * child is out of flow, so the flex panel collapsed to **2px** around a list that
 * measured 94px. The control opened onto an empty sliver.
 *
 * `min-block-size: 0` is required: a flex item will not shrink below its content
 * size without it, so the list would grow past the panel's cap instead of
 * scrolling inside it.
 */
.cs__list {
  position:relative;
  flex:1 1 auto; min-block-size:0;
  margin:0; padding:4px; list-style:none;
  overflow-y:auto; overscroll-behavior:contain;
}
.cs__list[hidden] { display:none; }

.cs__opt {
  display:flex; align-items:center; gap:8px;
  min-block-size:42px; padding:0 12px; border-radius:var(--r-xs);
  font:400 .875rem/1.35 var(--font-ui); color:var(--ink-2); cursor:pointer;
}
.cs__opt[data-active="1"] { background:var(--surface-3); color:var(--ink-1); }
.cs__opt[aria-selected="true"] { color:var(--accent-text); font-weight:600; }
.cs__opt[aria-selected="true"]::after {
  content:"✓"; margin-inline-start:auto; font-size:.875rem; color:var(--accent);
}
.cs__opt[data-placeholder="1"] { color:var(--ink-4); }

@media (hover:hover) { .cs__opt:hover { background:var(--surface-3); } }

/* the panel sits inside a form; give it room on a phone */
@media (max-width:560px) {
  .cs__list { max-block-size:min(52vh, 300px); }
}

@media (prefers-reduced-motion: reduce) { .cs__caret, .cs__btn { transition:none; } }
@media (forced-colors: active) {
  .cs__btn, .cs__list { border-color:CanvasText; }
  .cs__opt[data-active="1"] { outline:2px solid Highlight; outline-offset:-2px; }
}

/* ── token field ─────────────────────────────────────────────────────────────
   Question text where {{tokens}} are chips you can see, remove and replace,
   rather than braces buried in a sentence. The real <textarea> stays in the form
   and stays authoritative; with JavaScript off this is just a plain field. */

.tokfield { position:relative; }
.tokfield__native { position:absolute; inline-size:1px; block-size:1px; opacity:0;
                    pointer-events:none; margin:0; padding:0; border:0; overflow:hidden; clip-path:inset(50%); }

.tokfield__editor {
  min-block-size:64px; box-sizing:border-box; padding:8px 12px;
  background:var(--surface-2); color:var(--ink-1);
  border:1px solid var(--line-2); border-radius:var(--r-md);
  font:400 .875rem/1.7 var(--font-ui);
  overflow-wrap:anywhere; cursor:text;
  transition:border-color var(--d-2), box-shadow var(--d-2);
}
.tokfield__editor:hover { border-color:var(--line-control); }
.tokfield__editor:focus-visible, .tokfield__editor:focus {
  outline:none; border-color:var(--accent); box-shadow:0 0 0 3px var(--accent-soft);
}

/* a chip reads as an object: it has a surface, a border and its own remove */
.tok {
  display:inline-flex; align-items:center; gap:1px;
  margin:0 1px; padding:1px 2px 1px 6px; border-radius:var(--r-sm);
  background:var(--accent-soft); border:1px solid var(--accent-line);
  color:var(--accent-text); font:600 .875rem/1.5 var(--font-mono);
  white-space:nowrap; vertical-align:baseline; user-select:none;
}
.tok__name::before { content:"{{"; opacity:.55; }
.tok__name::after  { content:"}}"; opacity:.55; }
.tok__x {
  display:grid; place-items:center; inline-size:16px; block-size:16px;
  padding:0; border:0; border-radius:var(--r-xs); cursor:pointer;
  background:transparent; color:inherit; font:600 .875rem/1 var(--font-ui); opacity:.6;
}
.tok__x:hover { background:var(--accent); color:#fff; opacity:1; }
.tok__x:focus-visible { outline:2px solid var(--accent); outline-offset:1px; opacity:1; }

/* an authoring placeholder is a decision still to be made, not an error — it
   gets attention, not the error colour */
.tok--unresolved {
  background:color-mix(in srgb, var(--warn, #B45309) 14%, transparent);
  border-color:color-mix(in srgb, var(--warn, #B45309) 45%, transparent);
  color:color-mix(in srgb, var(--warn, #B45309) 88%, var(--ink-1));
  border-style:dashed;
}
/* `{{name|default}}` is not a live token but it does render, so it reads as
   neutral rather than as something you must fix */
.tok--fallback { background:var(--surface-3); border-color:var(--line-2); color:var(--ink-2); }

/* The same four colours as the token panel, applied to a token already written
   into a question. Tinting the chip's own border and text rather than filling it
   keeps the wording around it readable — the point is to see at a glance which
   KIND of value sits in the sentence, not to decorate it. */
.tok[data-group="current"]   { border-color:var(--cat-current);  color:var(--cat-current); }
.tok[data-group="previous"]  { border-color:var(--cat-previous); color:var(--cat-previous); }
.tok[data-group="last_year"] { border-color:var(--cat-lastyear); color:var(--cat-lastyear); }
.tok[data-group="parts"]     { border-color:var(--cat-parts);    color:var(--cat-parts); }
.tok[data-group] { border-inline-start-width:3px; }

.tokfield__bar { display:flex; align-items:center; gap:8px; margin-top:6px; }
.tokfield__toggle {
  padding:4px 8px; border-radius:var(--r-sm); cursor:pointer;
  background:var(--surface-2); border:1px solid var(--line-1); color:var(--ink-3);
  font:500 .75rem var(--font-ui);
}
.tokfield__toggle:hover { border-color:var(--accent-line); color:var(--accent-text); }
.tokfield__hint { font:500 .75rem var(--font-ui); color:var(--ink-4); }
.tokfield__hint.is-warn { color:var(--warn, #B45309); }

/* raw mode is the plain textarea, shown in place of the editor */
.tokfield.is-raw .tokfield__native {
  position:static; inline-size:100%; block-size:auto; opacity:1; pointer-events:auto;
  clip-path:none; overflow:visible; padding:8px 12px; border:1px solid var(--line-2);
  border-radius:var(--r-md); background:var(--surface-2); color:var(--ink-1);
  font:400 .875rem/1.6 var(--font-mono); resize:vertical;
}
.tokfield.is-raw .tokfield__native:focus { outline:none; border-color:var(--accent); box-shadow:0 0 0 3px var(--accent-soft); }
.tokfield.is-raw .tokfield__editor { display:none; }

/* the live preview under the field */
.tok-missing {
  padding:0 4px; border-radius:var(--r-xs); font-weight:600;
  background:color-mix(in srgb, var(--warn, #B45309) 16%, transparent);
  color:color-mix(in srgb, var(--warn, #B45309) 88%, var(--ink-1));
}

@media (prefers-reduced-motion: reduce) { .tokfield__editor, .tok { transition:none; } }
@media (forced-colors: active) {
  .tok { border:1px solid CanvasText; forced-color-adjust:none; }
  .tokfield__editor { border:1px solid CanvasText; }
}

/* ── inline edit ─────────────────────────────────────────────────────────────
   Text you can click and change where it sits. The affordance has to be
   discoverable without being noisy, so the resting state is plain text with a
   faint dotted underline, and the full treatment appears on hover or focus. */
.iedit {
  cursor:text; border-radius:5px; padding:1px 4px; margin:-1px -4px;
  border-bottom:1px dashed transparent;
  transition:background var(--d-2), border-color var(--d-2), color var(--d-2);
}
.iedit:hover { background:var(--surface-2); border-bottom-color:var(--line-control); }
.iedit:focus-visible { outline:2px solid var(--accent); outline-offset:2px; background:var(--surface-2); }

.iedit__input {
  font:inherit; color:var(--ink-1); box-sizing:border-box;
  padding:2px 6px; border-radius:7px;
  border:1px solid var(--accent); background:var(--surface-1);
  box-shadow:0 0 0 3px var(--accent-soft);
  outline:none; min-width:120px; max-width:100%;
}
.iedit__input.is-saving { opacity:.6; }
.iedit__input.is-error { border-color:var(--down); box-shadow:0 0 0 3px var(--down-soft); }
textarea.iedit__input { resize:vertical; line-height:1.55; }

.iedit__note {
  margin-left:8px; padding:1px 6px; border-radius:999px;
  font:600 .75rem var(--font-ui); white-space:nowrap;
}
.iedit__note--ok { background:var(--accent-soft); color:var(--accent-text); border:1px solid var(--accent-line); }
.iedit__note--error { background:var(--down-soft); color:var(--down); border:1px solid color-mix(in srgb,var(--down) 35%,transparent); }

@media (prefers-reduced-motion: reduce) { .iedit { transition:none; } }
@media (forced-colors: active) { .iedit:hover { border-bottom-color:CanvasText; } }

/* ── confirm modal ───────────────────────────────────────────────────────────
   A destructive action asks first. Built here rather than window.confirm(),
   which cannot be themed and ignores dark mode. */
.cf { position:fixed; inset:0; z-index:200; display:grid; place-items:center; padding:20px; }
.cf__scrim { position:absolute; inset:0; background:rgba(6,10,16,.55); backdrop-filter:blur(2px); }
.cf__box {
  position:relative; inline-size:min(440px,100%); box-sizing:border-box;
  background:var(--surface-1); border:1px solid var(--line-2); border-radius:16px;
  padding:20px 24px; box-shadow:0 24px 60px rgba(3,8,16,.35);
  animation:cf-in .16s cubic-bezier(.2,.8,.3,1);
}
@keyframes cf-in { from { opacity:0; transform:translateY(6px) scale(.98); } }
.cf__title { margin:0 0 8px; font:600 1.125rem/1.25 var(--font-display); letter-spacing:-.02em; color:var(--ink-1); }
.cf__body { margin:0 0 20px; font:400 .9375rem/1.6 var(--font-ui); color:var(--ink-2); }
.cf__row { display:flex; gap:8px; justify-content:flex-end; }
@media (prefers-reduced-motion: reduce) { .cf__box { animation:none; } }

/* ── keyboard shortcut list ──────────────────────────────────────────────────
   Opened with `?`. A custom panel, not alert(). Shortcuts have to be
   discoverable or nobody uses them, and WCAG 2.1.4 requires they be switchable
   off — the switch lives in here and in the header. */
.ks { position:fixed; inset:0; z-index:200; display:grid; place-items:center; padding:20px; }
.ks__scrim { position:absolute; inset:0; background:rgba(6,10,16,.55); backdrop-filter:blur(2px); }
.ks__box {
  position:relative; inline-size:min(430px,100%); box-sizing:border-box;
  background:var(--surface-1); border:1px solid var(--line-2); border-radius:16px;
  padding:20px 24px; box-shadow:0 24px 60px rgba(3,8,16,.35);
}
.ks__head { display:flex; align-items:center; gap:12px; margin-bottom:16px; }
.ks__head h2 { margin:0; font:600 1.125rem/1.25 var(--font-display); letter-spacing:-.02em; color:var(--ink-1); }
.ks__x {
  margin-left:auto; inline-size:30px; block-size:30px; display:grid; place-items:center;
  border:1px solid var(--line-1); border-radius:9px; background:var(--surface-2);
  color:var(--ink-2); font:600 1rem/1 var(--font-ui); cursor:pointer;
}
.ks__x:hover { border-color:var(--accent-line); color:var(--accent-text); }
.ks__list { margin:0 0 16px; display:flex; flex-direction:column; gap:2px; }
.ks__list > div { display:flex; align-items:center; gap:12px; padding:6px 0; border-bottom:1px solid var(--line-1); }
.ks__list > div:last-child { border-bottom:0; }
.ks__list dt { flex:0 0 122px; display:flex; gap:4px; align-items:center; }
.ks__list dd { margin:0; font:var(--t-sm); color:var(--ink-2); }
kbd {
  display:inline-block; min-inline-size:24px; padding:2px 6px; text-align:center;
  background:var(--surface-2); border:1px solid var(--line-2); border-bottom-width:2px;
  border-radius:6px; font:600 .75rem/1 var(--font-mono); color:var(--ink-1);
}
.ks__note { margin:0 0 12px; font:var(--t-xs); color:var(--ink-3); line-height:1.6; }
.ks .btn { width:100%; }

/* the header switch shows its state, so "off" is never a mystery */
[data-shortcut-toggle] .is-off, [data-shortcut-toggle][aria-pressed="false"] { color:var(--ink-4); }
@media (forced-colors: active) { kbd { border:1px solid CanvasText; } }

/* ── offline indicator ───────────────────────────────────────────────────────
   Says plainly what is happening and what to do. An interviewer on one bar needs
   to know their work is safe, not to guess. */
.ol {
  position:fixed; inset-block-end:0; inset-inline:0; z-index:90;
  display:flex; align-items:center; gap:8px;
  padding:11px var(--gutter); 
  background:var(--surface-inverse); color:#fff;
  font:500 .8125rem/1.4 var(--font-ui);
  box-shadow:0 -6px 18px rgba(3,8,16,.22);
}
.ol[hidden] { display:none; }
.ol__dot { inline-size:8px; block-size:8px; border-radius:50%; flex:none; background:var(--warn); }
.ol[data-state="offline"] .ol__dot { background:#FF9B90; }
.ol[data-state="pending"] .ol__dot { background:#6FD79B; animation:ol-pulse 1.6s ease-in-out infinite; }
@keyframes ol-pulse { 50% { opacity:.35; } }
.ol__btn {
  margin-inline-start:auto; padding:6px 12px; border-radius:8px; cursor:pointer;
  background:rgba(255,255,255,.14); border:1px solid rgba(255,255,255,.22); color:#fff;
  font:600 .8125rem var(--font-ui);
}
.ol__btn:hover { background:rgba(255,255,255,.22); }
.ol__btn:focus-visible { outline:2px solid #fff; outline-offset:2px; }
@media (prefers-reduced-motion: reduce) { .ol[data-state="pending"] .ol__dot { animation:none; } }
@media (forced-colors: active) { .ol { border-top:1px solid CanvasText; } }

/* ── emphasised subject inside a question ────────────────────────────────────
   Question templates write their subject in capitals — "Were NEW ORDERS or
   DEMAND for your services in …". That emphasis is meaningful: it names the
   thing being measured. Rendered as plain text it disappears into the sentence,
   so it is carried through as weight instead of being left as shouting.
   Period tokens resolve AFTER the marking, so dates never get bolded. */
.q-em {
  font-weight:700;
  color:var(--ink-1);
  letter-spacing:-.006em;
}
/* in the runner the label is already the focus; a touch less weight there */
.sv-q__label .q-em { font-weight:700; }

@media (forced-colors: active) { .q-em { font-weight:700; } }
