/* ============================================================
   tokens.css — design tokens for "The Price of Europe"
   FT editorial surface x Nadieh Bremer craft. Light is the default.

   ALL colours are HEX. d3 7.9 renders oklch()/color-mix() as BLACK inside
   a colour scale (this silently broke the Heatmap for ten sessions — see
   MASTER-PLAN PART 3). palette.js reads these with getComputedStyle().
   The one color-mix() token (--accent-veil) is CSS-only and never fed to d3.
   Theme switches via [data-theme="dark"] on <html>.
   ============================================================ */

:root {
  /* Surface — FT paper system */
  --bg              : #FFF1E5;   /* FT paper */
  --bg-elev         : #FFF7EF;   /* raised card / sticky panel (rarely framed) */
  --bg-sunken       : #F2DFCE;   /* wheat — code / side panels */
  --bg-veil         : rgba(255,241,229,0.86);   /* fixed-header backdrop */
  --bg-overlay      : rgba(255,241,229,0.96);

  /* Ink — FT black-N over paper */
  --ink             : #33302E;   /* body, 11.83:1 */
  --ink-strong      : #000000;   /* h1–h3 + hero numbers only */
  --ink-soft        : #4D4845;   /* source lines, captions, 8.15:1 */
  --ink-faint       : #807973;   /* >=18px text or graphics only, 3.87:1 */
  --ink-fainter     : #B3A9A0;   /* context lines, NEVER text */
  --ink-invert      : #FFF1E5;

  /* Lines / gridline */
  --rule            : #CCC1B7;   /* black-20; doubles as the horizontal gridline */
  --rule-soft       : #E6D9CE;
  --rule-bold       : #66605C;

  /* Editorial accent — claret is the ONE emphasis colour (focus only) */
  --accent          : #990F3D;   /* claret, 7.62:1 */
  --accent-text     : #990F3D;
  --accent-bright   : #CC1452;   /* hover / bright moments */
  --accent-rose     : #EB5E8D;   /* FT rose — strokes >=3px or fills ONLY, never text (2.91:1) */
  --accent-soft     : #D9A4B0;   /* soft claret wash — thin dashed leaders */
  --accent-veil     : color-mix(in srgb, var(--accent) 8%, transparent); /* CSS-only, never fed to d3 */
  /* [P6.4] Every color-mix() in the project now lives in this file. The values are the literals
     they replace, character for character — this pass moves colour OUT of the rule files, it does
     not retune anything. Keeping them here is what makes the D15 rule enforceable: a chart rule
     can no longer grow a color-mix() that someone later hands to a d3 scale, where it renders
     black. Each mixes a theme-aware token, so one definition serves light and dark. */
  --veil-non-eu-map   : color-mix(in srgb, var(--ink-faint) 14%, transparent);  /* choropleth */
  --ring-thumb        : color-mix(in srgb, var(--accent) 18%, transparent);     /* range thumb */
  --ring-thumb-hover  : color-mix(in srgb, var(--accent) 14%, transparent);
  /* [P8.2] The ledger's 2022 trough dot. It has to read as a MEMORY next to the solid endpoint
     dot, but it carries half the chart's information, so it is a graphic under WCAG 1.4.11 and
     owes 3:1 — which claret at the 0.34 fill-opacity it started at does not give (1.91:1 light,
     1.35:1 dark). Flat hex per theme instead of an opacity: light is claret at 60% over paper,
     dark is FT rose over slate, because dark claret tops out at 3.24:1 even at full strength. */
  --db-trough         : #C26980;
  --link              : #0D7680;   /* FT teal, 4.84:1 — links / controls / focus rings */
  --link-underline    : color-mix(in srgb, var(--link) 30%, transparent);
  --link-hover      : #08474D;

  /* Sequential severity ramp — GREEN -> AMBER -> RED (owner override, 2026-06-15).
     Low inflation = green (calm/good), high = red (bad). RdYlGn-style. seq encodes severity;
     claret encodes focus — DECOUPLED. Colour vision, MEASURED (D115, docs/accessibility_audit.md,
     tools/shoot-cvd.mjs): NOT colour-blind-safe at the ends. Lightness peaks at amber, so the
     ramp orders by lightness only on one side of it; under simulated deuteranopia / protanopia
     the green and red ends converge (closest calm-vs-severe CIEDE2000 5.6 / 2.5, against 55 for
     normal vision). The 2022 map, all on the darkening side, still orders; the heatmap does not. */
  --seq-1 : #1A9850;   /* low / sub-target — green */
  --seq-2 : #A6D96A;   /* near target — lime */
  --seq-3 : #FEE08B;   /* elevated 3–5% — amber */
  --seq-4 : #F46D43;   /* high 5–10% — orange-red */
  --seq-5 : #D73027;   /* extreme >10% — red */
  --seq-target : #0F5499;   /* ECB 2% reference — FT oxford, 6.90:1 */
  /* [debug 2026-07-06] seq-1/seq-4 read fine as large MAP FILL patches (their whole point is
     hue-coded severity, not text contrast) but fail WCAG AA as small TEXT fill — measured 3.36:1 /
     2.67:1 against --bg, both under the 4.5:1 small-text bar (the choropleth kicker's "▲ RO 3.9%" /
     "▼ PT 0.3%" extreme-country lines use these as `fill`, at 11.5px — text, not a colour patch).
     Same pattern as --accent-text below: a darker, same-hue variant, text-safe, for when a severity
     colour needs to render AS TEXT rather than as a shape. */
  --seq-hi-text : #B8431A;   /* darker seq-4 orange, 4.92:1 */
  --seq-lo-text : #157A40;   /* darker seq-1 green, 4.88:1 */

  /* Comparison-line palette (AMENDMENT-2 §B.8) — country lines in selection order; EU stays claret.
     [debug 2026-07-06] Extended 4→10 for the country-groups feature (a shared 10-slot cap across
     individual countries + groups, each slot its own hue). 5-10 checked ≥4.5:1 against --bg. */
  --cmp-1 : #0F5499;   /* oxford */
  --cmp-2 : #0D7680;   /* teal */
  --cmp-3 : #593380;   /* velvet */
  --cmp-4 : #806B00;   /* olive-dark */
  --cmp-5 : #2E6B4F;   /* forest, 5.69:1 */
  --cmp-6 : #B5502E;   /* rust, 4.57:1 */
  --cmp-7 : #4C5B66;   /* slate, 6.33:1 */
  --cmp-8 : #8A6416;   /* gold, 4.84:1 */
  --cmp-9 : #8A3E63;   /* plum, 6.43:1 */
  --cmp-10: #6B4226;   /* cocoa, 7.80:1 */

  /* Categorical — FT g-chartcolour. LOCK these; a category keeps its hue in EVERY chart. */
  --cat-overall   : #33302E;
  --cat-energy    : #FF8833;   /* mandarin — the "orange wall" */
  --cat-food      : #9DBF57;
  --cat-housing   : #208FCE;
  --cat-services  : #593380;   /* velvet */
  --cat-wages     : #00994D;   /* jade, 3.35:1 — a line/fill/large-number colour, NOT small text */
  /* [D93] jade AS TEXT. Exactly the --accent-text / --seq-lo-text pattern: a darker, same-hue
     (150deg, fully saturated) variant for when the wages series must render as a small LABEL
     rather than as a stroke. Needed because P2.1 makes the race chart's 12px "Pay 150" end name
     actually take its series colour for the first time, and --cat-wages measures 3.35:1 on paper
     — under the 4.5:1 small-text bar. The big kickers (44px/40px) keep pure --cat-wages: at
     large-text size 3:1 is the bar and 3.35 clears it. */
  --cat-wages-text: #007A3D;   /* darker jade, 4.92:1 */
  --cat-transport : #70DCE6;
  /* [D90-I3] Café & restaurants (CP11) gets its OWN hue at last. It had been coloured three
     different ways — housing blue in CH2, --cat-other grey in the CH6 bars, services violet in
     palette.js — which broke the "a category keeps its hue in EVERY chart" lock above. Tobacco:
     warm (it should read as coffee), 5.30:1 on paper, and separated from the neighbouring
     mandarin --cat-energy by LIGHTNESS and saturation rather than hue (30° vs 25°, but L 35%
     vs 60% and far less saturated) — the warm end of the wheel has no free hue slot that is not
     already claret. Every consumer labels the series directly, and the two only ever sit
     adjacent in the CH6 bar rows, where bright mandarin vs dark tobacco is unmistakable. */
  --cat-restaurants: #8A5A2B;
  --cat-other     : #C2B7AF;

  /* Coin metals (hero, PART 7) */
  --coin-gold-hi    : #F6E4B8;  --coin-gold    : #C8923D;  --coin-gold-lo    : #7A5A22;
  --coin-tarnish-hi : #D8D2C8;  --coin-tarnish : #B3A9A0;  --coin-tarnish-lo : #857F77;

  /* Receipt hero (D43) — the receipt is a lit physical object; its ink does NOT flip in dark
     mode (a real receipt stays printed). All hex (D15). Stamp = claret ink ON the receipt. */
  --receipt-paper    : #FBF7F1;
  --receipt-ink      : #211E1C;   /* near-black print — beats halation when the page goes dark */
  --receipt-ink-soft : #6B635C;
  --receipt-rule     : #D9CFC4;
  --receipt-stamp    : #990F3D;

  /* Event bands — flat FT tints behind line charts (rgba, never color-mix) */
  --event-covid   : rgba(204,230,255,.30);   /* sky */
  --event-energy  : rgba(255,136,51,.12);     /* mandarin */
  --event-policy  : rgba(15,84,153,.10);      /* oxford */
  --event-food    : rgba(150,204,40,.10);     /* wasabi */

  /* Country-spread envelope — neutral ink wash (reads as context; never competes with claret). */
  --anno-spread-fill : rgba(51,48,46,.072);
  --anno-spread-edge : rgba(51,48,46,.20);

  /* House grey-down level for non-focused marks (claret stays reserved for the focus). */
  --dim-nonfocus : 0.25;

  /* Typography stacks — FT voice: upright, authoritative. (Fraunces/Inter retired.) */
  --font-display  : "Source Serif 4", Georgia, "Times New Roman", serif;
  --font-body     : Georgia, "Times New Roman", serif;
  --font-ui       : "Schibsted Grotesk", "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-mono     : "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;

  /* Type scale (modular 1.250) */
  --fs-100 : 0.750rem;
  --fs-200 : 0.875rem;
  --fs-300 : 1.000rem;
  --fs-400 : 1.125rem;
  --fs-500 : 1.250rem;
  --fs-600 : 1.563rem;
  --fs-700 : 1.953rem;
  --fs-800 : 2.441rem;
  --fs-900 : 3.052rem;
  --fs-max : 3.815rem;

  /* Line heights */
  --lh-tight    : 1.10;
  --lh-snug     : 1.25;
  --lh-normal   : 1.55;
  --lh-relaxed  : 1.70;

  /* Spacing (4 px base) */
  --space-1  : 0.25rem;
  --space-2  : 0.50rem;
  --space-3  : 0.75rem;
  --space-4  : 1.00rem;
  --space-5  : 1.25rem;
  --space-6  : 1.50rem;
  --space-7  : 2.00rem;
  --space-8  : 2.50rem;
  --space-9  : 3.50rem;
  --space-10 : 5.00rem;
  --space-11 : 7.00rem;
  --space-12 : 10.0rem;

  /* Radii */
  --radius-1 : 2px;
  --radius-2 : 6px;
  --radius-3 : 12px;
  --radius-4 : 24px;

  /* Shadows (light-friendly, paper feel) */
  --shadow-1 : 0 1px 0 rgba(51,48,46,.04), 0 0 1px rgba(51,48,46,.08);
  --shadow-2 : 0 4px 14px rgba(51,48,46,.06), 0 1px 2px rgba(51,48,46,.05);
  --shadow-3 : 0 18px 40px rgba(51,48,46,.10), 0 6px 12px rgba(51,48,46,.06);

  /* Motion — tokens are the source of truth; never hardcode ms in CSS or JS */
  --ease-out        : cubic-bezier(.2,.7,.2,1);
  --ease-in-out     : cubic-bezier(.65,0,.35,1);
  --ease-spring     : cubic-bezier(.3,1.4,.4,1);
  --ease-emphasized : cubic-bezier(.05,.7,.1,1);  /* M3 emphasized-decelerate — premium chart-enter */
  --ease-accel      : cubic-bezier(.3,0,.8,.15);  /* exits — faster than enters */
  --dur-1 : 120ms;
  --dur-2 : 180ms;
  --dur-3 : 280ms;
  --dur-4 : 420ms;
  --dur-5 : 640ms;
  --dur-6 : 900ms;

  /* Canonical motion vocabulary (house set). The granular --dur-1..6 stay for per-chart d3 timings. */
  --motion-fast            : 180ms;   /* feedback, hovers, small toggles */
  --motion-base            : 280ms;   /* enters/exits, theme + chart-mode transitions */
  --motion-slow            : 640ms;   /* larger reveals, camera moves */
  --motion-ease            : var(--ease-out);
  --motion-ease-emphasized : var(--ease-in-out);

  /* Layout widths */
  --w-prose    : 38rem;
  --w-content  : 64rem;
  --w-wide     : 78rem;
  --w-full     : 96rem;

  /* Z-index — every fixed layer on the page, in stacking order, so a new one can be placed by
     reading this list instead of by grepping for the highest number in use. */
  --z-dock     : 40;    /* phone step dock */
  --z-header   : 50;
  --z-popover  : 60;    /* InfoPop */
  --z-tooltip  : 90;
  --z-modal    : 100;

  /* Shadows for the three fixed surfaces. NOT folded into --shadow-1..3: those are warm
     (rgba(51,48,46,...)) and these are neutral black, so reusing them would retune three
     surfaces during a hygiene pass. The mismatch is real and logged as a candidate; the values
     here are the literals, unchanged. */
  --shadow-pop  : 0 8px 30px rgba(0, 0, 0, 0.18);   /* InfoPop */
  --shadow-dock : 0 -2px 28px rgba(0, 0, 0, .14);   /* phone dock — throws UPWARD */
  --shadow-rail : 0 1px 6px rgba(0, 0, 0, 0.08);    /* step rail */
}

/* ============================================================
   Dark theme — [data-theme="dark"]. FT slate (warm-dark, no pure black).
   Kept as an opt-in; CONTRAST-TUNED in Phase 17 after light is perfect.
   ============================================================ */

[data-theme="dark"] {
  --bg              : #262A33;   /* FT slate */
  --bg-elev         : #2E333D;
  --bg-sunken       : #1F242C;
  --bg-veil         : rgba(38,42,51,0.90);
  --bg-overlay      : rgba(38,42,51,0.96);

  --ink             : #FFF1E5;   /* 12.98:1 */
  --ink-strong      : #FFFFFF;
  --ink-soft        : #D5C9BC;
  --ink-faint       : #9A938B;
  --ink-fainter     : #847E76;   /* context lines (never text); 3.58:1 (P17; was #6B6660 = 2.53, sub-AA) */
  --ink-invert      : #262A33;

  --rule            : #3D434E;
  --rule-soft       : #333842;
  --rule-bold       : #8A847C;

  --accent          : #E22A5C;   /* claret-bright for the slate ground — focus mark, 3.23:1 (P17; was #CC1452 = 2.59, sub-AA) */
  --accent-text     : #EE6993;   /* rose AS TEXT on slate, 4.84:1 (P17; was #EB5E8D = 4.46, a hair under AA) */
  --accent-bright   : #EE6993;   /* hover / bright graphic — unified rose */
  --accent-rose     : #EE6993;   /* strokes >=3px / fills */
  --accent-soft     : #7A2540;
  --accent-veil     : color-mix(in srgb, var(--accent) 14%, transparent);
  --link            : #5BC0C9;
  --link-hover      : #9BE0E6;

  /* GREEN -> AMBER -> RED severity ramp (owner override) brightened for the slate ground
     so every step clears AA non-text contrast on dark (hex — see D15). */
  --seq-1 : #3CB371;   /* green, lifted off slate */
  --seq-2 : #B6E07A;   /* lime */
  --seq-3 : #FEE08B;   /* amber (already bright) */
  --seq-4 : #FB8C5A;   /* orange-red, lifted */
  --seq-5 : #F2564B;   /* red, lifted for >=3:1 on slate */
  --seq-target : #5BA3E0;
  /* [debug 2026-07-06] dark seq-1/seq-4 already clear 4.5:1 as text (5.39/6.16, see
     tools/check-dark-contrast.mjs), so text-safe = the same values here, unlike light theme. */
  --seq-hi-text : #FB8C5A;
  --seq-lo-text : #3CB371;

  /* Comparison-line palette (AMENDMENT-2 §B.8) — dark theme. 5-10 added alongside the light set. */
  --cmp-1 : #5BA3E0;
  --cmp-2 : #3FB8C4;
  --cmp-3 : #A98FD6;
  --cmp-4 : #C7A800;   /* olive → brighter for dark */
  --cmp-5 : #5FBF93;
  --cmp-6 : #E08860;
  --cmp-7 : #93A9B8;
  --cmp-8 : #D9B24C;
  --cmp-9 : #D080A8;
  --cmp-10: #C08860;

  --cat-overall   : #FFF1E5;
  --cat-energy    : #FF9D52;
  --cat-food      : #B6D36F;
  --cat-housing   : #4FA9DD;
  --cat-services  : #8A6DB8;
  --cat-wages     : #1FB36A;
  --cat-wages-text: #1FB36A;   /* [D93] dark jade already clears 4.5:1 as text (5.28) — same value, like --seq-lo-text */
  --cat-transport : #8FE6EE;
  --cat-restaurants: #C98A4E;   /* [D90-I3] tobacco, lifted for slate: 4.95:1 on --bg */
  --cat-other     : #C2B7AF;

  /* Receipt hero on slate: tokens intentionally NOT overridden — the receipt is a lit object
     (a receipt under a lamp on a dark counter). Dimming the paper caused halation-washed item
     lines (owner attack, 2026-07-04); full paper + near-black ink keeps every line readable. */

  --event-covid   : rgba(120,180,235,.20);
  --event-energy  : rgba(255,136,51,.18);
  --event-policy  : rgba(91,163,224,.16);
  --event-food    : rgba(150,204,40,.16);

  --anno-spread-fill : rgba(255,241,229,.07);
  --anno-spread-edge : rgba(255,241,229,.22);

  --db-trough : #BC597B;   /* [P8.2] rose over slate — claret cannot reach 3:1 on this ground */
  --shadow-1 : 0 1px 0 rgba(0,0,0,.3),  0 0 1px rgba(0,0,0,.4);
  --shadow-2 : 0 4px 16px rgba(0,0,0,.5), 0 1px 2px rgba(0,0,0,.4);
  --shadow-3 : 0 20px 48px rgba(0,0,0,.6), 0 6px 14px rgba(0,0,0,.4);
}

/* Respect OS preference if the user hasn't picked manually */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) {
    color-scheme: dark;
  }
}
