/* NC Zoning Academy: theme tokens.
 *
 * Semantic CSS custom properties, mirroring the map's theme.css approach.
 * Default theme = Night Corp. To add a theme, define `html.theme-<name> { … }`
 * overriding the same semantic vars; nothing else in the app hardcodes colour.
 *
 * Palette values are the source of truth from the 0.1.0 shell's `C` object, so
 * the rebuild matches the live look pixel-for-pixel.
 */

@font-face {
  font-family: 'Night Corp Display';
  src: url('../font/NightCorpDisplay-Regular.woff2') format('woff2'),
       url('../font/NightCorpDisplay-Regular.otf') format('opentype');
  font-weight: 400;
  font-display: swap;
}

:root,
html.theme-night-corp {
  /* raw palette (Night Corp) */
  --navy:  #0a192f;
  --dark:  #112240;  /* no consumer: --surface/--panel-bg were deleted as dead.
                        Kept as palette: a theme author's input vocabulary, and
                        #17 derives panel fills from it. */
  --cyan:  #00f0ff;
  --amber: #ffb300;
  --gold:  #ffd400;
  --green: #00ff9d;
  --red:   #ff3355;
  --gray:  #8892b0;
  --white: #e6f1ff;

  /* semantic roles (reference these in components, never the raw palette) */
  --bg:          var(--navy);
  --surface:     var(--dark);   /* raised panels over the bg (menus, wells, rows) */
  --primary:     var(--cyan);   /* Zoning Cyan: links, focus, primary accents */
  --secondary:   var(--amber);  /* warnings / secondary emphasis */
  --tertiary:    var(--gold);   /* Academy gold: track titles, certificate */
  --success:     var(--green);
  --danger:      var(--red);
  /* Three text tiers. Grey is for things you glance at, not things you read.
     Tier 1 headings/emphasis, Tier 2 reading copy (AAA, ~7:1+), Tier 3 metadata. */
  --text:        var(--white);             /* Tier 1: headings / emphasis */
  --text-body:   #c3cfe2;                  /* Tier 2: reading copy */
  --text-soft:   var(--text-body);         /* legacy alias: orientation-card body copy */
  --muted:       var(--gray);              /* Tier 3: metadata / labels only */
  --placeholder: #54617f;                  /* also dim hints (skip hint, RETURNING OPERATOR?) */
  /* Derived colours use relative colour syntax so they FOLLOW the role above.
     Re-bind --primary to red and every line, glow and tint below turns red at
     the same alpha; no per-alpha token, no second edit. Value-identical to the
     literals they replaced (verified: computed-style diff is empty). */
  --primary-dim: rgb(from var(--primary) r g b / 0.55);  /* dimmed: idle button text */
  --field-bg:    #050a14;                  /* near-black input background */
  --hero-a:      #0d1f3a;                  /* course-card hero gradient start */
  --hero-b:      #122a4d;                  /* course-card hero gradient end */

  /* surfaces */
  --card-bg:   rgb(from var(--bg) r g b / 0.92);
  --card-glow: 0 0 40px rgb(from var(--primary) r g b / 0.15);

  /* lines / edges */
  --line:        rgb(from var(--primary) r g b / 0.25);
  --line-strong: rgb(from var(--primary) r g b / 0.35);
  --line-muted:  rgb(from var(--muted) r g b / 0.5);
  --line-faint:  rgb(from var(--muted) r g b / 0.2);

  /* scrollbar */
  --scrollbar-track:      var(--navy);
  --scrollbar-thumb:      #173254;
  --scrollbar-thumb-hover:#1e4470;

  /* scanline / vignette overlays */
  --scanline:  rgb(from var(--primary) r g b / 0.035);
  --vignette:  rgba(0, 0, 0, 0.45);   /* black, not theme-derived */

  /* typography */
  --font-display:  'Orbitron', system-ui, sans-serif;   /* headings */
  --font-body:     'Rajdhani', system-ui, sans-serif;    /* body / UI */
  --font-mono:     'Fira Code', ui-monospace, monospace; /* code / terminal */
  --font-identity: 'Night Corp Display', var(--font-display); /* Tier-0 wordmark, titlebars, cert */

  /* Type roles. Same discipline as the colour roles above: components name the
     ROLE, never a pixel size. Eight roles replaced 24 ad-hoc sizes; adjusting
     one here now moves every element that plays that part, which is the whole
     reason the CSS is split by concern.
     Sizes are not comparable across families: Orbitron at 15px and Rajdhani at
     18px have the SAME cap height (11px). That is why --fs-heading has to sit
     this far above --fs-body to read as a heading at all. Re-check cap heights
     if --font-display or --font-body ever change.

     These are the BASE ladder, tuned for the module player. Three rules:

       1. A call site names a role, never a pixel size. The only exception is a
          glyph sized as an icon (.order-arrow, .course-watermark), which must
          say so in a comment.
       2. A view re-binds roles on its own ROOT element, with a reason. Because
          --fs-* are inherited, one declaration re-tunes the whole subtree and
          every rule inside keeps saying var(--fs-label). See .radio-pill,
          .boot-screen, .cert-scrim, .app-header.
       3. Nobody invents a role name. If a context wants a size no role names,
          the role set is wrong; do not add --fs-heading-radio. That escape
          hatch is how this became 24 ad-hoc sizes the first time.

     A fixed/portalled element inherits from :root, not from the view that
     opens it. Overlays therefore need their own binding (.confirm-scrim,
     .shard-scrim, .sys-readout) or they silently get the base ladder. */
  --fs-title:     34px;  /* page titles, hero numerics */
  --fs-heading:   22px;  /* card headings, quiz prompts, glossary terms */
  --fs-body:      18px;  /* reading prose (see --measure) */
  --fs-secondary: 16px;  /* supporting text: table cells, options, debriefs */
  --fs-ui:        14px;  /* buttons, rail rows, status lines */
  --fs-code:      13px;  /* monospace code, terminal, JSON */
  --fs-label:     12px;  /* uppercase mono/display labels, field labels */
  --fs-micro:     10px;  /* sources, badges, captions, meta */

  /* 1.7, not 1.6: prose runs ~94 chars/line in the .player-body column, and a
     long line fails on the return sweep; the eye loses its place hunting for
     the next line's start. Extra leading is the standard mitigation. Narrow the
     measure and this can come back down. */
  --lh-body:  1.7;  /* reading prose */
  --lh-tight: 1.4;  /* headings, single-line UI */
  /* Letter-spacing scale. 158 uses sat on 17 values; tracking is in `em`, so the
     same rendered spacing came from many value/size pairs; the numbers were not
     a real scale. Five rungs, chosen at the rendered result (not the grep): some
     values deliberately collapse (0.14 → 0.12, 0.06 → 0.08), which is a visual
     change, signed off on the render. Uppercase mono/display labels at --fs-micro
     need more tracking than prose, so the rung is not independent of the size. */
  --tracking-tight: 0.04em; /* subtle: larger display text, mixed-case */
  --tracking-label: 0.08em; /* default label tracking */
  --tracking-mid:   0.12em; /* the dense cluster: nav, section labels */
  --tracking-caps:  0.16em; /* uppercase display labels, small caps */
  --tracking-wide:  0.20em; /* widest: rare, hero eyebrows */

  /* measure: width of the prose itself. Containers add their own padding on
     top (see .player-body, .modal-box.cyan), so prose fills its card rather
     than leaving a ragged gutter down the right.
     Not expressed in `ch`: that unit is the width of `0`, and Rajdhani's
     tabular zero is 27% wider than its average glyph; 68ch renders 81 chars. */
  --measure: 732px;

  /* geometry. Night Corp is sharp: no rounded corners */
  --radius: 0;

  /* layout */
  --header-h: 62px; /* measured; monolith header is 62, not 64 */

  /* z-index ladder: the whole stacking order in one place, bottom to top.
     Values are preserved exactly (this is a pure refactor); where two selectors
     share a token, they share a tier ON PURPOSE. The big jump from 60 to 9100
     is the monolith's: in-flow chrome lives below 100, fixed/portalled overlays
     live near 9999. Keep it. */
  --z-order-row:      1;    /* quiz order rows, in flow */
  --z-order-picked:  30;    /* a row lifted while being dragged */
  --z-rail-toggle:   40;    /* the ☰ module-map toggle */
  --z-view:          50;    /* full-screen views: boot, lock */
  --z-rail-backdrop: 55;    /* scrim behind the open module-map drawer */
  --z-rail:          60;    /* the module-map rail, above its own backdrop */
  --z-sys-readout: 9100;    /* fixed telemetry satellite (bottom-left) */
  --z-gloss-fab:   9200;    /* glossary FAB, sits above the readout */
  --z-broadcast:   9300;    /* bell popover + its click-away backdrop */
  --z-vignette:    9989;    /* CRT vignette overlay */
  --z-scanlines:   9990;    /* CRT scanlines, just above the vignette */
  --z-overlay:     9995;    /* modal scrim + radio pill/panel share this tier;
                               the radio wins the tie on DOM order (MusicPlayer
                               renders last in App.tsx); do NOT split them */
  --z-transfer:    9996;    /* eddies transfer overlay */
  --z-flyer:       9997;    /* eddies flyer animation */
  --z-scrim:       9998;    /* cert + shard overlays, under the confirms */
  --z-dialog:      9999;    /* name-prompt + confirm dialogs sit on top */

  /* Spacing scale. Two layers, because the data has two shapes (see #27).
     1) A 2px-step numeric scale over the dense region (≤24px), mirroring the
        map's --space-* naming. 88% of all spacing is this. Values on the scale
        are unchanged; a few odd values snap 1px to the nearest rung (signed off
        on the render). Sub-4px values are optical nudges, NOT spacing; they
        stay literal, which is also where the map's scale starts. */
  --space-2xs:  4px;
  --space-xs:   6px;
  --space-sm:   8px;
  --space-md:  10px;
  --space-lg:  12px;
  --space-xl:  14px;
  --space-2xl: 16px;
  --space-3xl: 18px;
  --space-4xl: 20px;
  --space-5xl: 22px;
  --space-6xl: 24px;

  /*  2) Named layout tokens for the large values that repeat by MEANING, not as
        scale steps; putting them on the numeric ladder would be false
        uniformity. Everything else >24px (page-frame top/bottom padding, the
        26–30px medium band, true one-offs like the 80px player runway) stays
        literal: frequent is not the same as a shared role. */
  --section-gap:   34px;  /* rhythm between record/dashboard section blocks */
  --scrim-pad:     32px;  /* inset of the fixed overlay scrims */
  --frame-gutter:  40px;  /* horizontal page gutter (dash, player, record, lock) */
}

/* Additional themes (Arasaka / Militech / …) will be added here as
   `html.theme-<name> { --primary: …; --bg: …; … }`, overriding only the
   semantic roles. The palette + component layers stay untouched. */
