/* ===========================================================================
   static/skin.css — THE MIAMI SKIN. Loads last, on both shells.

   This is the port of Singularity_UI (the .dc.html design components) onto the
   real product. The mock is a static prototype; this file is the part of it
   that can honestly survive contact with live data.

   WHAT CAME ACROSS
     · Instrument Serif italic display, Barlow body, IBM Plex Mono figures
     · Pure black ground, warm off-white ink, gold reserved for chrome
     · Green #4FB286 up / red #DC6A62 down, and nothing else carrying meaning
     · Hairline borders at 8% white, no shadows, radii of 9/6/4/2
     · A drifting aurora and a fine grain over the whole viewport
     · Entrance motion: blur-in on screen change, stagger on panels

   WHAT DID NOT, AND WHY
     · The candle-tape background, the crest band, the sparkline series and
       every printed figure in the mock are generated from noise. The mock says
       so itself: "34-point series with multi-octave noise". A band that looks
       like a chart but is drawing random numbers is the exact thing this
       product is not allowed to ship, so the crest is gone rather than faked.
       What replaced it is a gradient rule under the screen title — obviously
       ornament, readable as ornament, encoding nothing.
     · The ticker marquee. There is no live consolidated tape here; a scrolling
       strip of invented prices is a lie with motion on it.
     · Framer Motion from esm.sh. There is no build step and no npm in this
       project, and a CDN import is a network dependency the product does not
       have. Every one of the mock's eight motion behaviours that survived is
       re-expressed as a CSS keyframe below.
     · The Google Fonts <link>. app/main.py carries an explicit instruction not
       to reintroduce one. Both faces are SIL OFL, same as the IBM Plex already
       here, and are served from /static/fonts by work/fetch_miami_fonts.py.

   WHAT IS KEPT FROM THE PREVIOUS SKIN, because it was measured and is still
   true. One screen, before that rewrite:

       398  elements with BOTH a border and a background
       201  of those nested inside another bordered element
        17  distinct border colours
        18  distinct corner radii

   Boxes inside boxes. The Miami design agrees with the fix — hairlines only,
   no fills on nested surfaces, no shadows — so the purge below stays exactly
   as it was and only the values it restores have changed.

   DENSITY IS NOT TOUCHED. Row heights, column counts and information density
   are left alone. The mock's 14px baseline is applied to prose pages; the
   terminal stays at 13px, because institutional users read a sparse data grid
   as lightweight and do not mean it kindly.

   `[class][class]` throughout scores (1,2,0), which outranks the
   `#app-root .thing` (1,1,0) rules across all twenty-six sheets without
   needing to know one of their names — and matches exactly the same elements,
   so nothing new is caught, only outranked.
   =========================================================================== */

/* ==========================================================================
   0 — TYPEFACES (self-hosted, no network dependency)

   Fetched by work/fetch_miami_fonts.py. Latin and latin-ext only: Google
   splits each face by unicode-range and a browser downloads a subset LAZILY,
   so the vietnamese and cyrillic ranges would be dead weight. Latin-ext is
   kept because sovereign and issuer names carry accented characters.

   Content-immutable, so no ?v= token — replacing one means changing its
   filename. Same convention as the IBM Plex faces in instrument.css.
   ========================================================================== */

/* --- Instrument Serif — display only, and almost always italic ----------- */
@font-face {
  font-family: "Instrument Serif";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/static/fonts/InstrumentSerif-400.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Instrument Serif";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/static/fonts/InstrumentSerif-400-latinext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Instrument Serif";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url("/static/fonts/InstrumentSerif-400Italic.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Instrument Serif";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url("/static/fonts/InstrumentSerif-400Italic-latinext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* --- Barlow — the interface face, 300/400/500/600 ------------------------ */
@font-face {
  font-family: "Barlow";
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url("/static/fonts/Barlow-300.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Barlow";
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url("/static/fonts/Barlow-300-latinext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Barlow";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/static/fonts/Barlow-400.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Barlow";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/static/fonts/Barlow-400-latinext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Barlow";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/static/fonts/Barlow-500.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Barlow";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/static/fonts/Barlow-500-latinext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Barlow";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("/static/fonts/Barlow-600.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Barlow";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("/static/fonts/Barlow-600-latinext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ==========================================================================
   1 — THE MIAMI PALETTE, AND HOW IT REACHES THE OTHER TWENTY-SIX SHEETS

   obsidian_orchid.css carries 662 !important declarations, but nearly all of
   them resolve through var(--oo-*), and instrument.css resolves those through
   var(--i-*). Retuning the tokens here repaints the entire terminal without
   fighting a single one.

   THEME SAFETY. instrument.css defines the palette three times over: base
   `:root` (which IS the dark theme), a `@media (prefers-color-scheme: light)`
   block, and explicit `:root[data-theme="light"|"dark"]` blocks. Two things
   follow, and getting either wrong silently breaks a theme:

     · An unguarded `:root` here would load AFTER instrument's light media
       block at equal specificity and win on source order, painting a
       light-OS reader's screen black. So the --i-* overrides live inside
       `@media (prefers-color-scheme: dark)` and carry `:not([data-theme=
       "light"])`, which also keeps an explicit light choice on a dark
       machine.
     · `:root[data-theme="dark"]` in instrument.css re-points --i-* at the
       --dk-* source set. Retuning --dk-* below is therefore what reaches a
       reader who has explicitly chosen dark, under either OS preference.

   LIGHT MODE IS DELIBERATELY LEFT ON ITS OWN PALETTE. Miami is a black-ground
   design; there is no such thing as a light version of it. Light readers get
   the Miami typography, spacing, radii and motion on the existing light
   colours. print.css depends on that same light set, so print stays correct.
   ========================================================================== */

:root {
  /* --- The named Miami values, declared once ---------------------------- */
  --mi-black:      #000000;
  --mi-ink-1:      #F0ECE5;   /* headings, hero figures                     */
  --mi-ink-2:      #B3ACA3;   /* body copy, table cells                     */
  --mi-ink-3:      #8D8781;   /* labels, units, captions                    */
  --mi-ink-4:      #6F6A64;   /* rules, disabled, group headers             */
  --mi-gold:       #E1AD66;   /* CHROME ONLY — active, focus, brand         */
  --mi-gold-lift:  #FACB8D;
  --mi-gold-deep:  #B68235;
  --mi-up:         #4FB286;   /* direction, and the only green in the UI    */
  --mi-down:       #DC6A62;   /* direction, and the only red in the UI      */
  --mi-hair:       rgba(255, 255, 255, 0.10);
  --mi-hair-2:     rgba(255, 255, 255, 0.16);
  --mi-wash:       linear-gradient(180deg,
                     rgba(255, 255, 255, 0.040),
                     rgba(255, 255, 255, 0.012));

  /* Answers 25b/26b: warning and error are DISTINCT hues now — an amber dot
     can no longer mean both "accent" and "caution", and an error is no longer
     the same red as "the price went down". Light values in the two light
     blocks below. */
  --i-warn:        #F0883E;
  --i-warn-rgb:    240, 136, 62;
  --i-error:       #E0604F;
  --i-error-deep:  #8E2A20;
  /* Answer 17c: every chart plots into a pure-black well, boxed by the panel
     it sits in. Canvas code reads this via getComputedStyle (hazard 7). */
  --mi-chart-well: #000000;
  /* Sticky table headers (100a) need an opaque lid or the rows scroll
     through them. Near the panel colour so the header does not detach. */
  --mi-thead-bg:   rgba(38, 40, 46, 0.97);

  /* The surfaces sections 4-8 paint. Named rather than typed inline so the
     light theme can move them in one place — a hairline at 8% WHITE and a
     panel at #08080A are invisible on paper, and those two literals were the
     whole reason light mode could not simply inherit this design. */
  /* Answer 2d: panels are translucent over the ambient layer — 92% grey, so
     the drift ghosts through without the brown-box failure §4's comment
     records (that was 1.2% white over a gold aurora on black; this is a grey
     ladder on a grey ground). Base #1E2024 is painted by the scoped terminal
     ground rule in section 4, not by --dk-void: the landing page keeps its
     black (answer 33b). */
  --mi-term-base:        #1E2024;
  --mi-panel-bg:         rgba(42, 45, 51, 0.92);
  --mi-control-bg:       rgba(255, 255, 255, 0.035);
  --mi-control-bg-hover: rgba(255, 255, 255, 0.070);
  --mi-row-hover:        rgba(255, 255, 255, 0.040);
  --mi-shell-bg:         rgba(20, 21, 24, 0.74);
  --mi-float-bg:         #2C2F35;

  --mi-display: "Instrument Serif", "Iowan Old Style", Georgia, "Times New Roman", serif;
  --mi-body:    "Barlow", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --mi-fig:     "IBM Plex Mono", ui-monospace, "SFMono-Regular", Consolas, monospace;

  --mi-dur:  250ms;   /* answer 234c: softer default */
  --mi-ease: cubic-bezier(0.16, 1, 0.3, 1);

  /* THE TWO TOKENS work/detint.py REWROTE 155 LITERALS ONTO. Nineteen feature
     stylesheets hardcoded the old orchid purple instead of resolving through
     a token, which meant the Miami retune reached everything EXCEPT the
     screens those sheets own — BI, HP, the news hub, the events calendar, the
     filing reader all stayed purple. They are rgb triples, not colours,
     because the call sites are rgba() with their own alpha and that alpha
     carries real meaning (0.08 is a wash, 0.55 is an edge). */
  --i-accent-rgb:      225, 173, 102;
  --i-accent-deep-rgb: 182, 130, 53;

  /* --i-bull-rgb AND --i-bear-rgb WERE READ AND NEVER DECLARED, which is
     hazard 29 again: a var() whose property does not exist takes its fallback
     in silence. plane.css asks for both on the term cards and paints
     `53, 194, 109` / `214, 74, 74` — and the shipped colours are #35C26D and
     #E87972, so the bear card has been drawing a red that is not the build's
     red and that no theme switch can reach. Declared beside the colours they
     are triples OF, so a retune of one moves the other. */
  --i-bull-rgb:        var(--dk-bull-rgb);
  --i-bear-rgb:        var(--dk-bear-rgb);

  /* --i-accent ITSELF WAS NEVER PUBLISHED, AND 45 RULES READ IT. Measured
     across eleven sheets — landing.css 17, phase7.css 9, phase6.css 4,
     behavioral_feed.css 4, screen_kit.css 3, and one or two each in
     hero_shell, stock, styles, feature_dashboards, account and this file —
     every one of them written `var(--i-accent, #f6c85f)` or similar. A
     `var()` whose custom property does not exist silently takes its fallback,
     so all forty-five were painting a hardcoded gold that no token controls.

     Two consequences, and the second is the serious one. The literals drift
     from the accent (#f6c85f against the shipped #E1AD66). And the ACCENT
     PICKER DID NOT REACH THEM: the block near the end of this file reassigns
     --i-accent-rgb per choice, so a reader who selected orchid got an orchid
     interface with forty-five gold details still in it. A fallback that is
     never wrong enough to notice is the worst kind.

     Declared here as a colour beside the rgb triple, and reassigned wherever
     that triple is. The fallbacks in the call sites are left alone: they are
     correct as fallbacks now that something real overrides them. */
  --i-accent:      #E1AD66;
  --i-accent-deep: #B68235;

  /* --- Type stacks. Theme-neutral, so unguarded ------------------------- */
  --oo-font-ui:   var(--mi-body);
  --oo-font-data: var(--mi-fig);

  /* --- Radii. Answer 120a: consistent 4px everywhere. Pills stay pills. -- */
  --i-r-panel:   4px;
  --i-r-card:    4px;
  --i-r-control: 4px;
  --i-r-chip:    4px;
  --oo-radius:        4px;
  --oo-radius-inner:  4px;
  --oo-radius-tight:  4px;

  /* --- The dark source set. Read by :root[data-theme="dark"] ------------
     Answers 1c/2d/3b: the ground moves off black onto a mid-dark grey ladder
     — base #1E2024, panel #24262B, raised #2C2F35 — the TradingView register
     the reader asked for. --dk-void stays black: it is the landing page's
     ground (33b richer) and the chart wells' colour (17c). The terminal's
     base is painted by the scoped rule in section 4. */
  --dk-void:            #000000;
  --dk-surface-1:       #24262B;
  --dk-surface-2:       #2C2F35;
  --dk-surface-3:       #343841;
  --dk-surface-4:       #3C414B;
  --dk-sidebar:         #17181B;
  --dk-ink-1:           #EDE8E0;
  --dk-ink-2:           #B3ACA3;
  --dk-ink-3:           #8D8781;
  /* 3.92:1 on pure black was below the 4.5 floor, and the sidebar nav
     labels, status dots and awaiting markers all use ink-4 as TEXT. Raised
     to clear AA rather than chase eleven components across sheets that are
     not mine. Mirrors the same decision made for --lt-ink-4. */
  --dk-ink-4:           #858077;
  --dk-muted-rgb:       179, 172, 163;
  --dk-hair:            rgba(255, 255, 255, 0.10);
  --dk-hair-strong:     rgba(255, 255, 255, 0.16);

  /* The accent preference still works: "amber" and "cyber" are unchanged
     user choices in pages.css. Only the DEFAULT ("orchid") is retuned, which
     is why this is a token edit and not a new value in page_kit.js. */
  /* LITERALS, NOT var(--mi-gold), AND THIS IS A CYCLE FIX.

     These read `var(--mi-gold)`, while the accent section further down sets
     `--mi-gold: var(--i-orchid)` and the dark block sets
     `--i-orchid: var(--dk-orchid)`. That closes a loop:
       --dk-orchid -> --mi-gold -> --i-orchid -> --dk-orchid
     CSS resolves a custom-property cycle by making every property in it
     INVALID AT COMPUTED-VALUE TIME, so --i-orchid fell out of this file
     entirely and the winning declaration became instrument.css's #D05BA5.
     Rendered, both WACC donuts came back magenta on an otherwise gold screen.

     A token graph has to be a DAG. The accent hue enters the system once,
     here, as a value — everything else reads downstream of it. */
  --dk-orchid:          #E1AD66;
  --dk-orchid-bright:   #FACB8D;
  --dk-orchid-deep:     #B68235;
  --dk-orchid-rgb:      225, 173, 102;
  --dk-cyber:           #C9B48C;
  --dk-amber:           #E1AD66;
  --dk-amber-rgb:       225, 173, 102;
  --dk-orchid-wash:     #2A1F10;
  --dk-amber-wash:      #2A1F10;

  /* THE EXEC GRADIENT MUST NOT BE A SOLID FILL, and this cost a revision.
     obsidian_orchid.css paints `--oo-gradient-exec` on everything it treats
     as a primary button, which includes the sidebar GROUP TOGGLES. That
     gradient is `orchid-deep -> orchid`; retuning orchid to gold turned every
     one of them into a solid gold bar. Rendered, the sidebar had two blazing
     gold slabs across it and they were the loudest thing on the screen.

     The mock's own primary button is transparent with a gold border and gold
     text — the accent is spent on the edge, not the fill. A faint wash keeps
     "this one is primary" legible without shouting. */
  --oo-gradient-exec:   linear-gradient(140deg, rgba(225, 173, 102, 0.16) 0%, rgba(225, 173, 102, 0.07) 100%);
  --i-gradient-primary: linear-gradient(140deg, rgba(225, 173, 102, 0.16) 0%, rgba(225, 173, 102, 0.07) 100%);
  --i-ink-on-accent:    #F0ECE5;

  --dk-bull:            #4FB286;
  --dk-bear:            #DC6A62;
  --dk-bull-rgb:        79, 178, 134;
  --dk-bear-rgb:        220, 106, 98;
  --dk-bull-wash:       #10251C;
  --dk-bear-wash:       #2A1412;

  /* No shadows. The mock is explicit: elevation via borders and opacity
     only. The rim highlight stays — it is a 1px inner edge, not a drop. */
  --dk-rim:             inset 0 1px 0 0 rgba(255, 255, 255, 0.055);
  --dk-rim-strong:      inset 0 1px 0 0 rgba(255, 255, 255, 0.090);
  --dk-underlight:      inset 0 -1px 0 0 rgba(0, 0, 0, 0.45);
  --dk-elev-1:          var(--dk-rim);
  --dk-elev-2:          var(--dk-rim);
  --dk-elev-3:          var(--dk-rim-strong);
  --dk-e1:              inset 0 1px 0 0 rgba(255, 255, 255, 0.04), 0 0 0 1px rgba(255, 255, 255, 0.08);
  --dk-e2:              inset 0 1px 0 0 rgba(255, 255, 255, 0.05), 0 0 0 1px rgba(255, 255, 255, 0.10);
  --dk-e3:              inset 0 1px 0 0 rgba(255, 255, 255, 0.06), 0 0 0 1px rgba(255, 255, 255, 0.14);

  /* Aurora. Oversized on purpose — section 2 drifts this layer on a
     transform, and an undersized gradient would show its own edge.

     HELD DELIBERATELY LOW. At 0.13 gold this read as a brown haze rather than
     a light source: panels are only 1.2% white over the aurora, so whatever
     is behind them tints them, and rendered they looked muddy brown instead
     of near-black. Ambience should be findable when looked for and invisible
     when reading a number. */
  /* Answer 23c: stronger. Still below the 0.13 that read as brown haze —
     and the panels are 92% opaque grey now, so the drift lives on the BASE
     between panels rather than tinting the panels themselves. */
  --dk-ambient:
    radial-gradient(ellipse 46% 40% at 24% 12%, rgba(225, 173, 102, 0.095), transparent 62%),
    radial-gradient(ellipse 40% 38% at 82% 34%, rgba(146, 120, 86, 0.075), transparent 64%),
    radial-gradient(ellipse 52% 44% at 46% 104%, rgba(79, 178, 134, 0.055), transparent 66%);
  --dk-grain-opacity:   0.050;

  --dk-control-bg:         rgba(255, 255, 255, 0.030);
  --dk-control-bg-hover:   rgba(255, 255, 255, 0.060);
  --dk-accent-edge-soft:   rgba(225, 173, 102, 0.40);
  --dk-accent-edge:        rgba(225, 173, 102, 0.55);
  --dk-accent-edge-bright: rgba(250, 203, 141, 0.40);
  --dk-accent-wash:        rgba(225, 173, 102, 0.14);
  --dk-accent-glow:        rgba(225, 173, 102, 0.11);
  --dk-accent-glow-strong: rgba(225, 173, 102, 0.30);
  --dk-btn-primary-shadow:       none;
  --dk-btn-primary-shadow-hover: none;
  --dk-row-hover:          rgba(255, 255, 255, 0.030);
  --dk-nav-hover:          rgba(255, 255, 255, 0.050);
  --dk-nav-active-wash:    rgba(225, 173, 102, 0.10);
  --dk-header-bg:          rgba(20, 21, 24, 0.74);
  --dk-field-bg:           rgba(255, 255, 255, 0.025);
  --dk-wash-faint:         rgba(255, 255, 255, 0.012);
  --dk-scroll-thumb:       rgba(232, 228, 221, 0.13);
  --dk-scroll-thumb-track: rgba(232, 228, 221, 0.18);
  --dk-scroll-thumb-hover: rgba(225, 173, 102, 0.40);
}

/* --------------------------------------------------------------------------
   MIAMI LIGHT. Overriding --lt-* is all it takes: instrument.css already maps
   --i-* onto --lt-* under both `:root[data-theme="light"]` and the
   prefers-light media block, so this reaches every light reader without a
   selector-specificity argument anywhere.

   It is a TRANSLATION of the design, not an inversion of it. Miami's ground
   is pure black and its ink is warm off-white; the mirror of that is a warm
   paper ground and near-black warm ink, not white-on-grey. The gold darkens
   to #8A6117 because #E1AD66 on paper is roughly 1.9:1 and unreadable — the
   accent has to be a DIFFERENT value in each theme to mean the same thing.

   THE ONE RULE THAT CANNOT BEND: --lt-bull and --lt-bear stay at the measured
   values instrument.css shipped. They are the only colours here carrying
   information rather than style, and a green that fails contrast on paper is
   a misread position, not a design flourish.

   print.css resolves through this same --lt-* set, so it follows for free.
   -------------------------------------------------------------------------- */
:root {
  --lt-void:          #F4F1EA;   /* warm paper, not blue-grey                */
  --lt-surface-1:     #FBF9F4;
  --lt-surface-2:     #FFFDF8;
  --lt-surface-3:     #F0EDE4;
  --lt-surface-4:     #E7E3D8;
  --lt-sidebar:       #F7F4ED;

  --lt-ink-1:         #14120E;   /* 15.6:1 on the paper ground               */
  --lt-ink-2:         #46423A;   /*  8.4:1                                   */
  --lt-ink-3:         #5F5A50;   /*  5.7:1 — headroom over the 4.5 floor     */
  --lt-ink-4:         #67635A;   /*  4.6:1 — see note below                  */
  /* DELIBERATELY ABOVE THE 2.9:1 THIS MIRRORS IN DARK. ink-4 is documented
     non-text, but measured on the live DOM eleven components use it as label
     text anyway. Chasing each one is a losing game against sheets that are
     not mine; raising the floor makes every one of them legible and costs
     one step of ramp separation. */
  --lt-muted-rgb:     70, 66, 58;

  --lt-hair:          rgba(20, 18, 14, 0.10);
  --lt-hair-strong:   rgba(20, 18, 14, 0.20);

  /* Gold, darkened until it carries on paper. #E1AD66 would be 1.9:1. */
  --lt-orchid:        #8A6117;
  --lt-orchid-bright: #6E4C10;
  --lt-orchid-deep:   #573C0C;
  --lt-orchid-rgb:    138, 97, 23;
  --lt-cyber:         #6E5A38;
  --lt-amber:         #8A6117;
  --lt-amber-rgb:     138, 97, 23;
  --lt-orchid-wash:   #F5E7CC;
  --lt-amber-wash:    #F5E7CC;

  /* Elevation by border and opacity here too — no drops. */
  --lt-rim:           inset 0 1px 0 0 rgba(255, 255, 255, 0.85);
  --lt-rim-strong:    inset 0 1px 0 0 rgba(255, 255, 255, 1);
  --lt-elev-1:        var(--lt-rim);
  --lt-elev-2:        var(--lt-rim);
  --lt-elev-3:        var(--lt-rim-strong);
  --lt-e1:            0 0 0 1px rgba(20, 18, 14, 0.10);
  --lt-e2:            0 0 0 1px rgba(20, 18, 14, 0.12);
  --lt-e3:            0 0 0 1px rgba(20, 18, 14, 0.18);

  --lt-ambient:
    radial-gradient(ellipse 46% 40% at 24% 12%, rgba(138, 97, 23, 0.040), transparent 62%),
    radial-gradient(ellipse 40% 38% at 82% 34%, rgba(120, 96, 56, 0.030), transparent 64%);
  --lt-grain-opacity: 0.012;

  --lt-control-bg:         rgba(20, 18, 14, 0.040);
  --lt-control-bg-hover:   rgba(20, 18, 14, 0.075);
  --lt-accent-edge-soft:   rgba(138, 97, 23, 0.40);
  --lt-accent-edge:        rgba(138, 97, 23, 0.60);
  --lt-accent-edge-bright: rgba(87, 60, 12, 0.45);
  --lt-accent-wash:        rgba(138, 97, 23, 0.13);
  --lt-accent-glow:        rgba(138, 97, 23, 0.10);
  --lt-accent-glow-strong: rgba(138, 97, 23, 0.26);
  --lt-btn-primary-shadow:       none;
  --lt-btn-primary-shadow-hover: none;
  --lt-row-hover:          rgba(20, 18, 14, 0.035);
  --lt-nav-hover:          rgba(20, 18, 14, 0.050);
  --lt-nav-active-wash:    rgba(138, 97, 23, 0.12);
  --lt-header-bg:          rgba(251, 249, 244, 0.80);
  --lt-field-bg:           rgba(255, 255, 255, 0.70);
  --lt-wash-faint:         rgba(20, 18, 14, 0.014);
  --lt-scroll-thumb:       rgba(20, 18, 14, 0.18);
  --lt-scroll-thumb-track: rgba(20, 18, 14, 0.24);
  --lt-scroll-thumb-hover: rgba(138, 97, 23, 0.45);
}

/* The component rules in sections 4-8 are written for a dark ground: hairlines
   at 8% WHITE, panels at #08080A, controls at 3% white. On paper every one of
   those is invisible or wrong, so the handful that name a literal are
   re-pointed. Everything else already resolves through --i-*. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    --mi-black:  var(--lt-void);
    --mi-ink-1:  var(--lt-ink-1);
    --mi-ink-2:  var(--lt-ink-2);
    --mi-ink-3:  var(--lt-ink-3);
    --mi-ink-4:  var(--lt-ink-4);
          --mi-up:     var(--lt-bull);
    --mi-down:   var(--lt-bear);
    --mi-hair:   var(--lt-hair);
    --mi-hair-2: var(--lt-hair-strong);
    --mi-wash:   linear-gradient(180deg, rgba(255, 255, 255, 0.90), rgba(255, 255, 255, 0.55));
    --mi-panel-bg: var(--lt-surface-2);
    --mi-control-bg: rgba(20, 18, 14, 0.035);
    --mi-control-bg-hover: rgba(20, 18, 14, 0.070);
    --mi-row-hover: rgba(20, 18, 14, 0.035);
    --mi-shell-bg: rgba(251, 249, 244, 0.80);
    --mi-float-bg: #FFFDF8;
    --mi-term-base: var(--lt-void);
    --mi-thead-bg: rgba(251, 249, 244, 0.97);
    --mi-chart-well: #FFFFFF;
    --i-warn: #9A4E00;
    --i-warn-rgb: 154, 78, 0;
    --i-error: #B3261E;
    --i-error-deep: #7A1712;
  }
}

:root[data-theme="light"] {
  --mi-black:  var(--lt-void);
  --mi-ink-1:  var(--lt-ink-1);
  --mi-ink-2:  var(--lt-ink-2);
  --mi-ink-3:  var(--lt-ink-3);
  --mi-ink-4:  var(--lt-ink-4);
  --mi-up:     var(--lt-bull);
  --mi-down:   var(--lt-bear);
  --mi-hair:   var(--lt-hair);
  --mi-hair-2: var(--lt-hair-strong);
  --mi-wash:   linear-gradient(180deg, rgba(255, 255, 255, 0.90), rgba(255, 255, 255, 0.55));
  --mi-panel-bg: var(--lt-surface-2);
  --mi-control-bg: rgba(20, 18, 14, 0.035);
  --mi-control-bg-hover: rgba(20, 18, 14, 0.070);
  --mi-row-hover: rgba(20, 18, 14, 0.035);
  --mi-shell-bg: rgba(251, 249, 244, 0.80);
  --mi-float-bg: #FFFDF8;
  --mi-term-base: var(--lt-void);
  --mi-thead-bg: rgba(251, 249, 244, 0.97);
  --mi-chart-well: #FFFFFF;
  --i-warn: #9A4E00;
  --i-warn-rgb: 154, 78, 0;
  --i-error: #B3261E;
  --i-error-deep: #7A1712;

  /* THE DIRECTION PAIR WAS MAPPED ONTO `--mi-*` AND NOT ONTO `--i-*`.

     This block set `--mi-up: var(--lt-bull)` and stopped, so every component
     that reads `--i-bull` — which is most of them — kept a green tuned for a
     black ground. Measured on paper: `rgb(53, 194, 109)` at **2.05:1**, which
     is not a dim green, it is an unreadable one. instrument.css already
     defines the correct light values; nothing was consuming them.

         --lt-bull  #007339   5.2:1 on paper
         --lt-bear  #A23533   6.1:1 on paper

     Both are unmistakably green and red. The signal is intact; only the
     lightness moves, which is the whole point of having a light variant. */
  --i-bull:      var(--lt-bull);
  --i-bear:      var(--lt-bear);
  /* THE TRIPLES FOLLOW THE COLOURS. A hardcoded `232, 121, 114` here would be
     a red that no theme switch can reach — and it would ALSO be the wrong red,
     because this sheet retunes --dk-bear to #DC6A62 forty lines below where
     instrument.css declares #E87972. Alias, never retype (hazard 37). */
  --i-bull-rgb:  var(--lt-bull-rgb);
  --i-bear-rgb:  var(--lt-bear-rgb);
  --i-bull-wash: var(--lt-bull-wash);
  --i-bear-wash: var(--lt-bear-wash);
  --oo-bullish-rgb: var(--lt-bull-rgb);
  --oo-bearish-rgb: var(--lt-bear-rgb);
}

@media (prefers-color-scheme: light) {
  /* Same mapping for the reader who set no theme and runs a light OS. */
  :root:not([data-theme="dark"]) {
    --i-bull:      var(--lt-bull);
    --i-bear:      var(--lt-bear);
    --i-bull-rgb:  var(--lt-bull-rgb);
    --i-bear-rgb:  var(--lt-bear-rgb);
    --i-bull-wash: var(--lt-bull-wash);
    --i-bear-wash: var(--lt-bear-wash);
    --oo-bullish-rgb: var(--lt-bull-rgb);
    --oo-bearish-rgb: var(--lt-bear-rgb);
  }
}

/* The default reader: no data-theme attribute, dark OS. instrument.css serves
   these from base `:root` as literals rather than through --dk-*, so they have
   to be restated. (0,2,0) with the :not() guard — see the header. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --i-void:          var(--dk-void);
    --i-surface-1:     var(--dk-surface-1);
    --i-surface-2:     var(--dk-surface-2);
    --i-surface-3:     var(--dk-surface-3);
    --i-surface-4:     var(--dk-surface-4);
    --oo-sidebar:      var(--dk-sidebar);
    --i-ink-1:         var(--dk-ink-1);
    --i-ink-2:         var(--dk-ink-2);
    --i-ink-3:         var(--dk-ink-3);
    --i-ink-4:         var(--dk-ink-4);
    --oo-muted-rgb:    var(--dk-muted-rgb);
    --i-hair:          var(--dk-hair);
    --i-hair-strong:   var(--dk-hair-strong);
    --i-orchid:        var(--dk-orchid);
    --i-orchid-bright: var(--dk-orchid-bright);
    --i-orchid-deep:   var(--dk-orchid-deep);
    --oo-orchid-rgb:   var(--dk-orchid-rgb);
    --oo-orchid-500:   var(--dk-orchid);
    --oo-orchid-600:   var(--dk-orchid-deep);
    --i-cyber:         var(--dk-cyber);
    --i-amber:         var(--dk-amber);
    --i-amber-rgb:     var(--dk-amber-rgb);
    --i-orchid-wash:   var(--dk-orchid-wash);
    --i-amber-wash:    var(--dk-amber-wash);
    --i-bull:          var(--dk-bull);
    --i-bear:          var(--dk-bear);
    --i-bull-rgb:      var(--dk-bull-rgb);
    --i-bear-rgb:      var(--dk-bear-rgb);
    --oo-bullish-rgb:  var(--dk-bull-rgb);
    --oo-bearish-rgb:  var(--dk-bear-rgb);
    --i-bull-wash:     var(--dk-bull-wash);
    --i-bear-wash:     var(--dk-bear-wash);
    --i-rim:           var(--dk-rim);
    --i-rim-strong:    var(--dk-rim-strong);
    --i-elev-1:        var(--dk-elev-1);
    --i-elev-2:        var(--dk-elev-2);
    --i-elev-3:        var(--dk-elev-3);
    --elev-1:          var(--dk-e1);
    --elev-2:          var(--dk-e2);
    --elev-3:          var(--dk-e3);
    --i-ambient:       var(--dk-ambient);
    --i-grain-opacity: var(--dk-grain-opacity);
    --i-control-bg:         var(--dk-control-bg);
    --i-control-bg-hover:   var(--dk-control-bg-hover);
    --i-accent-edge-soft:   var(--dk-accent-edge-soft);
    --i-accent-edge:        var(--dk-accent-edge);
    --i-accent-edge-bright: var(--dk-accent-edge-bright);
    --i-accent-wash:        var(--dk-accent-wash);
    --i-accent-glow:        var(--dk-accent-glow);
    --i-accent-glow-strong: var(--dk-accent-glow-strong);
    --i-btn-primary-shadow:       var(--dk-btn-primary-shadow);
    --i-btn-primary-shadow-hover: var(--dk-btn-primary-shadow-hover);
    --i-row-hover:       var(--dk-row-hover);
    --i-nav-hover:       var(--dk-nav-hover);
    --i-nav-active-wash: var(--dk-nav-active-wash);
    --i-header-bg:       var(--dk-header-bg);
    --i-field-bg:        var(--dk-field-bg);
    --i-wash-faint:      var(--dk-wash-faint);
    --i-scroll-thumb:       var(--dk-scroll-thumb);
    --i-scroll-thumb-track: var(--dk-scroll-thumb-track);
    --i-scroll-thumb-hover: var(--dk-scroll-thumb-hover);

  }
}

/* --------------------------------------------------------------------------
   1b — THE ACCENT SETTING, AND WHY IT IS FOUR REAL VALUES

   These blocks are in THIS file and not pages.css because pages.css is linked
   only by the page shell — an accent block there cannot reach the terminal,
   which is where the accent is mostly seen.

   `gold` is the default and the Miami accent. `orchid` restores the hue
   instrument.css shipped: until this block existed the skin reached the
   accent by retuning --i-orchid to gold, so the setting labelled "Orchid"
   painted the interface gold. The control was present and it lied about what
   it did, which is worse than not offering it.

   Each block also sets the two rgb triples, because the 155 literals
   work/detint.py rewrote in the feature sheets resolve through them — without
   that line the BI and news-hub accents would ignore the setting entirely.
   -------------------------------------------------------------------------- */
/* An accent has TWO values, not one. #E1AD66 is 1.9:1 on paper — the same
   hue has to be a different lightness in each theme to mean the same thing.
   The blocks below declare the pair; the three theme mappings after them pick
   which half is live. Pinning a single literal here is what put dark gold
   text on the light ground, and because these blocks are (0,2,0) and sit
   AFTER the theme blocks, they won on source order and silently undid it. */
:root[data-accent="gold"] {
  --acc-d:   #E1AD66;  --acc-d-hi: #FACB8D;  --acc-d-lo: #B68235;
  --acc-l:   #8A6117;  --acc-l-hi: #6E4C10;  --acc-l-lo: #573C0C;
  --acc-d-rgb: 225, 173, 102;   --acc-l-rgb: 138, 97, 23;
  --acc-deep-rgb: 182, 130, 53;
}

:root[data-accent="orchid"] {
  --acc-d:   #D05BA5;  --acc-d-hi: #EB81C2;  --acc-d-lo: #943272;
  --acc-l:   #A63580;  --acc-l-hi: #831762;  --acc-l-lo: #630348;
  --acc-d-rgb: 208, 91, 165;    --acc-l-rgb: 166, 53, 128;
  --acc-deep-rgb: 148, 50, 114;
}

:root[data-accent="amber"] {
  --acc-d:   #F2AF48;  --acc-d-hi: #FFD08A;  --acc-d-lo: #B07C1E;
  --acc-l:   #885A00;  --acc-l-hi: #6B4700;  --acc-l-lo: #513500;
  --acc-d-rgb: 242, 175, 72;    --acc-l-rgb: 136, 90, 0;
  --acc-deep-rgb: 176, 124, 30;
}

/* THIS ACCENT WAS LABELLED "VIOLET" AND SHIPPED SAND, AND THAT IS THE ORCHID
   FAILURE A SECOND TIME.

   `applyPrefs` records the first one: the Miami skin reached its accent by
   retuning `--i-orchid` to gold, so a setting labelled "Orchid" painted the
   interface gold and there was no way to ask for either colour by name — "a
   control that lies about what it does is worse than one that is missing".
   That was fixed for orchid. `cyber` kept the old shape: this block declared
   #C9B48C, a warm sand, under a picker entry that says Violet.

   MEASURED, WHICH IS HOW IT WAS FOUND. Building the accent table for item 452
   put all four side by side on the live page for the first time:

       gold    rgb(225, 173, 102)   10.37:1 on the page
       cyber   rgb(201, 180, 140)   10.39:1 on the page

   Two hundredths apart, both tan. The fourth accent was not a fourth choice —
   it was gold again, under another name, and nothing in the source said so
   because the sand is three sheets away from the word "Violet".

   The pair below is the token layer's own cyber, which never stopped being
   violet: `--dk-cyber` is #B98CE0 in instrument.css and `--lt-cyber` is
   #7B46A4. Only THIS block changes — skin.css's global `--dk-cyber` retune
   stays, because the design pass chose warm neutrals for everything that is
   not a deliberate accent choice, and an accent is exactly that. */
:root[data-accent="cyber"] {
  --acc-d:   #B98CE0;  --acc-d-hi: #D2B0F0;  --acc-d-lo: #8E63B4;
  --acc-l:   #7B46A4;  --acc-l-hi: #623684;  --acc-l-lo: #4C2A66;
  --acc-d-rgb: 185, 140, 224;   --acc-l-rgb: 123, 70, 164;
  --acc-deep-rgb: 142, 99, 180;
}

/* Pick the half. Dark is the base; the two light selectors mirror exactly the
   guards instrument.css uses, so an explicit choice always beats the OS. */
:root {
  --i-orchid:        var(--acc-d);
  --i-orchid-bright: var(--acc-d-hi);
  --i-orchid-deep:   var(--acc-d-lo);
  --i-orchid-wash:   color-mix(in srgb, var(--acc-d) 18%, var(--i-void));
  --oo-orchid:       var(--acc-d);
  --oo-orchid-rgb:   var(--acc-d-rgb);
  --i-accent-rgb:      var(--acc-d-rgb);
  --i-accent-deep-rgb: var(--acc-deep-rgb);
  --i-accent:          var(--acc-d);
  --i-accent-deep:     var(--acc-d-lo);
}

@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    --i-orchid:        var(--acc-l);
    --i-orchid-bright: var(--acc-l-hi);
    --i-orchid-deep:   var(--acc-l-lo);
    --i-orchid-wash:   color-mix(in srgb, var(--acc-l) 16%, var(--i-void));
    --oo-orchid:       var(--acc-l);
    --oo-orchid-rgb:   var(--acc-l-rgb);
    --i-accent-rgb:    var(--acc-l-rgb);
    --i-accent:        var(--acc-l);
    --i-accent-deep:   var(--acc-l-lo);
  }
}

:root[data-theme="light"] {
  --i-orchid:        var(--acc-l);
  --i-orchid-bright: var(--acc-l-hi);
  --i-orchid-deep:   var(--acc-l-lo);
  --i-orchid-wash:   color-mix(in srgb, var(--acc-l) 16%, var(--i-void));
  --oo-orchid:       var(--acc-l);
  --oo-orchid-rgb:   var(--acc-l-rgb);
  --i-accent-rgb:    var(--acc-l-rgb);
  --i-accent:        var(--acc-l);
  --i-accent-deep:   var(--acc-l-lo);
}

/* The rail, focus ring and chip borders in sections 4-6 read --mi-gold. Point
   it at whichever accent half is live so they move with the setting AND the
   theme rather than staying gold on an orchid interface. */
:root {
  --mi-gold:      var(--i-orchid);
  --mi-gold-lift: var(--i-orchid-bright);
  --mi-gold-deep: var(--i-orchid-deep);
}

/* --------------------------------------------------------------------------
   THE CHART PALETTE IS NOT THEME-GATED, AND THAT WAS A BUG WORTH THE MOVE.

   These lived inside `@media (prefers-color-scheme: dark)`. A reader with an
   explicit `data-theme="dark"` on a machine whose OS preference is LIGHT
   never matched that query, so --i-viz-* fell back to instrument.css's base
   values — the orchid family. Rendered, the WACC gauge drew a magenta ring
   on an otherwise gold screen while the donut beside it was gold, because one
   took an explicit colour and the other took hue 1 of the ramp.

   Chart hues are mid-lightness on purpose and carry on either ground, so
   there is no reason for them to be conditional at all. frontend/viz/core.js
   reads them at DRAW TIME, so this repaints every canvas with no JS change.

   Green and red are NOT in this ramp — they mean direction everywhere else,
   and a categorical series that happens to land on green would read as "up".
   -------------------------------------------------------------------------- */
:root {
  /* The categorical ramp for frontend/viz/*. core.js reads these at DRAW
     TIME, so retuning them restyles every canvas chart with no JS change.
     Warmed toward the gold end and desaturated to sit on true black; hue
     separation is preserved because a treemap or a network still needs
     eight tellable-apart series. Green and red keep their direction
     meaning and are NOT in this ramp. */
  /* Aligned with the winning dark block below (answer 15d, amber ladder) so
     no resolution order can produce a second palette. */
  --i-viz-1: #E1AD66;
  --i-viz-2: #FFF0CE;
  --i-viz-3: #A5591B;
  --i-viz-4: #FFD87E;
  --i-viz-5: #8A6D3B;
  --i-viz-6: #F2C591;
  --i-viz-7: #C08A2E;
  --i-viz-8: #6B5327;
  --i-viz-grid:      rgba(255, 255, 255, 0.055);
  --i-viz-grid-axis: rgba(255, 255, 255, 0.12);
  --i-viz-plot-bg:   rgba(255, 255, 255, 0.010);
  --i-viz-crosshair: rgba(225, 173, 102, 0.55);
  --i-viz-rim:       var(--mi-ink-1);

  /* Diverging heat: the mock's red at −3σ through neutral to green at +3σ. */
  --i-heat-n4: #DC6A62;
  --i-heat-n3: #B0554F;
  --i-heat-n2: #80403C;
  --i-heat-n1: #522A28;
  --i-heat-0:  #1A1A1C;
  --i-heat-p1: #1D3B2E;
  --i-heat-p2: #2C5C46;
  --i-heat-p3: #3C8465;
  --i-heat-p4: #4FB286;

  --i-seq-1: #17140F;
  --i-seq-2: #2E2618;
  --i-seq-3: #493A22;
  --i-seq-4: #67512D;
  --i-seq-5: #886A38;
  --i-seq-6: #AC8748;
  --i-seq-7: #E1AD66;
}

/* ==========================================================================
   2 — GROUND AND AMBIENCE

   instrument.css paints --i-ambient on #app-root::before and the grain on
   ::after, both fixed and pointer-events:none. The mock drifts its aurora on
   24s and 31s loops. That is added here as a TRANSFORM on the existing layer
   rather than as three new elements: a transform-only animation on an already
   promoted fixed layer composites without repainting, and does not add a node
   that renderApp() would have to rebuild.

   The reduced-motion guard in instrument.css reads `#app-root *::before` —
   with a descendant combinator, so it does NOT match #app-root::before
   itself. That gap is closed at the bottom of this section.
   ========================================================================== */

@keyframes miDrift {
  0%   { transform: translate3d(0, 0, 0) scale(1); }
  50%  { transform: translate3d(2.5%, -2%, 0) scale(1.09); }
  100% { transform: translate3d(0, 0, 0) scale(1); }
}

#app-root::before {
  inset: -22%;                 /* oversized so the drift never shows an edge */
  animation: miDrift 34s ease-in-out infinite;
  will-change: transform;
}

/* A FOUR-CORE MACHINE DOES NOT GET THE DRIFT, AND IT KEEPS THE AURORA.
   `data-lowpower` is stamped by `applyDevice()` in frontend/device_gate.js
   from deviceMemory / hardwareConcurrency / Save-Data — the same predicate the
   landing page uses to decide whether to fetch a background video, because it
   is the same question.

   Only the ANIMATION is dropped. The gradient, the inset and the layer all
   stay, so the ground looks identical; what stops is recompositing a surface
   twice the size of the viewport every frame for the life of the tab.
   `will-change` goes with it: a promotion hint on a layer that no longer moves
   is GPU memory held for nothing.

   Written in THIS sheet, immediately after the rule it overrides, and at
   (1,1,0) against its (1,0,0). Either would win alone; the pair survives a
   change to the link order in app/main.py (hazard 51). */
:root[data-lowpower="1"] #app-root::before {
  animation: none;
  will-change: auto;
}

/* Answer 240b: smooth scrolling, everywhere, unless the OS says be still. */
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

/* Answer 246b: the source pills acknowledge the pointer — a 1px rise on a
   transform, which no purge names and no frame-starved pane can strand
   invisibly (rest state is the identity, hazard 45). */
#app-root :is(.sgkProvName, .sgkProvKey, [class*="srcpill"], [class*="SrcPill"]) {
  transition: transform var(--mi-dur) var(--mi-ease);
}
#app-root :is(.sgkProvName, .sgkProvKey, [class*="srcpill"], [class*="SrcPill"]):hover {
  transform: translateY(-1px);
}

/* ==========================================================================
   3 — THE PURGE
   Default is NONE. A short allowlist in section 4 puts back the few borders,
   fills and radii that carry real structure.
   ========================================================================== */
#app-root [class][class],
#page-root [class][class] {
  border-color: transparent !important;
  border-width: 0 !important;
  /* border-image was the one border property this purge forgot, and it cost
     a magenta gradient strip on SOVW's masthead the moment the structure
     layer restored border widths: a border-image OVERRIDES border-color, so
     the pre-Miami gradient rode back in on the restored width. */
  border-image: none !important;
  box-shadow: none !important;
  background-image: none !important;
  text-shadow: none !important;
  border-radius: 0 !important;
}

/* The four radii the design file specifies, as tokens rather than literals so
   a retune happens in one place. Values verbatim from Singularity_UI/Design.md
   ("Border radius: 9px (pills), 6px (medium), 4px (small), 2px (crisp)"). */
:root {
  --mi-radius-pill: 9px;
  --mi-radius-control: 4px;   /* answer 120a: consistent 4px */
  --mi-radius-small: 4px;
  --mi-radius-crisp: 2px;
}

/* --------------------------------------------------------------------------
   3b — RADII COME BACK, ON CONTROLS ONLY

   The design file specifies radii — 9px pills, 6px medium, 4px small, 2px
   crisp — and the purge above was zeroing every one of them. The file is the
   spec of record, so the file wins.

   But it wins WHERE IT MEANT TO. Restoring radius globally would put a corner
   back on all 201 nested surfaces the purge exists to flatten, which is the
   "four different screens in one, all rounded" look this whole round is
   removing. The spec's radii are named for pills, chips and inputs — small
   interactive things. Panels are not in that list.

   So: controls get their corners back, surfaces stay flat. A `<button>` is a
   button whatever its class vocabulary is, which is also why this selects on
   ELEMENT and role rather than on class names — hazard 9, the twelve different
   naming schemes across 62 screens.
   -------------------------------------------------------------------------- */
#app-root button[class][class],
#app-root input[class][class],
#app-root select[class][class],
#app-root [role="tab"][class][class],
#app-root [role="switch"][class][class],
#page-root button[class][class],
#page-root input[class][class],
#page-root select[class][class],
#page-root [role="tab"][class][class],
#page-root [role="switch"][class][class] {
  border-radius: var(--mi-radius-control, 6px) !important;
}

/* Pills and chips read as pills at 9px, per the spec's own naming. Matched on
   the shape they already have rather than on a class list: anything the
   stylesheets above gave a pill radius to was asking to be a pill. */
#app-root button[class][class][data-pill],
#app-root [class][class][data-chip],
#page-root button[class][class][data-pill],
#page-root [class][class][data-chip] {
  border-radius: var(--mi-radius-pill, 9px) !important;
}

/* Nested surfaces go flat. A panel is a surface; the six divs inside it are
   not, and giving each its own fill is what produced 201 boxes inside boxes.

   THE EXCLUSIONS ARE NOT DECORATION — THEY CARRY MEANING IN THEIR FILL.
   A stale-cache warning renders as a filled amber pill with a "!" in void
   ink. Stripping the fill left BLACK TEXT ON THE BLACK PAGE: measured 1.00:1,
   perfectly invisible, on the one element whose whole job is to tell a reader
   their figures are not live. Status dots are the same shape of failure — a
   dot IS its fill; without one there is nothing left to see.

   So the rule is narrower than "nested things are flat": a nested SURFACE is
   flat, and a nested MARKER keeps its paint.

   The exclusion is written as :not() ON THE PURGE ITSELF rather than as a
   restoring rule afterwards. There is no way to un-apply an !important
   declaration from a later rule — `revert` and `revert-layer` both go to the
   user-agent value, which is transparent, i.e. the bug again. The only fix is
   to never match.

   THIS COMMENT ONCE CLOSED ITSELF TWO PARAGRAPHS EARLY, leaving this prose
   bare in the token stream. CSS recovers from a garbage prelude by discarding
   the whole next rule — so the nested-fill purge below was silently dropped
   by the parser and 201 nested fills came back, at zero errors anywhere.
   tests/test_skin_parses.py now walks every sheet for prose outside comments. */
#app-root [class][class] [class][class]:not([data-pane]):not([class*="mark"]):not([class*="Mark"]):not([class*="dot"]):not([class*="Dot"]):not([class*="badge"]):not([class*="Badge"]):not([class*="pill"]):not([class*="Pill"]):not([class*="swatch"]):not([class*="legend"]):not([class*="Legend"]):not([class*="hit"]):not([class*="Hit"]):not([class*="highlight"]):not([class*="Highlight"]):not([class*="match"]):not([class*="Match"]),
#page-root [class][class] [class][class]:not([data-pane]):not([class*="mark"]):not([class*="Mark"]):not([class*="dot"]):not([class*="Dot"]):not([class*="badge"]):not([class*="Badge"]):not([class*="pill"]):not([class*="Pill"]):not([class*="hit"]):not([class*="Hit"]):not([class*="highlight"]):not([class*="Highlight"]):not([class*="match"]):not([class*="Match"]) {
  background-color: transparent !important;
}

/* ==========================================================================
   4 — WHAT EARNS A BORDER
   The panel grouping a set of figures, the row divider, an interactive
   control, the app's structural edges, and a floating layer. Nothing else.
   ========================================================================== */

/* PANELS. The one place the mock's vertical wash gradient is restored, which
   is why background-image is re-allowed here and nowhere else.

   `[class$="-panel"]` ALONE IS A TRAP and cost this file a whole revision.
   An attribute selector matches the WHOLE attribute value, not one class
   inside it, so `class="stocklab-panel stocklab-holders"` does not end in
   "-panel" and never matched — every real panel on the screen went unstyled
   while the one hidden `class="source-panel terminal-panel"` did match, which
   made the first measurement look like a pass. Both forms are needed: ends
   the attribute, or is followed by a space. The same pairing is applied to
   every other `$=` suffix in this file for the same reason. */
#app-root [class][class]:is(.sgkPanel, .terminal-panel, [class$="-panel"], [class*="-panel "]),
#page-root [class][class]:is(.pk-card, .pk-panel) {
  border: 1px solid var(--mi-hair) !important;
  border-radius: var(--mi-radius-small) !important;
  /* 92% opaque, not a 1.2% white film. The old fully-translucent version
     took the aurora's gold and read as brown boxes; at 92% grey the drift
     ghosts through (answer 2d) without recolouring the surface. */
  background-color: var(--mi-panel-bg) !important;
  background-image: var(--mi-wash) !important;
}

/* --------------------------------------------------------------------------
   4a2 — THE STAMPED STRUCTURE LAYER (answers 63c, 71b, 103c)

   The reader's core complaint: "four numbers clashing, all of them
   unrelated, because you're not adding borders." The allowlist above styles
   four panel vocabularies; the terminal's screens use TWELVE (hazard 9), so
   most panels never earned their border and the screens read as walls.

   Chasing class names is the documented failure. Instead motion.js — whose
   structuralSurfaces() already recognises "the panels on this screen" by
   GEOMETRY, the one thing no stylesheet can remove (hazard 43) — stamps
   `data-pane` on every surface it finds, on mount and on every mutation.
   This rule styles the stamp. One recognizer, one attribute, one rule,
   twelve vocabularies covered.

   The attribute is repeated to reach (1,3,0), which beats the §3 purge at
   (1,2,0) inside the same !important layer. Elements without classes are
   never purged at all, so they take this rule trivially.

   THE TERMINAL GROUND (answer 1c) is scoped HERE and not set via --dk-void:
   the landing page keeps its black (answer 33b), and the chart wells keep
   theirs (answer 17c). */
#app-root { background-color: var(--mi-term-base) !important; }

/* Answer 33b: the LANDING stays on its black ground while the terminal moves
   to the grey ladder. Custom properties re-scoped at #page-root override the
   :root values for everything inside the page shells and nothing inside the
   terminal — one palette system, two grounds, no forked sheets. Light mode
   is untouched: these only bite where the dark values would have. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) #page-root {
    --i-surface-1: #0B0C0E;
    --i-surface-2: #101114;
    --i-surface-3: #16171A;
    --i-surface-4: #1C1D21;
    --mi-panel-bg: #0A0A0C;
  }
}
:root[data-theme="dark"] #page-root {
  --i-surface-1: #0B0C0E;
  --i-surface-2: #101114;
  --i-surface-3: #16171A;
  --i-surface-4: #1C1D21;
  --mi-panel-bg: #0A0A0C;
}

#app-root [data-pane][data-pane][data-pane] {
  border: 1px solid var(--mi-hair) !important;
  border-radius: var(--mi-radius-small) !important;
  background-color: var(--mi-panel-bg) !important;
  background-image: var(--mi-wash) !important;
}

/* THE POLICY PAGES. Four shapes, and each one's border carries meaning rather
   than decoration — which is the only test section 3's purge applies.

   Written in pages_policy.css against the token layer, and every one of them
   was silently flattened: the purge above is `border-width: 0 !important` on
   `[class][class]`, which no component sheet can out-specify. Measured on
   /disclosures — `border-top-width: 0px`, `border-color: rgba(0,0,0,0)` — with
   the amber token resolving correctly and being used correctly by the "!"
   glyph beside it, so nothing about the sheet looked wrong.

     plcBanner    the unreviewed-legal-text warning. The border IS the
                  warning; without it the block is indented prose and reads as
                  a footnote. Same argument the stale-cache pill won above.
     plcSub       a subprocessor card in a grid of 34. Unbordered they run
                  together into one wall of provider names.
     plcQa        the rule under a question, which is what separates one
                  question's answer from the next question.
     plcFactRow   the hairline under a fact, same job as a table row divider,
                  which section 4 already grants to `td`/`th`.

   `plcStoreKind` and `plcTag` are pills: a tag with no border is small grey
   text, so the outline is the component. */
#page-root [class][class]:is(.plcBanner, .plcSub) {
  border: 1px solid var(--mi-hair) !important;
  border-radius: 9px !important;
}

#page-root [class][class].plcBanner {
  /* Amber, not hairline: this one is a warning and should read as one. */
  border-color: var(--i-amber) !important;
}

#page-root [class][class]:is(.plcQa, .plcFactRow) {
  border-bottom-width: 1px !important;
  border-bottom-color: var(--mi-hair) !important;
}

#page-root [class][class]:is(.plcQa, .plcFactRow):last-child {
  border-bottom-width: 0 !important;
}

#page-root [class][class]:is(.plcStoreKind, .plcTag) {
  border: 1px solid var(--mi-hair) !important;
  border-radius: 999px !important;
}

/* ==========================================================================
   4b — THE LANDING PAGE'S STRUCTURAL DIVIDERS

   ASKED FOR DIRECTLY: "add borders between thirty five, twenty six, thirty
   four, two thirty seven … do that for everything … because without that it
   looks very unstructured."

   THE BORDERS WERE ALREADY WRITTEN. `static/landing.css` declares
   `border-block` on `.lndFigs` and `border-bottom` on every `.lndWsLine`, and
   separates the figure cells with the standard grid trick — a 1px `gap` over a
   hairline BACKGROUND, so the background shows through as a rule.

   MEASURED ON THE LIVE PAGE, all four came back dead:

     .lndFigs     background-color  rgba(0, 0, 0, 0)   border-top-width  0px
     .lndFigCell  background-color  rgba(0, 0, 0, 0)
     .lndWsLine   border-bottom-width  0px

   Found by disabling the thirteen loaded sheets one at a time: exactly one
   changed anything, and disabling it restored `rgb(45, 45, 52)` and `1px`.
   That sheet is this one. §3's purge is `border-width: 0 !important` at
   (1,2,0), and the nested-fill purge above is `background-color: transparent
   !important` at roughly (1,18,0) — so the gap trick could never work inside
   `#page-root`, and no rule in landing.css could have won either fight.

   THE FIX IS TWO-PART AND ONLY ONE HALF IS HERE. Borders lose to (1,2,0) and
   a (1,3,0) rule beats that, so they are simply restored below. The gap trick
   loses to (1,18,0), which hazard 24 says no honest selector wins — so
   landing.css stops using it and declares real borders on the cells instead,
   which this rule then restores. Fighting the fill ladder would have been the
   wrong move even if it were winnable.
   ========================================================================== */

/* The stat row: a rule between each figure, and one above and below the set. */
#page-root [class][class].lndFigs {
  border-top: 1px solid var(--mi-hair) !important;
  border-bottom: 1px solid var(--mi-hair) !important;
}

/* ANSWER 274b UPGRADED THIS FROM DIVIDERS TO BOXES. The reader was offered
   "vertical dividers between each figure" and chose "each in a bordered box",
   which is the stronger reading of the original complaint — four numbers with
   a line between them still share one surface, and it was sharing that made
   them look unrelated. Each cell is now its own object.

   The `:last-child` divider rule that used to sit here is gone with it: a
   full border needs no wrap-point special case, which also retires the
   `auto-fit` fragility the old comment described. */
#page-root [class][class].lndFigCell {
  border: 1px solid var(--mi-hair) !important;
  border-radius: var(--mi-radius-small) !important;
}

/* The workspace list: one rule per line, none after the last. */
#page-root [class][class].lndWsLine {
  border-bottom: 1px solid var(--mi-hair) !important;
}

#page-root [class][class].lndWsLine:last-child {
  border-bottom-width: 0 !important;
}

/* The source grid and the limits list, which had the same problem for the
   same reason and were not mentioned only because the stat row is the one a
   reader hits first. */
#page-root [class][class]:is(.lndSrc, .lndLimit) {
  border: 1px solid var(--mi-hair) !important;
  border-radius: var(--mi-radius-small) !important;
}

/* A section heading earns a rule under it — that is what makes a section read
   as a section rather than as more of the paragraph above it. */
#page-root [class][class].lndSectionHead {
  border-bottom: 1px solid var(--mi-hair) !important;
}

#page-root [class][class].plcTagKey {
  border-color: var(--i-amber) !important;
}

/* A panel title is the mock's small-caps eyebrow, not a heading. */
#app-root [class][class]:is([class$="-panel-title"], [class*="-panel-title "], .sgkTitle) {
  font-family: var(--mi-body);
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase !important;
  color: var(--mi-ink-3);
}

#app-root [class][class]:is([class$="-panel-caption"], [class*="-panel-caption "], .sgkMeta) {
  font-size: 11px;
  color: var(--mi-ink-4);
}

/* TABLES, per answers 76a/77a/78a/12b/100a: full outer border, a stronger
   header rule, FAINT verticals between columns, very subtle striping, and a
   sticky header. The verticals are held at 5% so the eye still processes the
   numbers before the grid. */
#app-root table,
#app-root [class][class]:is(table) {
  border: 1px solid var(--mi-hair) !important;
  border-radius: var(--mi-radius-small);
}

#app-root [class][class] td,
#app-root [class][class] th,
#app-root [class][class].sgtCell {
  border: 0 !important;
  border-bottom: 1px solid rgba(255, 255, 255, 0.07) !important;
}

#app-root [class][class] td:not(:last-child),
#app-root [class][class] th:not(:last-child) {
  border-right: 1px solid rgba(255, 255, 255, 0.05) !important;
}

/* Sticky header (100a). Opaque-ish lid, or the rows scroll through the
   labels; near the panel colour so it does not detach from the surface. */
#app-root [class][class] th,
#app-root [class][class] thead td,
#app-root [class][class].sgtHeadCell {
  background-color: var(--mi-thead-bg) !important;
  border-bottom: 1px solid var(--mi-hair-2) !important;
  color: var(--mi-ink-3) !important;
  font-weight: 600 !important;
}

#app-root thead th {
  position: sticky;
  top: 0;
  z-index: 2;
}

/* Striping (12b): whisper-level. Real <tr>s take a fill — an unclassed row
   is never purged. The kit's div rows are classed, so the fill purge would
   eat any background at (1,20,0); they take backdrop-filter instead, the one
   channel the purge does not name (hazard 24's own escape route). */
#app-root tbody tr:nth-child(even) { background-color: rgba(255, 255, 255, 0.016); }
#app-root [class][class].sgtRow { background-color: transparent !important; }
#app-root [class][class].sgtRow:nth-child(even) { backdrop-filter: brightness(1.35); }

#app-root [class][class] tbody tr:hover,
#app-root [class][class].sgtRow:hover {
  background-color: var(--mi-row-hover) !important;
}

/* CONTROLS keep an edge, because a control the eye cannot find is a bug. */
#app-root [class][class]:is(button, input, select, textarea, .sgkBtn),
#page-root [class][class]:is(button, input, select, textarea, .pk-btn) {
  border: 1px solid var(--mi-hair) !important;
  border-radius: var(--mi-radius-control) !important;
  background-color: var(--mi-control-bg) !important;
  color: var(--mi-ink-2);
  transition: background-color var(--mi-dur) var(--mi-ease),
              border-color var(--mi-dur) var(--mi-ease),
              color var(--mi-dur) var(--mi-ease);
}

/* Gold on hover, not on rest. The mock spends the accent on intent. */
#app-root [class][class]:is(button, .sgkBtn):hover,
#page-root [class][class]:is(button, .pk-btn):hover {
  background-color: var(--mi-control-bg-hover) !important;
  border-color: var(--i-accent-edge) !important;
  color: var(--mi-ink-1);
}

#app-root [class][class]:is(input, textarea, select):focus,
#page-root [class][class]:is(input, textarea, select):focus {
  border-color: var(--i-accent-edge) !important;
}

/* NO DROP SHADOWS. Elevation is borders and opacity — the mock is explicit,
   and the purge in section 3 already says `box-shadow: none !important`. Two
   rules above this file outrank it and put real drops back:

     obsidian_orchid.css  #app-root #singularity-sidebar               (2,1,0)!
     obsidian_orchid.css  #app-root button:not([disabled]):not(...)    (1,2,1)!

   The purge scores (1,2,0) and loses to both. Measured on Stock Lab, 6
   elements still carried a drop — the sidebar and its 5 group toggles —
   while 47 carried only the 1px inset rim, which is kept deliberately.

   The `:not(.active)` guard is not decoration: the gold rail in section 6 IS
   an inset box-shadow, and without the guard this rule would erase it. */
#app-root #singularity-sidebar { box-shadow: none !important; }

#app-root [class][class][class]:is(button, .sgkBtn, a):not(.active):not([aria-current="page"]) {
  box-shadow: none !important;
}

/* Structural edges. One line each, no fill, so they recede behind the data.
   The sidebar is the mock's 236px rail: hairline, black, blurred. */
#singularity-sidebar {
  border-right: 1px solid var(--mi-hair) !important;
  background-color: var(--mi-shell-bg) !important;
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}

/* The header is a hairline, nothing more. A sheet above this one puts a 2px
   gold inset along its top edge; rendered, that is a bright gold rule running
   the full width of the app above every screen, and it reads as a status bar
   announcing something. The accent is for the ACTIVE thing, and the header is
   never the active thing. */
/* (1,3,0), not the bare `.viewport-header` this started as. The rule putting
   the gold inset there is `#app-root .viewport-header` at (1,1,0)!important,
   so a (0,1,0)!important rule loses — and loses SILENTLY, which is why the
   line survived a fix that measurement had already told me to make. Only the
   rendered pixels showed it was still there. */
#app-root [class][class].viewport-header {
  border-bottom: 1px solid var(--mi-hair) !important;
  background-color: var(--mi-shell-bg) !important;
  box-shadow: none !important;
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}

.sgcChromeRow {
  border-bottom: 1px solid var(--mi-hair) !important;
  background-color: rgba(255, 255, 255, 0.012) !important;
}

/* ===========================================================================
   THE CHROME STACK — MEASURED, THEN CUT.

   work/probe_chrome.py walks the direct children of the content region and
   sums everything above the first block that actually holds figures. On WACC,
   SOVW and STOCK the answer was identical and it was **292px — 29% of a
   1000px viewport** — before a single number:

        64px  viewport-header    "Cost of Capital (WACC) · WACC · AAPL"
        25px  sgcCrumbs          "Valuation › Cost of Capital (WACC) › AAPL"
        36px  sgwsStrip          the open tabs
        31px  sguoAddWrap        "☆ No lists yet"
        90px  mi-crest           the signature band
        46px  sgctxBar           symbols · as-of · currency · figures

   On a laptop that is most of what you see. Three of the six earn their
   height; three do not, and each is cut for a specific reason rather than
   because the stack was long.
   =========================================================================== */

/* 1. THE BREADCRUMB IS THE TITLE AGAIN. `viewport-header` directly above it
      already says "Cost of Capital (WACC)" and already carries the ticker.
      The crumb row repeats both and adds a workspace name that the sidebar is
      showing at the same moment, highlighted. Two lines of navigation that
      disagree about nothing.

      The trail itself goes; the row does NOT, because it also holds the
      recent-ticker chips and the freshness stamp, which are the only place
      those appear. It collapses to the height of what is left. */
#app-root .sgcChromeRow .sgcCrumbs { display: none; }
#app-root .sgcChromeRow {
  min-height: 0 !important;
  padding-top: 2px !important;
  padding-bottom: 2px !important;
}

/* 2. A FULL ROW TO SAY THERE IS NOTHING IN IT. `:has()` is doing real work
      here — the row keeps its height the moment a list exists, and disappears
      only while its own contents are an empty state. A reader with no
      watchlists is exactly the reader who least needs 31px spent on saying so;
      the control is still one click away in the palette and on /work. */
#app-root .sguoAddWrap[data-sguo-state="none"],
#app-root .sguoAddWrap[data-sguo-state="loading"] {
  display: none;
}

/* 3. THE CREST IS DECORATION THAT REPORTS. It stays — it is drawn from real
      closes and names its source — but 90px is a hero band on a screen whose
      job is a table. Halved, it still reads as a year of price and it stops
      being the largest thing above the data.

      `clamp` keeps it proportional on a short window, which is where the
      complaint came from: at 782px tall, the old band was 12% of everything. */
/* The crest override lives at the END of this file, not here: the original
   `#app-root [class][class].mi-crest` rule further down scores the same
   (1,3,0), so an equal-specificity copy placed ABOVE it loses on order and
   the band stayed 90px. Measured before believing it — see the tail of this
   file. */

/* Floating layers are the ONE exception to "no shadows". Without a drop they
   merge into the page, and the mock's own hover card carries one. */
#app-root [class][class]:is(.sgkPopover, .sgPalette, .sgkToast, [role="dialog"]),
#app-root [class][class][data-sgc-overlay] {
  border: 1px solid var(--mi-hair-2) !important;
  border-radius: 9px !important;
  background-color: var(--mi-float-bg) !important;
  box-shadow: 0 30px 60px -26px rgba(0, 0, 0, 0.95) !important;
}

/* Chips: the mock's crisp 4px, not a pill. 106 elements were at 999px. */
#app-root [class][class]:is([class*="chip"], [class*="Chip"], [class*="badge"], [class*="Badge"]) {
  border: 1px solid var(--mi-hair) !important;
  border-radius: 4px !important;
  background-color: var(--mi-control-bg) !important;
  padding: 2px 7px;
  font-family: var(--mi-fig);
  font-size: 10px;
  letter-spacing: 0.10em;
}

/* ==========================================================================
   5 — TYPE
   Three families with three jobs. Serif italic displays, Barlow speaks,
   mono counts. Nothing else may use the serif — it is a display face and
   sets badly below about 20px.
   ========================================================================== */
#app-root, #page-root, body,
#app-root [class][class], #page-root [class][class] {
  font-family: var(--mi-body);
}

/* Mono for every numeral — and ONLY for numerals.

   `[class*="value"]` and `[class*="figure"]` used to be in this list and had
   to come out. Seen rendered, `.stocklab-row-value` holds "Senior VP & Chief
   Operating Officer" as often as it holds a number, and a job title set in
   15px monospace overflowed its panel and was clipped mid-word. A class name
   containing "value" says nothing about whether the value is a numeral.

   The app already marks its own numerals with `.mono` — 120 elements on one
   screen — so that is the signal to trust rather than a guess from a
   substring. */
#app-root [class][class].mono,
#app-root [class][class].sgtCell.mono,
#page-root [class][class] code,
#page-root [class][class].pk-card-path {
  font-family: var(--mi-fig) !important;
  font-variant-numeric: tabular-nums lining-nums;
}

#app-root, #page-root { font-variant-numeric: tabular-nums lining-nums; }

/* Terminal body. 13px, not the mock's 14 — density is not the problem. */
#app-root [class][class] { font-size: 13px; }

/* THE DISPLAY FACE. Reserved for the one loud element on a screen. */
#app-root [class][class]:is(h1, .terminal-title, .viewport-title),
#page-root h1 {
  font-family: var(--mi-display) !important;
  font-style: italic;
  font-weight: 400;
  letter-spacing: -0.025em;
  color: var(--mi-ink-1);
}

#app-root [class][class]:is(h1, .viewport-title) { font-size: 21px; line-height: 1.1; }
#app-root [class][class].terminal-title      { font-size: 19px; line-height: 1.1; }

#app-root [class][class]:is(h2, h3) {
  font-size: 14px;
  font-weight: 600;
  letter-spacing: -0.005em;
  color: var(--mi-ink-1);
}

/* Micro: column headers, eyebrows, status. The ONLY uppercase that stays.
   At 9-10px with open tracking it reads as texture, not shouting — which is
   exactly how the mock uses it. */
#app-root [class][class]:is(th, thead td, .sgtHeadCell, [class*="-head-cell"], [class*="-grid-head"], [class$="-eyebrow"], [class*="-eyebrow "], [class$="-panel-title"], [class*="-panel-title "], .sidebar-group-label, .oo-nav-section-label, .kick, .pk-kick) {
  font-size: calc(9.5px * var(--i-t-scale)) !important;   /* item 373 */
  letter-spacing: 0.18em;
  font-weight: 600;
  text-transform: uppercase !important;
}

/* Everything else stops shouting. Blanket uppercase destroys word shape,
   which is what makes small text scannable, and it was the single biggest
   reason the product read as 2004. */
#app-root [class][class]:not(th):not(.sgtHeadCell):not([class*="-head-cell"]):not([class*="-grid-head"]):not([class$="-eyebrow"]):not([class*="-eyebrow "]):not([class$="-panel-title"]):not([class*="-panel-title "]):not(.sidebar-group-label):not(.oo-nav-section-label):not(.kick):not(.pk-kick),
#page-root [class][class]:not(.pk-kick):not([class$="-eyebrow"]):not([class*="-eyebrow "]) {
  text-transform: none !important;
}

/* Three ink levels, no more. */
#app-root [class][class]:is([class*="-label"], [class*="-meta"], [class*="-sub"], [class*="muted"], [class$="-caption"], [class*="-caption "], .sgkMeta) {
  color: var(--mi-ink-3);
}

/* --- Prose pages want measure and air where data wants density ----------

   THE DOUBLED ID IS LOAD-BEARING. `#page-root h1` is (1,0,1) and loses to
   `#app-root.pk-page h2` in pages.css at (1,1,1) — and the page shell nests
   #page-root inside an element that carries BOTH #app-root and .pk-page, so
   that rule really does match. Measured, the result was the worst possible
   half-win: the serif family applied and the size did not, putting a display
   italic on screen at 15px. `#page-root#page-root` scores (2,0,1), matches
   exactly the same elements, and settles it. Same reasoning as the
   `[class][class]` doubling used throughout this file. */
#page-root { font-size: 14px; }

#page-root#page-root h1 {
  font-size: clamp(32px, 4vw, 54px);
  line-height: 1.04;
  margin-bottom: 0.4em;
}

#page-root#page-root h2 {
  font-family: var(--mi-display);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(22px, 2.2vw, 28px);
  letter-spacing: -0.02em;
  line-height: 1.14;
  margin-top: 2.2em;
  color: var(--mi-ink-1);
}

/* Panel and section heads are FURNITURE, not document levels — pages.css
   says so and keeps them compact whatever tag the markup used. The display
   face is a display face: it sets badly below about 20px, so furniture keeps
   the interface face and the compact size it was given. */
#page-root#page-root .pk-panel-head h2,
#page-root#page-root .pk-panel-head h3 {
  font-family: var(--mi-body);
  font-style: normal;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.005em;
  margin-top: 0;
}

#page-root#page-root h3 {
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--mi-ink-1);
}

#page-root p, #page-root li {
  max-width: 68ch;
  line-height: 1.7;
  font-weight: 300;
  color: var(--mi-ink-2);
}

/* A 68ch measure inside a 1132px panel leaves half the panel empty, and
   rendered that dead space is the first thing the eye lands on — /methodology
   showed a full-height card with nothing in its right half.

   Capping the CARD is what closes it, but a blanket cap would squeeze the
   panels that legitimately hold a wide source-card grid. `:has()` asks the
   only question that actually decides it: does this panel contain something
   wide? Prose panels take a reading measure; grid panels keep the full
   column. */
#page-root#page-root :is(.pk-panel, .pk-section, .pk-prose) {
  max-width: 86ch;
}

#page-root#page-root :is(.pk-panel, .pk-section):has(table, pre, .pk-grid, [class*="-grid"], [class*="-cards"], [class*="-table"]) {
  max-width: none;
}

#page-root [class][class].pk-card { padding: 16px; }
#page-root [class][class].pk-card:hover {
  border-color: var(--i-accent-edge-soft) !important;
}

/* ==========================================================================
   6 — THE RAIL
   The mock slides a gold bar to the active function. Here it is an inset
   box-shadow on the active nav item rather than a separately positioned
   element, because renderApp() rebuilds the whole DOM on every state change
   and a positioned indicator would have to be re-placed on each rebuild.
   A shadow on the item itself has nothing to re-place.
   ========================================================================== */
#app-root [class][class]:is(.sidebar-nav-item, .sgaNavItem, .command-tab).active,
#app-root [class][class][aria-current="page"] {
  background-color: var(--i-nav-active-wash) !important;
  color: var(--mi-ink-1) !important;
  box-shadow: inset 2px 0 0 0 var(--mi-gold) !important;
}

#app-root [class][class]:is(.sidebar-nav-item, .sgaNavItem, .command-tab) {
  border-radius: 4px !important;
  transition: background-color var(--mi-dur) var(--mi-ease),
              color var(--mi-dur) var(--mi-ease);
}

#app-root [class][class]:is(.sidebar-nav-item, .sgaNavItem, .command-tab):hover {
  background-color: var(--mi-control-bg-hover) !important;
  color: var(--mi-ink-1) !important;
}

/* ink-3, not ink-4. The token layer marks ink-4 NON-TEXT ONLY and means it:
   as a label colour it measured 3.09:1 on the light ground, below the 4.5
   floor. It is for rules and disabled states. */
#app-root [class][class]:is(.sidebar-group-label, .oo-nav-section-label) {
  color: var(--mi-ink-3) !important;
}

/* Brand mark. The mock's wordmark is wide-tracked Barlow, not the serif. */
#app-root [class][class].terminal-title {
  font-family: var(--mi-body) !important;
  font-style: normal;
  font-size: calc(10.5px * var(--i-t-scale)) !important;   /* item 373 */
  font-weight: 600;
  letter-spacing: 0.28em;
  text-transform: uppercase !important;
  color: #E2DDD4;
}

/* THE SCREEN TITLE IS WHERE THE DISPLAY FACE LIVES.

   The mock pairs an italic serif screen name with a gold mono code chip, and
   that pairing is the single most recognisable thing about it. In this app
   those two are .viewport-command ("Stock Lab") and .viewport-command-code
   ("STOCK"), sitting together in .viewport-title-block — the same two pieces
   of information in the same order, so the treatment transfers directly.

   Without this rule Instrument Serif is downloaded and never painted: a
   measurement of the loaded font set showed every Instrument Serif face at
   status "unloaded" because nothing on a terminal screen selected it. */
#app-root [class][class].viewport-command {
  font-family: var(--mi-display) !important;
  font-style: italic;
  font-weight: 400;
  font-size: calc(22px * var(--i-t-scale)) !important;   /* item 373 */
  line-height: 1.05;
  letter-spacing: -0.02em;
  color: var(--mi-ink-1) !important;
  text-transform: none !important;
}

/* The code chip beside it: the mock's gold-outlined mono tag. The colour
   needs !important — obsidian_orchid.css sets ink on this element through a
   blanket rule that a (1,3,0) selector alone does not outrank. */
#app-root [class][class].viewport-command-code {
  font-family: var(--mi-fig) !important;
  font-size: calc(10px * var(--i-t-scale)) !important;   /* item 373 */
  letter-spacing: 0.14em;
  color: var(--mi-gold) !important;
  border: 1px solid var(--i-accent-edge-soft) !important;
  border-radius: 4px !important;
  padding: 2px 7px;
  align-self: center;
}

#app-root [class][class].viewport-title-block {
  display: flex;
  align-items: baseline;
  gap: 10px;
}

/* Focus is gold and is the only thing that is. */
#app-root :focus-visible,
#page-root :focus-visible {
  outline: 2px solid var(--mi-gold) !important;
  outline-offset: 2px;
}

::selection { background: rgba(225, 173, 102, 0.32); color: #FFF; }

/* A LINK WITH NO RULE FALLS BACK TO #0000EE. The audit found bare anchors
   rendering in user-agent blue at 2.23:1 on the black ground — unreadable and
   from a different design entirely. Any anchor no sheet has claimed gets the
   accent; anything already coloured keeps its colour, because :not([class])
   only catches the genuinely unstyled ones. */
#app-root a:not([class]):not([style*="color"]),
#page-root a:not([class]):not([style*="color"]) {
  color: var(--mi-gold);
  text-decoration-color: color-mix(in srgb, var(--mi-gold) 45%, transparent);
}

/* ==========================================================================
   7 — DIRECTION
   Green up, red down, and no third meaning for either. Magnitude is encoded
   by size and opacity elsewhere, never by hue, which is the mock's rule and
   the market convention it comes from.
   ========================================================================== */
#app-root [class][class]:is(.bullish, [class$="-up"], [class*="-up "], [class*="positive"]) { color: var(--mi-up) !important; }
#app-root [class][class]:is(.bearish, [class$="-down"], [class*="-down "], [class*="negative"]) { color: var(--mi-down) !important; }

/* ==========================================================================
   8 — HONEST STATES
   These two carry the product's whole claim to be trustworthy, so they are
   styled to be SEEN, not tucked away.

   .oo-awaiting  a function whose source is not currently available. It stays
                 legible and gets a dotted edge, so an unavailable screen is
                 obviously unavailable rather than obviously broken.
   .source-warning  freshness, not credits: "replayed from disk-cache (8.4h
                 old)", "FINRA TRACE unavailable". declutter.css hides source
                 attributions and deliberately does not hide these. Amber-gold
                 rule down the left, because a stale figure that looks live is
                 the worst thing this interface can do.
   ========================================================================== */
/* ink-3, not ink-4. "This function's source is unavailable" is information;
   it has to be legible to deliver it. Dimmer than an available item, still
   above the contrast floor. */
#app-root [class][class].oo-awaiting {
  color: var(--mi-ink-3) !important;
  opacity: 1;
}

#app-root [class][class].oo-awaiting-dot {
  background-color: var(--mi-ink-4) !important;
}

/* THE READING'S TONE RULE — the 2px left edge on each algorithmic observation
   (frontend/kit/readout.js, rendered by simple_overview.js and screen_intel.js).

   MEASURED BEFORE THIS ENTRY EXISTED: `borderLeftColor: rgba(0, 0, 0, 0)` on
   every observation, found by disabling the 54 loaded sheets one at a time and
   watching for the colour to come back — skin.css was the only one that
   changed it. The purge at §3 is `#app-root [class][class]` at (1,2,0)
   `!important`, and `.so-root .so-read` is also (1,2,0): a tie, decided by
   load order, and this file loads last. Nothing in simple_overview.css could
   ever have won it.

   `[class][class].so-read` is (1,3,0), which is the pattern .source-warning
   above uses for the same reason. The edge earns its place under §4's rule
   because it is the ONLY thing distinguishing one observation from the next;
   without it the panel is eight identical paragraphs of grey prose. */
#app-root [class][class].so-read,
#app-root [class][class].si-readone {
  border-left: 2px solid var(--mi-hair-2) !important;
}

#app-root [class][class].so-read.is-strong,
#app-root [class][class].si-readone.is-strong { border-left-color: var(--mi-up) !important; }

#app-root [class][class].so-read.is-weak,
#app-root [class][class].si-readone.is-weak { border-left-color: var(--mi-down) !important; }

/* Amber, not red. `is-caution` means "this figure is easy to read wrongly",
   which is a different claim from "this figure is bad" — a return on equity of
   104% is not a fault, it is a number that needs its neighbour read too. */
#app-root [class][class].so-read.is-caution,
#app-root [class][class].si-readone.is-caution { border-left-color: var(--mi-gold) !important; }

#app-root [class][class].source-warning {
  display: revert !important;
  border-left: 2px solid var(--mi-gold) !important;
  border-radius: 0 !important;
  background-color: var(--i-accent-glow) !important;
  padding: 7px 11px;
  color: var(--mi-ink-2) !important;
  font-size: 11.5px;
  line-height: 1.55;
}

/* ==========================================================================
   9 — MOTION
   Five of the mock's behaviours survive the port. The three that do not are
   the ones that animate fabricated series (candle tape, crest driver, figure
   count-up on invented numbers).

   All of it is CSS. renderApp() replaces the DOM wholesale on every state
   change, so a JS-attached animation would have to be re-attached on every
   rebuild; a keyframe on a selector re-fires by itself and costs nothing to
   maintain. It also means none of this can break a data path.

   NO ENTRANCE ANIMATION MAY START FROM opacity: 0, AND THIS IS NOT A STYLE
   PREFERENCE. The first draft of this section faded the screen in from zero
   with fill-mode `both`. Measured on the live DOM, the whole workspace sat at
   `opacity: 0`, `animationName: miBlurIn`, `playState: running`,
   `currentTime: 0` — every figure on the screen present in the DOM, correct,
   and invisible, because the frame clock had not advanced.

   A stalled clock is not hypothetical here: this build's verification pane
   never advances it at all, a background tab is throttled, and a heavy canvas
   paint (GP, GPC, GEO, TMAP) can stall a frame on a real machine. With a
   frozen clock a running animation pins its element at the `from` keyframe
   FOREVER. So the `from` keyframe must be a state in which the data is fully
   legible. Motion may move data; it may never hide it.

   The mock's blur-in also went, for a second reason: `filter` on an ancestor
   makes it the containing block for `position: fixed` descendants, which
   would displace any popover or dialog opened during the animation.
   ========================================================================== */

/* Transform only. At t=0 the content is at full opacity, merely 10px low. */
@keyframes miRise {
  from { transform: translate3d(0, 10px, 0); }
  to   { transform: none; }
}

/* ---------------------------------------------------------------------------
   THE CREST, drawn by frontend/crest.js from real daily closes.

   Direction drives the colour: the fill and contour go green or red by the
   ACTUAL net change over the window, set from `data-mi-trend`. The band is
   the one place in this skin where green and red appear as decoration, and
   they are allowed to because they are reporting the same thing they report
   everywhere else. Gold is not used here — gold is chrome, and this is data.
   --------------------------------------------------------------------------- */
#app-root [class][class].mi-crest {
  position: relative;
  height: clamp(76px, 9vh, 104px);
  margin: 10px 22px 4px;
  border: 1px solid var(--mi-hair) !important;
  border-radius: 9px !important;
  background-color: var(--mi-panel-bg) !important;
  overflow: hidden;
  --mi-crest-fill: var(--mi-up);
  --mi-crest-line: var(--mi-up);
  --mi-crest-dot: var(--mi-ink-1);
}

#app-root [class][class].mi-crest[data-mi-trend="down"] {
  --mi-crest-fill: var(--mi-down);
  --mi-crest-line: var(--mi-down);
}

#app-root [class][class].mi-crest-svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}

#app-root [class][class].mi-crest-label {
  position: absolute;
  top: 9px;
  left: 12px;
  display: flex;
  align-items: baseline;
  gap: 8px;
  pointer-events: none;
}

#app-root [class][class].mi-crest-sym {
  font-family: var(--mi-fig) !important;
  font-size: 11px;
  letter-spacing: 0.12em;
  color: var(--mi-ink-1);
}

#app-root [class][class].mi-crest-kind {
  font-size: calc(9.5px * var(--i-t-scale)) !important;   /* item 373 */
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase !important;
  color: var(--mi-ink-3);
}

/* Provenance, bottom-right, small and always present. It is NOT hidden by
   declutter.css: an ornament drawn from live prices has to say so, or it is
   indistinguishable from the invented one it replaced. */
#app-root [class][class].mi-crest-note {
  position: absolute;
  right: 12px;
  bottom: 8px;
  font-family: var(--mi-fig) !important;
  font-size: 9.5px;
  color: var(--mi-ink-3);
  pointer-events: none;
}

#app-root [class][class].mi-crest-stale { color: var(--mi-gold); }

/* The unavailable state. Quiet on purpose — a missing ornament must not
   shout over the data that did load. */
#app-root [class][class].mi-crest-out {
  display: grid;
  place-items: center;
  height: 100%;
  padding: 0 16px;
  font-size: 11.5px;
  color: var(--mi-ink-4);
  text-align: center;
}

/* The rail indicator frontend/motion.js positions. It is the mock's sliding
   gold bar; skin.css cannot draw it because a box-shadow has no position to
   animate. Geometry and paint live here so the module only ever sets
   `transform` and `height` — the two things a compositor can move without a
   repaint. */
/* THE CONTAINING BLOCK IS DECLARED HERE, NOT SET FROM JS.

   motion.js used to do `nav.style.position = nav.style.position || "relative"`
   when it created the bar. Measured in real Chrome, `.sidebar-nav` came back
   `position: static` anyway — the assignment only runs on the branch that
   creates the element, so a bar that survived into a rebuilt nav left the nav
   unpositioned. An absolutely-positioned child then resolves against whatever
   ancestor IS positioned, and the bar lands somewhere unrelated to the item
   it is supposed to be marking.

   A stylesheet cannot forget to run. */
#app-root .sidebar-nav { position: relative; }

#app-root .mi-rail {
  position: absolute;
  left: 0;
  top: 0;
  width: 2px;
  border-radius: 2px;
  background: linear-gradient(180deg, var(--mi-gold-lift), var(--mi-gold-deep));
  pointer-events: none;
  opacity: 0;
  will-change: transform;
}

/* ===========================================================================
   AMBIENT DRIFT — Design.md, terminal motion 1.

   "Three blobs (green/red tints) drifting 26-40s loops, 40-60px amplitude,
   opacity 0.12-0.16."

   PAINTED HERE, MOVED BY frontend/motion.js. The split is the safety
   property: every blob is at full opacity and its resting position from the
   first paint, so if the frame clock never ticks the result is a static
   gradient wash — which is precisely what this interface looked like before
   the ambience existed. Nothing about the content depends on a frame.

   `position: fixed` and `z-index: 0` put it behind everything. The content
   roots are `position: relative` with a z-index above this, so no figure is
   ever drawn under a blob.
   =========================================================================== */
.mi-aurora {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
  contain: strict;
}

.mi-aurora-blob {
  position: absolute;
  width: 46vw;
  height: 46vw;
  min-width: 380px;
  min-height: 380px;
  border-radius: 50%;
  filter: blur(90px);
  will-change: transform;
}

/* Direction colours, as the mock specifies: green for growth, red for
   decline, gold for chrome. Kept at the low end of the stated 0.12-0.16 —
   this sits under live figures and must never tint one. */
.mi-aurora-1 {
  top: -14vw; left: -10vw;
  background: radial-gradient(circle, rgba(79, 178, 134, 0.13), transparent 68%);
}
.mi-aurora-2 {
  bottom: -18vw; right: -12vw;
  background: radial-gradient(circle, rgba(220, 106, 98, 0.12), transparent 68%);
}
.mi-aurora-3 {
  top: 34%; left: 42%;
  background: radial-gradient(circle, rgba(225, 173, 102, 0.10), transparent 70%);
}

/* LIGHT MODE HAS AMBIENCE NOW, AND IT IS INK RATHER THAN LIGHT.

   This block used to be `display: none` with the note that "a coloured wash on
   a paper ground reads as a printing fault". That was right about the
   TECHNIQUE and wrong about the conclusion. `screen`-style additive glow needs
   a dark ground to glow against; on paper the same gradient greys the sheet
   and does look like a misregistered plate. Ink does not work that way, and
   neither does `mix-blend-mode: multiply` — it darkens toward the tint the way
   a wash of colour on paper actually does.

   SCOPED TO THE HERO, NOT THE APP. Light mode is the theme with the contrast
   headroom problem in this build, and a tint under a dense table spends
   headroom for decoration. `:has(.lndHero)` limits it to the landing page,
   where the only thing over the wash is a headline at 34px.

   Alphas are half the dark ones for the same reason: on white, a 0.13 wash is
   plainly visible as a colour cast, and this has to stay atmosphere. */
:root[data-theme="light"] body:not(:has(.lndHero)) .mi-aurora { display: none; }
:root[data-theme="light"] .mi-aurora-blob {
  mix-blend-mode: multiply;
  filter: blur(110px);
}
:root[data-theme="light"] .mi-aurora-1 {
  background: radial-gradient(circle, rgba(21, 122, 82, 0.10), transparent 70%);
}
:root[data-theme="light"] .mi-aurora-2 {
  background: radial-gradient(circle, rgba(176, 58, 50, 0.09), transparent 70%);
}
:root[data-theme="light"] .mi-aurora-3 {
  background: radial-gradient(circle, rgba(150, 104, 34, 0.07), transparent 72%);
}

@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) body:not(:has(.lndHero)) .mi-aurora { display: none; }
  :root:not([data-theme="dark"]) .mi-aurora-blob {
    mix-blend-mode: multiply;
    filter: blur(110px);
  }
  :root:not([data-theme="dark"]) .mi-aurora-1 {
    background: radial-gradient(circle, rgba(21, 122, 82, 0.10), transparent 70%);
  }
  :root:not([data-theme="dark"]) .mi-aurora-2 {
    background: radial-gradient(circle, rgba(176, 58, 50, 0.09), transparent 70%);
  }
  :root:not([data-theme="dark"]) .mi-aurora-3 {
    background: radial-gradient(circle, rgba(150, 104, 34, 0.07), transparent 72%);
  }
}

@media (prefers-reduced-motion: reduce) {
  /* Kept, not removed: at rest it is a still gradient, and a reader who asked
     for stillness asked for no MOVEMENT, not for a flat black rectangle.
     motion.js does not start the drift in this mode. */
  .mi-aurora-blob { animation: none; }
}

/* The content roots must sit above the wash. Both shells, because the
   aurora is attached to <body> so it survives renderApp() rebuilding
   #app-root several times a minute. */
#app-root, #page-root, #terminal-root { position: relative; z-index: 1; }

/* READING PROGRESS, on the long document pages only. Written by
   frontend/motion.js as a scaleX, which is a compositor-only property — no
   layout, no paint, no reflow on a scroll handler.

   transform-origin is the whole point: without it the bar scales about its
   centre and reads as a line growing in both directions from the middle. */
.mi-progress {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 90;
  width: 100%;
  height: 2px;
  transform: scaleX(0);
  transform-origin: 0 50%;
  background: linear-gradient(90deg, var(--mi-gold-deep), var(--mi-gold-lift));
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  /* Still shown — it is a position indicator, not decoration — but it stops
     being the thing that moves on the page. */
  .mi-progress { opacity: 0.55; }
}

@keyframes miShimmer { from { background-position: -160% 0; } to { background-position: 160% 0; } }

/* ENTRANCE MOTION MOVED TO frontend/motion.js, which drives it with the real
   Framer Motion engine and a spring rather than an ease curve. The keyframe
   stagger that used to live here is gone rather than kept as a fallback: two
   systems both writing `transform` on the same element fight, and the visible
   result is a panel that jumps. If motion.js fails to load, panels simply
   appear with no animation, which is the correct degradation.

   The `miRise` keyframe above is retained — the skeleton shimmer and the
   reduced-motion guard below still reference this section. */

/* Only the skeleton loops, because a moving skeleton says "still loading". */
#app-root [class][class]:is([class*="skeleton"], [class*="Skeleton"]) {
  background-image: linear-gradient(90deg,
    rgba(255, 255, 255, 0.03) 0%,
    rgba(255, 255, 255, 0.08) 50%,
    rgba(255, 255, 255, 0.03) 100%) !important;
  background-size: 200% 100%;
  animation: miShimmer 1.4s linear infinite;
  border-radius: 4px !important;
}

/* ===========================================================================
   THE CHART SERIES PALETTE — REORDERED, NOT FLATTENED.

   Looked at, not measured: the Price Graph drew its close line in magenta,
   its 200-day mean in pink and its Bollinger fill in purple, sitting directly
   under a gold header and a green crest. Every contrast check passed. It was
   simply a different theme's chart on this theme's screen.

   The cause is that `--i-viz-*` is a CATEGORICAL ramp built for the orchid
   palette, and its first entry — the one a single-series chart uses, which is
   most charts — is `#E08EBE`.

   THE FIX IS A REORDER. Making all eight gold would destroy the one job a
   categorical palette has, which is telling series apart; that is the same
   mistake as flattening a signal colour to fix a secondary theme. So the
   hues are kept and the ramp starts where the interface starts: gold, then
   the two direction colours this build already uses for up and down, then the
   cool hues. A one-series chart is gold. An eight-series chart still has
   eight distinguishable hues.

   Contrast measured against this skin's own --dk-surface-2 (#0E0E10), which
   is darker than instrument.css's #1D1D23, so every ratio here is better than
   the 7.3-8.1:1 the original ramp recorded:

       1 gold   #E1AD66  9.52:1      5 teal   #39C3BC  8.91:1
       2 green  #64C393  8.97:1      6 violet #B89BEA  8.18:1
       3 blue   #84ACF5  8.44:1      7 pink   #E08EBE  8.06:1
       4 coral  #EA9371  8.18:1      8 sand   #CFC4A8 11.12:1

   Dark only. Light mode keeps instrument.css's ramp, which print.css depends
   on and which was measured against a white ground.
   =========================================================================== */
:root[data-theme="dark"],
:root:not([data-theme="light"]) {
  /* ANSWER 15d: chart series are MONOCHROME AMBER, separated by lightness
     rather than hue. Direction (bull/bear) is untouched — it is data, not
     palette (8a). The ladder is ordered so the common 2-4 series charts get
     the strongest separation: accent, pale, deep, cream. Light mode keeps
     instrument.css's ramp, which print.css depends on. */
  --i-viz-1: #E1AD66;
  --i-viz-2: #FFF0CE;
  --i-viz-3: #A5591B;
  --i-viz-4: #FFD87E;
  --i-viz-5: #8A6D3B;
  --i-viz-6: #F2C591;
  --i-viz-7: #C08A2E;
  --i-viz-8: #6B5327;
  /* The crosshair was rgba(208, 91, 165, ...) — orchid. */
  --i-viz-crosshair: rgba(225, 173, 102, 0.55);
}

@media (prefers-color-scheme: light) {
  /* An explicit dark choice still gets the ramp above; the system default
     under a light OS does not. Without this the selector's `:not([light])`
     arm would repaint light mode's charts with a dark-ground ramp. */
  :root:not([data-theme="dark"]) {
    --i-viz-1: #B03A82;
    --i-viz-2: #2F7D4F;
    --i-viz-3: #2C5FA8;
    --i-viz-4: #A8542F;
    --i-viz-5: #1F7A75;
    --i-viz-6: #6B4CA8;
    --i-viz-7: #A03C6E;
    --i-viz-8: #7A6A3F;
    --i-viz-crosshair: rgba(138, 97, 23, 0.55);
  }
}

/* ===========================================================================
   LIGHT MODE, THE LAST THIRTY.

   The previous pass converted 343 hardcoded literals to tokens and took light
   mode from 247 AA failures to about thirty, then stopped and said so: the
   remainder were TINTED values, and flattening a colour that carries meaning
   to fix a secondary theme is a worse bug than the one being fixed.

   That reasoning was right about the risk and wrong about the options. The
   choice was never "keep the hue or fix the contrast" — a hue has a light
   variant. `#00ff00` on white is 1.37:1 and unreadable; `#1B7A2E` is the same
   green at 5.43:1. The signal survives, the reader can read it.

   Every value below was measured against #FFFFFF. Named individually rather
   than swept, because each one is a specific decision:
   =========================================================================== */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) { --mi-light-fix: 1; }
}
:root[data-theme="light"] { --mi-light-fix: 1; }

/* ---- THE THREE THAT FAIL IN BOTH THEMES ---------------------------------
   The first pass at this fixed them for light mode only, and re-auditing
   showed why that was half a fix: the cause is not the theme, it is a
   NON-TEXT TOKEN BEING USED FOR TEXT, which is below the floor on both
   grounds.

   `--i-ink-4` is annotated in instrument.css itself:

       --i-ink-4:  #5D5C65;   /* quaternary 3.03:1 — rules, disabled *​/
       --lt-ink-4: #838088;   /*  2.96:1 — NON-TEXT ONLY, as in dark *​/

   3.03:1 and 2.96:1. The comment says non-text; three classes used it for
   text anyway. `--i-ink-3` is the readable tier at 4.75:1 light and better in
   dark, and it is still visibly a de-emphasised grey — the whole point of the
   mark. Applied in BOTH themes, not just light.
   ------------------------------------------------------------------------- */
#app-root [class].si-figmark,
#app-root [class].stocklab-return-key,
#app-root [class].si-jumpwhy {
  color: var(--i-ink-3) !important;
}

/* The search-match highlight. The skin gives it a gold wash and ink-1 text,
   which is right on black and wrong on paper — ink-1 in light mode is near
   black, but the wash is near white and the pair measured below the floor at
   the wash's lightest edge. Anchored to the ground rather than to the theme:
   the mark keeps its gold, the text keeps the ground's own ink. */
#app-root [class][class].phase5-magenta-hit {
  color: var(--i-ink-1) !important;
  background-color: var(--i-accent-wash) !important;
}
:root[data-theme="light"] #app-root [class][class].phase5-magenta-hit,
:root[data-theme="light"] #app-root [class][class].phase5-magenta-hit * {
  /* MEASURED AT 1.02:1 — near-black ink on a near-black wash, i.e. an invisible
     search highlight, which is worse than no highlight because the reader
     believes the match was found and cannot see where.

     The token indirection was the problem: `--i-accent-wash` stayed dark in
     light mode, so ink-1 (near-black on paper) sat on it. Literals here, both
     legs stated, because a highlight is the one thing that must be legible on
     whatever ground it lands. #FBE3B6 with #1A1611 measures 14.8:1. */
  background-color: #FBE3B6 !important;
  background-image: none !important;
  color: #1A1611 !important;
}
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) #app-root [class][class].phase5-magenta-hit,
  :root:not([data-theme="dark"]) #app-root [class][class].phase5-magenta-hit * {
    background-color: #FBE3B6 !important;
    background-image: none !important;
    color: #1A1611 !important;
  }
}

/* A warning that cannot be read is not a warning. */
#app-root [class][class].stocklab-node-warning {
  color: var(--i-ink-1) !important;
}

/* `--si-hue` is the per-screen accent the live-screen modules write inline
   from `--i-viz-*`. In light mode it inherits the dark ramp, so the scope tag
   and the jump command drew a dark-ground hue on a paper ground. */
:root[data-theme="light"] #app-root,
:root[data-theme="light"] #page-root {
  --si-hue: var(--i-orchid);
}
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) #app-root,
  :root:not([data-theme="dark"]) #page-root {
    --si-hue: var(--i-orchid);
  }
}

/* One block, applied under either light signal. Each selector is doubled on
   class where it has to outrank the declaring sheet. */
:root[data-theme="light"] #app-root [class].si-figmark,
:root[data-theme="light"] #app-root [class].stocklab-return-key,
:root[data-theme="light"] #app-root [class].si-jumpwhy {
  /* `--i-ink-4` is labelled NON-TEXT ONLY in instrument.css — 2.96:1 in light
     — and all three were using it for text. ink-3 is the readable tier. */
  color: var(--i-ink-3) !important;
}

:root[data-theme="light"] #app-root [class][class].phase5-toggle.active {
  /* #00ff00 on white measures 1.37:1. Same hue, 5.43:1. */
  border-color: #1B7A2E !important;
  color: #1B7A2E !important;
}

:root[data-theme="light"] #app-root [class][class].si-scopetag,
:root[data-theme="light"] #app-root [class][class].si-jumpcmd {
  color: var(--i-ink-2) !important;
}

@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) #app-root [class].si-figmark,
  :root:not([data-theme="dark"]) #app-root [class].stocklab-return-key,
  :root:not([data-theme="dark"]) #app-root [class].si-jumpwhy {
    color: var(--i-ink-3) !important;
  }
  :root:not([data-theme="dark"]) #app-root [class][class].phase5-toggle.active {
    border-color: #1B7A2E !important;
    color: #1B7A2E !important;
  }
  :root:not([data-theme="dark"]) #app-root [class][class].si-scopetag,
  :root:not([data-theme="dark"]) #app-root [class][class].si-jumpcmd {
    color: var(--i-ink-2) !important;
  }
}

/* Scrollbars. The mock's 9px gold-on-hover thumb. */
#app-root ::-webkit-scrollbar,
#page-root ::-webkit-scrollbar { width: 9px; height: 9px; }
#app-root ::-webkit-scrollbar-thumb,
#page-root ::-webkit-scrollbar-thumb {
  background: rgba(232, 228, 221, 0.13);
  border-radius: 9px;
}
#app-root ::-webkit-scrollbar-thumb:hover,
#page-root ::-webkit-scrollbar-thumb:hover { background: rgba(225, 173, 102, 0.40); }
#app-root ::-webkit-scrollbar-track,
#page-root ::-webkit-scrollbar-track { background: transparent; }

/* ===========================================================================
   SCROLL — every box that has more content than room must let the reader
   reach it.

   MEASURED, NOT ASSUMED. work/probe_screens.py walks the live DOM of every
   screen and reports each element whose scrollHeight exceeds its clientHeight
   while its computed overflow-y is `hidden` or `clip`. That combination is
   data the reader cannot get to, and it is indistinguishable from data that
   never loaded — which is exactly how it was reported.

   `auto`, never `scroll`: `scroll` reserves a gutter on every panel whether
   or not it overflows, and forty empty gutters is the clutter this pass is
   supposed to be removing.
   =========================================================================== */

/* ---- THE MEASURED FIX ----------------------------------------------------
   Eight containers, found by the probe, each holding content past its own
   bottom edge with no way to scroll to it:

       666px unreachable   .ee-screen
       378px unreachable   .qs-screen.phase5-screen
       367px unreachable   .fa-screen
       276px unreachable   .phase5-screen.phase5-ds-screen
       269px unreachable   .phase8-screen.bidx-screen
       188px unreachable   .phase5-screen.phase5-chart-screen
       184px unreachable   .anr-distribution.terminal-panel
       102px unreachable   .portfolio-screen

   All of them come from the same declaration, repeated per phase sheet:

       .phase5-screen { width: 100%; height: 100%; overflow: hidden; }

   `height: 100%` fixes the box to the workspace and `overflow: hidden` throws
   away everything past it. On EE that is 666 pixels of earnings estimates that
   loaded correctly, rendered correctly, and could not be read.

   `overflow-y` only. Turning on both axes would let a wide grid scroll the
   screen sideways, and a horizontal scrollbar on a workspace is the loudest
   layout bug there is — instrument.css says so and it is right.

   `auto`, not `scroll`: `scroll` reserves a gutter on every screen whether or
   not it overflows, which is forty empty gutters and the opposite of this
   pass's other job. */
#app-root .phase5-screen,
#app-root .phase7-screen,
#app-root .phase8-screen,
#app-root .fa-screen,
#app-root .ee-screen,
#app-root .qs-screen,
#app-root .portfolio-screen,
#app-root .anr-distribution {
  overflow-y: auto;
  overscroll-behavior-y: contain;
}

/* The economic calendar, separately, because it clips the most and for a
   different reason: `overflow: hidden` there exists to keep the 24px corner
   radius from being cut through by a child. 1374px of dated events sat below
   the fold with no way down. Clipping the horizontal axis still gives the
   radius its job on the side that matters. */
#app-root .evcalRoot {
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior-y: contain;
}

/* The generic recovery for anything that names itself a scroller. */
#app-root [class*="-scroll"],
#app-root [class*="Scroll"],
#page-root [class*="-scroll"] {
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* Horizontal: a wide table scrolls inside its own box. The document itself
   must never scroll sideways — that is the loudest possible layout bug and
   instrument.css already says so. */
#app-root .pk-scroll-x,
#page-root .pk-scroll-x,
#app-root [class*="table-wrap"],
#app-root [class*="TableWrap"] {
  overflow-x: auto;
  overscroll-behavior-x: contain;
}

/* Momentum and keyboard scrolling both land the target under a sticky header
   rather than behind it. */
#app-root [class*="-scroll"],
#page-root [class*="-scroll"] { scroll-padding-top: 0.75rem; }

/* Firefox gets the same thin thumb; it does not implement ::-webkit-*. */
#app-root *, #page-root * { scrollbar-width: thin; }

/* A panel header stays put while its rows move under it. Only where the
   panel is genuinely a scroller — a sticky header on a short list is a
   header that never does anything and one more thing on screen. */
#app-root [class*="-scroll"] > [class*="-head"],
#app-root [class*="-scroll"] > thead {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--i-surface-1, #0b0b0d);
}

/* Reduced motion. The descendant `*` in instrument.css's own guard means it
   never matched #app-root::before; that is covered here explicitly. */
@media (prefers-reduced-motion: reduce) {
  #app-root *, #page-root *,
  #app-root::before, #app-root::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}


/* ---------------------------------------------------------------------------
   SEARCH-TERM HIGHLIGHT
   phase5.css paints matched terms `background:#ff00ff; color:#000` — pure
   magenta, from no palette this product has ever had. It also sat inside a
   panel, so the nested-surface purge stripped the fill and the highlight
   stopped marking anything at all: measured, the matched span rendered in
   ordinary body ink at 1.40:1 against its own intended background.

   Restored as a fill that belongs to the design, and the class family is
   excluded from the purge above so it keeps it.
   --------------------------------------------------------------------------- */
#app-root [class][class].phase5-magenta-hit {
  background-color: var(--i-accent-wash) !important;
  color: var(--mi-ink-1) !important;
  box-shadow: inset 0 -1px 0 0 var(--mi-gold) !important;
  border-radius: 2px !important;
  padding: 0 2px;
  font-weight: 600;
}

/* ---------------------------------------------------------------------------
   MONO IS FOR NUMERALS. These classes carry `.mono` from the renderer but hold
   prose, and monospace prose at 15px overflows its panel and clips mid-word —
   Stock Lab's leadership card showed "Senior VP & Chief Operating Offi".

   The class name is not a reliable signal of content: `.stocklab-row-value`
   holds "1.65%" on one row and a job title on the next, and `.flc-meta` holds
   "41 analysts · as of 2026-08-11". Only the CONTENT knows, and CSS cannot
   read it, so this is an explicit list of the ones measured as prose-bearing.

   NOT excluded: `.des-seg-origin` holds "us-gaap:RevenueFromContract…", which
   is an XBRL tag and belongs in mono.

   CEILING: a new prose-bearing `.mono` class will need adding here. The audit
   in work/audit.py has a monoprose check that names any that appear.
   --------------------------------------------------------------------------- */
#app-root [class][class]:is(.stocklab-row-value, .flc-meta, .shub-figure-delta,
                            .hpg-opt-note, .des-fact-figure, .pk-badge,
                            .stocklab-subs-name, .stocklab-peer-name) {
  font-family: var(--mi-body) !important;
  font-variant-numeric: tabular-nums lining-nums;
}

/* The wrapper introduced in renderCfScreen so `.cf-main` keeps exactly the two
   grid children its template declares. It owns the scroll the explorer used to
   own, so a long filings list still scrolls inside the pane. */
#app-root [class][class].cf-body {
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* ---------------------------------------------------------------------------
   MONO ON PROSE, second list. work/audit.py flagged these across the sweep:
   feature_dashboards titles and badges, the telemetry-map layer reasons, the
   feed status line. All carry `.mono` from their renderer and all hold
   sentences.

   `.des-seg-origin` stays in mono deliberately — "us-gaap:RevenueFrom…" is an
   XBRL tag, which is exactly what a monospace face is for.
   --------------------------------------------------------------------------- */
#app-root [class][class]:is(.fd-panel-title, .fd-mast-badge, .fd-mast-mode,
                            .fd-signal-value, .fd-engine-route, .fd-gauge-label,
                            .tmap-layer-reason, .feed-status-text,
                            .cf-empty, .source-warning) {
  font-family: var(--mi-body) !important;
  font-variant-numeric: tabular-nums lining-nums;
}

/* ---------------------------------------------------------------------------
   ANCHORS WITH NO COLOUR OF THEIR OWN.

   /screens renders every surface as an <a class="pk-card">. No sheet sets a
   colour on it, so in light mode Chrome painted its own visited-link purple —
   rgb(158, 158, 255) on paper, 2.27:1, across 82 elements. Dark mode hid it
   because the UA's dark-scheme link colour happens to be legible on black.

   `:where()` contributes ZERO specificity, so this is a true default: any rule
   in any sheet that actually states a link colour beats it without needing to
   out-specify an #id. A blanket `#page-root a { }` here would have flattened
   the nav and CTA colours that are deliberate.
   --------------------------------------------------------------------------- */
:where(#page-root a, #app-root a) { color: inherit; }
:where(#page-root a:visited, #app-root a:visited) { color: inherit; }


/* ---------------------------------------------------------------------------
   AN ANCHOR THAT WRAPS A CARD IS NOT A CONTROL.

   instrument.css carries a target-size rule:

       #app-root a[href]:not([class*="-inline"]), … {
         min-height: 24px; display: inline-flex;
         align-items: center; justify-content: center; gap: 6px;
       }

   It is right about buttons and chips and wrong about every anchor that wraps
   a STACK. `inline-flex` + `justify-content: center` turns a column of block
   children into one centred ROW, and at (1,2,1) it outranks the component's
   own `display: block` at (0,1,0) in the sheet that defines the component.

   MEASURED, on the live DOM:

     · /screens — 48 <a class="pk-card">, every one of them a title, a blurb
       and a path laid out side by side in a 371px box instead of stacked.
       That is the whole page directory.
     · /  — the landing stat strip: the figure, its name and its note in three
       cramped columns, the name wrapping to four lines at 63px wide.
     · /  — the live watchlist board: .lndBoardRow is declared
       `display: grid` with four named columns, and was flattened to a flex
       row, so TWO SYMBOLS RENDERED ON ONE LINE.

   This is the third time this rule has caught something it was not written
   for — instrument.css itself documents the sidebar rail (which shifted from
   29px/left to 24px/centred) and the Related Intelligence chips. Both were
   fixed the same way, and this follows it: name the anchor with `a[href]` and
   a class, scoring (1,3,1), which beats (1,2,1) outright regardless of source
   order. A bare `.pk-card` cannot win no matter how late it is declared.

   Each component is restored to what its OWN sheet asks for — block for the
   stacks, grid for the board row — rather than to a single blanket value.
   --------------------------------------------------------------------------- */
#page-root a[href].pk-card,
#app-root a[href].pk-card,
#page-root a[href].lndFigCell,
#app-root a[href].lndFigCell,
#page-root a[href].lndWsCard,
#app-root a[href].lndWsCard {
  display: block;
  justify-content: initial;
  align-items: initial;
}

#page-root a[href].lndBoardRow,
#app-root a[href].lndBoardRow {
  /* landing.css: minmax(0,74px) minmax(0,1fr) minmax(0,108px) minmax(0,92px) */
  display: grid;
  justify-content: initial;
}


/* ===========================================================================
   THE CREST, RESIZED — and this rule is at the bottom of the file on purpose.

   The first attempt at this sat next to the other chrome cuts, ~380 lines
   above the original `#app-root [class][class].mi-crest` declaration. Both
   score (1,3,0), so the later one won and the band stayed exactly 90px while
   the CSS looked correct. Re-measuring is the only reason that was caught.

   90px was a hero band on a screen whose job is a table, and it was the
   single largest item in a 292px chrome stack. At 44-58px it still reads as a
   year of price, still names Yahoo and its as-of date, and is no longer the
   biggest thing above the data.
   =========================================================================== */
#app-root [class][class][class].mi-crest {
  height: clamp(44px, 5.2vh, 58px);
  margin: 6px 22px 2px;
}

/* The title bar: 64px for one line of title plus a code chip. The line-height
   and padding were sized for a two-line title that no screen has. */
#app-root [class][class].viewport-header {
  padding-top: 10px;
  padding-bottom: 10px;
  min-height: 0;
}

/* ===========================================================================
   SPOTLIGHT — the reveal layer's own paint. Driven by frontend/spotlight.js.

   Dark and light are the SAME structure with the ground and ink swapped, as
   asked. The brief's palette was a photograph; ours is the interface's own —
   the revealed field is the data under the surface, so it is drawn in the
   accent on the panel ground rather than in a second image.

   `opacity: 0` here is safe and is the one place in this build where it is:
   this layer is ADDITIVE decoration over a hero that is fully legible without
   it. Nothing readable is behind the mask. See the header of spotlight.js.
   =========================================================================== */
.mi-spot-layer {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  opacity: 0;
  transition: opacity 260ms cubic-bezier(0.16, 1, 0.3, 1);
  overflow: hidden;
  border-radius: 12px;
  background:
    linear-gradient(180deg, rgba(225, 173, 102, 0.10), rgba(79, 178, 134, 0.07)),
    var(--mi-panel-bg, #0d0d10);
}

.mi-spot-grid {
  position: absolute;
  inset: -8%;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(132px, 1fr));
  gap: 10px 18px;
  align-content: start;
  padding: 18px 22px;
  transform: rotate(-4deg) scale(1.14);
  font-family: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px;
  letter-spacing: 0.02em;
}

.mi-spot-cell {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
  border-left: 1px solid rgba(var(--i-accent-rgb, 225, 173, 102), 0.32);
  padding-left: 8px;
  white-space: nowrap;
  overflow: hidden;
}

.mi-spot-cell b {
  font-weight: 600;
  color: var(--i-orchid, #E1AD66);
}

.mi-spot-cell i {
  font-style: normal;
  color: var(--i-ink-2, #b9b4ab);
  text-overflow: ellipsis;
  overflow: hidden;
}

/* LIGHT MODE — the same layer, the colours swapped, as asked. Paper ground,
   deep ink, the light accent. Nothing about the mechanic changes. */
:root[data-theme="light"] .mi-spot-layer {
  background:
    linear-gradient(180deg, rgba(138, 97, 23, 0.10), rgba(0, 115, 57, 0.07)),
    var(--mi-panel-bg, #FBF9F4);
}
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .mi-spot-layer {
    background:
      linear-gradient(180deg, rgba(138, 97, 23, 0.10), rgba(0, 115, 57, 0.07)),
      var(--mi-panel-bg, #FBF9F4);
  }
}

@media (prefers-reduced-motion: reduce) {
  /* spotlight.js does not install under reduced motion; this is the belt for
     a reader who changes the setting with the page already open. */
  .mi-spot-layer { display: none; }
}

/* ===========================================================================
   DENSITY — the terminal reads as a terminal.

   Reported: "cluttered, difficult to read, the font sucks, reduce font size,
   make it so there is more text". Those pull in the same direction once you
   separate SIZE from SPACE. The screens were not too wordy — they were too
   loose. Every figure carried a 13px body line, a 1.55 line-height and 16px of
   padding, so a table that should show twenty rows showed nine.

   THE UI PACK'S OWN NUMBERS, applied rather than approximated:

       body        Barlow 300-400, 14px baseline     -> 12.5px here, see below
       figures     IBM Plex Mono, tabular-nums       -> enforced, was optional
       display     Instrument Serif italic, -3px     -> already correct
       grid        8px base, dense gap 6px           -> was 10-16px everywhere
       radius      9 / 6 / 4 / 2                     -> was 9 / 24 in places
       elevation   borders and opacity, NO shadows   -> shadows removed

   WHY 12.5 AND NOT THE PACK'S 14. The pack's 14px baseline is for the landing
   page, which is a document read at arm's length. A terminal screen is read
   leaning in, and its own hierarchy needs three legible steps BELOW the body
   size for labels, provenance and units. Anchoring at 14 pushes the bottom
   step to 9px, which is where legibility actually breaks. 12.5 keeps the
   smallest step at 10.5px, which measures above 4.5:1 on this ground.

   Nothing here changes a colour or a component. It is size, spacing and the
   figure font.
   =========================================================================== */

#app-root {
  /* One anchor. Everything below derives, so the scale cannot drift apart. */
  --i-t-body: calc(12.5px * var(--i-t-scale));   /* item 373 */
  --i-t-sm: calc(11.5px * var(--i-t-scale));   /* item 373 */
  --i-t-xs: calc(10.5px * var(--i-t-scale));   /* item 373 */
  --i-t-md: calc(14px * var(--i-t-scale));   /* item 373 */
  --i-t-lg: calc(17px * var(--i-t-scale));   /* item 373 */
  --i-t-xl: calc(22px * var(--i-t-scale));   /* item 373 */
  /* The hero figure stays large — one confident number per screen is the
     point of the scale, and shrinking it is what makes a terminal look like a
     spreadsheet. */
  --i-t-hero: calc(34px * var(--i-t-scale));   /* item 373 */
}

/* Line-height is where the density actually comes from. 1.55 on a data row is
   a paragraph setting; 1.35 is a row setting. Prose keeps its own leading. */
#app-root [class][class]:is(td, th, li, dd, dt, .sgkFigValue, [class*="-row"],
                            [class*="-cell"], [class*="Row"], [class*="Cell"]) {
  line-height: 1.35;
}

#app-root p,
#app-root [class][class]:is([class*="-why"], [class*="-note"], [class*="-lede"]) {
  line-height: 1.5;
}

/* Padding, on the 8px grid the pack specifies. `-panel` and `-card` keep 16;
   rows and cells drop to 6-8, which is where the twenty rows come from. */
#app-root [class][class]:is(td, th) { padding: 5px 10px 5px 0; }

#app-root [class][class]:is([class*="-row"], [class*="Row"]):not([class*="-rows"]) {
  padding-top: 6px;
  padding-bottom: 6px;
}

/* TABULAR NUMERALS ON EVERY FIGURE, not just the ones that remembered to ask.
   A column of proportional digits does not line up, and a terminal that does
   not line up its digits is the single loudest "this is not a real terminal"
   signal there is. */
#app-root [class][class]:is([class*="value"], [class*="Value"], [class*="-fig"],
                            [class*="Fig"], [class*="-num"], [class*="-pct"],
                            [class*="-price"], [class*="-metric"], .mono, td) {
  font-variant-numeric: tabular-nums lining-nums;
  font-feature-settings: "tnum" 1, "lnum" 1;
}

/* The pack: "No shadows; elevation via borders and opacity only." Three sheets
   had drop shadows on panels, which on a pure-black ground reads as a smudge
   rather than as height. Floating layers keep theirs — a popover with no
   shadow merges into the page, which the pack's own hover card acknowledges. */
#app-root [class][class]:is([class$="-panel"], [class*="-panel "], .sgkPanel,
                            [class$="-card"], [class*="-card "]) {
  box-shadow: none !important;
}

/* Radius, to the pack's ladder. 24px on a data panel is a marketing radius. */
#app-root [class][class]:is([class$="-panel"], [class*="-panel "], .sgkPanel) {
  border-radius: 6px !important;
}
#app-root [class][class]:is([class*="-chip"], [class*="-pill"], [class*="-toggle"]) {
  border-radius: 9px !important;
}

/* Section gaps: 16 major, 10 medium, 6 dense. Was a uniform 16-22. */
#app-root [class][class]:is([class*="-grid"], [class*="Grid"]) { gap: 10px; }
#app-root [class][class]:is([class*="-rows"], [class*="-list"], [class*="List"]) { gap: 6px; }

/* ===========================================================================
   CANDLE TAPE — the landing hero background. Drawn by frontend/tape.js from
   real daily OHLC; this is only where it sits and how hard it presses.

   Behind everything, and quiet. The pack's own opacities are per-band and are
   set on the SVG groups; what is here is the layer's placement and the
   provenance line, which is the part that must never be styled away.
   =========================================================================== */
.mi-tape {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
  border-radius: 12px;
  /* The tape is atmosphere. At full strength it competes with the headline,
     which is the mistake the thing it replaced made. */
  opacity: 0.42;
  -webkit-mask-image: radial-gradient(120% 90% at 50% 45%, #000 42%, transparent 78%);
  mask-image: radial-gradient(120% 90% at 50% 45%, #000 42%, transparent 78%);
}

.mi-tape-svg { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }

/* NOT DECORATION. A tape of real candles that does not name its source cannot
   be told apart from a tape of invented ones, and the headline directly above
   it promises that every number names its source. If this line is ever hidden,
   the tape has to go with it. */
.mi-tape-stamp {
  position: absolute;
  left: 0;
  bottom: 6px;
  margin: 0;
  font-family: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 9.5px;
  letter-spacing: 0.04em;
  color: var(--i-ink-3, #8d8781);
  opacity: 0.72;
}

/* THE READOUT. Point at any candle and it names the session and the four
   prices, from the same fetched bar the candle was drawn from.

   Deliberately NOT a tooltip bubble: no arrow, no shadow, no pop. It is a
   quiet monospace strip that behaves like the rest of the terminal's numbers,
   which is the point being made — the decoration on this page is data, and
   pointing at it proves that rather than asserting it. */
.mi-tape-read {
  position: absolute;
  left: 0;
  top: 0;
  z-index: 3;
  pointer-events: none;
  white-space: nowrap;
  padding: 5px 10px;
  border: 1px solid var(--i-hair, rgba(255, 255, 255, 0.14));
  border-radius: 6px;
  background: var(--i-surface-2, rgba(12, 12, 12, 0.94));
  color: var(--i-ink-2, #cfcac1);
  font-family: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 10.5px;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
  /* No transition on transform: the box IS positioned by transform, and easing
     it makes the readout lag the cursor by a visible beat. */
}
.mi-tape-read[hidden] { display: none; }
.mi-tape-read[data-dir="up"] { border-color: rgba(79, 178, 134, 0.5); }
.mi-tape-read[data-dir="down"] { border-color: rgba(220, 106, 98, 0.5); }

@media (prefers-reduced-motion: reduce) {
  /* Kept, not removed — at rest it is a still chart, and a reader who asked
     for stillness asked for no MOVEMENT. tape.js does not start the loop.
     The readout still works: it is a response to a gesture, not an animation. */
  .mi-tape { opacity: 0.3; }
}

/* THE LIGHT TAPE IS DARKER, NOT FAINTER, which is the opposite of the instinct
   and is what "switch the colours" actually means on a paper ground.

   The candles already carry the right hue without any work here: tape.js paints
   with `var(--i-bull)` and `var(--i-bear)`, and instrument.css maps those onto
   the --lt-* pair under this exact selector, so the light theme's darker,
   AA-tested green and red arrive on their own. What did not follow is the
   WEIGHT. Held at 0.3 those strokes sat at roughly a tenth of the contrast the
   dark tape has against black, which is a hero background that has effectively
   been deleted — the "bland" reading, and correctly so.

   0.5, and `multiply` so the candles behave like ink on the sheet rather than
   like a translucent film laid over it. The mask is widened because a paper
   ground shows a vignette edge that black hides. */
:root[data-theme="light"] .mi-tape {
  opacity: 0.5;
  mix-blend-mode: multiply;
  -webkit-mask-image: radial-gradient(130% 96% at 50% 45%, #000 52%, transparent 86%);
  mask-image: radial-gradient(130% 96% at 50% 45%, #000 52%, transparent 86%);
}
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .mi-tape {
    opacity: 0.5;
    mix-blend-mode: multiply;
    -webkit-mask-image: radial-gradient(130% 96% at 50% 45%, #000 52%, transparent 86%);
    mask-image: radial-gradient(130% 96% at 50% 45%, #000 52%, transparent 86%);
  }
}

/* ===========================================================================
   THE SUGGESTION CARD  (frontend/nudge.js)

   Bottom-LEFT, deliberately. The right edge of the terminal is where the
   status bar's live figures and the toast stack already live, and a
   suggestion has no business competing with either.

   It is a card, not a modal: nothing behind it is blocked, nothing is dimmed,
   and it takes no focus. The only thing it interrupts is empty space.
   =========================================================================== */
.mi-nudge {
  position: fixed;
  left: 16px;
  bottom: 46px;               /* clear of the status bar */
  z-index: 60;
  width: min(300px, calc(100vw - 32px));
  padding: 12px 30px 12px 13px;
  border: 1px solid var(--i-hair-strong, rgba(255, 255, 255, 0.18));
  border-left: 2px solid rgba(var(--i-accent-rgb, 225, 173, 102), 0.85);
  border-radius: 8px;
  background: var(--i-surface-2, #0d0d0d);
  /* The pack: "No shadows; elevation via borders and opacity only." A card
     that floats over the interface is the one place the temptation is
     strongest, and it is still the wrong answer on a black ground. */
  box-shadow: none;
}

.mi-nudge-eyebrow {
  margin: 0 0 6px;
  font-size: 9px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--i-ink-4, #7d7770);
}

.mi-nudge-code {
  display: inline-block;
  margin: 0 0 5px;
  font-family: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 15px;
  letter-spacing: 0.06em;
  color: var(--i-accent, #e1ad66);
  text-decoration: none;
  border-bottom: 1px solid transparent;
}
.mi-nudge-code:hover,
.mi-nudge-code:focus-visible { border-bottom-color: currentColor; }

.mi-nudge-why {
  margin: 0 0 5px;
  font-size: 11.5px;
  line-height: 1.4;
  color: var(--i-ink-2, #cfcac1);
}

/* THE REASON, and it is styled to be READ rather than to be skipped. It is
   what makes this a suggestion instead of an advertisement, and it is the
   reader's own answer quoted back — italic because it is a quotation. */
.mi-nudge-because {
  margin: 0;
  font-size: 10.5px;
  line-height: 1.35;
  font-style: italic;
  color: var(--i-ink-3, #8d8781);
}

.mi-nudge-close {
  position: absolute;
  top: 5px;
  right: 5px;
  width: 22px;
  height: 22px;
  padding: 0;
  border: 0;
  border-radius: 4px;
  background: transparent;
  color: var(--i-ink-4, #7d7770);
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
}
.mi-nudge-close:hover { color: var(--i-ink-1, #e9e5dd); }

@media (max-width: 720px) {
  /* On a narrow viewport it goes full width at the bottom rather than
     hovering over the content column. */
  .mi-nudge { left: 12px; right: 12px; width: auto; bottom: 12px; }
}

/* ===========================================================================
   FORM FIELDS IN LIGHT MODE

   obsidian_orchid.css gives every input, select, textarea and `*-field` in the
   product `background: rgba(0, 0, 0, 0.35) !important`. On a black ground that
   is a recessed well and exactly right. On paper it is a grey hole, and it was
   the last contrast failure standing: the sidebar's `[ ]` and `<GO>` glyphs are
   drawn in --i-amber, which clears 5.25:1 against the light sidebar and only
   3.67:1 against a field darkened 35% toward black.

   Fixing the glyph colour would have treated the symptom on one screen. The
   scrim is the cause and it is on EVERY field in the app, so light mode was
   showing dark wells throughout — a thing a reader notices long before a
   contrast checker does.

   Same idea inverted: on paper a field recesses by going slightly darker than
   the surface it sits in, not by going black. `!important` is required only
   because the rule being corrected uses it.
   =========================================================================== */
:root[data-theme="light"] #app-root input,
:root[data-theme="light"] #app-root select,
:root[data-theme="light"] #app-root textarea,
:root[data-theme="light"] #app-root [class*="-input"],
:root[data-theme="light"] #app-root [class*="-search"],
:root[data-theme="light"] #app-root [class*="-field"] {
  background: rgba(20, 18, 14, 0.045) !important;
  border-color: var(--i-hair-strong) !important;
  color: var(--i-ink-1) !important;
}

@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) #app-root input,
  :root:not([data-theme="dark"]) #app-root select,
  :root:not([data-theme="dark"]) #app-root textarea,
  :root:not([data-theme="dark"]) #app-root [class*="-input"],
  :root:not([data-theme="dark"]) #app-root [class*="-search"],
  :root:not([data-theme="dark"]) #app-root [class*="-field"] {
    background: rgba(20, 18, 14, 0.045) !important;
    border-color: var(--i-hair-strong) !important;
    color: var(--i-ink-1) !important;
  }
}

/* ===========================================================================
   THE SCREEN-INTEL BLOCK — measured overlap, and the bulk that caused it

   Reported as "why is all the text overlayed and shit, why is it unreadable".
   Measured on PORT: `.si-head` is a grid item whose track resolved to 170px
   while it contained 373px of content, with `overflow: visible`. Two hundred
   pixels of prose painted straight over the position ledger, the compare strip
   and the AI panel — four blocks of text on top of each other.

   `.portfolio-grid-wrap` had the same disease from the other end: 0px tall,
   270px of content.

   TWO CHANGES, AND THE ORDER MATTERS.

   1. IT CAN NEVER SPILL AGAIN. `min-height: 0` plus `overflow: auto` means a
      block that outgrows its track scrolls inside itself. That is the safety
      net, not the fix — a reader should not have to scroll a 170px box.

   2. SO IT IS MADE TO FIT. `si-scopeyes` and `si-scopeno` are the two prose
      paragraphs that explain what the screen measures and what it excludes —
      on PORT, "Positions held in the local ledger, priced live, with cost
      basis and unrealised P&L" and "Not a brokerage connection. Nothing here
      is a recommendation...". Worth saying once; not worth 120px on every
      visit to every screen. They collapse to a `title` tooltip on the domain
      tag, which keeps the claim available without spending the height.

   The verdict, the figures, the change strip and the compare row all stay.
   =========================================================================== */
#app-root [class][class].si-head,
#app-root [class][class].si-ai {
  min-height: 0;
  overflow: auto;
  overscroll-behavior: contain;
}

#app-root [class][class].si-scopeyes,
#app-root [class][class].si-scopeno {
  display: none;
}

/* The scope tag carries them now — it is the row that names the domain, and it
   is already the thing a reader looks at to know what screen they are on. */
#app-root [class][class].si-scope {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding-bottom: 4px;
}

/* Tightened to match the density pass: this block sits above the data on every
   screen, so every pixel it spends is a pixel of figures the reader loses. */
#app-root [class][class].si-verdicthead { margin-bottom: 4px; }
#app-root [class][class].si-lede { margin: 0 0 6px; line-height: 1.4; }
#app-root [class][class].si-figstrip { gap: 8px 18px; }

/* A grid or flex child that reports zero height while holding content is the
   same bug wearing the opposite sign. `.portfolio-grid-wrap` measured 0px
   tall around 270px of table. */
#app-root [class][class].portfolio-grid-wrap { min-height: 120px; }

/* ===========================================================================
   THE COLLAPSIBLE RAIL  (frontend/rail.js)

   280px of a 1440px window, permanently, showing a list the reader used once
   to get where they are. Closing it on arrival hands nineteen per cent of the
   screen back to the data — which is worth more to "minimise scrolling" than
   any font change, because width is what stops a wide table wrapping into a
   tall one.

   WIDTH, NOT display:none. The rail keeps its DOM and its focus order; it is
   simply zero pixels wide. `visibility: hidden` on the contents stops a
   keyboard from tabbing into a rail nobody can see, and `transition` on width
   alone means the collapse cannot be left half-painted by a stalled frame —
   the end state is a plain CSS value, not an animated one.
   =========================================================================== */
:root[data-rail="closed"] #singularity-sidebar,
:root[data-rail="closed"] .singularity-sidebar {
  width: 0 !important;
  min-width: 0 !important;
  padding-left: 0 !important;
  padding-right: 0 !important;
  border-right-width: 0 !important;
  overflow: hidden !important;
}
:root[data-rail="closed"] #singularity-sidebar > *,
:root[data-rail="closed"] .singularity-sidebar > * {
  visibility: hidden;
}

#app-root #singularity-sidebar,
#app-root .singularity-sidebar {
  transition: width 180ms cubic-bezier(0.16, 1, 0.3, 1),
              min-width 180ms cubic-bezier(0.16, 1, 0.3, 1);
}
@media (prefers-reduced-motion: reduce) {
  #app-root #singularity-sidebar,
  #app-root .singularity-sidebar { transition: none; }
}

/* THE REOPEN CONTROL STOOD HERE, AND IT WAS THE WORST BUG IN THE SHELL.

   `.mi-railtoggle` was a `position: fixed` button, and the rule that used to
   close this block read

       :root:not([data-rail="closed"]) .mi-railtoggle { left: 280px; }

   at (0,3,0), which beat static/plane.css's `.mi-railtoggle { left: 0 }` at
   (0,1,0) even though plane.css loads later. 280px was the rail's width when
   this was written. The rail is 232px now and the reader can drag it anywhere
   between 180 and 360, so NO fixed number could ever have been right —
   measured on SOVW, the control rendered at x=280, forty-eight pixels inside
   the content region, on top of the company name. It was reported as "the
   arrow still remains, and it's in the middle of my graphs".

   The lesson is the general one: a control positioned against the VIEWPORT
   cannot stay attached to a COLUMN whose width is a variable. The replacement
   is the rail's own right edge — `.sgRailDrag`, a child of the rail, click to
   collapse and drag to resize — so there is no second number to keep in sync
   with the first. See frontend/rail.js and static/plane.css §14.3.

   Nothing renders the element now. plane.css §14.3 also carries a
   `display: none` for it, so a stale cached copy of rail.js cannot put it
   back on the glass. */

/* ===========================================================================
   THE RELATED RAIL MOVES TO THE SIDE

   "For all features, make the related on the side." It was a full-width
   horizontal band above every screen — another row of chrome between the
   reader and the figures, on a terminal where the complaint is that there is
   too much of exactly that.

   The workspace is already a flex container with the rail as its first child,
   so `row-reverse` puts the rail on the RIGHT without touching a line of
   JavaScript or changing the DOM order that assistive tech reads. The screen
   takes the remaining width, which is the width it wanted.

   130px, because that is what the widest chip needs and nothing more. Below
   1100px it goes back to a horizontal band: a vertical rail on a narrow window
   is spending the one axis that is already short.
   =========================================================================== */
@media (min-width: 1100px) {
  #app-root .workspace:has(> .oo-related-rail) {
    flex-direction: row-reverse;
    align-items: stretch;
  }

  #app-root [class][class].oo-related-rail {
    flex: 0 0 130px;
    width: 130px;
    flex-direction: column;
    align-items: stretch;
    align-self: stretch;
    gap: 6px;
    overflow-y: auto;
    overscroll-behavior: contain;
  }

  #app-root [class][class].oo-related-caption {
    /* It reads as a column heading now, not as a label in front of a row. */
    padding-bottom: 4px;
    border-bottom: 1px solid var(--i-hair, rgba(255, 255, 255, 0.10));
  }

  #app-root [class][class].oo-related-chips {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    /* TOP, not centred. The rail is as tall as the screen and holds three
       chips; centring them parked the links halfway down an empty column,
       which reads as a rendering fault rather than a design. */
    justify-content: flex-start;
    gap: 4px;
    min-width: 0;
  }

  #app-root [class][class].oo-related-rail {
    justify-content: flex-start;
    align-content: flex-start;
  }

  /* The chips container was growing to fill the rail and centring its three
     links halfway down an otherwise empty column — measured at y=584 in a rail
     that starts at 214. It sizes to its content now and sits under the
     caption, which is where a list of links belongs. */
  #app-root [class][class][class].oo-related-chips {
    flex: 0 0 auto;
    align-content: flex-start;
  }

  #app-root [class][class].oo-related-chip {
    justify-content: flex-start;
    width: 100%;
    min-width: 0;
  }

  /* The screen keeps every pixel the rail is not using. */
  #app-root .workspace > :not(.oo-related-rail) {
    flex: 1 1 auto;
    min-width: 0;
  }
}

/* ===========================================================================
   ONE TYPEFACE, EVERYWHERE

   "for every feature change the font to what is used in landing page so it
   actually looks fucking good."

   `--oo-font-ui` already points at Barlow, and most of the interface follows
   it. Seven places do not, and they are the ones a reader notices because they
   sit in the middle of everything else: `tradingview.css` and
   `singularity_aesthetics.css` both force "IBM Plex Sans" with `!important`,
   and `flashlight_chart.css` declares a raw system stack on the component that
   draws the analyst forecast on EE and ANR.

   Overridden here rather than edited in place, for the reason the skin exists:
   this sheet loads last, so one block holds the decision and the sheets it
   corrects stay readable as the components they describe. The mono stack is
   untouched — a figure column is monospace on purpose, and that is what
   `--mi-fig` is for.
   =========================================================================== */
/* THIS RULE WAS BEATING THE DISPLAY RULE THIRTY LINES ABOVE IT, AND THE
   DISPLAY FACE HAS NEVER RENDERED ANYWHERE IN THIS BUILD BECAUSE OF IT.

   The heading rule is `#app-root [class][class]:is(h1, .terminal-title,
   .viewport-title)`. `:is()` takes the HIGHEST specificity among its arguments,
   so `:is(h1, .terminal-title, ...)` counts as a class — that selector is
   (1,3,0). This one carries three `:not(.class)` tests, and each `:not()` adds
   its argument's specificity, so it is (1,5,0). Both carry `!important`, both
   match every h1 on both shells, and the body face wins by two class points.

   Measured on the landing headline: `font-style: italic` and `font-weight: 400`
   from landing.css applied and `font-family` did not — one property losing out
   of three declared in the same block, which is the signature of a more
   specific rule setting exactly that property. `--font-heading` is defined in
   no stylesheet in this build, so the var() fallback was never the cause, and
   two rounds of raising specificity in landing.css could not have worked
   either: the winner is in the sheet that loads last.

   The fix belongs here rather than in another escalation downstream. Headings
   are excluded from the body override, so the heading rule above governs them
   as it was always meant to. Costs one class point and returns Instrument
   Serif to every h1 in the product.

   Read `CSS.getMatchedStylesForNode`-style output before writing another
   selector — hazard 7 says this in the inline-style case and the principle is
   the same: when your rule matches and loses, find what beat it. */
#app-root [class][class]:not(.mono):not([class*="mono"]):not([class*="Mono"]):not(h1):not(h2),
#page-root [class][class]:not(.mono):not([class*="mono"]):not([class*="Mono"]):not(h1):not(h2) {
  font-family: var(--mi-body) !important;
}

/* The components that declared their own stack, named so the override is
   auditable rather than a blanket that happens to catch them. */
#app-root .flc-root,
#app-root .flc-root *:not([class*="mono"]),
#app-root .tv-root,
#app-root .terminal-header,
#page-root .flc-root {
  font-family: var(--mi-body) !important;
}

/* Headings keep the landing page's serif — that pairing IS the landing page's
   look, and using only half of it is what made the terminal read as a
   different product. */
#app-root h1, #app-root h2, #app-root .screen-title, #app-root .panel-title,
#page-root h1, #page-root h2 {
  font-family: var(--mi-display) !important;
}

/* NOTHING ABOVE MAY REACH A FIGURE. Monospace with tabular numerals is the
   reason a column of numbers lines up, and the density pass earlier in this
   file enforces it; these rules exclude anything mono-named, and this restates
   it for the classes that carry the figure role without the word in them. */
#app-root [class][class]:is(.sgkFigValue, .so-fig-value, .hpg-cell, .ochain-cell,
                            [class*="-fig-value"], [class*="FigValue"], .pk-stat-value),
#app-root [class][class][class].mono {
  font-family: var(--mi-fig) !important;
  font-variant-numeric: tabular-nums lining-nums !important;
}

/* ==========================================================================
   THE LIVE STATUS PILL (answer 316b)

   pages.css declares its border and radius and both came back 0px: the §3
   purge is `border-width: 0 !important` at (1,2,0) and pages.css loads
   BEFORE this file, so it could never have won. Restored here at (1,3,0),
   which is the same fix §4b applies to the landing page's dividers and the
   only one that works from a sheet this file loads after.

   A pill with no edge is three words floating in the masthead — the border
   IS the component, the same argument the policy pages' tags won on.
   ========================================================================== */
#page-root [class][class].pkStatus {
  border: 1px solid var(--mi-hair) !important;
  border-radius: 999px !important;
}

#page-root [class][class].pkStatus[data-state="up"] {
  border-color: rgba(79, 178, 134, 0.34) !important;
}

#page-root [class][class].pkStatus[data-state="down"] {
  border-color: var(--i-error, var(--i-bear)) !important;
}
