/* ═══════════════════════════════════════════════════════════════
   TOKENS — THE GOOD NEWS LINE CONSOLE (GNL-77)
   Materials first, roles second. Nothing here is decorative.
   ═══════════════════════════════════════════════════════════ */

/* ── THE PANEL FACE ────────────────────────────────────────────
   Self-hosted variable Mannin: 133 KB subset, both axes kept.
   The width axis is the reason it is here — instrument legends are
   condensed, and no static face can do that without faking it with
   letter-spacing. Licence: UFL 1.0, see assets/fonts/LICENCE_UFL.txt. */
@font-face {
  font-family: 'Mannin';
  src: url('../assets/fonts/Mannin.woff2') format('woff2-variations');
  font-weight: 100 900;
  font-stretch: 62% 100%;
  font-display: swap;
}

/* ── THE SCREEN VOICE ──────────────────────────────────────────
   Space Mono, now self-hosted too. It was the last exception, loaded
   from a font CDN — which is an external point of failure and hands
   every visitor's IP to a third party for nothing. Latin subset, both
   weights, 19 KB total. Licence: SIL OFL 1.1. */
@font-face {
  font-family: 'Space Mono';
  src: url('../assets/fonts/SpaceMono-400.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Space Mono';
  src: url('../assets/fonts/SpaceMono-700.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

:root {
  /* ── DAY ELEVATION RAMP ────────────────────────────────────
     Same discipline as night: one stepped neutral ramp, every
     surface is a step, roles alias the steps. e0 is the paper
     catching the most light; e4 is the deepest well.
       e0 #FFFDF8   paper highlight
       e1 #F6F1E6   raised surfaces, flanges, keys
       e2 #EFE9DA   the board
       e3 #E1D9C6   lowered surfaces, gradient partners
       e4 #CFC5AE   wells and recesses                          */
  --e0: #FFFDF8;
  --e1: #F6F1E6;
  --e2: #EFE9DA;
  --e3: #E1D9C6;
  --e4: #CFC5AE;

  /* ── 60% dominant · roles alias the ramp ───────────────── */
  --enamel:          var(--e1);
  --paper-hi:        var(--e0);
  --enamel-shade:    var(--e2);
  --enamel-deep:     var(--e3);
  --enamel-recess:   var(--e4);

  /* ── 30% secondary · the teal the machine is painted in ──
     This is the signature colour: reel hubs, head block, keys,
     routed traces, engraved rules. Green is retired.          */
  --teal:            #6FB2B0;
  --teal-light:      #8FC9C6;
  --teal-mid:        #4E9997;
  --teal-dark:       #27615F;   /* Lc ~60 on enamel — the lightest teal safe for text */
  --teal-ink:        #1B5254;
  --teal-deep:       #12403F;   /* glyphs printed ON a teal key */

  /* ── 10% accent · lamps, live states, the record key ───── */
  --amber:           #C9A227;
  --lamp-red:        #C8352C;
  --lamp-green:      #2D7A3E;

  /* screen phosphor — the pale aqua of the tape-out lines */
  --phosphor:        #8FE3E0;
  --phosphor-dim:    #6EC5C2;

  /* digital readout — the orange LED counter */
  --led:             #FFA524;
  --led-dim:         #6A3F04;

  /* ── materials ─────────────────────────────────────────── */
  --steel:           #BEBCB6;
  --steel-dark:      #82807A;
  --steel-light:     #E8E6E0;
  /* Brushed aluminium — matte, not chrome. The highlight is broad and soft
     rather than a specular point; that is the whole difference between
     "machined part" and "shiny plastic". */
  --alu-hi:          #F4F4F1;
  --alu:             #C6C5C0;
  --alu-lo:          #8E8D87;
  --alu-edge:        #5E5D58;
  --brass:           #C9A83C;
  --brass-dark:      #8A6F1E;
  /* Polished sheet brass for fitted panels — no brushing, just a specular
     sweep like the one on the dial. Darker and richer than raw sheet.
     The floor (--brass-sheet-lo) is set exactly as low as it can go while
     engraved labels still clear 4.5:1 over it. Go darker than this and the
     legend has to move off the metal. */
  --brass-sheet:     #C0A25C;
  --brass-sheet-hi:  #EBDAA8;
  --brass-sheet-lo:  #A5863F;
  --ink-on-brass:    #241F0F;   /* 4.8:1 on the darkest reflection */
  --bakelite:        #2A2724;
  --bakelite-light:  #423D37;
  /* A key sitting ON a bakelite housing has to read as raised off it, so it
     gets its own pair rather than reusing the bed's. Both flip to the night
     ramp in the dark block — see the note there about why the housings were
     reading brown. */
  --housing-key:     #3E3933;
  --housing-key-deep:#282521;

  /* magnetic tape */
  --tape:            #6E4A2C;
  --tape-light:      #8A6039;
  --tape-dark:       #4A2F18;

  /* ── ink ───────────────────────────────────────────────────
     Every value here clears 4.5:1 against the *darkest* surface it
     is allowed to sit on (--enamel-recess, the transport housing).
     Engraved type is dark-and-stamped, not pale-and-pretty.        */
  /* Retuned against APCA (Lc), not WCAG2 ratios — WCAG2 passed label inks
     that sat at Lc 53–55 where fluent small text needs Lc 60+. Engraved
     labels must clear Lc 60 on the DEEPEST surface they sit on.            */
  --ink:             #2C3734;   /* body: Lc ~82 on enamel */
  --ink-soft:        #4B473F;   /* Lc ~66 */
  --engrave:         #43403A;   /* Lc ~64 on enamel, ~61 on the deep bays */
  --engrave-hi:      rgba(255, 255, 255, 0.72);
  --placeholder:     #56524A;   /* Lc ~60 inside a field */

  /* ── screens ───────────────────────────────────────────── */
  --crt-bg:          #061716;
  --counter-bg:      #1A1305;
  --counter-digit:   var(--led);

  /* ── type ──────────────────────────────────────────────────
     Three voices, one per material — this is what keeps it premium
     rather than costume.

     · METAL  — anything engraved, stamped or printed on the panel.
                A grotesque, because that is what is actually on a
                Braun or a Revox. Monospace here reads as "computer",
                and the machine predates computers.
     · SCREEN — anything behind glass: CRT legends, phosphor readouts,
                timecodes. Monospace is correct here; it is a character
                display.
     · LED    — the counters. Not a font at all: real seven-segment
                geometry drawn in SVG (see modules/counter.js).          */
  --font-ui: 'Mannin', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  --font-display: 'Space Mono', ui-monospace, 'SFMono-Regular', 'Courier New', monospace;

  --track-label: 0.15em;    /* engraved caps want air */
  --track-display: 0.04em;
  --track-title: 0.02em;

  /* ── spacing ───────────────────────────────────────────── */
  --gap-bay: clamp(1rem, 2vw, 2rem);
  --gap-module: clamp(0.9rem, 1.7vw, 1.6rem);
  --gap-lg: 1.25rem;
  --gap-md: 0.875rem;
  --gap-sm: 0.5rem;
  --gap-xs: 0.25rem;

  /* ── depth ─────────────────────────────────────────────── */
  --inset-1: inset 1px 1px 2px rgba(0, 0, 0, 0.16), inset -1px -1px 1px rgba(255, 255, 255, 0.55);
  --inset-2: inset 2px 3px 6px rgba(0, 0, 0, 0.28), inset -1px -1px 2px rgba(255, 255, 255, 0.4);
  --inset-3: inset 3px 4px 10px rgba(0, 0, 0, 0.42), inset -1px -1px 3px rgba(255, 255, 255, 0.3);

  --raise-1: 1px 1px 2px rgba(60, 50, 35, 0.22), -1px -1px 2px rgba(255, 255, 255, 0.7);
  --raise-2: 2px 3px 6px rgba(60, 50, 35, 0.24), -1px -2px 4px rgba(255, 255, 255, 0.75);
  --raise-3: 3px 5px 12px rgba(52, 44, 30, 0.28), -2px -3px 6px rgba(255, 255, 255, 0.8);

  --engrave-text: 0 1px 0 var(--engrave-hi);

  /* ── radii ─────────────────────────────────────────────── */
  --r-xs: 2px;
  --r-sm: 3px;
  /* Pressable things get real corner radius. Engraved plates and screen
     bezels stay tight — the softness belongs to what your finger touches,
     not to what is stamped into metal. */
  --r-key: 10px;
  --r-window: 5px;
  --r-md: 5px;
  --r-lg: 9px;
  --r-xl: 14px;

  /* ── motion · everything has mass ──────────────────────── */
  --t-tap: 90ms;
  --t-quick: 180ms;
  --t-panel: 620ms;
  --t-drawer: 720ms;
  --ease-mech: cubic-bezier(0.62, 0.02, 0.16, 1);
  --ease-settle: cubic-bezier(0.16, 0.9, 0.28, 1.02);
  --ease-rail: cubic-bezier(0.36, 0.02, 0.12, 1);

  /* ── board texture ─────────────────────────────────────── */
  --perf-size: 13px;
  --perf-dot: rgba(86, 64, 38, 0.34);

  --focus-ring: 3px solid var(--amber);
  --focus-offset: 3px;
  --tap-min: 44px;
}

/* ── LAB FINISH · an experiment, not the default ──────────────
   The same machine sprayed white instead of enamel. Try it with:
       document.documentElement.dataset.finish = 'lab'
   and take it off with `delete document.documentElement.dataset.finish`.

   Two things to judge honestly when you look at it:
   · It reads as *new* — lab instrument, not restored object. That is a real
     and respectable direction, but it argues with "nothing should look new,
     everything should feel maintained" in the brief.
   · Brass against pure white can read as yellowed rather than rich, because
     there is no warmth in the surround to make it look deliberate. The dots
     are pulled cool here to stop the whole board going cream by association.  */
:root[data-finish='lab'] {
  /* The board sits a shade below pure white on purpose. The reel flanges are
     --enamel; if the board were also #FFF the empty take-up reel would vanish
     into it. White backgrounds cost you the separation that a warm plate gives
     for free, and every white part has to be re-separated by hand. */
  --enamel:          #FFFFFF;
  --enamel-shade:    #F2F3F4;
  --enamel-deep:     #E6E7E8;
  --enamel-recess:   #D8DADB;
  --perf-dot:        rgba(38, 44, 48, 0.2);
  --ink:             #23302E;
  --ink-soft:        #4E524F;
  --engrave:         #4A4E4C;
  --engrave-hi:      rgba(255, 255, 255, 0.9);
  --steel:           #C9C9C6;
  --steel-light:     #F0F0EE;
  /* brass warms up slightly so it doesn't read as a stain on the white */
  --brass-sheet:     #C6A860;
  --brass-sheet-hi:  #EFDFAE;
  --brass-sheet-lo:  #AB8C45;
}

/* ── HIGH CONTRAST ────────────────────────────────────────────
   Same machine, harder light. Raises ink contrast and flattens
   the softest bevels so labels survive on a beige plate.        */
:root[data-contrast='high'] {
  --enamel:        #FFFDF6;
  --enamel-shade:  #F6F2E7;
  --enamel-deep:   #DCD3BF;
  --teal:          #2C7C7E;
  --teal-light:    #4E9997;
  --teal-mid:      #1F6567;
  --teal-dark:     #12484B;
  --teal-ink:      #0A3234;
  --ink:           #10302E;
  --ink-soft:      #38342C;
  --engrave:       #47433A;
  --perf-dot:      rgba(40, 30, 16, 0.42);
  --phosphor:      #B4FFFC;
  --led:           #FFC15C;
  --engrave-text:  none;
  --focus-ring: 3px solid #7A5B00;
}

@media (prefers-contrast: more) {
  :root:not([data-contrast='normal']) {
    --ink: #10302E;
    --engrave: #47433A;
    --engrave-text: none;
  }
}


/* ── NIGHT ─────────────────────────────────────────────────────
   The workshop lights are off; the machine's own lamps carry the room.
   Same object, same materials — the enamel goes to shadow, the teal,
   brass, LED and phosphor stay lit because they are the light sources.
   Chosen by the NIGHT switch, seeded from prefers-color-scheme.
   Session-only by design: nothing about the visitor is stored.        */
:root[data-theme='dark'] {
  /* ── NIGHT ELEVATION RAMP ──────────────────────────────────
     Material-style dark: depth is expressed by LIGHTNESS, not by
     shadow. The nearer a surface is to you, the lighter it is.
     One neutral ramp, every surface maps to a step — no ad-hoc
     hexes below this line.
       n0 #0A0A0A  wells, recesses, the void
       n1 #121212  the board (the base surface)
       n2 #1A1A1A  bays sitting on the board
       n3 #222222  panels, the plate, paper
       n4 #2B2B2B  raised controls on those surfaces
       n5 #363636  hover / top edge light                        */
  --n0: #0A0A0A;
  --n1: #121212;
  --n2: #1A1A1A;
  --n3: #222222;
  --n4: #2B2B2B;
  --n5: #363636;

  --enamel:          var(--n3);   /* raised/panel surfaces */
  --enamel-shade:    var(--n1);   /* the board */
  --enamel-deep:     var(--n2);   /* gradient partner */
  --enamel-recess:   var(--n0);
  --paper-hi:        var(--n4);   /* paper catches the most light */
  --perf-dot:        rgba(224, 224, 220, 0.07);

  /* THE HOUSINGS JOIN THE RAMP.
     Bakelite is a warm brown-black in daylight and that is correct — it is
     a real material and it is what the transport bed, the scope bezel and
     the VU bezel are made of. But it was never mapped to the night ramp,
     so at night every dark housing stayed warm while the board around it
     went neutral, and the whole machine read brown instead of dark.

     Night is an elevation ramp, and a housing is a step on it like
     everything else: n0 for the face, n2 for the lit edge. Same object,
     different light — which is the rule the whole dark theme runs on. */
  --bakelite:        var(--n0);
  --bakelite-light:  var(--n2);
  --housing-key:     var(--n3);
  --housing-key-deep:var(--n1);

  /* ink tuned by APCA, not WCAG2 — see the audit note in CLAUDE.md */
  --ink:             #F0EEE9;   /* Lc ~93 on n1 */
  --ink-soft:        #CFCCC5;   /* Lc ~66 on n3, the lightest surface it sits on */
  --engrave:         #CBC8C1;   /* Lc ~64 on n3 */
  --engrave-text:    none;
  --placeholder:     #B0ADA6;

  /* text-role teals flip to ~200-tone tints (Material: desaturate on dark) */
  --teal-ink:        #ABDEDB;
  --teal-dark:       #93CCC9;

  --steel:           #4E4E4E;
  --steel-dark:      #2E2E2E;
  --steel-light:     #707070;

  --focus-ring: 3px solid #E9C35A;

  /* raised things at night: mostly shadow-free — elevation does the work */
  --raise-1: 0 1px 2px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255, 255, 255, 0.04);
  --raise-2: 0 2px 5px rgba(0, 0, 0, 0.55), 0 0 0 1px rgba(255, 255, 255, 0.05);
  --raise-3: 0 4px 10px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(255, 255, 255, 0.06);
  --inset-1: inset 1px 1px 2px rgba(0, 0, 0, 0.55), inset -1px -1px 1px rgba(255, 255, 255, 0.05);
  --inset-2: inset 2px 3px 6px rgba(0, 0, 0, 0.6), inset -1px -1px 2px rgba(255, 255, 255, 0.04);
  --inset-3: inset 3px 4px 10px rgba(0, 0, 0, 0.7), inset -1px -1px 3px rgba(255, 255, 255, 0.04);
  --engrave-hi: rgba(0, 0, 0, 0.4);
}

/* surfaces built from literals get one override each */
/* `html[data-theme]`, not `[data-theme] html`. The attribute lives ON the
   root element, and a descendant selector needs an ancestor to match — of
   which <html> has none, so the dark canvas silently kept the daylight
   colour. Only visible during an overscroll, which is exactly where it
   would have been missed. */
html[data-theme='dark'],
[data-theme='dark'] body {
  background: radial-gradient(120% 90% at 50% 0%, #0C0C0C 0%, #050505 55%, #000000 100%);
  background-color: #000000;
}
[data-theme='dark'] .console {
  background: linear-gradient(158deg, #2A2A2A 0%, #1C1C1C 22%, #141414 52%, #1C1C1C 78%, #232323 100%);
  box-shadow: 0 42px 90px -30px rgba(0, 0, 0, 0.9),
    0 1px 0 rgba(255, 255, 255, 0.08) inset, 0 -2px 0 rgba(0, 0, 0, 0.5) inset;
}
[data-theme='dark'] .nameplate__title { color: #DCDAD5; text-shadow: 0 1px 0 rgba(0, 0, 0, 0.6); }
[data-theme='dark'] .nameplate__model { color: #B8B6B0; }
[data-theme='dark'] .toggle { background: linear-gradient(#2A2A2A, #1B1B1B); border-color: rgba(0, 0, 0, 0.7); }
[data-theme='dark'] .toggle__label { color: #D6D4CE; }
[data-theme='dark'] .board {
  background-image:
    radial-gradient(var(--perf-dot) 1.1px, transparent 1.2px),
    radial-gradient(120% 80% at 50% 0%, rgba(255, 255, 255, 0.05), transparent 60%),
    linear-gradient(180deg, rgba(255, 255, 255, 0.02), rgba(0, 0, 0, 0.3));
}
[data-theme='dark'] .grain__fine { mix-blend-mode: screen; opacity: 0.035; }
[data-theme='dark'] .grain__coarse { mix-blend-mode: screen; opacity: 0.05; }
[data-theme='dark'] .bay--deck {
  /* one step above the board — elevation, not shadow */
  background: var(--n2);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05), 0 0 0 1px rgba(0, 0, 0, 0.4);
}

/* the reels are still cream — the object doesn't change, only the light */
[data-theme='dark'] .stop-enamel       { stop-color: #F6F1E6; }
[data-theme='dark'] .stop-enamel-shade { stop-color: #E8E1D2; }
[data-theme='dark'] .stop-enamel-deep  { stop-color: #D2C9B4; }
[data-theme='dark'] .reel__rim { stroke: #EFE9DA; }
[data-theme='dark'] .reel__hub-sheen { stroke: rgba(255, 255, 255, 0.3); }

[data-theme='dark'] .plate {
  /* the plate sits ON the board, so it is lighter than the board — n3 */
  background: linear-gradient(118deg, #262626 0%, #1F1F1F 38%, #282828 62%, #1D1D1D 100%);
  border-color: rgba(0, 0, 0, 0.55);
  box-shadow: var(--raise-3), inset 0 1px 0 rgba(255, 255, 255, 0.08), inset 0 -1px 0 rgba(0, 0, 0, 0.4);
}
[data-theme='dark'] .plate__title { text-shadow: none; }
[data-theme='dark'] .panel {
  box-shadow: 0 30px 50px -14px rgba(0, 0, 0, 0.8),
    inset 0 0 0 1px rgba(0, 0, 0, 0.55), inset 0 1px 0 1px rgba(255, 255, 255, 0.07);
}
[data-theme='dark'] .panel__title { text-shadow: none; }
[data-theme='dark'] .archive__row:hover { background: rgba(255, 255, 255, 0.05); }
[data-theme='dark'] .archive__row.is-loaded { background: rgba(143, 227, 224, 0.08); }
[data-theme='dark'] .lamp:hover { background: rgba(255, 255, 255, 0.07); }
[data-theme='dark'] .lamp:active { background: rgba(255, 255, 255, 0.1); }
[data-theme='dark'] .field input,
[data-theme='dark'] .field textarea {
  background: var(--n1);
  border-color: rgba(0, 0, 0, 0.6);
}
[data-theme='dark'] .archive__filters .field--search input {
  background: none;
  border-bottom-color: rgba(226, 214, 188, 0.3);
}
[data-theme='dark'] .notes__chips li {
  color: #BFE8E5;
  background: rgba(143, 227, 224, 0.1);
  border-color: rgba(143, 227, 224, 0.35);
}
[data-theme='dark'] .ticket {
  background:
    repeating-linear-gradient(180deg, transparent 0 27px, rgba(143, 227, 224, 0.05) 27px 28px),
    linear-gradient(180deg, var(--n3), var(--n2));
  border-color: rgba(0, 0, 0, 0.55);
}
[data-theme='dark'] .ticket-list li { background: var(--n3); }
[data-theme='dark'] .coin-mech { background: linear-gradient(180deg, var(--n4), var(--n3)); }
[data-theme='dark'] .jack { background: linear-gradient(180deg, var(--n4), var(--n3)); }
[data-theme='dark'] .transport__buttons::before,
[data-theme='dark'] .transport__buttons::after {
  box-shadow: inset 0 -1px 1px rgba(0, 0, 0, 0.7), 0 1px 0 rgba(255, 255, 255, 0.1);
}


/* at night the lit instruments bloom — the dreaminess comes from the light
   sources widening, never from blurring the room around them */
[data-theme='dark'] .readout {
  text-shadow: 0 0 9px rgba(143, 227, 224, 0.6), 0 0 24px rgba(143, 227, 224, 0.25);
}
[data-theme='dark'] .seg__bar.is-lit {
  filter:
    drop-shadow(0 0 3px rgba(255, 165, 36, 1))
    drop-shadow(0 0 9px rgba(255, 132, 0, 0.6));
}
[data-theme='dark'] .scope__legend {
  text-shadow: 0 0 8px rgba(143, 227, 224, 0.55), 0 0 20px rgba(143, 227, 224, 0.22);
}
[data-theme='dark'] .lamp--teal.is-lit .lamp__glass::after {
  background: radial-gradient(circle, rgba(143, 227, 224, 0.55), transparent 64%);
}
[data-theme='dark'] .lamp--amber.is-lit .lamp__glass::after {
  background: radial-gradient(circle, rgba(255, 198, 74, 0.5), transparent 64%);
}

/* durations sit at body size, so they take body ink at night */
[data-theme='dark'] .archive__len { color: var(--ink); opacity: 0.92; }

/* night: the CRT ghost labels earn full phosphor; the rubber stamp stays
   legible as decoration (aria-hidden, spot threshold only) */
[data-theme='dark'] .locator__when { opacity: 1; }
[data-theme='dark'] .ticket__stamp {
  color: rgba(255, 140, 130, 0.8);
  border-color: rgba(255, 140, 130, 0.55);
}
