/* ===========================================================================
   wopr.css · platform design tokens
   600-INF/Style Guide/wopr.css · v6.2.0 · 2026-09-29

   SOURCE OF TRUTH. Every surface carries a BYTE-IDENTICAL copy: no provenance
   header, no local edits. Provenance lives beside the copy in WOPR-VENDOR
   (see STYLE.md § One version everywhere). Drift check:
     md5sum "600-INF/Style Guide/wopr.css" <surface>/static/wopr.css
   style-lint.py rule `vendor-version` fails a surface whose copy is older or
   whose md5 differs.

   Governed by 600-INF/Style Guide/STYLE.md. Changing a token here requires the
   matching STYLE.md edit and style-lint.py rule in the SAME commit.

   5.0.0 IN ONE PARAGRAPH. Tokens are named by role (--accent, --status-ok),
   with every 4.x hue name kept as an alias. The theme is two attributes on
   <html>: data-theme (dark | light) and data-palette (amber | green | blue | white;
   white since 6.0.0), eight combinations. A palette replaces the accent family and nothing else;
   structure, type and space are shared by all six. Dark green and dark blue
   report status by VT100 levels (dim, normal, bright, reverse video) in the
   one phosphor colour; dark amber and every light combination keep real
   status colour. Every text/ground pair is measured in all six against the
   floor in STYLE.md § Contrast floor.
   =========================================================================== */

:root {
  --wopr-css-version: "6.2.0";
}

/* ===========================================================================
   COLOUR · MODE BLOCKS
   ---------------------------------------------------------------------------
   Selector plan. Specificity does the work, so the order below is part of the
   contract and MUST NOT be rearranged:
     :root, [data-theme="dark"]                      0,1,0  dark · amber
     [data-theme="light"]                            0,1,0  light · amber
     [data-palette="green"]:not([data-theme="light"])  0,2,0  dark · green
     [data-palette="blue"]:not([data-theme="light"])   0,2,0  dark · blue
     [data-theme="light"][data-palette="green"]      0,2,0  light · green
     [data-theme="light"][data-palette="blue"]       0,2,0  light · blue
     [data-palette="white"]:not([data-theme="light"])  0,2,0  dark · white
     [data-theme="light"][data-palette="white"]      0,2,0  light · white
   Both attributes are set together, on the same element, by theme-script.js.
   A page with no attributes renders dark · amber. A page with only
   data-theme="light" renders light · amber. Attribute selectors match any
   element, so a specimen may scope a combination to a panel.
   =========================================================================== */

:root,
[data-theme="dark"] {
  color-scheme: dark;

  /* --- STRUCTURAL: racks, cabinets, room. Settled; shared by all palettes */
  --bunker:        #2A2D31;   /* darkest structural grey                    */
  --slate:         #43484D;   /* mid structural                             */
  --steel:         #6E757B;   /* light structural, labels                   */
  --panel-beige:   #B8AF9D;   /* warm neutral, BODY PROSE on dark           */

  /* --- SURFACE LADDER. Settled. Three steps and no more ----------------- */
  --surface-0:     #0D0F11;   /* page ground                                */
  --surface-1:     #16191C;   /* card                                       */
  --surface-2:     #1E2226;   /* raised card, hover                         */
  --border:        var(--bunker);
  --border-light:  #3A4046;   /* the dialog, and nothing else               */

  /* --- INK. Figures are the WORST surface of the ladder, not surface-0 --- */
  --text-1:        #E8E6E1;   /* 12.8:1 worst (15.4 on surface-0)           */
  --text-2:        var(--panel-beige);   /* 7.4:1 worst (8.8 on surface-0)  */
  --text-3:        var(--steel);         /* 3.4:1 worst; labels only        */

  /* --- ACCENT, amber palette (default) --------------------------------- */
  --accent:        #F5A623;   /* 7.9:1 worst. Links, h2, controls, focus    */
  --accent-deep:   #D98200;   /* hover and pressed only                     */
  --accent-bright: #FFC766;   /* VT100 bright; the terminal ink (6.2.0)     */
  --accent-dim:    #B8801F;   /* VT100 dim; the terminal dim (6.2.0)        */
  --accent-rgb:    245 166 35;

  /* --- STATUS, real colour. Always beside a word ------------------------ */
  --status-ok:        #4CAF50;   /* up / pass / live         lamp 5.8:1     */
  --status-warn:      #FFD54F;   /* degraded / caution       lamp 11.3:1    */
  --status-bad:       #D72638;   /* down / fail / destructive lamp 3.2:1    */
  --status-bad-text:  #FF6B78;   /* the same fault set as TEXT, 5.8:1       */
  --status-muted:     #9D1D27;   /* inactive error: fills and edges only    */
  --status-none:      var(--steel);  /* unbound, deliberately not routed    */
  --status-ok-ink:    var(--text-1);
  --status-warn-ink:  var(--text-1);
  --status-bad-ink:   var(--text-1);
  --status-bad-ground: transparent;
  --status-muted-ink: var(--text-2);

  /* --- PHOSPHOR. Quarantined: .terminal and theatre only ---------------- */
  --phosphor:      #67D96B;   /* P1 green, normal. Also the green accent    */
  --crt-green:     #00FF41;   /* P1 green, bright                           */
  --phosphor-dim:  #34A853;   /* P1 green, dim. 6.5:1 (was #006B1A, 2.9:1)  */
  --terminal-black: #0A0A0A;  /* the CRT ground (was a literal in .terminal)*/

  /* --- TERMINAL roles. 6.2.0 (Po, 2026-09-29, review R3): the terminal on
     an amber display is amber phosphor (P3), not a green box, as blue and
     white carry their own. Status stays real colour, so warn (#FFD54F, near
     the ink) is told apart by weight, and the accent by underline. ------- */
  --terminal-ground:     var(--terminal-black);
  --terminal-ink:        var(--accent-bright);   /* #FFC766 */
  --terminal-dim:        var(--accent-dim);      /* #B8801F, 5.8:1 */
  --terminal-bright:     var(--accent-bright);
  --terminal-accent:     var(--accent);
  --terminal-warn:       var(--status-warn);
  --terminal-bad-ink:    var(--status-bad-text);
  --terminal-bad-ground: transparent;
  --terminal-accent-line: underline;
  --terminal-warn-weight: 700;
  --terminal-scanlines:  repeating-linear-gradient(0deg, transparent, transparent 2px,
                         rgba(0,0,0,.05) 2px, rgba(0,0,0,.05) 4px);

  /* --- LAYER ------------------------------------------------------------ */
  --backdrop:      rgb(13 15 17 / .7);
}

/* Light: warm paper, ratified 3.0.0. The ladder runs lighter. */
[data-theme="light"] {
  color-scheme: light;

  --bunker:        #D6D1C4;
  --slate:         #8A8375;
  --steel:         #8A8375;
  --panel-beige:   #5C564A;

  --surface-0:     #EDE8DC;
  --surface-1:     #F5F2EA;
  --surface-2:     #FBF9F4;
  --border:        #D6D1C4;   /* warmed; cool greys read green on paper     */
  --border-light:  #BDB6A6;

  --text-1:        #2B2721;   /* 12.1:1 worst (was quoted 13.9)             */
  --text-2:        #5C564A;   /*  6.0:1 worst (was quoted 7.2)              */
  --text-3:        #8A8375;   /*  3.1:1 worst; labels only (was quoted 3.6) */

  --accent:        #A8410D;   /* burnt orange, 5.0:1 worst (was quoted 6.2) */
  --accent-deep:   #8A3309;
  --accent-bright: var(--accent-deep);   /* parity only; light has no VT100 */
  --accent-dim:    var(--accent);        /* parity only                     */
  --accent-rgb:    168 65 13;

  --status-ok:        #256B2A;
  --status-warn:      #74560B;   /* the biggest move: #FFD54F vanishes     */
  --status-bad:       #A81E2B;
  --status-bad-text:  #A81E2B;   /* already 6.0:1 as text on paper          */
  --status-muted:     #7A1620;
  --status-none:      var(--steel);
  --status-ok-ink:    var(--text-1);
  --status-warn-ink:  var(--text-1);
  --status-bad-ink:   var(--text-1);
  --status-bad-ground: transparent;
  --status-muted-ink: var(--text-2);

  /* The terminal on paper renders light (4.0.0). Levels tightened at 5.0.0
     so the dim line meets the text floor: ink text-1, dim text-2. */
  --terminal-ground:     var(--surface-2);
  --terminal-ink:        var(--text-1);
  --terminal-dim:        var(--text-2);
  --terminal-bright:     var(--text-1);
  --terminal-accent:     var(--accent);
  --terminal-warn:       var(--status-warn);
  --terminal-bad-ink:    var(--status-bad-text);
  --terminal-bad-ground: transparent;
  --terminal-accent-line: none;
  --terminal-warn-weight: 400;
  --terminal-scanlines:  none;   /* a CRT artefact printed on paper is theatre
                                    about theatre */

  --backdrop:      rgb(43 39 33 / .35);
}

/* Dark · green. A P1 green-phosphor display. The accent is the ratified
   phosphor family, so nothing is invented: normal --phosphor, bright
   --crt-green, dim --phosphor-dim. Status by VT100 level, one colour. */
[data-palette="green"]:not([data-theme="light"]) {
  --accent:        var(--phosphor);       /* 8.9:1 worst */
  --accent-deep:   #4CBF55;
  --accent-bright: var(--crt-green);
  --accent-dim:    var(--phosphor-dim);
  --accent-rgb:    103 217 107;

  --status-ok:        var(--accent);         /* normal  */
  --status-warn:      var(--accent-bright);  /* bright  */
  --status-bad:       var(--accent-bright);  /* reverse video, on the word */
  --status-bad-text:  var(--accent-bright);
  --status-muted:     var(--accent-dim);     /* dim     */
  --status-ok-ink:    var(--accent);
  --status-warn-ink:  var(--accent-bright);
  --status-bad-ink:   var(--surface-0);
  --status-bad-ground: var(--accent-bright);
  --status-muted-ink: var(--accent-dim);

  /* The green CRT, stated here since 6.2.0 moved the dark default to amber. */
  --terminal-ink:        var(--crt-green);
  --terminal-dim:        var(--phosphor-dim);
  --terminal-bright:     var(--crt-green);
  --terminal-warn:       var(--crt-green);
  --terminal-warn-weight: 700;
  --terminal-accent-line: underline;
  --terminal-bad-ink:    var(--terminal-black);
  --terminal-bad-ground: var(--crt-green);
}

/* Dark · blue. A blue-phosphor display. Not the retired FALKEN blue: the
   ground stays the structural near-black, and #4B8EFF appears nowhere. */
[data-palette="blue"]:not([data-theme="light"]) {
  --accent:        #6CB4F0;   /* 7.2:1 worst */
  --accent-deep:   #4F9BDB;
  --accent-bright: #B5DCFF;
  --accent-dim:    #4F8FCC;   /* 4.7:1 worst */
  --accent-rgb:    108 180 240;

  --status-ok:        var(--accent);
  --status-warn:      var(--accent-bright);
  --status-bad:       var(--accent-bright);
  --status-bad-text:  var(--accent-bright);
  --status-muted:     var(--accent-dim);
  --status-ok-ink:    var(--accent);
  --status-warn-ink:  var(--accent-bright);
  --status-bad-ink:   var(--surface-0);
  --status-bad-ground: var(--accent-bright);
  --status-muted-ink: var(--accent-dim);

  /* The terminal on a blue display is blue phosphor, not a green box. */
  --terminal-ink:        var(--accent-bright);
  --terminal-dim:        var(--accent-dim);
  --terminal-bright:     var(--accent-bright);
  --terminal-warn:       var(--accent-bright);
  --terminal-warn-weight: 700;
  --terminal-accent-line: underline;
  --terminal-bad-ink:    var(--terminal-black);
  --terminal-bad-ground: var(--accent-bright);
}

/* Light · green and light · blue. Accent family only; status stays real. */
[data-theme="light"][data-palette="green"] {
  --accent:        #4A6B00;   /* olive, 5.1:1 worst; not --status-ok's hue  */
  --accent-deep:   #3A5500;
  --accent-bright: var(--accent-deep);
  --accent-dim:    var(--accent);
  --accent-rgb:    74 107 0;
}
[data-theme="light"][data-palette="blue"] {
  --accent:        #1F5C99;   /* 5.6:1 worst */
  --accent-deep:   #174A7C;
  --accent-bright: var(--accent-deep);
  --accent-dim:    var(--accent);
  --accent-rgb:    31 92 153;
}

/* Dark · white and light · white. 6.0.0, ratified by Po 2026-09-29.
   A P4 white-phosphor display. Measured against the contrast floor on the
   worst surface: dark accent #E6EAEF 13.25:1, deep 9.07:1, bright 16.01:1,
   dim 6.27:1; light accent #1B1E22 13.68:1, deep 8.58:1.
   White is the colour of the text in both modes (accent against --text-1:
   1.03:1 dark, 1.13:1 light), so the accent cannot say what is clickable.
   Links therefore carry their underline at full strength on this palette.
   Status stays in real colour in both modes, as on amber: VT100 levels need
   normal and bright to differ, and on white they do not. */
[data-palette="white"]:not([data-theme="light"]) {
  --accent:        #E6EAEF;   /* 13.25:1 worst */
  --accent-deep:   #BCC4CC;   /*  9.07:1 worst */
  --accent-bright: #FFFFFF;   /* 16.01:1 worst */
  --accent-dim:    #9BA3AB;   /*  6.27:1 worst */
  --accent-rgb:    230 234 239;
  --accent-underline: rgb(var(--accent-rgb) / 1);   /* links: full-strength underline (6.0.0); outranks the derived .35 */
  --affordance-line: underline;   /* 6.1.0: controls, see § Affordance */

  /* The terminal on a white display is white phosphor. */
  --terminal-ink:        var(--accent);
  --terminal-dim:        var(--accent-dim);
  --terminal-bright:     var(--accent-bright);
  --terminal-accent-line: underline;
  --terminal-warn-weight: 400;   /* held at 6.1.0's value when 6.2.0 moved the dark default to 700 */
}
[data-theme="light"][data-palette="white"] {
  --accent:        #1B1E22;   /* 13.68:1 worst */
  --accent-deep:   #3A4046;   /*  8.58:1 worst */
  --accent-bright: var(--accent-deep);
  --accent-dim:    var(--accent);
  --accent-rgb:    27 30 34;
  --accent-underline: rgb(var(--accent-rgb) / 1);   /* links: full-strength underline (6.0.0); outranks the derived .35 */
  --affordance-line: underline;   /* 6.1.0: controls, see § Affordance */
}

/* ===========================================================================
   DERIVED TOKENS AND ALIASES
   Declared on every element that carries an attribute, so they recompute
   wherever the accent does. Fixed alphas: .06 fill, .12 hover, .30 and .40
   edges, .35 underline, .25 selection. Do not invent new ones.
   The 4.x hue names are ALIASES. No call site breaks; new code uses roles.
   =========================================================================== */

:root,
[data-theme],
[data-palette] {
  --accent-fill:        rgb(var(--accent-rgb) / .06);
  --accent-hover-fill:  rgb(var(--accent-rgb) / .12);
  --accent-edge:        rgb(var(--accent-rgb) / .30);
  --accent-edge-strong: rgb(var(--accent-rgb) / .40);
  --accent-underline:   rgb(var(--accent-rgb) / .35);
  --accent-select:      rgb(var(--accent-rgb) / .25);

  --amber:         var(--accent);          /* alias, 4.x */
  --deep-amber:    var(--accent-deep);     /* alias, 4.x */
  --status-green:  var(--status-ok);       /* alias, 4.x */
  --status-amber:  var(--status-warn);     /* alias, 4.x */
  --alert-red:     var(--status-bad);      /* alias, 4.x */
  --warning-red:   var(--status-muted);    /* alias, 4.x */
}


/* ===========================================================================
   TYPE, SPACE, FORM · theme-independent
   =========================================================================== */

:root {
  /* Two families, strict division of labour. Settled.
     Inter         everything a human reads as language.
     IBM Plex Mono machine speech: hostnames, code, specs, status, wordmark. */
  --font-prose: 'Inter', system-ui, -apple-system, sans-serif;
  --font-mono:  'IBM Plex Mono', ui-monospace, 'Courier New', monospace;

  --step--1: .78rem;                          /* captions, hostnames        */
  --step-0:  .925rem;                         /* body                       */
  --step-1:  1.15rem;                         /* lead, h3                   */
  --step-2:  clamp(1.25rem, 2.5vw, 1.6rem);   /* section heading            */
  --step-3:  clamp(1.8rem, 4.5vw, 2.75rem);   /* page title                 */

  /* Control scale, 2.1.0. Furniture only, never body copy. */
  --step-ui:    .875rem;   /* buttons, inputs, tabs, the wordmark (14px)    */
  --step-micro: .6875rem;  /* 11px. The floor for any text. Was .68rem
                              (10.88px), under the floor, at 4.x           */

  /* Affordance, 6.1.0. The second cue for a control whose only cue at rest
     is the accent colour. none on amber, green and blue, where the accent
     stands apart from the text; underline on white, where it does not. */
  --affordance-line: none;

  --leading-prose: 1.75;
  --leading-tight: 1.2;
  --tracking-label: .08em;   /* uppercase labels only                     */
  --tracking-mark:  .18em;   /* the wordmark only                         */

  /* SPACE (4px base). Settled. */
  --sp-1: .25rem;  --sp-2: .5rem;   --sp-3: .75rem;  --sp-4: 1rem;
  --sp-5: 1.5rem;  --sp-6: 2rem;    --sp-7: 3rem;    --sp-8: 4.5rem;

  --radius:    8px;
  --radius-sm: 4px;
  --control-h: 36px;
  --measure:   68ch;
  --gutter:    1.25rem;
  --chart-h:   340px;
}

@media (pointer: coarse) {
  :root { --control-h: 44px; }
}

/* ===========================================================================
   FONTS · self-hosted, SIL OFL 1.1. Paths resolve relative to THIS sheet, so
   static/wopr.css and static/fonts/ travel together. Both OFL files travel
   with every copy. Latin subset, woff2 only.
   =========================================================================== */

@font-face {
  font-family: 'Inter';
  src: url('fonts/InterVariable.woff2') format('woff2-variations');
  font-weight: 100 900;
  font-display: swap;
}
@font-face {
  font-family: 'IBM Plex Mono';
  src: url('fonts/IBMPlexMono-Regular.woff2') format('woff2');
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: 'IBM Plex Mono';
  src: url('fonts/IBMPlexMono-Bold.woff2') format('woff2');
  font-weight: 700;
  font-display: swap;
}

/* ===========================================================================
   BASE
   =========================================================================== */

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html { -webkit-text-size-adjust: 100%; }

/* Keyboard focus. MUST NOT be removed, MUST NOT be swapped for a border. */
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

::selection { background: var(--accent-select); color: var(--text-1); }

/* The `hidden` attribute MUST hide (2026-08-23). A component MUST NOT be able
   to override it, which is what the !important is for. */
[hidden] { display: none !important; }

/* Motion: colour and border only, 120ms ease. Named elements, not `*`. */
a, button, input, select, textarea, summary,
.btn, .tile, .tab, .row--link, .chip {
  transition: color 120ms ease, background-color 120ms ease,
              border-color 120ms ease, outline-color 120ms ease;
}

body {
  background: var(--surface-0);
  color: var(--text-2);
  font-family: var(--font-prose);
  font-size: var(--step-0);
  line-height: var(--leading-prose);
}

h1, h2, h3 { font-weight: 700; line-height: var(--leading-tight); color: var(--text-1); }
h1 { font-size: var(--step-3); letter-spacing: -.02em; }
h2 { font-size: var(--step-2); color: var(--accent); margin-top: var(--sp-7); }
h3 { font-size: var(--step-1); }

p { margin-bottom: var(--sp-4); max-width: var(--measure); }
strong { color: var(--text-1); font-weight: 600; }

a { color: var(--accent); text-decoration: none; border-bottom: 1px solid var(--accent-underline); }
a:hover { color: var(--accent-deep); border-bottom-color: var(--accent-deep); }

code, kbd, samp, .mono { font-family: var(--font-mono); font-size: .875em; }
code { background: var(--surface-2); padding: .1rem .35rem; border-radius: var(--radius-sm); color: var(--accent); }

hr { border: 0; border-top: 1px solid var(--border); margin: var(--sp-6) 0; }

.label { font-family: var(--font-mono); font-size: var(--step--1);
         letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-3); }

/* ===========================================================================
   PAGE TYPES · 5.0.0 (D8). Declared on <body data-page="…">.
     reading   narratives, SOPs, logs, about, the PERSONNEL FILE
     working   application screens: dashboards, sittings, registers
     theatre   the wopr.ltd intro and /play/ only. A quarantine, like
               .terminal, at page scope; not a third reading mode.
   =========================================================================== */

/* Reading: one column, the measure, headings divided by rules, no sidebars. */
[data-page="reading"] .wrap { max-width: calc(var(--measure) + 2 * var(--gutter)); }
[data-page="reading"] h2:not(.entry__title) {
  margin-top: var(--sp-6); padding-top: var(--sp-6);
  border-top: 1px solid var(--border);
}
[data-page="reading"] h1 + p,
[data-page="reading"] .lede { font-size: var(--step-1); color: var(--text-1); }
[data-page="reading"] ul, [data-page="reading"] ol { padding-left: var(--sp-5);
  margin-bottom: var(--sp-4); max-width: var(--measure); }
[data-page="reading"] li { margin-bottom: var(--sp-2); }

/* Theatre: the page is the terminal. Tokens only; no :root of its own. */
body[data-page="theatre"] {
  background: var(--terminal-ground);
  color: var(--terminal-ink);
  font-family: var(--font-mono);
  font-size: var(--step-0);
  line-height: 1.6;
}
body[data-page="theatre"]::after {
  content: ''; position: fixed; inset: 0; pointer-events: none;
  background: var(--terminal-scanlines);
}
body[data-page="theatre"] .dim    { color: var(--terminal-dim); }
body[data-page="theatre"] .bright { color: var(--terminal-bright); font-weight: 700; }

/* ===========================================================================
   LAYOUT · 4.1.0. Two declared containers, one measure.
   =========================================================================== */

.wrap    { max-width: 780px; margin: 0 auto; padding: var(--sp-7) var(--gutter) var(--sp-8); }
.wrap--wide { max-width: 1200px;
              padding-top: var(--sp-5); padding-bottom: var(--sp-6); }

.cols       { display: grid; gap: var(--sp-4); }
.cols--2    { grid-template-columns: repeat(2, 1fr); }
.cols--3    { grid-template-columns: repeat(3, 1fr); }
.cols--4    { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 900px) {
  .cols--3, .cols--4 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 560px) {
  .cols--2, .cols--3, .cols--4 { grid-template-columns: 1fr; }
}

.chart-wrap { position: relative; height: var(--chart-h); }

/* List and detail (4.2.0 pattern; classes adopted 5.0.0 from treasury .ld).
   Detail beside the list at 900px and wider, below it otherwise. */
.ld { display: grid; gap: var(--sp-4); }
@media (min-width: 900px) {
  .ld { grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); align-items: start; }
}

/* ===========================================================================
   CONTENT COMPONENTS
   =========================================================================== */

.card    { background: var(--surface-1); border: 1px solid var(--border);
           border-radius: var(--radius); padding: var(--sp-5); }
.card--raised { background: var(--surface-2); }

/* Status dot. The one round thing. Always beside a word. No glow: the 4.x
   box-shadow on .dot--up was the only shadow in the sheet and is removed. */
.dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%;
       flex-shrink: 0; vertical-align: middle; }
.dot--up      { background: var(--status-ok); }
.dot--warn    { background: var(--status-warn); }
.dot--down    { background: var(--status-bad); }
.dot--unbound { background: var(--status-none); }

/* Status word · 5.0.0. The word rule 2 requires, made a class, so VT100
   modes can carry the level on the word: normal, bright, reverse, dim. */
.status { display: inline-flex; align-items: center; gap: var(--sp-2);
          font-family: var(--font-mono); font-size: var(--step--1); }
.status__word { padding: 0 var(--sp-1); border-radius: var(--radius-sm); }
.status--ok    .status__word { color: var(--status-ok-ink); }
.status--warn  .status__word { color: var(--status-warn-ink); font-weight: 700; }
.status--bad   .status__word { color: var(--status-bad-ink); background: var(--status-bad-ground); }
.status--muted .status__word { color: var(--status-muted-ink); }
.status--none  .status__word { color: var(--text-3); }

.tile { display: flex; align-items: center; gap: var(--sp-3);
        padding: var(--sp-3) var(--sp-4); border-radius: var(--radius-sm);
        border: 1px solid var(--border); font-family: var(--font-mono);
        font-size: var(--step--1); }
.tile--live { border-color: var(--accent-edge); color: var(--accent);
              background: var(--accent-fill); }
.tile--live:hover { border-color: var(--accent); background: var(--accent-hover-fill); }
.tile--dark { color: var(--text-3); background: transparent; cursor: default; }
.tile__host { display: block; font-size: var(--step-micro); color: var(--text-3); }

.spec { font-family: var(--font-mono); font-size: var(--step--1);
        color: var(--text-3); line-height: 1.8; background: var(--surface-1);
        border: 1px solid var(--border); border-radius: var(--radius);
        padding: var(--sp-4); }
.spec .hl { color: var(--accent); }

.wip { display: inline-block; font-family: var(--font-mono); font-size: var(--step-micro);
       letter-spacing: var(--tracking-label); padding: .2rem .5rem;
       border-radius: var(--radius-sm); border: 1px solid var(--accent-edge-strong);
       color: var(--accent); background: var(--accent-fill); }

/* Tag · 5.0.0. INERT: no accent, no focus ring. A tag labels; a chip acts.
   Nomenclature: a shape means one thing estate-wide. */
.tags { display: flex; flex-wrap: wrap; gap: var(--sp-2); list-style: none; }
.tag  { display: inline-block; font-family: var(--font-mono); font-size: var(--step--1);
        color: var(--text-3); border: 1px solid var(--border);
        border-radius: var(--radius-sm); padding: 0 var(--sp-2); }

/* A stamp: a date or an as-of line. Machine speech, so mono. */
.stamp { font-family: var(--font-mono); font-size: var(--step--1); color: var(--text-3); }

/* ===========================================================================
   READING PATTERNS · 5.0.0
   Entry list: title (the only link), date, updated stamp, tags, summary.
   Divided by a 1px --border rule. Pure text. The PERSONNEL FILE's history
   is the same list with unlinked titles.
   =========================================================================== */

.entries { list-style: none; }
.entry { padding: var(--sp-5) 0; border-top: 1px solid var(--border); }
.entry:first-child { border-top: 0; padding-top: 0; }
.entry__title { font-size: var(--step-1); color: var(--text-1); margin: 0 0 var(--sp-2); }
.entry__meta { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-3);
               font-family: var(--font-mono); font-size: var(--step--1);
               color: var(--text-3); margin-bottom: var(--sp-3); }
.entry__summary { margin-bottom: var(--sp-3); }

/* ===========================================================================
   HERO BANNER · 5.0.0. Theatre only (wopr.ltd intro, /play/). Never
   furniture, never a nav link, never more than one per page.
   The 14px wordmark floor binds a glyph set as type. Here a glyph is one
   pixel of a letter five rows tall, so the floor binds the letterform:
   at the 6px minimum each letter is 30px tall. No glow: colour carries the
   phosphor, and the shadow ban holds. Rows are visible unless a script
   has set .is-building, so no-JS renders it whole; under reduced motion
   the rule below shows every row even if a script sets .is-building, and
   the build script SHOULD not set it at all.
   =========================================================================== */

.hero-banner { font-family: var(--font-mono); font-weight: 400;
               font-size: clamp(6px, 1.6vw, 12px); line-height: 1;
               letter-spacing: 0; white-space: pre; color: var(--accent);
               margin: 0 0 var(--sp-5); overflow: hidden; }
.hero-banner > span { display: block; }
.hero-banner.is-building > span:not(.on) { visibility: hidden; }
@media (prefers-reduced-motion: reduce) {
  .hero-banner.is-building > span { visibility: visible; }
}

/* ===========================================================================
   APPLICATION KIT · ratified 2.1.0, page 06. Extended 4.2.0 and 5.0.0.
   =========================================================================== */

/* --- Buttons ------------------------------------------------------------- */

.btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--sp-2);
  height: var(--control-h); padding: 0 var(--sp-4);
  border: 1px solid transparent; border-radius: var(--radius-sm);
  font-family: var(--font-prose); font-size: var(--step-ui); font-weight: 600;
  line-height: 1; cursor: pointer; background: transparent;
}
.btn--primary   { background: var(--accent); border-color: var(--accent);
                  color: var(--surface-0); }
.btn--primary:hover   { background: var(--accent-deep); border-color: var(--accent-deep); }
.btn--secondary { color: var(--accent); border-color: var(--accent-edge-strong); }
.btn--secondary:hover { border-color: var(--accent); background: var(--accent-hover-fill); }
.btn--ghost     { color: var(--text-2); font-weight: 400; }
.btn--ghost:hover     { color: var(--text-1); background: var(--surface-2); }
/* Danger: the label is text-1 and the fault is the edge. Alert red as label
   text was 3.2:1 on a card, under the floor. */
.btn--danger    { color: var(--text-1); border-color: var(--status-bad); }
.btn--danger:hover    { background: var(--surface-2); }
.btn--small     { height: auto; padding: var(--sp-2) var(--sp-3); font-size: var(--step--1); }
.btn[disabled], .btn--disabled { opacity: .45; cursor: not-allowed; }

/* --- Form fields --------------------------------------------------------- */

.field { display: block; margin-bottom: var(--sp-4); }
.field__label { display: block; font-size: var(--step-ui); font-weight: 600;
                color: var(--text-1); margin-bottom: var(--sp-2); }
.field__help  { font-size: var(--step--1); color: var(--text-3); margin-top: .35rem; }
.field__error { font-size: var(--step--1); color: var(--text-1);
                margin-top: .35rem; display: flex; gap: var(--sp-2); align-items: center; }

.input {
  width: 100%; height: var(--control-h);
  background: var(--surface-0); color: var(--text-1);
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 0 var(--sp-3);
  font-family: var(--font-prose); font-size: var(--step-ui);
}
.input:hover { border-color: var(--border-light); }
.input--mono { font-family: var(--font-mono); }
.input--invalid { border-color: var(--status-bad); }
textarea.input { height: auto; padding: var(--sp-3); line-height: var(--leading-prose); }
select.input { cursor: pointer; }

.segmented { display: flex; height: var(--control-h); overflow: hidden;
             border: 1px solid var(--border); border-radius: var(--radius-sm); }
.segmented__option { flex: 1; display: flex; align-items: center;
                     justify-content: center; font-size: var(--step--1);
                     color: var(--text-3); cursor: pointer; }
.segmented__option + .segmented__option { border-left: 1px solid var(--border); }
.segmented__option--on { background: var(--accent-hover-fill); color: var(--accent);
                         font-weight: 600; }

.choice { display: flex; gap: .6rem; align-items: center; cursor: pointer;
          font-size: var(--step-0); }
.choice--disabled { opacity: .45; cursor: not-allowed; }

/* --- Range · 5.0.0, adopted from doe (quick, progress) ------------------- */
/* A native <input type="range">, never a scripted one. The readout beside it
   is the value in words or figures; the track alone is not a reading. The
   thumb is square-cornered: nothing is round but the status dot. --fill is
   set by the page's script (0% to 100%); it has a real default here. */
.range { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; }
.range__input { --fill: 0%;
  flex: 1 1 12rem; -webkit-appearance: none; appearance: none;
  height: var(--control-h); margin: 0; background: transparent; cursor: pointer; }
.range__input::-webkit-slider-runnable-track {
  height: var(--sp-1); border-radius: var(--radius-sm);
  background: linear-gradient(to right, var(--accent) 0 var(--fill),
              var(--border-light) var(--fill) 100%); }
.range__input::-moz-range-track { height: var(--sp-1); border-radius: var(--radius-sm);
  background: var(--border-light); }
.range__input::-moz-range-progress { height: var(--sp-1); border-radius: var(--radius-sm);
  background: var(--accent); }
.range__input::-webkit-slider-thumb { -webkit-appearance: none; appearance: none;
  width: var(--sp-3); height: var(--sp-5); margin-top: calc((var(--sp-1) - var(--sp-5)) / 2);
  border-radius: var(--radius-sm); background: var(--accent);
  border: 2px solid var(--surface-0); }
.range__input::-moz-range-thumb { width: var(--sp-3); height: var(--sp-5);
  border-radius: var(--radius-sm); background: var(--accent);
  border: 2px solid var(--surface-0); }
.range__input:hover::-webkit-slider-thumb { background: var(--accent-deep); }
.range__input:hover::-moz-range-thumb { background: var(--accent-deep); }
.range__value { min-width: 4ch; text-align: right; font-family: var(--font-mono);
                font-variant-numeric: tabular-nums; color: var(--text-1); }
.range__cap { font-size: var(--step--1); color: var(--text-3); }

/* --- Period · 5.0.0, adopted from treasury _range.html ------------------- */
/* Preset words, a From/To date pair, and one line saying what was chosen.
   Presets wrap; the row MUST NOT scroll sideways. The pressed preset carries
   aria-pressed, so its state is not colour alone. */
.period { display: grid; gap: var(--sp-2); margin-bottom: var(--sp-4); }
.period__bar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.period__preset { height: var(--control-h); padding: 0 var(--sp-3);
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: transparent; color: var(--accent); cursor: pointer;
  font-family: var(--font-mono); font-size: var(--step-ui); }
.period__preset:hover { border-color: var(--accent); }
.period__preset[aria-pressed="true"] { background: var(--accent-hover-fill);
  border-color: var(--accent); font-weight: 700; }
.period__sep { width: 1px; align-self: stretch; background: var(--border); }
.period__date { width: auto; font-family: var(--font-mono); }
.period__note { font-family: var(--font-mono); font-size: var(--step--1); color: var(--text-3); }

/* --- Chips · 5.0.0, adopted from doe and treasury ------------------------ */
/* INTERACTIVE: accent and a focus ring. Removing a filter is the chip's one
   action; the × is a character, like ‹ and ›, not an icon. */
.chips { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.chip { display: inline-flex; align-items: center; gap: var(--sp-2);
        height: var(--control-h); padding: 0 var(--sp-3);
        border: 1px solid var(--accent-edge-strong); border-radius: var(--radius-sm);
        background: var(--accent-fill); color: var(--accent); cursor: pointer;
        font-family: var(--font-prose); font-size: var(--step-ui); }
.chip:hover { border-color: var(--accent); background: var(--accent-hover-fill); }
.chip__x { font-family: var(--font-mono); }

/* --- Figures · 5.0.0, adopted from treasury (.fig in three pages) -------- */
.fig { background: var(--surface-1); border: 1px solid var(--border);
       border-radius: var(--radius); padding: var(--sp-4); }
.fig__label { font-family: var(--font-mono); font-size: var(--step--1);
              letter-spacing: var(--tracking-label); text-transform: uppercase;
              color: var(--text-3); }
.fig__value { font-family: var(--font-mono); font-size: var(--step-2); font-weight: 700;
              color: var(--text-1); font-variant-numeric: tabular-nums;
              line-height: var(--leading-tight); margin-top: var(--sp-2); }
.fig__sub   { font-size: var(--step--1); color: var(--text-3); margin-top: var(--sp-1); }

/* --- Detail block · 5.0.0. The class 4.2.0 named and did not define ----- */
.detail { display: grid; grid-template-columns: max-content 1fr; gap: var(--sp-2) var(--sp-4); }
.detail dt { font-family: var(--font-mono); font-size: var(--step--1);
             letter-spacing: var(--tracking-label); text-transform: uppercase;
             color: var(--text-3); }
.detail dd { color: var(--text-1); }
@media (max-width: 560px) { .detail { grid-template-columns: 1fr; } }

/* --- Meter · 5.0.0. Real progress only; MUST NOT be sized by money ------- */
/* A native <progress>, so its value is in the markup. Always beside a count
   in words ("12 of 40 classified"). Nothing animates. */
progress.meter { -webkit-appearance: none; appearance: none; display: block;
  width: 100%; height: var(--sp-2); border: 0; border-radius: var(--radius-sm);
  background: var(--surface-2); color: var(--text-2); }
progress.meter::-webkit-progress-bar { background: var(--surface-2); border-radius: var(--radius-sm); }
progress.meter::-webkit-progress-value { background: var(--text-2); border-radius: var(--radius-sm); }
progress.meter::-moz-progress-bar { background: var(--text-2); border-radius: var(--radius-sm); }

/* --- Pager · PROPOSED 5.0.0. Not ratified; see STYLE.md § Pager --------- */
/* A position map inside one sitting. The current question is marked by a
   full accent edge and weight; a verdict by its bottom edge AND the summary
   line of words beside the map. Distinct from .pagination, which lists. */
.pager { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.pager__q { min-width: var(--control-h); height: var(--control-h);
  border: 1px solid var(--border); border-bottom-width: 2px;
  border-radius: var(--radius-sm); background: var(--surface-1);
  color: var(--accent); cursor: pointer;
  font-family: var(--font-mono); font-size: var(--step-ui); }
.pager__q:hover { border-color: var(--border-light); }
.pager__q[aria-current="true"] { color: var(--text-1); border-color: var(--accent); font-weight: 700; }
.pager__q--right   { border-bottom-color: var(--status-ok); }
.pager__q--wrong   { border-bottom-color: var(--status-bad); }
.pager__q--partial { border-bottom-color: var(--status-warn); }
.pager__q--waiting { border-bottom-style: dashed; }
.pager__summary { font-family: var(--font-mono); font-size: var(--step--1);
                  color: var(--text-3); margin-top: var(--sp-2); }

/* --- Table --------------------------------------------------------------- */

.table-wrap { border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
.table { width: 100%; border-collapse: collapse; font-size: var(--step-0); }
.table th {
  background: var(--surface-2); text-align: left; font-weight: 400;
  font-family: var(--font-mono); font-size: var(--step-micro);
  letter-spacing: var(--tracking-label); text-transform: uppercase;
  color: var(--text-3); padding: var(--sp-3) var(--sp-4);
}
.table td { padding: var(--sp-3) var(--sp-4); border-top: 1px solid var(--border); }
.table tbody tr:first-child td { border-top: 0; }

.table th button {
  all: unset; box-sizing: border-box; display: flex; width: 100%;
  align-items: center; gap: var(--sp-2); cursor: pointer;
  margin: calc(var(--sp-3) * -1) calc(var(--sp-4) * -1);
  padding: var(--sp-3) var(--sp-4);
  font: inherit; letter-spacing: inherit; text-transform: inherit;
  color: inherit; transition: color 120ms ease, background 120ms ease;
}
.table th button:hover { color: var(--accent); background: var(--surface-1); }
.table th button:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.table th button::after { content: ""; color: var(--text-3); font-family: var(--font-mono); }
.table th[aria-sort="ascending"]  button::after { content: "\2191"; color: var(--accent); }
.table th[aria-sort="descending"] button::after { content: "\2193"; color: var(--accent); }
.table th[aria-sort] button { color: var(--text-1); }

.cell--machine { font-family: var(--font-mono); }
.cell--num { text-align: right; font-family: var(--font-mono);
             font-variant-numeric: tabular-nums; }

.table tbody tr.row--link { cursor: pointer; }
.table tbody tr.row--link:hover { background: var(--surface-2); }
/* The selected row (List and detail) is an accent RULE, not a fill and not
   a box-shadow. 5.0.0, replacing treasury's inset shadow. */
.table tbody tr.row--on td:first-child { border-left: 2px solid var(--accent); }
.table tbody tr.row--on { color: var(--text-1); }

@media (max-width: 560px) {
  .table thead { position: absolute; width: 1px; height: 1px;
                 overflow: hidden; clip-path: inset(50%); }
  .table, .table tbody, .table tr, .table td { display: block; width: 100%; }
  .table tr { border-top: 1px solid var(--border); padding: var(--sp-3) 0; }
  .table tbody tr:first-child { border-top: 0; }
  .table td { border-top: 0; display: flex; justify-content: space-between;
              gap: var(--sp-4); padding: var(--sp-1) var(--sp-4); }
  .table td::before {
    content: attr(data-label);
    font-family: var(--font-mono); font-size: var(--step-micro);
    letter-spacing: var(--tracking-label); text-transform: uppercase;
    color: var(--text-3);
  }
  .table tbody tr.row--on td:first-child { border-left: 0; }
  .table tbody tr.row--on { border-left: 2px solid var(--accent); }
}

.pagination { display: flex; align-items: center; justify-content: space-between;
              gap: var(--sp-4); padding: var(--sp-3) var(--sp-4);
              font-family: var(--font-mono); font-size: var(--step-micro);
              color: var(--text-3); }

/* --- Nav, wordmark, mode and palette control ------------------------------ */
/* 5.1.0, Po's ruling of 2026-09-29 (STYLE.md § The wordmark in every nav).
   Order, left to right: the service name (to the service root), its routes,
   the mode and palette control, the session (name, then Sign out), and the
   WOPR wordmark rightmost (to https://wopr.ltd/). No route is called Home.
   The service name is at doe and treasury brand scale: Plex Mono 700, accent,
   --step-1, 0.06em. One line at desktop; below 900px the bar wraps. */

.nav { background: var(--surface-1); border-bottom: 1px solid var(--border);
       padding: 0 var(--gutter); display: flex; align-items: center;
       gap: var(--sp-2) var(--sp-5); flex-wrap: nowrap; overflow-x: auto; }
.nav__service { padding: var(--sp-3) 0; white-space: nowrap; }
.nav__service a { font-family: var(--font-mono); font-size: var(--step-1); font-weight: 700;
                  letter-spacing: 0.06em; color: var(--accent); border-bottom: 0; }
.nav__service a:hover { color: var(--accent-deep); }
.nav__routes { display: flex; align-items: center; gap: var(--sp-5);
               padding: var(--sp-3) 0; font-size: var(--step-ui);
               flex-wrap: nowrap; white-space: nowrap; }
.nav__routes a { color: var(--text-2); border-bottom: 0; }
.nav__routes a:hover, .nav__routes a.is-here { color: var(--accent); }
.nav__session { display: flex; align-items: center; gap: var(--sp-3);
                font-family: var(--font-mono); font-size: var(--step-micro);
                color: var(--text-3); white-space: nowrap; }
.nav__session a { color: var(--accent); border-bottom: 0; }
.nav__session a:hover { color: var(--accent-deep); }
.nav__mark { margin-left: auto; font-family: var(--font-mono); font-weight: 700;
             text-transform: uppercase; letter-spacing: var(--tracking-mark);
             color: var(--accent); font-size: var(--step-ui);
             padding: var(--sp-3) 0; border-bottom: 0; }
a.nav__mark:hover { color: var(--accent-deep); }
.nav .themectl { flex-wrap: nowrap; white-space: nowrap; }
@media (max-width: 900px) {
  .nav, .nav__routes, .nav .themectl { flex-wrap: wrap; overflow-x: visible; }
  .nav__service, .nav__routes, .nav__mark { padding: var(--sp-2) 0; }
  .nav .themectl { padding: var(--sp-1) 0; }
}

/* Mode and palette control · 5.0.0 (D7). Words, not icons. Both rows show
   every state at once. The current choice is text-1 with an accent rule;
   the others are accent because they are the ones that do something. */
.themectl { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-4);
            padding: var(--sp-2) 0; font-size: var(--step-micro); }
.themectl__group { display: flex; align-items: center; gap: var(--sp-3); }
.themectl__name { font-family: var(--font-mono); letter-spacing: var(--tracking-label);
                  text-transform: uppercase; color: var(--text-3); }
.themectl button { background: transparent; border: 0; border-bottom: 1px solid transparent;
                   padding: var(--sp-1) 0; cursor: pointer; color: var(--accent);
                   font-family: var(--font-prose); font-size: var(--step-ui); }
.themectl button:hover { color: var(--accent-deep); }
.themectl button[aria-pressed="true"] { color: var(--text-1); font-weight: 600;
                                        border-bottom-color: var(--accent); }

/* Tabs and pivots. 5.0.0: every tab is accent at rest, because it is
   interactive (rule 1; 4.2.0 Hub and pivots). Adopted from treasury's
   .pivots override, which had been right. The current tab adds weight and
   an accent rule. */
.tabs { display: flex; flex-wrap: wrap; border-bottom: 1px solid var(--border); }
.tab { padding: var(--sp-2) var(--sp-3); margin-bottom: -1px;
       font-family: var(--font-prose); font-size: var(--step-ui);
       color: var(--accent); background: transparent; cursor: pointer;
       border: 0; border-bottom: 2px solid transparent; }
.tab:hover { color: var(--accent-deep); }
.tab--on { color: var(--accent); border-bottom-color: var(--accent); font-weight: 600; }

.breadcrumb { font-family: var(--font-mono); font-size: var(--step-micro); color: var(--text-3); }
.breadcrumb a { color: var(--accent); border-bottom: 0; }
.breadcrumb__here { color: var(--text-3); }

/* Affordance · 6.1.0 (Po, 2026-09-29). Every control whose only cue at rest
   is the accent colour takes --affordance-line as its second cue. On amber,
   green and blue it is none, so nothing changes; on white, where the accent
   is the text colour, it underlines. A control with its own visible border
   (chips, presets, secondary buttons, live tiles, pager) already has a
   second cue and is not listed. style-lint rule affordance-line fails a new
   accent-at-rest control that is neither bordered nor listed here. */
.nav__service a, .nav__session a, .nav__mark, .themectl button, .tab,
.breadcrumb a { text-decoration: var(--affordance-line);
                text-decoration-thickness: 1px; text-underline-offset: .25em; }
.themectl button[aria-pressed="true"], .tab--on { text-decoration: none; }

/* --- Empty, loading, error ------------------------------------------------ */

.state { background: var(--surface-1); border: 1px solid var(--border);
         border-radius: var(--radius); padding: var(--sp-5); }
.state__kind { font-family: var(--font-mono); font-size: var(--step-micro);
               letter-spacing: var(--tracking-label); text-transform: uppercase;
               color: var(--text-3); margin-bottom: var(--sp-3); }
.state__what { display: flex; gap: var(--sp-2); align-items: center;
               font-size: var(--step-ui); color: var(--text-1); margin-bottom: var(--sp-2); }
.state__why  { font-size: var(--step--1); color: var(--text-3); margin-bottom: var(--sp-4); }

.skeleton { display: grid; gap: var(--sp-2); }
.skeleton__row { height: 10px; background: var(--surface-2); }

/* --- Toasts and banners --------------------------------------------------- */

.notice { display: flex; gap: var(--sp-3); align-items: flex-start;
          background: var(--surface-1);
          border: 1px solid var(--border); border-left: 2px solid var(--status-none);
          border-radius: 0 var(--radius) var(--radius) 0;
          padding: var(--sp-4) var(--sp-5); }
.notice--ok   { border-left-color: var(--status-ok); }
.notice--warn { border-left-color: var(--status-warn); }
.notice--bad  { border-left-color: var(--status-bad); }
.notice__what { font-size: var(--step-ui); color: var(--text-1); }
.notice__meta { font-size: var(--step--1); color: var(--text-3); }

.toasts { position: fixed; top: var(--sp-4); right: var(--sp-4); z-index: 100;
          display: grid; gap: var(--sp-3); max-width: 360px; }

/* --- Dialog ---------------------------------------------------------------- */

.backdrop { position: fixed; inset: 0; z-index: 200; background: var(--backdrop);
            display: flex; align-items: center; justify-content: center;
            padding: var(--sp-5); }
.dialog { background: var(--surface-1); border: 1px solid var(--border-light);
          border-radius: var(--radius); padding: var(--sp-5);
          max-width: 420px; width: 100%; }
.dialog__title { font-size: var(--step-1); font-weight: 700; color: var(--text-1);
                 line-height: var(--leading-tight); margin-bottom: var(--sp-3); }
.dialog__actions { display: flex; gap: var(--sp-3); justify-content: flex-end;
                   flex-wrap: wrap; margin-top: var(--sp-5); }

/* --- Error pages ----------------------------------------------------------- */

.errorpage { background: var(--surface-1); border: 1px solid var(--border);
             border-radius: var(--radius); padding: var(--sp-6); }
.errorpage__code { font-family: var(--font-mono); font-size: var(--step-3);
                   font-weight: 700; line-height: 1; color: var(--accent);
                   margin-bottom: var(--sp-4); }
.errorpage__code--down { color: var(--status-bad-text); }
.errorpage__meta { font-family: var(--font-mono); font-size: var(--step-micro); color: var(--text-3); }

/* ===========================================================================
   TERMINAL · the quarantine zone
   Phosphor lives here, on theatre pages, and nowhere else. Every value is a
   --terminal-* role set per combination above:
     dark · amber   green CRT on black, as ratified. Status in real colour.
     dark · green   the same CRT. .warn bright, .red reverse video.
     dark · blue    blue phosphor on black. .warn bright, .red reverse video.
     light · any    a transcript on paper: no ground, no scanlines, no green.
   `.amber` is kept as an alias of `.accent`.
   =========================================================================== */

.terminal {
  background: var(--terminal-ground);
  color: var(--terminal-ink);
  font-family: var(--font-mono);
  line-height: 1.6;
  position: relative;
}
.terminal .dim    { color: var(--terminal-dim); }
.terminal .bright { color: var(--terminal-bright); font-weight: 700; }
.terminal .accent,
.terminal .amber  { color: var(--terminal-accent); text-decoration: var(--terminal-accent-line); }
.terminal .warn   { color: var(--terminal-warn); font-weight: var(--terminal-warn-weight); }
.terminal .red    { color: var(--terminal-bad-ink); background: var(--terminal-bad-ground); }

.terminal::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: var(--terminal-scanlines);
}

/* ===========================================================================
   DENSITY · ratified 4.2.0. `.dense` on a WORKING page's <body> only.
   =========================================================================== */
body.dense { line-height: 1.55; }
.dense .card, .dense .fig { padding: var(--sp-4); }
.dense section + section { margin-top: var(--sp-6); }

/* ===========================================================================
   MOTION. Global; grants no exemptions, the theatre included.
   =========================================================================== */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important;
                           animation-iteration-count: 1 !important;
                           transition-duration: .01ms !important; }
}
