/* tokens.css — SPEC §5.1.
 *
 * This is the ONLY file under webapp/app/ that defines a custom property or a
 * literal colour. Everything else reads `var(--…)`. Cascade position: first.
 *
 * The dark palette is declared TWICE, with an identical property set and
 * identical values: once inside `@media (prefers-color-scheme: dark)` guarded by
 * `:root:not([data-theme="light"])` so an explicit Light choice wins over the
 * system, and once as `:root[data-theme="dark"]` so an explicit Dark choice wins
 * over a light system. tests/lint.js asserts the two blocks stay identical.
 */

:root {
  color-scheme: light;

  /* ── colour — light is the base definition ─────────────────────────────── */
  --bg: #fbfbfa;
  --bg-subtle: #f4f4f2;
  --bg-inset: #eeeeec;
  --surface: #ffffff;
  --surface-hover: #f7f7f5;
  --border: #e2e2dd;
  --border-strong: #878783; /* §5.1 said #c9c9c2 — see "contrast" below */
  --text: #1a1a17;
  --text-muted: #5f5f57;
  --text-faint: #6b6b64; /* §5.1 said #8a8a80 — see "contrast" below */
  --accent: #2f6f4f;
  --accent-hover: #255a40;
  --accent-fg: #ffffff;
  --accent-subtle: #e8f2ec;
  --danger: #a32b1f;
  --danger-fg: #ffffff;
  --danger-subtle: #fbeceb;
  --warn: #8a5a00;
  --warn-subtle: #fdf3e0;
  --ok: #2f6f4f;
  --ok-subtle: #e8f2ec;
  --info: #2a5b8f;
  --info-subtle: #e9f0f8;
  --focus: #2f6f4f;
  --selection: #cfe3d8;
  --code-bg: #f4f4f2;
  --code-border: #e2e2dd;
  --mark-bg: #fdf3e0;
  --scrim: rgb(26 26 23 / 0.38);

  /* ── type ──────────────────────────────────────────────────────────────── */
  --font-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, "Noto Sans", sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
    "Liberation Mono", "Courier New", monospace;
  --fs-xs: 12px;
  --fs-sm: 13px;
  --fs-base: 15px;
  --fs-md: 17px;
  --fs-lg: 20px;
  --fs-xl: 25px;
  --fs-2xl: 31px; /* 1.2 minor third */
  --lh-tight: 1.25;
  --lh-base: 1.5;
  --lh-prose: 1.65;
  --fw-normal: 400;
  --fw-medium: 500;
  --fw-semibold: 600;
  --tracking-caps: 0.06em;

  /* ── space (4px base) ──────────────────────────────────────────────────── */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 24px;
  --sp-6: 32px;
  --sp-7: 48px;
  --sp-8: 64px;

  /* ── radius / elevation ────────────────────────────────────────────────── */
  --r-sm: 4px;
  --r-md: 8px;
  --r-lg: 12px;
  --r-xl: 16px;
  --r-full: 999px;
  --sh-1: 0 1px 2px rgb(0 0 0 / 0.05);
  --sh-2: 0 2px 8px rgb(0 0 0 / 0.08);
  --sh-3: 0 8px 32px rgb(0 0 0 / 0.14);

  /* ── motion ────────────────────────────────────────────────────────────── */
  --dur-fast: 120ms;
  --dur-base: 180ms;
  --dur-slow: 280ms;
  --ease-out: cubic-bezier(0.2, 0.8, 0.2, 1);
  --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);

  /* ── layout ────────────────────────────────────────────────────────────── */
  --rail-w: 260px;
  --inspector-w: 340px;
  --measure: 68ch;
  --header-h: 48px;
  --tap: 44px; /* the §5.3 touch-target floor, as a token so no file hard-codes it */
  --z-sticky: 10;
  --z-drawer: 40;
  --z-dialog: 50;
  --z-toast: 60;

  /* ── the two dynamic hooks (§5.4 rule 4) ───────────────────────────────────
   * JS may only ever write these, with a plain number, via
   * el.style.setProperty(). No `style` attribute is built from content.
   *   --pct           0…100  meter fill, usage bar length
   *   --rows          1…n    composer textarea row floor
   *   --pop-x --pop-y <px>   where a popover / coach mark is anchored
   *   --coach-room    <px>   the room a coach mark reserves at the transcript's end
   */
  --pct: 0;
  --rows: 3;
  --pop-x: 0px;
  --pop-y: 0px;
  --coach-room: 0px;
}

/* ── dark #1: the system preference, unless Light was chosen explicitly ───── */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --bg: #16171a;
    --bg-subtle: #1c1e22;
    --bg-inset: #121316;
    --surface: #1f2126;
    --surface-hover: #262930;
    --border: #2e313a;
    --border-strong: #70747d;
    --text: #e8e8e4;
    --text-muted: #a2a49f;
    --text-faint: #8f928b;
    --accent: #63b98c;
    --accent-hover: #7ccba0;
    --accent-fg: #0e1a13;
    --accent-subtle: #1a2b21;
    --danger: #f07a6c;
    --danger-fg: #2a0d09;
    --danger-subtle: #2c1715;
    --warn: #e0a94e;
    --warn-subtle: #2b2113;
    --ok: #63b98c;
    --ok-subtle: #1a2b21;
    --info: #79aee0;
    --info-subtle: #152430;
    --focus: #63b98c;
    --selection: #274634;
    --code-bg: #14161a;
    --code-border: #2e313a;
    --mark-bg: #332a14;
    --scrim: rgb(0 0 0 / 0.62);
    --sh-1: 0 1px 2px rgb(0 0 0 / 0.4);
    --sh-2: 0 2px 8px rgb(0 0 0 / 0.5);
    --sh-3: 0 8px 32px rgb(0 0 0 / 0.6);
  }
}

/* ── dark #2: the explicit choice, identical to the block above ───────────── */
:root[data-theme="dark"] {
  color-scheme: dark;
  --bg: #16171a;
  --bg-subtle: #1c1e22;
  --bg-inset: #121316;
  --surface: #1f2126;
  --surface-hover: #262930;
  --border: #2e313a;
  --border-strong: #70747d;
  --text: #e8e8e4;
  --text-muted: #a2a49f;
  --text-faint: #8f928b;
  --accent: #63b98c;
  --accent-hover: #7ccba0;
  --accent-fg: #0e1a13;
  --accent-subtle: #1a2b21;
  --danger: #f07a6c;
  --danger-fg: #2a0d09;
  --danger-subtle: #2c1715;
  --warn: #e0a94e;
  --warn-subtle: #2b2113;
  --ok: #63b98c;
  --ok-subtle: #1a2b21;
  --info: #79aee0;
  --info-subtle: #152430;
  --focus: #63b98c;
  --selection: #274634;
  --code-bg: #14161a;
  --code-border: #2e313a;
  --mark-bg: #332a14;
  --scrim: rgb(0 0 0 / 0.62);
  --sh-1: 0 1px 2px rgb(0 0 0 / 0.4);
  --sh-2: 0 2px 8px rgb(0 0 0 / 0.5);
  --sh-3: 0 8px 32px rgb(0 0 0 / 0.6);
}

/* ── motion ───────────────────────────────────────────────────────────────
 * Both the OS preference and the Appearance override collapse every duration
 * to 1ms and stop the four things that move on their own.
 */
@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-fast: 1ms;
    --dur-base: 1ms;
    --dur-slow: 1ms;
  }

  .caret,
  .dot--pulse,
  .skeleton,
  .spinner,
  .plan__mark {
    animation: none !important;
  }
}

:root[data-motion="reduce"] {
  --dur-fast: 1ms;
  --dur-base: 1ms;
  --dur-slow: 1ms;
}

:root[data-motion="reduce"] .caret,
:root[data-motion="reduce"] .dot--pulse,
:root[data-motion="reduce"] .skeleton,
:root[data-motion="reduce"] .spinner,
:root[data-motion="reduce"] .plan__mark {
  animation: none !important;
}

/* ── contrast ─────────────────────────────────────────────────────────────
 * Two tokens per palette differ from the §5.1 table, so that §5.5's contract
 * ("≥4.5:1 for body text, ≥3:1 for borders") holds without a media query. Each
 * moved along its own hue — toward black in light, toward white in dark — just
 * past the threshold on EVERY neutral ground (--bg, --bg-subtle, --bg-inset,
 * --surface, --surface-hover, --code-bg), with a 0.1 margin:
 *
 *   --text-faint     light #8a8a80 → #6b6b64   3.00 → 4.62:1 at worst
 *                    dark  #74776f → #8f928b   3.20 → 4.61:1 at worst
 *   --border-strong  light #c9c9c2 → #878783   1.43 → 3.10:1 at worst
 *                    dark  #454a56 → #70747d   1.64 → 3.11:1 at worst
 *
 * --text-faint is real text (timestamps, rail group headings, the Reasoning
 * toggle, .code__lang, .turn__hint), so WCAG 1.4.3 applies. --border-strong
 * draws the edge of a field, a checkbox, a switch and the composer — the
 * boundary WCAG 1.4.11 asks 3:1 for. The ordering text > muted > faint
 * survives (muted is 5.54–6.44 light, 5.79–7.38 dark).
 *
 * --border and --code-border keep their §5.1 values on purpose: they separate
 * content and frame static code, which 1.4.11 does not cover, and raising them
 * would draw every card and table rule as heavily as an input.
 * tests/cases/a11y.js computes every pairing and FAILS if either is ever used
 * to draw a control boundary.
 *
 * Where the user asks for more contrast, every line becomes --text-faint
 * (5.37:1 light / 5.10:1 dark on --surface) and muted text becomes body text.
 * The selector list names both dark selectors ON PURPOSE: a bare `:root` is
 * specificity (0,1,0) and loses to `:root[data-theme="dark"]` and
 * `:root:not([data-theme="light"])`, both (0,2,0) — which is how this block
 * used to be silently switched off in dark. Later in the file, equal
 * specificity, so it wins in every theme.
 */
@media (prefers-contrast: more) {
  :root,
  :root[data-theme="dark"],
  :root:not([data-theme="light"]) {
    --border-strong: var(--text-faint);
    --border: var(--border-strong);
    --code-border: var(--border-strong);
    --text-muted: var(--text);
  }
}

/* ── forced colours ───────────────────────────────────────────────────────
 * A checked radio, checkbox or switch is drawn as a FILL, and a forced
 * background is Canvas, so all of them painted as unselected. components.css
 * opts those inputs out of the repaint; these system colour keywords (never
 * literals) are what they draw with. Same selector list as the contrast block:
 * a bare :root loses to both dark selectors.
 */
@media (forced-colors: active) {
  :root,
  :root[data-theme="dark"],
  :root:not([data-theme="light"]) {
    --accent: Highlight;
    --accent-fg: HighlightText;
    --text-muted: CanvasText;
    --text-faint: GrayText;
    --border-strong: CanvasText;
    --border: GrayText;
    --surface: Canvas;
    --bg-inset: Canvas;
  }
}

/* ── density ──────────────────────────────────────────────────────────────── */
:root[data-density="compact"] {
  --sp-4: 12px;
  --sp-5: 18px;
  --lh-prose: 1.5;
}

/* ── text size: four steps, 0…3 → 14 / 15 / 16 / 18 px base ───────────────── */
:root[data-scale="0"] {
  --fs-xs: 11px;
  --fs-sm: 12px;
  --fs-base: 14px;
  --fs-md: 16px;
  --fs-lg: 18px;
  --fs-xl: 23px;
  --fs-2xl: 29px;
}

:root[data-scale="1"] {
  --fs-xs: 12px;
  --fs-sm: 13px;
  --fs-base: 15px;
  --fs-md: 17px;
  --fs-lg: 20px;
  --fs-xl: 25px;
  --fs-2xl: 31px;
}

:root[data-scale="2"] {
  --fs-xs: 13px;
  --fs-sm: 14px;
  --fs-base: 16px;
  --fs-md: 18px;
  --fs-lg: 21px;
  --fs-xl: 27px;
  --fs-2xl: 33px;
}

:root[data-scale="3"] {
  --fs-xs: 14px;
  --fs-sm: 15px;
  --fs-base: 18px;
  --fs-md: 20px;
  --fs-lg: 24px;
  --fs-xl: 30px;
  --fs-2xl: 37px;
}
