/* app/shared/tokens.css: every constant the two shells share, defined once.

   Layers, in order:
     1. Constants that do not vary by theme: fonts, the type scale, space, radii,
        the 44px target floor, layout widths, motion durations.
     2. Semantic colour tokens named for the ROLE (--surface, --text-muted), never the
        value. LIGHT is the base definition: the owner decision is a light canvas with one
        accent (benchmark: mintlify) and a dark toggle a person chooses.
     3. Dark, under [data-theme="dark"] on <html>. Only the toggle sets it; the OS
        preference is not consulted, so the default is the same on every device.
        app/shared/theme.ts owns the attribute, and the inline script in each shell's
        index.html sets it before first paint from localStorage "paideia:theme".

   THE TYPE SCALE IS THREE SIZES PER SURFACE, PLUS ONE HERO. NN/g puts the ceiling at
   three: large for the one thing that matters, medium for supporting context, small for
   chrome. --fs-hero is the North Star (the studio's revenue, the learner's Continue card)
   and appears once on a screen. A component that needs a fourth size is a component that
   is doing two jobs. Sizes are rem so the reader's browser font size scales the UI
   (WCAG 1.4.4); inputs sit at 1rem so iOS does not zoom on focus.

   MOTION IS GATED. Under prefers-reduced-motion every duration below collapses to 0ms and
   base.css stops animations globally, so nothing has to remember to opt out. A component
   that must still communicate under reduced motion (the completion ring) does so with
   opacity or a static state change, never with movement. */

:root {
  color-scheme: light;

  /* THE FIRST NAME IN THIS LIST IS DELIBERATELY NOT A WEBFONT. The stack read
     "Inter", ... and nothing in this repo ever served Inter, so the product rendered in
     whatever each machine happened to have: San Francisco for most people, Inter for the
     handful who install it for other work, and those two set different metrics. A name we
     do not ship is not a typeface choice, it is a difference nobody can reproduce.
     system-ui is the reader's own interface face, it is already resident, it costs no
     request and no layout shift, and it is what the dark toggle and the 44px targets were
     measured against. If a licensed face is ever vendored it goes in front of system-ui
     here and nowhere else, with the file in public/fonts and its licence in the repo. */
  --font-sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial,
    "Noto Sans", sans-serif;
  --font-mono: ui-monospace, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;

  /* Type: three working sizes per surface, plus the hero. */
  /* The FLOOR is 2.75rem and not 2.5rem, because the floor is what every phone gets. The
     clamp bottoms out below a 457px viewport, so the North Star was 40px against a 22px
     --fs-lg, which is 1.82x: under the 2x this file's own section 2 of DESIGN.md claims and
     under the doctrine's 2 to 3x. It read correctly on a laptop (2.72x at 1024px), which is
     why it survived. 44px against 22px is exactly 2.0x and the ceiling is untouched. */
  --fs-hero: clamp(2.75rem, 1.5rem + 3.5vw, 3.75rem);
  --fs-lg: 1.375rem;
  --fs-md: 1rem;
  --fs-sm: 0.8125rem;
  --lh-tight: 1.15;
  --lh-body: 1.5;

  /* Space. Whitespace is the tool that makes cards read as separate rooms (Gestalt:
     common region), so it is a scale and not a per-component guess. */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 20px;
  --sp-6: 24px;
  --sp-7: 32px;
  --sp-8: 48px;

  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 16px;
  --radius-pill: 999px;

  /* Every control a finger or a pointer lands on is at least this on both axes
     (WCAG 2.5.5 at the AAA figure, which is the one a phone in one hand needs). */
  --target-min: 44px;

  /* Layout */
  --sidebar-width: 240px;
  --topbar-height: 64px;
  --bottom-bar-height: 60px;
  --content-max: 1120px;
  --reading-max: 880px;

  /* Motion */
  --motion-fast: 150ms;
  --motion-base: 200ms;
  --motion-drawer: 300ms;
  --ease: cubic-bezier(0.2, 0, 0, 1);

  /* Surfaces */
  --canvas: #F8FAFB;
  --surface: #FFFFFF;
  --surface-raised: #FFFFFF;
  --surface-subtle: #F1F5F9;
  --hover: rgba(15, 23, 42, 0.04);
  --overlay: rgba(15, 23, 42, 0.45);

  /* Lines */
  --border: #E2E8F0;
  /* 3.38:1 on --surface and 3.23:1 on --canvas. It was #CBD5E1, which is 1.48:1 and 1.42:1,
     under WCAG 1.4.11's 3:1 floor for a control boundary. This is the resting border of every
     input, select, colour swatch and chip in both wizards, so a low-vision reader could not
     see where a field began until they focused it. Found by the design council, 2026-09-11. */
  --border-strong: #7C8DA6;

  /* Text. --text-muted is #5B6B80 and not the slate-500 it started as: #64748B measured
     4.57:1 on --canvas, which is a pass with no room, and muted text sits on the canvas
     under every KPI label. #5B6B80 is 5.2:1 there and 5.4:1 on white. */
  --text: #0F172A;
  --text-secondary: #475569;
  --text-muted: #5B6B80;

  /* Accent. One accent, teal, used as ink (links, the active nav item, icons) and as the
     primary fill. #0F766E takes white on top at 5.5:1, so ink and fill can be the same
     value here; dark mode has to split them (see below). */
  --accent: #0F766E;
  --accent-solid: #0F766E;
  --accent-contrast: #FFFFFF;
  --accent-hover: #115E59;
  --accent-soft: rgba(15, 118, 110, 0.08);
  --accent-ring: rgba(15, 118, 110, 0.35);

  /* Status. Green is done or healthy, amber needs attention, red is an alert. Never
     decoration. All four pass 4.5:1 on white as text. */
  --success: #047857;
  --warn: #B45309;
  --danger: #B91C1C;
  --info: #1D4ED8;

  /* The tint behind a callout, one per status, matching --accent-soft's job for the accent.
     They exist because base.css wrote these as bare rgba() literals mixed from the LIGHT
     palette, so a note, a tip and a warning kept a light background in dark mode. A tint is
     re-picked per theme exactly like the accent it sits under. */
  --success-soft: rgba(4, 120, 87, 0.09);
  --warn-soft: rgba(180, 83, 9, 0.09);

  --shadow-card: 0 1px 2px rgba(15, 23, 42, 0.04);
  --shadow-pop: 0 20px 50px rgba(15, 23, 42, 0.18);
}

/* Dark. Not a filter over the light values: the accent is re-picked. #0F766E reads
   2.9:1 on a dark surface, so the ink becomes #2DD4BF (9.4:1 on --surface) and the fill
   #14B8A6 carries dark text (#042F2E, 5.8:1) instead of white. */
:root[data-theme="dark"] {
  color-scheme: dark;

  --canvas: #0B1220;
  --surface: #111A2B;
  --surface-raised: #182338;
  --surface-subtle: rgba(255, 255, 255, 0.04);
  --hover: rgba(255, 255, 255, 0.05);
  --overlay: rgba(0, 0, 0, 0.55);

  --border: rgba(148, 163, 184, 0.16);
  /* 3.28:1 on --surface and 3.36:1 on --canvas once flattened. It was alpha 0.28, which is
     1.67:1 and 1.66:1. Same 1.4.11 failure as the light value, and the alpha is why neither
     showed up in a naive hex comparison. */
  --border-strong: rgba(148, 163, 184, 0.6);

  --text: #F1F5F9;
  --text-secondary: #A7B3C5;
  --text-muted: #8B99AE;

  --accent: #2DD4BF;
  --accent-solid: #14B8A6;
  --accent-contrast: #042F2E;
  --accent-hover: #2DD4BF;
  --accent-soft: rgba(45, 212, 191, 0.12);
  --accent-ring: rgba(45, 212, 191, 0.4);

  --success: #34D399;
  --warn: #FBBF24;
  --danger: #F87171;
  --info: #60A5FA;

  --success-soft: rgba(52, 211, 153, 0.12);
  --warn-soft: rgba(251, 191, 36, 0.12);

  --shadow-card: none;
  --shadow-pop: 0 24px 60px rgba(0, 0, 0, 0.55);
}

/* Reduced motion, gated at the token: every transition in both shells reads a duration
   from here, so this one block silences all of them. base.css adds the global animation
   stop for anything that did not read a token. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --motion-fast: 0ms;
    --motion-base: 0ms;
    --motion-drawer: 0ms;
  }
}
