/* =============================================================================
   PAPER CONSOLE — the light reading of /newshub/, used by
   /newshub/indexnews.html
   =============================================================================

   The console is a dark document: ~2000 inline utility classes, 112 KB of its
   own <style>, and a palette that assumes a black ground throughout. This sheet
   is the whole of the difference between it and the news hub. It is loaded last
   and scoped to html[data-paper], which means two things worth stating plainly:

     - the console's own rules are never edited, so nothing here can regress the
       dark edition, and
     - indexnews.html can be regenerated from newshub/index.html at any time
       (mknewshub.py) without re-doing any of this.

   Palette is the site's existing paper palette, lifted from assets/css/site.css
   rather than invented, so the news hub reads as the same publication as the
   paper homepage. The contrast reasoning recorded there applies here too: the
   secondary ink sits at .64 rather than .55 because .55 measures 3.6:1 on white
   and most of this page is small type.

   THE ONE THING TO UNDERSTAND before editing: on a dark ground the console
   builds every surface out of *white at low opacity* — `bg-white/5` is a 5%
   lift off black, `border-white/10` a faint edge. Invert the page and those
   become white-on-white, i.e. nothing at all. They are not recoloured here so
   much as re-polarised: white washes become ink washes at comparable weight.
   ========================================================================== */

html[data-paper] {
    --p-paper:     #ffffff;
    --p-ink:       #1E262B;
    --p-ink-77:    rgba(30, 38, 43, .77);
    --p-ink-64:    rgba(30, 38, 43, .64);   /* body-text floor: 4.7:1 */
    --p-muted:     #717171;                 /* 4.6:1 — #878787 was 3.4:1 */
    --p-line:      rgba(30, 38, 43, .12);
    --p-line-soft: rgba(30, 38, 43, .07);
    --p-wash:      rgba(30, 38, 43, .035);  /* the bg-white/5 equivalent */
    --p-wash-2:    rgba(30, 38, 43, .06);

    /* The brand orange survives as a FILL and dies as TEXT. #ff8800 measures
       about 2.2:1 on white — it is not a colour you can set type in. These two
       are the same demotion the paper homepage and the pills site already make:
       a burnt orange for rules and small marks, a deeper one for type. */
    --p-accent:      #C2410C;   /* rules, borders, live dots        */
    --p-accent-type: #9A3412;   /* anything that is actually read   */

    /* ...but the accent is not always orange. The CONTROL panel ships 22 artist
       themes, and with SAVE SETTINGS off — which is the default — every reload
       rolls a new one into --primary-orange. On black they all work. On white,
       LSD RAINBOW's #ff00aa and NEON's #f472b6 are around 3:1 and GRAYSCALE's
       #d4d4d8 is 1.4:1, so a fixed pair of burnt oranges would be a lie the
       moment the roll came up pink.
       These two derive from whatever the live accent is, mixing it toward ink
       until it clears the floor. Hue survives — you can still tell which theme
       you rolled — and legibility stops depending on the roll. Fills are left
       alone: a neon fill on paper is fine, it is neon *type* that is not. */
    --p-accent-live: color-mix(in srgb, var(--primary-orange, #ff8800) 55%, #23150A);
    --p-accent-rule: color-mix(in srgb, var(--primary-orange, #ff8800) 72%, #3A1F0A);

    background: var(--p-paper);
    color-scheme: light;
}

/* ====================================================================== TYPE
   The console is set in Inter with Space Grotesk and Orbitron for display, and
   it leans hard on weight: 109 font-bold, 72 font-semibold, 15 font-black in the
   markup alone. That is the right voice on black, where heavy type is what stops
   a headline dissolving into the ground. On paper it reads as shouting, and it
   is not the voice of the rest of the light edition.

   So the hub is reset to the paper edition's own face — DM Sans, the same
   self-hosted variable file /index.html and the mem pages use, at the same
   weights: 200 for display, 300 for reading.

   WEIGHT IS ASSIGNED BY SIZE, NOT BY THE UTILITY. `font-bold` sits on a 3rem
   hero word and on a 10px desk label in this document, and 200 is elegant at the
   first and illegible at the second. Mapping the utility alone would have made
   the small type worse than it started. So every weight utility lands on a
   readable default and the *size* classes then thin the large end down. Below
   ~12px nothing goes under 400 — this page is full of 10px labels and hairline
   type on white is the one thing paper punishes harder than black does.
   ========================================================================== */

/* The same two files site.css loads, declared again because this sheet is the
   only stylesheet the hub shares with the light edition. Variable, 200–700, so
   one file covers the whole range asked for below. */
@font-face {
    font-family: 'DM Sans';
    font-style: normal;
    font-weight: 200 700;
    font-display: swap;
    src: url('../fonts/dm-sans-latin.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: 'DM Sans';
    font-style: normal;
    font-weight: 200 700;
    font-display: swap;
    src: url('../fonts/dm-sans-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF,
                   U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

html[data-paper],
html[data-paper] body,
html[data-paper] button,
html[data-paper] input,
html[data-paper] select,
html[data-paper] textarea {
    font-family: 'DM Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
                 Helvetica, Arial, sans-serif !important;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}
/* Space Grotesk and Orbitron carried the display and the clock. Both go; the
   clock and the phone number keep a monospace so their digits stay on the same
   grid as they tick, which is the only reason they were not Inter already. */
html[data-paper] .font-display,
html[data-paper] .featured-chip-name,
html[data-paper] .domain-name,
html[data-paper] .section-header,
html[data-paper] .section-header-modern {
    font-family: 'DM Sans', -apple-system, BlinkMacSystemFont, sans-serif !important;
}
html[data-paper] .font-phone,
html[data-paper] #nav-clock .clk-face,
html[data-paper] #nav-clock .clk-zone,
html[data-paper] .featured-chip-cat,
html[data-paper] .font-mono,
html[data-paper] .tabular-nums {
    font-family: ui-monospace, SFMono-Regular, Menlo, 'DM Sans', monospace !important;
}

/* --- the base is 400, and only the large end is thinned -------------------
   This is the way round site.css does it: it sets no font-weight on body at all,
   so everything inherits DM Sans normal, and 200/300 appear only on .d1, .d3 and
   .lede — the display and the standfirst.
   Doing it the other way (body at 200/300, then propping the small type back up)
   was the first attempt and it leaks: eight elements came out at 300 and 8px,
   including several with no class of their own to hook, because they inherit
   from a generic flex wrapper. Inheriting a legible weight and thinning
   deliberately cannot leak in that direction — anything unstyled is already
   safe, and the thin type is exactly the type someone chose to make thin. */
html[data-paper] .font-black,
html[data-paper] .font-extrabold,
html[data-paper] .font-bold,
html[data-paper] .font-semibold,
html[data-paper] .font-medium,
html[data-paper] .font-normal   { font-weight: 400 !important; }

/* --- then size thins the large end ---------------------------------------- */
/* Display. 200 is the paper homepage's .d1 weight, and the tight tracking is
   its -.035em: at this size DM Sans needs pulling in or the words drift apart. */
html[data-paper] .text-8xl,
html[data-paper] .text-7xl,
html[data-paper] .text-6xl,
html[data-paper] .text-5xl,
html[data-paper] .text-4xl,
html[data-paper] .section-header,
html[data-paper] .section-header-modern,
html[data-paper] .holo-text      { font-weight: 200 !important; letter-spacing: -.035em !important; }
html[data-paper] .text-3xl,
html[data-paper] .text-2xl       { font-weight: 300 !important; letter-spacing: -.028em !important; }
html[data-paper] .text-xl,
html[data-paper] .text-lg        { font-weight: 300 !important; letter-spacing: -.018em !important; }
/* Reading sizes and the standfirst — site.css's .lede is 300, and this is the
   same job. Everything below these sizes keeps the inherited 400. */
html[data-paper] body            { font-weight: 400; line-height: 1.62; }
html[data-paper] .text-base,
html[data-paper] .text-sm,
html[data-paper] .leading-relaxed { font-weight: 300 !important; }

/* Inheritance cuts both ways: a .text-xs label inside a .text-sm block changes
   its size and inherits the parent's 300, which is how "STORIES LOADED" came out
   at 12px/300. The small sizes therefore re-assert 400 rather than trusting what
   they are nested in. */
html[data-paper] .text-xs,
html[data-paper] [class*="text-[8"],
html[data-paper] [class*="text-[9"],
html[data-paper] [class*="text-[10"],
html[data-paper] [class*="text-[11"],
html[data-paper] [class*="text-[12"] { font-weight: 400 !important; }

/* Small caps: letter-spacing thins a face further, so a tracked 10px label at
   300 would be a rumour. They inherit 400 from body, and the ones the console
   tracks hardest get 500 back. No floor rule is needed for anything else —
   inheritance is the floor. */
html[data-paper] .snap-eyebrow,
html[data-paper] .contact-label,
html[data-paper] .uppercase.text-xs,
html[data-paper] .uppercase[class*="tracking-["] { font-weight: 500 !important; }
/* Tracking the console set deliberately on small caps stays where it was — the
   display rules above must not reach down here and pull it in. */
html[data-paper] [class*="tracking-["],
html[data-paper] .tracking-wide,
html[data-paper] .tracking-wider,
html[data-paper] .tracking-widest { letter-spacing: revert-layer; }

/* --- the console's own heavy rules ---------------------------------------- */
html[data-paper] .section-header-modern { font-weight: 200 !important; }
html[data-paper] .font-display          { font-weight: 300 !important; }
html[data-paper] .font-phone,
html[data-paper] #nav-clock .clk-face,
html[data-paper] #nav-clock .clk-mer,
html[data-paper] #nav-clock .clk-zone,
html[data-paper] #nav-menu-count b,
html[data-paper] .contact-submit,
html[data-paper] .featured-chip-name,
html[data-paper] .featured-refresh,
html[data-paper] #panel-content .orb-btn { font-weight: 400 !important; }
/* The CONTROL deck's labels are 700 at 10–12px and mostly carry no class of
   their own, so they are reached through the panel rather than individually.
   The deck's own tab — the word CONTROL — is an unclassed div with the weight
   set inline, hence the !important and the reach down from the panel id: it was
   the single heaviest piece of type left on a page whose headlines are 200. */
html[data-paper] #panel-content,
html[data-paper] #panel-content *   { font-weight: 400; }
html[data-paper] #modern-control-panel div { font-weight: 500 !important; }

/* ================================================== THE CONTROL DECK =======
   Collapsed, this is the one thing left on the page that was still a black pill
   — and it is pinned to the bottom of every screen, so it was the most visible
   thing that had not been converted.

   Its surfaces are written inline on unclassed divs (background:#111113 on the
   tab, border:1px solid #333 on the dividers), which is why these reach in
   structurally by position rather than by name, and why they all carry
   !important: an inline style is otherwise the last word.
   ========================================================================== */

/* The tab itself — the bar carrying the word CONTROL and the ▾. It is the first
   child div of the panel; :first-of-type rather than a class because it has
   none, and nth-child would break the moment a wrapper is added. */
html[data-paper] #modern-control-panel > div:first-of-type {
    background: rgba(255, 255, 255, .9) !important;
    border-bottom-color: var(--p-line) !important;
}
html[data-paper] #modern-control-panel > div:first-of-type > div {
    color: var(--p-accent-live) !important;
}
/* The 2px accent ring around the whole panel is the brand mark of the control;
   it keeps the accent, inked so it does not glare on white, and the halo that
   GLOW INTENSITY drives is cut right back — a 40px coloured bloom on paper is
   a smudge rather than a light. */
html[data-paper] #modern-control-panel {
    border-color: var(--p-accent-rule) !important;
    background: rgba(255, 255, 255, .93) !important;
    box-shadow: 0 2px 10px rgba(30, 38, 43, .1),
                0 0 calc(14px * var(--glow-intensity, 1))
                color-mix(in srgb, var(--primary-orange-raw, #ff8800) 22%, transparent) !important;
}
html[data-paper] #panel-content { color: var(--p-ink) !important; }
/* The internal dividers, inline at #333. */
html[data-paper] #panel-content div[style*="#333"] {
    border-color: var(--p-line) !important;
}

/* --- the orb intensity slider (OFF / LOW / MED / HIGH) -------------------- */
/* A sunken dark track with a lit thumb. On paper it inverts to a raised light
   track: the inset shadow that read as "recessed" against black reads as grime
   against white, so it becomes a hairline instead. The thumb keeps the accent
   gradient — it is the one thing in the control that should be vivid, and it is
   what tells you which of the four is live. Raw accent, not inked: it is a fill
   with dark type on it, same rule as the hero button. */
html[data-paper] #panel-content .orb-seg,
html[data-paper] .orb-seg {
    background: rgba(30, 38, 43, .05) !important;
    border-color: var(--p-line) !important;
    box-shadow: inset 0 1px 1px rgba(30, 38, 43, .05) !important;
}
html[data-paper] #panel-content .orb-seg__thumb,
html[data-paper] .orb-seg__thumb {
    background: linear-gradient(180deg,
                color-mix(in srgb, var(--primary-orange-raw, #ff8800) 78%, #ffffff) 0%,
                var(--primary-orange-raw, #ff8800) 55%,
                color-mix(in srgb, var(--primary-orange-raw, #ff8800) 88%, #000000) 100%) !important;
    box-shadow: 0 1px 4px rgba(30, 38, 43, .18),
                inset 0 1px 0 rgba(255, 255, 255, .45) !important;
}
/* Unlit segments are ink on the light track; the lit one is dark on the accent
   fill, which is the same polarity it had on black. */
html[data-paper] #panel-content .orb-btn { color: var(--p-ink-64) !important; }
html[data-paper] #panel-content .orb-btn:hover { color: var(--p-ink) !important; }
html[data-paper] #panel-content .orb-btn.active { color: #1A0F00 !important; }
/* The pill row and the snapshot chips are set at 600 by the console at 8.5–9.5px.
   500 keeps them distinct from the prose around them without being the heaviest
   thing on a page whose headlines are 200. */
html[data-paper] .feed-pill,
html[data-paper] .feed-pill-count,
html[data-paper] .feed-grid-opt,
html[data-paper] .snap-pill,
html[data-paper] .snap-chip,
html[data-paper] .snap-btn        { font-weight: 500 !important; }

/* Inverted pills carry paper-white type on solid ink — those need a touch more
   body than 400 to hold at 10px against a dark fill. */
html[data-paper] .feed-pill[aria-pressed="true"],
html[data-paper] .feed-grid-opt[aria-pressed="true"],
html[data-paper] #panel-content .orb-btn.active,
html[data-paper] .premium-badge,
html[data-paper] button.bg-\[\#ff8800\] { font-weight: 500 !important; }

/* --- Font Awesome is not type, and weight is how it picks a FACE ----------
   This must be the last word on font-weight in this sheet.

   Font Awesome selects its face by weight, not by name: .fas/.fa-solid is
   "Font Awesome 6 Free" at 900 and .far/.fab are the same family at 400. The
   icons in this document carry size classes too — `class="fas fa-phone
   text-[10px]"` — so the small-size floor above was setting them to 400, which
   resolves to the *regular* face, which does not contain the solid glyphs. They
   rendered as tofu boxes: the phone in the navbar, the refresh, the arrow on
   "View All". Nothing reports this — the element is there, the contrast audit
   passes, and only looking at it against the dark console shows the difference.

   So the weights are handed straight back. Element+class for specificity, and
   last in the file so ordering cannot betray it either. */
html[data-paper] i.fas,  html[data-paper] i.fa-solid,
html[data-paper] .fas,   html[data-paper] .fa-solid   { font-weight: 900 !important; }
html[data-paper] i.far,  html[data-paper] i.fa-regular,
html[data-paper] i.fab,  html[data-paper] i.fa-brands,
html[data-paper] .far,   html[data-paper] .fa-regular,
html[data-paper] .fab,   html[data-paper] .fa-brands  { font-weight: 400 !important; }
/* And the family, in case a parent rule ever reaches them. */
html[data-paper] [class*="fa-"]::before { font-family: inherit; }

/* --------------------------------------------------------------- page ---- */
html[data-paper] body { background: var(--p-paper); color: var(--p-ink); }
html[data-paper] .lab-bg { background: var(--p-paper); }
/* body carries .text-white in the markup. */
html[data-paper] body.text-white { color: var(--p-ink); }

/* ------------------------------------------------------- the washes ------ */
/* The glassmorphism layer. Weights are matched by eye to the dark original's
   *contrast against its ground*, not by numeric equivalence: 5% white on black
   reads much stronger than 5% black on white, so the ink washes run lighter. */
html[data-paper] .bg-white\/5   { background-color: var(--p-wash) !important; }
html[data-paper] .bg-white\/10  { background-color: var(--p-wash-2) !important; }
html[data-paper] .bg-white\/90,
html[data-paper] .bg-white      { background-color: var(--p-paper) !important; }

html[data-paper] .border-white\/5   { border-color: var(--p-line-soft) !important; }
html[data-paper] .border-white\/10  { border-color: var(--p-line) !important; }
html[data-paper] .border-white\/15  { border-color: rgba(30, 38, 43, .16) !important; }
html[data-paper] .border-white\/20  { border-color: rgba(30, 38, 43, .2) !important; }
html[data-paper] .border-white\/60  { border-color: rgba(30, 38, 43, .45) !important; }

/* bg-black/N is used two different ways and they invert in opposite directions.
   As a PANEL (dropdowns, the nav sheet, sticky bars) it is a surface and must
   become paper. As a SCRIM behind a modal it is there to dim what is behind it,
   and dimming is still dimming on a light page — those keep a dark wash. The
   split is by opacity, which in this document happens to separate them cleanly:
   /70 and above are panels, below that are scrims. */
html[data-paper] .bg-black\/70,
html[data-paper] .bg-black\/90,
html[data-paper] .bg-black\/95  { background-color: rgba(255, 255, 255, .93) !important; }
html[data-paper] .bg-black\/30,
html[data-paper] .bg-black\/60  { background-color: rgba(30, 38, 43, .38) !important; }
html[data-paper] .bg-black      { background-color: var(--p-paper) !important; }

/* ------------------------------------------------- greyscale families ---- */
/* slate reads as "quiet ink" on the console. The scale inverts: the lighter the
   slate, the darker it has to become. */
html[data-paper] .text-white     { color: var(--p-ink) !important; }
html[data-paper] .text-slate-100 { color: var(--p-ink) !important; }
html[data-paper] .text-slate-200 { color: var(--p-ink) !important; }
html[data-paper] .text-slate-300 { color: var(--p-ink-77) !important; }
html[data-paper] .text-slate-400 { color: var(--p-ink-64) !important; }
html[data-paper] .text-slate-500 { color: var(--p-muted) !important; }
html[data-paper] .text-slate-600 { color: var(--p-muted) !important; }
html[data-paper] .text-slate-700 { color: var(--p-ink-64) !important; }
html[data-paper] .text-stone-300 { color: var(--p-ink-77) !important; }
html[data-paper] .text-black     { color: var(--p-ink) !important; }
html[data-paper] .placeholder-slate-500::placeholder { color: var(--p-muted) !important; }

html[data-paper] .bg-slate-800,
html[data-paper] .bg-slate-900,
html[data-paper] .bg-slate-950        { background-color: #F4F5F6 !important; }
html[data-paper] .bg-slate-900\/70,
html[data-paper] .bg-slate-900\/80,
html[data-paper] .bg-slate-900\/90,
html[data-paper] .bg-slate-950\/50,
html[data-paper] .bg-slate-950\/60,
html[data-paper] .bg-slate-950\/70    { background-color: rgba(244, 245, 246, .92) !important; }
html[data-paper] .bg-slate-500\/10,
html[data-paper] .bg-slate-600\/10,
html[data-paper] .bg-slate-700\/10,
html[data-paper] .bg-stone-500\/10    { background-color: var(--p-wash) !important; }

html[data-paper] .border-slate-700,
html[data-paper] .border-slate-800,
html[data-paper] .border-slate-800\/80 { border-color: var(--p-line) !important; }

/* Gradient stops that fade to black fade to paper instead. */
html[data-paper] .to-black,
html[data-paper] .to-black\/85        { --tw-gradient-to: rgba(255,255,255,.9) var(--tw-gradient-to-position) !important; }
html[data-paper] .to-slate-950\/60    { --tw-gradient-to: rgba(244,245,246,.6) var(--tw-gradient-to-position) !important; }
html[data-paper] .via-black\/60       { --tw-gradient-via: rgba(255,255,255,.6) !important; }
html[data-paper] .via-white\/40       { --tw-gradient-via: rgba(30,38,43,.14) !important; }

/* ------------------------------------------- arbitrary dark hex values --- */
html[data-paper] .bg-\[\#0a0a0a\]\/95,
html[data-paper] .bg-\[\#0a0a0f\],
html[data-paper] .bg-\[\#0b0b12\]\/90,
html[data-paper] .bg-\[\#0b0b12\]\/95 { background-color: rgba(255,255,255,.94) !important; }
html[data-paper] .bg-\[\#222\]        { background-color: #EFEFEF !important; }
html[data-paper] .text-\[\#0a0a0a\]   { color: var(--p-ink) !important; }
html[data-paper] .from-\[\#1a1a2e\]   { --tw-gradient-from: #F2F3F7 var(--tw-gradient-from-position) !important; }

/* Violet and cyan are decorative accents that survive the inversion, but both
   are set at dark-ground brightness and go weak on white. Deepened, not
   replaced — the desks are colour-coded and the coding has to keep working. */
html[data-paper] .text-\[\#7c3aed\]   { color: #6D28D9 !important; }
html[data-paper] .bg-\[\#7c3aed\]     { background-color: #6D28D9 !important; }
html[data-paper] .border-\[\#7c3aed\] { border-color: #6D28D9 !important; }
html[data-paper] .to-\[\#67e8f9\]     { --tw-gradient-to: #0E7490 var(--tw-gradient-to-position) !important; }

/* ------------------------------------------------------------ accent ----- */
/* Fills keep the brand orange; type does not. */
html[data-paper] .text-\[\#ff8800\]   { color: var(--p-accent-type) !important; }
html[data-paper] .border-\[\#ff8800\] { border-color: var(--p-accent) !important; }
html[data-paper] .border-\[\#ff8800\]\/50 { border-color: rgba(194,65,12,.5) !important; }
html[data-paper] .border-\[\#ff8800\]\/40 { border-color: rgba(194,65,12,.4) !important; }
html[data-paper] .bg-\[\#ff8800\]\/10 { background-color: rgba(194,65,12,.08) !important; }
html[data-paper] .bg-\[\#ff8800\]\/15 { background-color: rgba(194,65,12,.1) !important; }
/* A solid orange fill stays orange and takes dark type — white on #ff8800 is
   1.9:1. The console already has a rule forcing these buttons legible; this is
   the paper half of the same idea. */
html[data-paper] button.bg-\[\#ff8800\],
html[data-paper] button.bg-\[\#ff8800\] span,
html[data-paper] .bg-\[\#ff8800\]     { color: #1A0F00 !important; }

/* --- fills get the raw accent back ----------------------------------------
   The palette is inked at source so that TYPE is legible under any of the 22
   themes (see mknewshub.py). A solid fill does not need that and is worse for
   it — an inked yellow is olive. These few surfaces are blocks of colour with
   dark text on them, so they take --primary-orange-raw, the pre-ink value the
   same script publishes. Everything else on the page keeps the inked one. */
html[data-paper] a.bg-\[\#ff8800\],
html[data-paper] button.bg-\[\#ff8800\],
html[data-paper] .bg-\[\#ff8800\] {
    background-color: var(--primary-orange-raw, #ff8800) !important;
    background-image: none !important;
}
/* NOT `[class*="from-[#ff8800]"]`. That was here to give the hero button's
   gradient its colour back, and it also matched every feed card's hover
   overlay — `from-[#ff8800]/5`, a five per cent wash — because a substring
   match cannot see the /5. Setting --tw-gradient-from discards the alpha, so
   every card turned into a solid slab of accent under the cursor with the
   headline still in ink on top of it.
   The hero button no longer needs the rule at all: [data-hero-cta] sets
   background-image:none, so there is no gradient left to colour. */

/* ============================================= HOVER AND FOCUS STATES =====
   A blind spot worth naming: `hover:bg-slate-900` is a DIFFERENT class from
   `bg-slate-900`, so every rule above missed the state variants entirely. The
   page has 96 of them. Most are hue tints at /15 that read correctly on either
   ground, but the greyscale ones inverted exactly the way the base utilities
   did — and worse, invisibly, because you have to be pointing at the element to
   see it. `Top Headlines` turned into a black slab under the cursor on a white
   page for precisely this reason.
   ========================================================================== */
html[data-paper] .hover\:bg-slate-900:hover      { background-color: rgba(30, 38, 43, .06) !important; }
html[data-paper] .hover\:bg-emerald-900\/30:hover { background-color: rgba(4, 120, 87, .1) !important; }
html[data-paper] .hover\:bg-white\/5:hover       { background-color: var(--p-wash) !important; }
html[data-paper] .hover\:bg-white\/10:hover      { background-color: var(--p-wash-2) !important; }
html[data-paper] .hover\:bg-white\/90:hover      { background-color: rgba(30, 38, 43, .08) !important; }
html[data-paper] .hover\:text-white:hover        { color: var(--p-ink) !important; }
html[data-paper] .hover\:text-emerald-300:hover  { color: #047857 !important; }
html[data-paper] .hover\:text-red-400:hover      { color: #b91c1c !important; }
html[data-paper] .group:hover .group-hover\:text-purple-400 { color: #7e22ce !important; }
html[data-paper] .hover\:text-\[\#ff8800\]:hover,
html[data-paper] .group:hover .group-hover\:text-\[\#ff8800\] { color: var(--p-accent-live) !important; }
html[data-paper] .hover\:border-\[\#ff8800\]\/50:hover,
html[data-paper] .hover\:border-\[\#ff8800\]\/60:hover,
html[data-paper] .hover\:border-\[\#ff8800\]\/80:hover { border-color: var(--p-accent-rule) !important; }
/* hover:text-black and focus:text-black are already dark — left alone. */

/* ------------------------------------------------------ the hero pair ---- */
/* Two buttons, and until now two different languages: a solid accent slab and
   an outline. On black the slab is the thing that draws the eye; on paper it is
   a heavy block in the middle of a light page, and next to the outlined one it
   read as a mismatch rather than a hierarchy.
   Both become outlines. The primary keeps the accent on its border and its type
   so it is still plainly the first of the two — clear, not colourless. Hooked
   through :has() on the stable span ids, because the button labels themselves
   are rewritten at random by the landing-copy system and cannot be selected on. */
html[data-paper] button[data-hero-cta="primary"],
html[data-paper] button[data-hero-cta="secondary"] {
    background-color: transparent !important;
    background-image: none !important;
    box-shadow: none !important;
    border-width: 1px !important;
    border-style: solid !important;
    font-weight: 400 !important;
    transition: background-color .18s ease, border-color .18s ease, color .18s ease !important;
}
html[data-paper] button[data-hero-cta="primary"] {
    border-color: var(--p-accent-rule) !important;
    color: var(--p-accent-live) !important;
}
html[data-paper] button[data-hero-cta="secondary"] {
    border-color: var(--p-line) !important;
    color: var(--p-ink) !important;
}
/* One hover for both: a wash, never a fill. */
html[data-paper] button[data-hero-cta="primary"]:hover {
    background-color: color-mix(in srgb, var(--primary-orange-raw, #ff8800) 9%, transparent) !important;
    border-color: var(--p-accent-live) !important;
}
html[data-paper] button[data-hero-cta="secondary"]:hover {
    background-color: var(--p-wash-2) !important;
    border-color: rgba(30, 38, 43, .3) !important;
}
/* The icons inside inherit the button's colour rather than keeping the accent. */
html[data-paper] button[data-hero-cta="primary"] i,
html[data-paper] button[data-hero-cta="secondary"] i { color: inherit !important; }

/* ---------------------------------------------- feed cards on hover ------ */
/* With the overlay back to its own 5% the hover barely registers on white — 5%
   of a colour over #fff is most of nothing. The card gets a real hover instead:
   a faint tint, the accent on the border, and a lift in the shadow. Same three
   signals the dark card uses, at paper strength. */
html[data-paper] .news-card,
html[data-paper] .feed-tile {
    transition: background-color .2s ease, border-color .2s ease, box-shadow .2s ease,
                transform .3s cubic-bezier(.4, 0, .2, 1) !important;
}
html[data-paper] .news-card:hover,
html[data-paper] .feed-tile:hover {
    background-color: color-mix(in srgb, var(--primary-orange-raw, #ff8800) 4%, #ffffff) !important;
    border-color: var(--p-accent-rule) !important;
    box-shadow: 0 10px 28px rgba(30, 38, 43, .1) !important;
}
/* The overlay div itself: hold it to a wash whatever the roll is. */
html[data-paper] .news-card [class*="from-[#ff8800]"],
html[data-paper] .feed-tile [class*="from-[#ff8800]"] {
    --tw-gradient-from: color-mix(in srgb, var(--primary-orange-raw, #ff8800) 7%, transparent)
                        var(--tw-gradient-from-position) !important;
}
/* The round arrow that fills with accent on hover — dark glyph on the raw
   accent, matching every other fill on the page. */
html[data-paper] .news-card .group-hover\:bg-\[\#ff8800\],
html[data-paper] .feed-tile .group-hover\:bg-\[\#ff8800\] { color: #1A0F00 !important; }
html[data-paper] .group:hover .group-hover\:bg-\[\#ff8800\] {
    background-color: var(--primary-orange-raw, #ff8800) !important;
}

/* ------------------------------------------------- the source pills ------ */
/* White monospace on a saturated brand colour at 10px. The maths is fine —
   #0f2d5c gives 13.5:1 — and it still read badly, because contrast ratio does
   not model what small light strokes do on a mid-dark saturated ground: they
   bloom and fill in. The console had these at font-bold and got away with it;
   the type pass took every 10px label to 400 and these went with it.
   They are the one kind of small text on the page that sits on a coloured fill
   rather than on paper, so they are the one kind that needs the weight back —
   500, plus a hair of tracking to stop the mono characters touching. */
html[data-paper] .news-card [style*="background"][class*="rounded-full"],
html[data-paper] .feed-tile [style*="background"][class*="rounded-full"],
html[data-paper] #news-grid [style*="background"][class*="rounded-full"],
html[data-paper] #live-feed-tiles [style*="background"][class*="rounded-full"] {
    font-weight: 500 !important;
    letter-spacing: .02em !important;
    -webkit-font-smoothing: antialiased;
}

/* ------------------------------------------------------ the burger ------- */
/* Two problems, one of them invisible until you look for it.
   The bars are `bg-white` — literally white — because on the console they sit on
   a near-black button. On paper they were white on white, and the only reason
   the control read as anything at all was the faint card behind it.
   And that card is the console's chrome: a 48px rounded-2xl tile with a border
   and a hover glow. The light edition draws its burger as bare strokes with no
   container (see .nav__burger in site.css), so this matches that instead.

   Bars take the ink; hover takes the inked accent, so the control still answers
   the theme without depending on it to be legible. */
html[data-paper] #nav-menu-toggle {
    background: transparent !important;
    border-color: transparent !important;
    box-shadow: none !important;
    width: 40px !important;
    height: 40px !important;
}
/* The gradient wash that lit the tile on hover — nothing to light now. */
html[data-paper] #nav-menu-toggle > span[class*="absolute"] { background: none !important; }

html[data-paper] #nav-menu-toggle span.bg-white,
html[data-paper] #nav-menu-toggle .bg-white {
    background-color: var(--p-ink) !important;
}
/* Each bar carries its own group-hover colour on the console (orange, cyan,
   orange). On paper all three move together to the inked accent — three
   different hues at 2px on white reads as a rendering fault, not as a flourish. */
html[data-paper] #nav-menu-toggle:hover span.bg-white,
html[data-paper] .group:hover #nav-menu-toggle span.bg-white,
html[data-paper] #nav-menu-toggle:hover .group-hover\:bg-\[\#ff8800\],
html[data-paper] #nav-menu-toggle:hover .group-hover\:bg-\[\#67e8f9\] {
    background-color: var(--p-accent-live) !important;
}

/* ----------------------------------------------------- back to top ------- */
/* A 5% white disc floating on black becomes nothing at all on paper, so this
   inverts to a solid card with a hairline — the same treatment the snapshot
   tiles get. It sits over scrolling content rather than a fixed ground, so it
   is opaque rather than a wash: a translucent control passing over a headline
   is unreadable at exactly the moment you reach for it. */
html[data-paper] #to-top {
    background: var(--p-paper) !important;
    border-color: var(--p-line) !important;
    color: var(--p-ink-64) !important;
    box-shadow: 0 2px 10px rgba(30, 38, 43, .12) !important;
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
}
html[data-paper] #to-top:hover {
    background: var(--p-paper) !important;
    border-color: var(--p-accent-rule) !important;
    color: var(--p-accent-live) !important;
    box-shadow: 0 3px 14px rgba(30, 38, 43, .16) !important;
}
html[data-paper] #to-top i { color: inherit !important; }
html[data-paper] #to-top span { font-weight: 500 !important; letter-spacing: .12em !important; }

/* ------------------------------------------------- named components ------ */
/* The console draws these in its own <style>; each is re-declared rather than
   patched so the paper value is readable in one place. */
html[data-paper] .neon-orange {
    color: var(--p-accent-live) !important;
    text-shadow: none !important;          /* a glow on white is a smudge */
}
html[data-paper] .neon-border {
    border-color: var(--p-accent-rule) !important;
    box-shadow: 0 1px 3px rgba(30, 38, 43, .08) !important;
}

/* Everything the console colours from the live accent directly. */
html[data-paper] .contact-label .req,
html[data-paper] .tagline-caret,
html[data-paper] #nav-clock .clk-zone { color: var(--p-accent-live) !important; }

/* The holo headline. Its gradient is stamped inline by the theme repaint, so it
   cannot be recoloured from here without hard-coding one theme's colours back
   in — and it is the largest type on the page, so it is also the one place a
   pale roll is most obviously unreadable. Darkening the whole gradient with a
   filter keeps every theme's own two colours and their travel, and just moves
   the pair into ink territory. */
html[data-paper] .holo-text { filter: brightness(.52) saturate(1.35) !important; }

/* Accent glows: on black they are light spilling off a surface, on paper they
   are dirt around it. Scoped to the glow carriers rather than a blanket rule,
   so the holo filter above is not caught by it. */
html[data-paper] .neon-orange,
html[data-paper] .neon-border,
html[data-paper] [class*="glow"] { filter: none !important; text-shadow: none !important; }

/* Chrome surfaces. The console runs a two-mode glass system (html.lg-on /
   html.lg-off); both land on paper here, with the blur kept because it is
   structural — it is what separates a sticky bar from the text under it. */
html[data-paper].lg-on nav,
html[data-paper].lg-off nav,
html[data-paper].lg-on #nav-menu-panel,
html[data-paper].lg-off #nav-menu-panel {
    background: rgba(255, 255, 255, .86) !important;
    border-color: var(--p-line) !important;
    color: var(--p-ink) !important;
}
html[data-paper] .liquid-glass {
    background: rgba(255, 255, 255, .72) !important;
    border-color: var(--p-line) !important;
    box-shadow: 0 1px 2px rgba(30, 38, 43, .05), 0 8px 24px rgba(30, 38, 43, .06) !important;
}
html[data-paper].lg-on .liquid-glass::before { opacity: .25 !important; }

/* The hamburger's colour-coded rows. */
html[data-paper] .menu-row        { color: var(--p-ink-77) !important; }
html[data-paper] .menu-row:hover  { background: var(--p-wash-2) !important; color: var(--p-ink) !important; }
html[data-paper] .menu-group-h::after { background: var(--p-line) !important; }

/* Contact form. */
html[data-paper] .contact-label   { color: var(--p-ink-64) !important; }
html[data-paper] .contact-label .opt { color: var(--p-muted) !important; }
html[data-paper] .contact-input {
    background: var(--p-paper) !important;
    border-color: var(--p-line) !important;
    color: var(--p-ink) !important;
}
html[data-paper] .contact-input::placeholder { color: var(--p-muted) !important; }
html[data-paper] .contact-input:hover { border-color: rgba(30, 38, 43, .24) !important; }
html[data-paper] select.contact-input option { background: var(--p-paper) !important; color: var(--p-ink) !important; }
html[data-paper] .contact-consent { color: var(--p-ink-64) !important; }

/* The crawling featured strip. */
html[data-paper] .featured-chip        { background: var(--p-paper) !important; border-color: var(--p-line) !important; color: var(--p-ink) !important; }
html[data-paper] .featured-chip:hover  { background: var(--p-wash) !important; border-color: rgba(194,65,12,.4) !important; }
html[data-paper] .featured-chip-cat    { color: var(--p-muted) !important; }
html[data-paper] .featured-refresh     { color: var(--p-ink-64) !important; border-color: var(--p-line) !important; }
html[data-paper] .featured-refresh:hover { color: var(--p-accent-type) !important; border-color: var(--p-accent) !important; }

/* Snapshot deck. */
html[data-paper] .snap-tile     { background: var(--p-paper) !important; border-color: var(--p-line) !important; }
html[data-paper] .snap-tile:hover { border-color: rgba(194,65,12,.35) !important; box-shadow: 0 6px 20px rgba(30,38,43,.07) !important; }
html[data-paper] .snap-pillbar,
html[data-paper] .snap-pill,
html[data-paper] .snap-row,
html[data-paper] .snap-btn,
html[data-paper] .snap-chip     { background: var(--p-paper) !important; border-color: var(--p-line) !important; color: var(--p-ink-77) !important; }
html[data-paper] .snap-pill:hover,
html[data-paper] .snap-row:hover { background: var(--p-wash) !important; }

/* Feed topic + grid-size pills. */
html[data-paper] .feed-pill,
html[data-paper] .feed-grid-opt { background: var(--p-paper) !important; border-color: var(--p-line) !important; color: var(--p-ink-64) !important; }
html[data-paper] .feed-pill:hover { border-color: var(--p-accent) !important; color: var(--p-accent-type) !important; }
html[data-paper] .feed-pill[aria-pressed="true"],
html[data-paper] .feed-grid-opt[aria-pressed="true"] {
    background: var(--p-ink) !important; border-color: var(--p-ink) !important; color: var(--p-paper) !important;
}

/* The edition pill. Same geometry as everywhere else on the site — only the
   surface changes. The thumb keeps the accent gradient. */
html[data-paper] .mode-pill {
    border-color: var(--p-line) !important;
    background: linear-gradient(180deg, rgba(30,38,43,.045), rgba(30,38,43,.02)) !important;
    box-shadow: inset 0 1px 0 rgba(255,255,255,.6), 0 1px 3px rgba(30,38,43,.1) !important;
}
html[data-paper] .mode-pill__seg { color: var(--p-ink-64) !important; }
html[data-paper] .mode-pill__seg.is-on { color: var(--p-paper) !important; }

/* Clock face. */
html[data-paper] #nav-clock .clk-ring  { stroke: var(--p-line) !important; }
html[data-paper] #nav-clock .clk-ticks line { stroke: rgba(30,38,43,.28) !important; }
html[data-paper] #nav-clock .clk-sec   { stroke: var(--p-accent) !important; }
html[data-paper] #nav-clock .clk-mer   { color: var(--p-muted) !important; }

html[data-paper] .premium-badge { background: var(--p-ink) !important; color: var(--p-paper) !important; }
html[data-paper] .section-header-modern { color: var(--p-ink) !important; }

/* --------------------------------------------- the semantic scale -------- */
/* The desks are colour-coded and the market numbers are red/green, and all of
   it is pitched at the 200–400 end of Tailwind's scale because that is what
   reads on black. On white the same shades are 1.4–1.9:1 — emerald-400 for a
   "+32.11%" is a pale mint smear, not a number.
   Every one moves to its -700, which clears 4.5:1 on paper while keeping the
   hue, so green still means up and the desk colours still distinguish desks.
   Generated from the classes actually present in the document, not guessed:
   28 of them, listed in full so a new one is a visible omission. */
html[data-paper] .text-amber-200,
html[data-paper] .text-amber-300,
html[data-paper] .text-amber-400   { color: #b45309 !important; }
html[data-paper] .text-yellow-300  { color: #a16207 !important; }
html[data-paper] .text-orange-300,
html[data-paper] .text-orange-400  { color: #c2410c !important; }
html[data-paper] .text-red-300,
html[data-paper] .text-red-400     { color: #b91c1c !important; }
html[data-paper] .text-rose-300,
html[data-paper] .text-rose-400    { color: #be123c !important; }
html[data-paper] .text-pink-300    { color: #be185d !important; }
html[data-paper] .text-fuchsia-300,
html[data-paper] .text-fuchsia-400 { color: #a21caf !important; }
html[data-paper] .text-purple-300,
html[data-paper] .text-purple-400  { color: #7e22ce !important; }
html[data-paper] .text-violet-300,
html[data-paper] .text-violet-400  { color: #6d28d9 !important; }
html[data-paper] .text-indigo-300  { color: #4338ca !important; }
html[data-paper] .text-blue-300,
html[data-paper] .text-blue-400    { color: #1d4ed8 !important; }
html[data-paper] .text-sky-300,
html[data-paper] .text-sky-400     { color: #0369a1 !important; }
html[data-paper] .text-cyan-300    { color: #0e7490 !important; }
html[data-paper] .text-teal-300    { color: #0f766e !important; }
html[data-paper] .text-emerald-200,
html[data-paper] .text-emerald-300,
html[data-paper] .text-emerald-400 { color: #047857 !important; }
html[data-paper] .text-green-400   { color: #15803d !important; }
html[data-paper] .text-lime-300    { color: #4d7c0f !important; }

/* The -950 tints are near-black washes used as panel grounds behind those
   colours; on paper they become the palest tint of the same hue. The /10 and
   /15 washes are left alone — a 10% hue tint reads correctly on either ground. */
html[data-paper] .bg-amber-950\/20   { background-color: rgba(180, 83, 9, .07) !important; }
html[data-paper] .bg-emerald-950\/20 { background-color: rgba(4, 120, 87, .07) !important; }
html[data-paper] .bg-sky-950\/20     { background-color: rgba(3, 105, 161, .07) !important; }
html[data-paper] .bg-violet-950\/20  { background-color: rgba(109, 40, 217, .07) !important; }
html[data-paper] .bg-emerald-900,
html[data-paper] .bg-emerald-900\/60 { background-color: rgba(4, 120, 87, .12) !important; }
html[data-paper] .border-emerald-700 { border-color: rgba(4, 120, 87, .45) !important; }
html[data-paper] .from-amber-950\/40   { --tw-gradient-from: rgba(180, 83, 9, .09) var(--tw-gradient-from-position) !important; }
html[data-paper] .from-emerald-950\/40 { --tw-gradient-from: rgba(4, 120, 87, .09) var(--tw-gradient-from-position) !important; }
html[data-paper] .from-purple-950\/40,
html[data-paper] .from-purple-950\/60  { --tw-gradient-from: rgba(126, 34, 206, .09) var(--tw-gradient-from-position) !important; }
html[data-paper] .from-sky-950\/40     { --tw-gradient-from: rgba(3, 105, 161, .09) var(--tw-gradient-from-position) !important; }
html[data-paper] .via-violet-950\/40   { --tw-gradient-via: rgba(109, 40, 217, .09) !important; }

/* ------------------------------------------ every white-text rule -------- */
/* The console's own <style> sets white type in twelve places. Each one is
   invisible on paper, and they are the failure that does not announce itself —
   the element is present, sized and clickable, just blank. Enumerated from the
   stylesheet rather than found by eye, so the list is the complete set:
   grep for `color:` with a white value in the <style> block and every hit is
   answered here. Re-run that grep after pulling console changes through
   mknewshub.py; a thirteenth would arrive silently otherwise. */
html[data-paper] .featured-chip-name          { color: var(--p-ink) !important; }
html[data-paper] .featured-refresh:hover      { color: var(--p-accent-live) !important; }
html[data-paper] #nav-clock:hover .clk-hm,
html[data-paper] #nav-clock:hover .clk-sec    { color: var(--p-ink) !important; stroke: var(--p-ink) !important; }
html[data-paper] .snap-pill:hover,
html[data-paper] .snap-btn:hover,
html[data-paper] .snap-chip:hover             { color: var(--p-ink) !important; background: var(--p-wash-2) !important; }
html[data-paper] .feed-pill:hover,
html[data-paper] .feed-grid-opt:hover         { color: var(--p-accent-live) !important; }
/* The pressed pill inverts to solid ink, so white type on it is correct. */
html[data-paper] .feed-grid-opt[aria-pressed="true"] { color: var(--p-paper) !important; }
html[data-paper] .mode-pill__seg:not(.is-on):hover   { color: var(--p-ink) !important; }

/* ------------------------------------------------------------ misc ------- */
/* Every dark-ground shadow is a black glow, which on paper is grime. */
html[data-paper] [class*="shadow-"] { --tw-shadow-color: rgba(30, 38, 43, .10) !important; }
html[data-paper] ::selection { background: rgba(194, 65, 12, .18); color: var(--p-ink); }
html[data-paper] ::-webkit-scrollbar-track { background: #F1F1F1; }
html[data-paper] ::-webkit-scrollbar-thumb { background: rgba(30, 38, 43, .25); }
html[data-paper] hr { border-color: var(--p-line); }

/* Images and embeds keep their own colour — a news photograph is not chrome. */
html[data-paper] img, html[data-paper] video, html[data-paper] iframe { filter: none !important; }
