/* ─────────────────────────────────────────────────────────────
   Design tokens. Every appearance is one scoped block that
   remaps the same ~30 custom properties, so the whole app
   re-skins from this single file.

   TOKEN-NAMING CONTRACT — read before adding a theme:

     --gold*  is the app-wide PRIMARY ACTION color, not literally
              gold. Buttons, links, active nav, focus rings, FAB
              and chart accents all resolve through it (~235 call
              sites). Classic holds antique gold, Arsenal indigo,
              Jarvis cyan, Windows 2000 navy. Never rename it
              without touching every one of those call sites.

     --wood*  is the SECONDARY accent.
     --sand*  is PENDING / in-progress.
     --green* / --red* are semantic success / failure.

   Non-color tokens (layout, motion, radii) live in the shared
   block below and are deliberately NOT re-declared per theme,
   except where a theme's material demands it (Windows 2000 squares
   off every corner).
   ──────────────────────────────────────────────────────────── */

/* ─────────────────────────────────────────────────────────────
   Shared, theme-independent tokens.
   ──────────────────────────────────────────────────────────── */
:root {
  /* Layout */
  --sidebar-width:           200px;
  --sidebar-collapsed-width: 52px;
  --ribbon-height:           41px;

  /* Type. Only --font-label lives here: it is the one face token that has a
     meaningful default, so an appearance that never sets it falls back to its
     own body face rather than to nothing. The Arsenal blocks override it;
     every other appearance keeps its body face. */
  --font-label: var(--font-body);

  /* Motion */
  --speed: 0.22s;

  /* Shape */
  --radius-card:    14px;
  --radius-control: 10px;
  --radius-pill:    999px;

  /* PRIMARY alias. Custom properties resolve lazily, so this
     follows whatever --gold the active theme sets. Several
     components read --accent; it used to be undefined and fell
     back to --text-dim. */
  --accent: var(--gold);

  /* Plot background. Themes only override this when their card surface
     can't carry a validated palette (see Windows 2000). */
  --chart-surface: var(--surface);
}

/* ─────────────────────────────────────────────────────────────
   Arsenal — the default appearance.

   Near-white cool canvas, pure-white cards separated by hairline
   borders rather than shadow, indigo primary with a blue
   secondary. Inter throughout (no display serif — the reference
   look is a single geometric sans at several weights).
   ──────────────────────────────────────────────────────────── */
:root,
:root[data-theme="arsenal"] {
  /* Tells the browser which way round this theme is, so NATIVE controls —
     dropdown lists, scrollbars, focus rings, date pickers — are painted to
     match. Without it the OS paints a <select>'s option list on its own
     default background while the page supplies the text colour, which is
     how the engine's answer dropdowns ended up light grey on white. */
  color-scheme: light;


  /* ── The inverse palette ──────────────────────────────────────────────────
     This appearance's own opposite, used to flip a single element into the
     other appearance (see .notes-engine in pages/notes.css). Nothing reads
     these by default.

     TEMPERED ON PURPOSE — these are NOT the other block's values verbatim, and
     that is the fix for "the inversion is hard to look at". Inverting to the
     far end put a 16:1 edge on the light page and an 18.9:1 edge on the dark
     one; black-on-white text is 21:1, so the panel's OUTLINE was carrying
     nearly as much contrast as type does, over a large area rather than a thin
     glyph. Every glance across that border forces the eye to re-adapt. Pulling
     the surfaces toward the page lands both edges near 11.5:1 — still
     unmistakably the other appearance, no longer a light bomb. Ink inside is
     left strong, because reading the panel was never the problem.

     Each block carries its own opposite, so the two stay self-contained and
     the mapping rule that consumes them exists exactly once. */
  --inv-bg:           #262b39;
  --inv-bg-warm:      #2b3140;
  --inv-surface:      #2f3547;
  --inv-border:       #454c60;
  --inv-border-light: #3a4155;
  --inv-text:         #e8eaf0;
  --inv-text-muted:   #9aa0b0;
  --inv-text-dim:     #7b8194;
  --inv-gold:         #a49bff;
  --inv-gold-soft:    rgba(164,155,255,0.18);
  --inv-gold-hover:   #b9b2ff;
  --inv-green:        #34d399;
  --inv-green-soft:   rgba(52,211,153,0.16);
  --inv-red:          #f87171;
  --inv-red-soft:     rgba(248,113,113,0.16);
  --inv-sand:         #fbbf24;
  --inv-sand-soft:    rgba(251,191,36,0.16);
  --inv-wood:         #6fb0ff;
  --inv-wood-soft:    rgba(111,176,255,0.16);
  --inv-hover:        rgba(255,255,255,0.06);
  --inv-shadow-rgb:   0, 0, 0;
  /* Canvas */
  --bg:           #f7f8fb;
  --bg-warm:      #f1f3f8;
  --surface:      #ffffff;

  /* Structure — hairlines carry the separation, not shadow */
  --border:       #e4e7ee;
  --border-light: #edeff3;

  /* Ink */
  --text:         #171a26;
  --text-muted:   #5c6273;
  --text-dim:     #8b90a0;

  /* PRIMARY = indigo */
  --gold:         #5347ce;
  --gold-soft:    rgba(83,71,206,0.10);
  --gold-hover:   #4238a8;

  /* Semantic */
  --green:        #16a34a;
  --green-soft:   rgba(22,163,74,0.10);

  --red:          #dc2626;
  --red-soft:     rgba(220,38,38,0.10);

  /* PENDING = amber */
  --sand:         #f59e0b;
  --sand-soft:    rgba(245,158,11,0.12);

  /* SECONDARY = blue */
  --wood:         #4896fe;
  --wood-soft:    rgba(72,150,254,0.10);

  /* Surface interaction */
  --hover:        rgba(23,26,38,0.04);

  /* Elevation — deliberately almost nothing */
  /* Base color for every elevation/scrim in the app, as an "R, G, B"
     triple so component CSS can vary only the alpha. */
  --shadow-rgb:   16, 24, 40;
  --shadow-card:  0 1px 2px rgba(16,24,40,0.04);
  --shadow-pop:   0 8px 28px rgba(16,24,40,0.12);


    /* Azure, sea blue, periwinkle, indigo — the specified blues plus the
     purples. Zero FAILs and zero WARNs against white at ΔE 16.6.

     THE BLUES ALONE CANNOT DO THIS, and that is why the purples are here
     rather than as decoration. Given #008080 / #89CFF0 / #007FFF / #006994,
     every lightness step of all four hues was searched: not one arrangement
     passes, because #006994 and #008080 sit ΔE 8.7 apart in NORMAL vision
     (floor is 15) — one colour, to most people, twice. Even any three of the
     four fail. Adding the purple end buys back the hue spread that colourblind
     separation is actually paid for in.

     Two of the four specified hexes are not here, for measured reasons:
     #008080 falls under the chroma floor on white (0.093 — reads grey), and
     #89CFF0 sits at 1.71:1 where a mark needs 3:1. Both are used where they
     do work — #89CFF0 opens the sequential ramp below, and #008080's hue
     returns lifted as #00a3a3 in Arsenal Dark, where it holds contrast.

     FOUR slots, not six. Slots 5–6 are neutrals for the folded "Other" bucket.

     ORDER is the mechanism, not decoration: the same four rearranged drop the
     worst adjacent pair well below the floor. Re-run
     scripts/validate_palette.js before touching any of it. */
  --series-1: #007fff;   /* azure     */
  --series-2: #006994;   /* sea blue  */
  --series-3: #887cfd;   /* periwinkle */
  --series-4: #5347ce;   /* indigo    */

  /* Overflow only — the folded "Other" bucket and anything past it. Neutral
     on purpose: "Other" is not an entity and must not look like one. */
  --series-5: #64748b;
  --series-6: #94a3b8;

  /* --seq-* is a single-hue ORDINAL ramp for part-of-whole pairs, where
     one measure is a subset of the other (issued ⊂ submitted, net ⊂ gross,
     closes ⊂ billables). Those are NOT categorical — two unrelated hues
     would imply two unrelated things. seq-1 recedes toward the surface;
     seq-4 carries the most emphasis. Direction is surface-relative, so on
     dark themes the hexes run dark→light. */
  --seq-1: #89cff0;
  --seq-2: #4da3e8;
  --seq-3: #007fff;
  --seq-4: #006994;

  /* Typography */
  /* SF Pro Display is the brand face, and it cannot be self-hosted:
     Apple licenses it for Apple platforms, and font-src 'self' rules
     out a CDN regardless. Naming it without an @font-face is legal and
     CSP-safe — Apple devices resolve the real thing from the system.
     Everywhere else falls through to Inter, which is self-hosted and
     was drawn against the same brief. Windows and Android therefore
     get Inter, by design. */
  --font-body:    'SF Pro Display', -apple-system, BlinkMacSystemFont, 'Inter', system-ui, sans-serif;
  --font-display: 'SF Pro Display', -apple-system, BlinkMacSystemFont, 'Inter', system-ui, sans-serif;
  /* The label face — the small headers on tables, stat blocks and form fields.
     Unlike SF Pro this one really ships: it is OFL, self-hosted in src/fonts/,
     and renders identically on every platform. Applied by
     components/labels.css, which lists every selector that wears it.

     The family is named for a historic script but carries the standard Noto
     latin subsets, which is what these labels actually render in. It is
     REGULAR ONLY — no 500/600/700 upstream — so anything heavier is
     synthesised by the browser. */
  --font-label:   'Noto Sans Caucasian Albanian', 'Inter', system-ui, sans-serif;
}

/* ─────────────────────────────────────────────────────────────
   Arsenal Dark — the same hues re-seated on a near-black cool
   canvas. Primary and secondary are lifted (lighter, slightly
   desaturated) so they hold contrast against the dark surface
   instead of vibrating on it.
   ──────────────────────────────────────────────────────────── */
:root[data-theme="arsenal-dark"] {
  /* Tells the browser which way round this theme is, so NATIVE controls —
     dropdown lists, scrollbars, focus rings, date pickers — are painted to
     match. Without it the OS paints a <select>'s option list on its own
     default background while the page supplies the text colour, which is
     how the engine's answer dropdowns ended up light grey on white. */
  color-scheme: dark;


  /* ── The inverse palette ──────────────────────────────────────────────────
     This appearance's own opposite, used to flip a single element into the
     other appearance (see .notes-engine in pages/notes.css). Nothing reads
     these by default.

     TEMPERED ON PURPOSE — these are NOT the other block's values verbatim, and
     that is the fix for "the inversion is hard to look at". Inverting to the
     far end put a 16:1 edge on the light page and an 18.9:1 edge on the dark
     one; black-on-white text is 21:1, so the panel's OUTLINE was carrying
     nearly as much contrast as type does, over a large area rather than a thin
     glyph. Every glance across that border forces the eye to re-adapt. Pulling
     the surfaces toward the page lands both edges near 11.5:1 — still
     unmistakably the other appearance, no longer a light bomb. Ink inside is
     left strong, because reading the panel was never the problem.

     Each block carries its own opposite, so the two stay self-contained and
     the mapping rule that consumes them exists exactly once. */
  --inv-bg:           #bfc5d1;
  --inv-bg-warm:      #c4cad5;
  --inv-surface:      #c9cdd8;
  --inv-border:       #a9b0bf;
  --inv-border-light: #b7bdca;
  --inv-text:         #171a26;
  --inv-text-muted:   #4e5464;
  --inv-text-dim:     #666c7d;
  --inv-gold:         #5347ce;
  --inv-gold-soft:    rgba(83,71,206,0.14);
  --inv-gold-hover:   #4238a8;
  --inv-green:        #136a33;
  --inv-green-soft:   rgba(19,106,51,0.14);
  --inv-red:          #b01919;
  --inv-red-soft:     rgba(176,25,25,0.14);
  --inv-sand:         #a86a05;
  --inv-sand-soft:    rgba(168,106,5,0.16);
  --inv-wood:         #1f5fa8;
  --inv-wood-soft:    rgba(31,95,168,0.14);
  --inv-hover:        rgba(23,26,38,0.06);
  --inv-shadow-rgb:   16, 24, 40;
  --bg:           #0f1117;
  --bg-warm:      #141721;
  --surface:      #171a22;

  --border:       #262a36;
  --border-light: #1f2330;

  --text:         #e8eaf0;
  --text-muted:   #9aa0b0;
  --text-dim:     #6b7183;

  /* PRIMARY = lifted indigo */
  --gold:         #887cfd;
  --gold-soft:    rgba(136,124,253,0.16);
  --gold-hover:   #a49bff;

  --green:        #34d399;
  --green-soft:   rgba(52,211,153,0.14);

  --red:          #f87171;
  --red-soft:     rgba(248,113,113,0.14);

  --sand:         #fbbf24;
  --sand-soft:    rgba(251,191,36,0.14);

  /* SECONDARY = lifted blue */
  --wood:         #4896fe;
  --wood-soft:    rgba(72,150,254,0.14);

  --hover:        rgba(255,255,255,0.05);

  /* On dark, shadow reads as depth rather than lift */
  /* Base color for every elevation/scrim in the app, as an "R, G, B"
     triple so component CSS can vary only the alpha. */
  --shadow-rgb:   0, 0, 0;
  --shadow-card:  0 1px 2px rgba(0,0,0,0.36);
  --shadow-pop:   0 12px 32px rgba(0,0,0,0.55);


    /* Same hue sequence as light, one step lifted for the dark surface — slot
     identity has to survive a theme switch or a chart repaints its meaning.
     Validated against #171a22: worst adjacent ΔE 15. */
  --series-1: #007fff;   /* azure       */
  --series-2: #00a3a3;   /* teal, lifted off #008080 so it holds on black */
  --series-3: #887cfd;   /* periwinkle  */
  --series-4: #0d6fc4;   /* deep blue   */

  /* Overflow only — see the light block. */
  --series-5: #94a3b8;
  --series-6: #64748b;

  /* --seq-* is a single-hue ORDINAL ramp for part-of-whole pairs, where
     one measure is a subset of the other (issued ⊂ submitted, net ⊂ gross,
     closes ⊂ billables). Those are NOT categorical — two unrelated hues
     would imply two unrelated things. seq-1 recedes toward the surface;
     seq-4 carries the most emphasis. Direction is surface-relative, so on
     dark themes the hexes run dark→light. */
  --seq-1: #0d6fc4;
  --seq-2: #007fff;
  --seq-3: #4da3e8;
  --seq-4: #89cff0;

  /* SF Pro Display is the brand face, and it cannot be self-hosted:
     Apple licenses it for Apple platforms, and font-src 'self' rules
     out a CDN regardless. Naming it without an @font-face is legal and
     CSP-safe — Apple devices resolve the real thing from the system.
     Everywhere else falls through to Inter, which is self-hosted and
     was drawn against the same brief. Windows and Android therefore
     get Inter, by design. */
  --font-body:    'SF Pro Display', -apple-system, BlinkMacSystemFont, 'Inter', system-ui, sans-serif;
  --font-display: 'SF Pro Display', -apple-system, BlinkMacSystemFont, 'Inter', system-ui, sans-serif;
  /* The label face — the small uppercase tracked headers on tables, stat
     blocks and form fields. Unlike SF Pro this one really ships: it is OFL,
     self-hosted in src/fonts/, and renders identically on every platform.
     Applied by components/labels.css, which lists every selector that wears
     it. Regular only upstream — anything heavier is synthesised. */
  --font-label:   'Noto Sans Caucasian Albanian', 'Inter', system-ui, sans-serif;
}

/* ─────────────────────────────────────────────────────────────
   Classic — the original appearance. Warm earth tones on a cream
   canvas with an antique-gold primary, DM Sans paired with
   Cormorant Garamond for the display face.

   This was the bare `:root` block until the Arsenal redesign;
   it is now scoped like every other theme. The attribute
   selector out-specifies the plain `:root` above, so selecting
   Classic restores exactly the previous palette.
   ──────────────────────────────────────────────────────────── */
:root[data-theme="classic"] {
  /* Tells the browser which way round this theme is, so NATIVE controls —
     dropdown lists, scrollbars, focus rings, date pickers — are painted to
     match. Without it the OS paints a <select>'s option list on its own
     default background while the page supplies the text colour, which is
     how the engine's answer dropdowns ended up light grey on white. */
  color-scheme: light;

  --bg:           #f5f0e8;
  --bg-warm:      #ede8de;
  --surface:      #faf7f2;

  --border:       #d8cfc0;
  --border-light: #e8e2d6;

  --text:         #2e2820;
  --text-muted:   #7a6f60;
  --text-dim:     #a89e90;

  /* PRIMARY = antique gold */
  --gold:         #b5893a;
  --gold-soft:    rgba(181,137,58,0.10);
  --gold-hover:   #9a7230;

  --green:        #5a7a52;
  --green-soft:   rgba(90,122,82,0.10);

  --red:          #8a4a40;
  --red-soft:     rgba(138,74,64,0.10);

  --sand:         #c4a96a;
  --sand-soft:    rgba(196,169,106,0.12);

  --wood:         #8b6340;
  --wood-soft:    rgba(139,99,64,0.10);

  --hover:        rgba(46,40,32,0.06);

  /* Base color for every elevation/scrim in the app, as an "R, G, B"
     triple so component CSS can vary only the alpha. */
  --shadow-rgb:   46, 40, 32;
  --shadow-card:  0 1px 4px rgba(46,40,32,0.06);
  --shadow-pop:   0 8px 28px rgba(46,40,32,0.16);


  /* ── Data-viz ramps ──────────────────────────────────────────
     Validated with the dataviz skill's validate_palette.js against
     this theme's own chart surface (#faf7f2, light mode):
     lightness band, chroma floor, adjacent CVD separation, normal-vision
     floor and contrast all PASS. Re-run the validator before touching a
     value — the ORDER is the colorblind-safety mechanism, not cosmetic.
     gold leads so single-series charts stay on-theme. Worst adjacent CVD ΔE 10.2.

     --series-* is CATEGORICAL (identity: one carrier per slot). Assign in
     fixed order and never cycle — a 7th category folds into "Other". */
  --series-1: #a3762b;
  --series-2: #2563eb;
  --series-3: #15803d;
  --series-4: #6d28d9;
  --series-5: #0d9488;
  --series-6: #e11d48;

  /* --seq-* is a single-hue ORDINAL ramp for part-of-whole pairs, where
     one measure is a subset of the other (issued ⊂ submitted, net ⊂ gross,
     closes ⊂ billables). Those are NOT categorical — two unrelated hues
     would imply two unrelated things. seq-1 recedes toward the surface;
     seq-4 carries the most emphasis. Direction is surface-relative, so on
     dark themes the hexes run dark→light. */
  --seq-1: #c9a253;
  --seq-2: #ab8034;
  --seq-3: #8e6826;
  --seq-4: #6b4d1c;

  /* Original 8px card corner */
  --radius-card:    8px;
  --radius-control: 6px;

  --font-body:    'DM Sans', system-ui, -apple-system, sans-serif;
  --font-display: 'Cormorant Garamond', Georgia, serif;
}

/* ─────────────────────────────────────────────────────────────
   Windows 2000 theme — "a boring gray program."
   Set on <html data-theme="win2000"> by src/js/theme.js.
   (Previously shipped as 'circa1990' / 'dos' / 'apple'; theme.js
   migrates all three saved ids forward.)

   Targets WINDOWS 2000 specifically, not the earlier Win3.1/95
   look this block used to carry. The differences are small but
   they are the whole tell: the 3D face is the warmer #d4d0c8
   rather than #c0c0c0 silver, and title bars are a horizontal
   #0a246a → #a6caf0 gradient rather than flat #000080. Beveled
   gray panels, plain black ink, and the navy system-highlight for
   selected items and the primary action all carry over. Semantic
   states use the muted VGA-16 palette (dark green / maroon /
   olive) so nothing looks modern. Token-naming quirk carries over
   too: --gold* is the app-wide PRIMARY action color, so it holds
   the navy highlight.

   Typography is the real bitmap MS Sans Serif, self-hosted in
   src/css/fonts-pixel.css (see that file for the licence and for
   why the system font stack could not do the job). It is designed
   for 11px and integer multiples — win2000.css collapses the
   whole app's type ramp onto that grid. Deliberately plain: the
   display face is the same as the body face, exactly as Windows
   itself had one UI font at one size.

   Pages already consume the tokens above, so this single block
   re-skins everything. The material flourishes — raised/sunken
   3D bevels, gradient caption bars, sunken white client areas,
   square corners, dotted focus rectangles — live in
   src/css/win2000.css, scoped to :root[data-theme="win2000"].
   ──────────────────────────────────────────────────────────── */
:root[data-theme="win2000"] {
  /* Tells the browser which way round this theme is, so NATIVE controls —
     dropdown lists, scrollbars, focus rings, date pickers — are painted to
     match. Without it the OS paints a <select>'s option list on its own
     default background while the page supplies the text colour, which is
     how the engine's answer dropdowns ended up light grey on white. */
  color-scheme: light;

  /* Canvas — the Windows 2000 "3D face", warmer than Win95 silver */
  --bg:           #d4d0c8;
  --bg-warm:      #c8c4bc;
  --surface:      #d4d0c8;

  /* Bevel edges — shadow gray + highlight (flourishes build the 3D look) */
  --border:       #808080;
  --border-light: #dfdfdf;

  /* Plain black ink ramp, kept readable on the gray face */
  --text:         #000000;
  --text-muted:   #3a3a3a;
  --text-dim:     #5c5c5c;

  /* PRIMARY = the Win2000 active-caption / selection navy (maps to --gold).
     This is the dark end of the title-bar gradient, so a selected row and a
     caption bar read as the same system color. */
  --gold:         #0a246a;
  --gold-soft:    rgba(10,36,106,0.14);
  --gold-hover:   #1a3a8a;

  /* Semantic — muted VGA-16 green / maroon */
  --green:        #007a00;
  --green-soft:   rgba(0,122,0,0.14);

  --red:          #b00000;
  --red-soft:     rgba(176,0,0,0.12);

  /* SECONDARY / Pending = dark amber-olive */
  --sand:         #8a6a00;
  --sand-soft:    rgba(138,106,0,0.16);

  /* Secondary accent = neutral gray */
  --wood:         #5c5c5c;
  --wood-soft:    rgba(92,92,92,0.14);

  --hover:        rgba(0,0,0,0.08);

  /* No elevation — the bevels in win2000.css do the work */
  /* Base color for every elevation/scrim in the app, as an "R, G, B"
     triple so component CSS can vary only the alpha. */
  --shadow-rgb:   0, 0, 0;
  --shadow-card:  none;
  --shadow-pop:   2px 2px 0 rgba(0,0,0,0.4);


  /* ── Data-viz ramps ──────────────────────────────────────────
     Validated with the dataviz skill's validate_palette.js against
     this theme's own chart surface (#ffffff, light mode):
     lightness band, chroma floor, adjacent CVD separation, normal-vision
     floor and contrast all PASS. Re-run the validator before touching a
     value — the ORDER is the colorblind-safety mechanism, not cosmetic.
     plots render on a WHITE panel, not the gray face. On a mid gray like
     #d4d0c8 a categorical palette cannot satisfy both the 3:1 contrast
     floor and the lightness band at once — the two requirements pull
     opposite ways. A white client area is period-correct anyway, and is
     now literally how every panel in this appearance is built (see the
     WELL primitive in win2000.css), so the era survives in the bevels
     and the type rather than in the plot hues. The surface these were
     validated against did not change with the Win2000 repalette, so the
     validation still holds.

     --series-* is CATEGORICAL (identity: one carrier per slot). Assign in
     fixed order and never cycle — a 7th category folds into "Other". */
  --series-1: #2563eb;
  --series-2: #15803d;
  --series-3: #6d28d9;
  --series-4: #d97706;
  --series-5: #0d9488;
  --series-6: #e11d48;

  /* --seq-* is a single-hue ORDINAL ramp for part-of-whole pairs, where
     one measure is a subset of the other (issued ⊂ submitted, net ⊂ gross,
     closes ⊂ billables). Those are NOT categorical — two unrelated hues
     would imply two unrelated things. seq-1 recedes toward the surface;
     seq-4 carries the most emphasis. Direction is surface-relative, so on
     dark themes the hexes run dark→light. */
  --seq-1: #7ab0ef;
  --seq-2: #4a89dd;
  --seq-3: #2563eb;
  --seq-4: #1a4ba8;

  --chart-surface: #ffffff;

  /* Square everything — a 1990 GUI has no rounded corners */
  --radius-card:    0;
  --radius-control: 0;
  --radius-pill:    0;

  /* Period GUI sans. 'MS Sans Serif Web' is the self-hosted bitmap face
     (src/css/fonts-pixel.css); the installed names behind it are the
     fallback if that file ever fails to load. Body and display are the
     same family on purpose — Windows had one UI font. */
  --font-body:    'MS Sans Serif Web', 'MS Sans Serif', 'Microsoft Sans Serif', Tahoma, sans-serif;
  --font-display: 'MS Sans Serif Web', 'MS Sans Serif', 'Microsoft Sans Serif', Tahoma, sans-serif;
}

/* ─────────────────────────────────────────────────────────────
   Ivory theme — white canvas, near-black ink, navy-blue accent
   in place of the gold. Same self-hosted DM Sans + Cormorant
   Garamond pair as Classic, so the serif italic emphasis carries
   through without pulling DM Serif Display from Google (CSP only
   allows 'self' for fonts).
   ──────────────────────────────────────────────────────────── */
:root[data-theme="ivory"] {
  /* Tells the browser which way round this theme is, so NATIVE controls —
     dropdown lists, scrollbars, focus rings, date pickers — are painted to
     match. Without it the OS paints a <select>'s option list on its own
     default background while the page supplies the text colour, which is
     how the engine's answer dropdowns ended up light grey on white. */
  color-scheme: light;

  --bg:           #ffffff;
  --bg-warm:      #f7f6f4;
  --surface:      #ffffff;

  --border:       #e4e1db;
  --border-light: #f0eeeb;

  --text:         #111111;
  --text-muted:   #444444;
  --text-dim:     #888888;

  --gold:         #1a3a5c;
  --gold-soft:    rgba(26,58,92,0.08);
  --gold-hover:   #102a45;

  --green:        #2f6b3a;
  --green-soft:   rgba(47,107,58,0.08);

  --red:          #a3382c;
  --red-soft:     rgba(163,56,44,0.08);

  --sand:         #9aa9b8;
  --sand-soft:    rgba(154,169,184,0.14);

  --wood:         #444444;
  --wood-soft:    rgba(68,68,68,0.08);

  --hover:        rgba(17,17,17,0.05);

  /* Base color for every elevation/scrim in the app, as an "R, G, B"
     triple so component CSS can vary only the alpha. */
  --shadow-rgb:   17, 17, 17;
  --shadow-card:  0 1px 4px rgba(17,17,17,0.05);
  --shadow-pop:   0 8px 28px rgba(17,17,17,0.14);


  /* ── Data-viz ramps ──────────────────────────────────────────
     Validated with the dataviz skill's validate_palette.js against
     this theme's own chart surface (#ffffff, light mode):
     lightness band, chroma floor, adjacent CVD separation, normal-vision
     floor and contrast all PASS. Re-run the validator before touching a
     value — the ORDER is the colorblind-safety mechanism, not cosmetic.
     blue leads, matching the navy primary. Worst adjacent CVD ΔE 10.2.

     --series-* is CATEGORICAL (identity: one carrier per slot). Assign in
     fixed order and never cycle — a 7th category folds into "Other". */
  --series-1: #2563eb;
  --series-2: #15803d;
  --series-3: #6d28d9;
  --series-4: #d97706;
  --series-5: #0d9488;
  --series-6: #e11d48;

  /* --seq-* is a single-hue ORDINAL ramp for part-of-whole pairs, where
     one measure is a subset of the other (issued ⊂ submitted, net ⊂ gross,
     closes ⊂ billables). Those are NOT categorical — two unrelated hues
     would imply two unrelated things. seq-1 recedes toward the surface;
     seq-4 carries the most emphasis. Direction is surface-relative, so on
     dark themes the hexes run dark→light. */
  --seq-1: #7ab0ef;
  --seq-2: #4a89dd;
  --seq-3: #2563eb;
  --seq-4: #1a4ba8;

  --radius-card:    8px;
  --radius-control: 6px;

  --font-body:    'DM Sans', system-ui, -apple-system, sans-serif;
  --font-display: 'Cormorant Garamond', Georgia, serif;
}

/* ─────────────────────────────────────────────────────────────
   Jarvis theme — J.A.R.V.I.S. holographic HUD (Iron Man /
   Avengers). Deep space-navy canvas, electric-cyan as the
   primary glow, arc-reactor gold/amber as the secondary.

   Token-naming quirk: --gold* is the app-wide PRIMARY action
   color (buttons, links, active nav, FAB), so it carries the
   CYAN. The arc-reactor gold/amber rides --sand* / --wood*.

   These tokens re-skin every page that consumes the variables.
   The immersive flourishes (animated backdrop, glow, HUD
   brackets, boot shimmer) live in src/css/jarvis.css, scoped to
   :root[data-theme="jarvis"] so the other themes are untouched.

   Display font becomes a system MONOSPACE stack (referenced by
   family name, not @font-face) for the techy HUD feel — CSP-safe
   (font-src 'self') and zero new font files. Body stays DM Sans
   for readability.
   ──────────────────────────────────────────────────────────── */
:root[data-theme="jarvis"] {
  /* Tells the browser which way round this theme is, so NATIVE controls —
     dropdown lists, scrollbars, focus rings, date pickers — are painted to
     match. Without it the OS paints a <select>'s option list on its own
     default background while the page supplies the text colour, which is
     how the engine's answer dropdowns ended up light grey on white. */
  color-scheme: dark;

  /* Deep space-navy canvas */
  --bg:           #060b14;
  --bg-warm:      #0a1322;
  --surface:      #0d1826;

  /* Cyan-tinted structure */
  --border:       #1c3a52;
  --border-light: #14283c;

  /* Cool HUD text */
  --text:         #d6ecff;
  --text-muted:   #7fa6c4;
  --text-dim:     #4f7390;

  /* PRIMARY = electric cyan (maps to the gold token) */
  --gold:         #3fd0ff;
  --gold-soft:    rgba(63,208,255,0.12);
  --gold-hover:   #74ddff;

  /* Semantic */
  --green:        #2ee6a6;
  --green-soft:   rgba(46,230,166,0.12);

  --red:          #ff5c7a;
  --red-soft:     rgba(255,92,122,0.12);

  /* SECONDARY = arc-reactor gold/amber */
  --sand:         #ffb547;
  --sand-soft:    rgba(255,181,71,0.14);

  --wood:         #ffb547;
  --wood-soft:    rgba(255,181,71,0.10);

  --hover:        rgba(63,208,255,0.08);

  /* Base color for every elevation/scrim in the app, as an "R, G, B"
     triple so component CSS can vary only the alpha. */
  --shadow-rgb:   0, 0, 0;
  --shadow-card:  0 1px 4px rgba(0,0,0,0.5);
  --shadow-pop:   0 12px 32px rgba(0,0,0,0.7);


  /* ── Data-viz ramps ──────────────────────────────────────────
     Validated with the dataviz skill's validate_palette.js against
     this theme's own chart surface (#0d1826, dark mode):
     lightness band, chroma floor, adjacent CVD separation, normal-vision
     floor and contrast all PASS. Re-run the validator before touching a
     value — the ORDER is the colorblind-safety mechanism, not cosmetic.
     cyan leads, matching the HUD primary. Worst adjacent CVD ΔE 14.2.

     --series-* is CATEGORICAL (identity: one carrier per slot). Assign in
     fixed order and never cycle — a 7th category folds into "Other". */
  --series-1: #12a2cf;
  --series-2: #059669;
  --series-3: #8b7cf5;
  --series-4: #d97706;
  --series-5: #3b82f6;
  --series-6: #f43f5e;

  /* --seq-* is a single-hue ORDINAL ramp for part-of-whole pairs, where
     one measure is a subset of the other (issued ⊂ submitted, net ⊂ gross,
     closes ⊂ billables). Those are NOT categorical — two unrelated hues
     would imply two unrelated things. seq-1 recedes toward the surface;
     seq-4 carries the most emphasis. Direction is surface-relative, so on
     dark themes the hexes run dark→light. */
  --seq-1: #0e6d8c;
  --seq-2: #12a2cf;
  --seq-3: #3fc8f0;
  --seq-4: #7fdcf7;

  --radius-card:    8px;
  --radius-control: 6px;

  /* Techy display font; body stays DM Sans */
  --font-body:    'DM Sans', system-ui, -apple-system, sans-serif;
  --font-display: ui-monospace, 'SF Mono', 'Cascadia Code', 'Segoe UI Mono', Consolas, monospace;
}
