/* ════════════════════════════════════════════════════════════════════════
   feral·work — the palette.

   🚨 HARD RULE, INHERITED NOT INVENTED: THE PALETTE IS NOT FORKED.
   Every value below is copied verbatim from
   feral-network/apps/inbox/styles/tokens.css (dark) and light.css (light),
   which is itself feral·desk's. apps/home/index.html copies it the same way
   and says so in the same words. If a token here ever disagrees with that
   file, that file wins — change this one.

   Why a copy at all: feral·inbox is a Next app that imports its tokens through
   a build step. feral·work has NO build step (it is served as static files by
   a 400-line node broker), so it loads Geist from Google Fonts and restates
   the names. The alternative — a build pipeline for one CSS file — costs more
   than it saves.

   TWO CONSEQUENCES, BOTH LOAD-BEARING:

   1. NO HEX LITERAL MAY APPEAR OUTSIDE THIS FILE. style.css contains zero.
      Light mode works by REDEFINING these names, so one hand-written colour
      silently opts that whole surface out of the second theme. That is exactly
      how feral·inbox once "looked nothing like feral·desk".

   2. ONE ACCENT, COUNTED PER ZONE, OR IT IS WALLPAPER. --red means exactly
      three things here and the whole budget is:
        RAIL   .brand .dot        the identity mark. Always lit, exempt.
               .nav a.on::before  2px edge: which view you are in.
               .srow.on::before   2px edge: which terminal you are looking at.
               .crow.on::after    the same fact, about a specialist.
        PANE   .pane.on::after    the same fact again, once the screen is split.
        ANY    one alarm, and only while it is true (.err, the dead-socket dot).
      That is it.
      (⚠️ 2026-08-04, eighth pass: only the LIST moved, never the budget. This
      named `.tab.on::after` until the tab strip was deleted. "Which terminal you
      are looking at" is now answered by the rail row, the crew row and the
      focused pane — three surfaces carrying one fact, which is the same single
      use. A comment naming a selector that no longer exists is how a budget
      quietly stops being counted.) The primary button is NOT red — #fff on #ff0033 measures
      3.96:1, an AA failure tolerated in exactly one place in this family
      (mail's Composer) and not repeated. Everything else is carried by
      luminance, size, position and weight.
   ════════════════════════════════════════════════════════════════════════ */
:root{
  /* surfaces */
  --bg:#050505; --card:#0c0c0c; --elev:#141414; --elev2:#1b1b1d;
  --well:rgba(0,0,0,.32);
  --line:rgba(237,237,237,.08); --line2:rgba(237,237,237,.14);

  /* ── --paper: THE SURFACE YOU READ AND TYPE ON, WHICH IS NOT THE GROUND ────
     Added 2026-08-12. In DARK it is `--bg` and nothing changes by a single
     pixel — the whole point is that this token is free here and load-bearing in
     light, which is the only way to fix light without touching dark at all.

     🚨 IN LIGHT THE APP HAD ONE GROUND AND IT WAS THE FAULT. `.rail`, `.main`,
     `.convo`, `.thead` and `.composer` were all `--bg`, so the sidebar and the
     transcript were THE SAME BONE — and then `--term-bg` was pure #fff, which
     is how a beautifully-argued light theme ends up as a white rectangle sitting
     on a beige page. Every Mac app worth copying answers this the same way: the
     sidebar is the RECESSED ground and the content is PAPER, one step lighter,
     with a hairline between them. That is what this token buys.

     ⚠️ IT IS NOT `--card`, EVEN THOUGH IT EQUALS IT IN LIGHT TODAY. A card is an
     OBJECT you put on a surface; this is the surface. They will diverge the
     first time a panel needs to sit on the paper and be seen — write the one
     that says what the thing IS. */
  --paper:var(--bg);

  /* ── THREE MORE THAT ARE FREE IN DARK AND LOAD-BEARING IN LIGHT ───────────
     Same trick as --paper, same reason, and every one of them is set to exactly
     what the selector said before, so DARK DOES NOT MOVE.

     --fill / --on-fill / --fill-edge / --fill-hover — THE ONE FILLED CONTROL.
       🚨 `.abtn.solid` was `--elev2`, and `--elev2` means OPPOSITE THINGS in the
       two themes. In dark it is the top of the ladder, so the primary button
       reads as raised. In light it is the WELL — below the paper — so the same
       rule painted the primary action of the whole empty screen as a dead beige
       lozenge that looks disabled. It is not a colour problem: "elevated" cannot
       be one token when one theme lifts by getting lighter and the other by
       getting darker. So the FILL is named, and light fills it with ink.
     --field — AN INPUT'S GROUND.
       `--card` was right while the composer sat on `--bg`. Now that the content
       side is `--paper` and `--card` equals it, a `--card` input on the paper is
       white on white. A field has to be a distinct object you can aim at.
     --hover — WHAT A ROW OR A GHOST BUTTON DOES UNDER THE POINTER.
       `background:var(--elev)` lifts toward white, which on white paper is no
       feedback at all. In light a hover DARKENS. */
  --fill:var(--elev2); --on-fill:var(--ink);
  /* ⚠️ `--fill-hover` IS `--fill` HERE ON PURPOSE. Dark's filled button has
     never changed its ground on hover — only its border — and "while I am in
     here I will also improve dark" is how a light-mode fix turns into a change
     nobody asked for and nobody reviewed. */
  --fill-edge:var(--line2); --fill-hover:var(--elev2);
  --field:var(--card);
  --hover:var(--elev);

  /* ── THE GAUGE'S FOUR WASHES, FOR THE REASON --volt-wash IS ALREADY A TOKEN ─
     🚨 THE SAME ALPHA IS NOT THE SAME COLOUR OVER TWO GROUNDS, AND ON A DIAL
     THAT IS NOT A NUANCE — IT REVERSES WHICH PART OF THE INSTRUMENT SHOUTS.
     Measured on the empty screen at 1440px: the redline zone is
     `rgba(crit,.20)`, which over #050505 is a whisper you have to look for and
     over bone is a 180px dusty-pink block — the loudest object on a screen whose
     headline is "Nothing open yet" and whose box is 16% full. The `rest` band
     and the reclaimable wash invert the same way, so in light the two parts
     nothing can be done about were the two parts you saw first.
     Dark keeps every number it had. Light is pulled down until the fill is once
     again the brightest thing on the dial, which is the one comparison the whole
     bar exists to make. */
  --g-zone:linear-gradient(90deg,rgba(var(--warn-rgb),.09),rgba(var(--crit-rgb),.20));
  --g-rest:rgba(var(--ink-rgb),.14);
  --g-soft:rgba(var(--ink-rgb),.055);
  --g-seat:rgba(var(--good-rgb),.46);

  /* type */
  --ink:#ededed; --sec:#b5b5b5; --mut:#808080; --dim:#5c5c62;
  --ink-max:#fff;

  /* the one accent */
  --red:#ff0033; --red-core:#ff2b55;
  --red-deep:#26040b; --red-ink:#180307;
  --red-glow:rgba(255,43,85,.38); --red-dim:rgba(255,0,51,.14);
  --red-line:rgba(255,0,51,.5);

  /* ── THE VOICE CHANNEL — the human's own colour ─────────────────────────
     HARRY, 2026-08-10: "when someone's doing the microphone, at the moment in
     the terminal it's red… could you do an electric blue… so it just looks
     really fucking expensive", and of his own sent message: "don't do red".

     🚨 THIS IS AN ADDITION, NOT A FORK. Every value above is still verbatim
     from feral·desk's tokens and must stay that way. This family has no
     upstream twin yet — if desk or inbox ever grow one, that file wins and
     this changes to match it.

     ⚠️ AND IT IS NOT A SECOND ACCENT — IT IS A CHANNEL SPLIT, which makes the
     budget above EASIER to count, not harder:
         --red   FERAL, and where you are.        Identity and place.
         --volt  YOU.  Your voice while you are speaking it, and your words
                 once you have sent them.
     Nothing else may wear it. A blue on a status, a link outside your own
     card, or a button is this hue becoming wallpaper — the exact failure
     --red already has a rule against, three lines up.

     ⚠️ IT ALSO FINISHES A COLLISION THIS FILE ALREADY PAID FOR. #cSend.stop
     wore --crit-ink because the record light did, and Harry read the stop
     button as a microphone (see the long note at #cSend.stop in style.css).
     With the record light on its own hue, red means one thing on that strip.

     6.4:1 on --bg and 6.1:1 on --card in dark; 5.8:1 on --bg in light — so it
     carries type, not just marks, in both themes. */
  --volt:#4d8dff; --volt-core:#7ea9ff;
  --volt-deep:#050d1e;
  --volt-glow:rgba(126,169,255,.34); --volt-dim:rgba(77,141,255,.13);
  --volt-line:rgba(77,141,255,.46);
  /* ⚠️ THE WASH IS A TOKEN BECAUSE THE TWO THEMES NEED DIFFERENT NUMBERS AND
     STYLE.CSS MUST NOT KNOW WHICH THEME IT IS IN. The same alpha over #0c0c0c
     and over #fbfaf8 is not the same colour to an eye: at .16 the light card
     reads as a clear blue wash and the dark one goes grey. Measured on the
     painted page in both, then set here — which is the only place in this
     codebase allowed to hold a number like this. */
  --volt-wash:rgba(77,141,255,.20); --volt-wash-soft:rgba(77,141,255,.075);

  /* ── THE APP MARK'S OWN HUE — the dot after `work` in the rail ─────────────
     HARRY, 2026-08-22, on the terminal's wordmark matching feral·yap's exactly:
     *"the exact same font as YAP … an exact dot exactly after it, exact same
     spacing and size, but just a different color … not red."*

     ⚠️ IT IS A THIRD IDENTITY INK WITH EXACTLY ONE JOB — `.brand .dot`, which
     the accent budget at the head of this file already lists as exempt and
     always lit. Nothing else may wear it, on the same terms --volt is held to.
     Three channels, still countable on one hand:
         --red   FERAL, and where you are.
         --volt  YOU, while you are speaking and once you have sent it.
         --work  THIS APP. One 5px disc, and nothing else.

     🚨 WHY A NEW NAME RATHER THAN ONE ALREADY HERE. Every other hue on this
     wheel is spoken for, and a permanently lit disc six pixels from the logo
     would have said something untrue in all of them: --good is a live session
     and --warn a waiting one (both are discs in this very rail), --crit and
     --red are an alarm, --volt is your own voice, --cyan is the focus ring.
     Violet is the one arc with no job, so a disc in it can only mean the app.
     Measured: 5.80:1 on --bg, 5.57:1 on --card — above --red's 5.14 and below
     --volt's 6.38, so it reads as lit without out-shouting either. */
  --work:#9d6bff;
  --work-glow:rgba(157,107,255,.38); --work-rgb:157,107,255;

  /* status — a SECOND register. Mixing it with --red is the defect. */
  --crit:#d03b3b; --good:#36d399; --warn:#f5a524;
  --cyan:#38e0ff;
  --crit-ink:#e26a6a;

  /* channels — the same hues, at any alpha */
  --ink-rgb:237,237,237;
  --good-rgb:54,211,153; --warn-rgb:245,165,36; --crit-rgb:208,59,59;
  --red-rgb:255,0,51; --cyan-rgb:56,224,255;
  --volt-rgb:77,141,255;

  --on-accent:#fff;
  --on-good:#03170f; --on-warn:#1a1204;
  --on-media:#9a948a;

  --skel:var(--elev);
  --media:#101012;

  /* No build step, so the family names come from Google Fonts rather than
     next/font's CSS variables. Same faces, same weights. */
  --sans:'Geist',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
  --mono:'Geist Mono',ui-monospace,'SF Mono',Menlo,monospace;
  --focus:rgba(56,224,255,.55);

  --rail:216px;
  --r-xl:20px; --r-lg:16px; --r-md:12px; --r-sm:8px;

  --sh-card:inset 0 1px 0 rgba(237,237,237,.05),0 1px 1px rgba(0,0,0,.5);
  --sh-lift:inset 0 1px 0 rgba(237,237,237,.05),0 1px 1px rgba(0,0,0,.5),0 12px 32px -16px rgba(0,0,0,.8);
  --sh-pop:0 30px 80px rgba(0,0,0,.7),inset 0 1px 0 rgba(237,237,237,.05);
  --sh-float:0 16px 44px rgba(0,0,0,.6);
  --sh-hero:0 14px 36px -18px rgba(0,0,0,.8);
  --sh-inset:inset 0 1px 2px rgba(0,0,0,.45);
  --sh-btn:0 1px 2px rgba(0,0,0,.25);

  --scrim:rgba(3,3,4,.62); --scrim-strong:rgba(4,4,6,.8);
  --page-glow:radial-gradient(90% 60% at 50% 108%,rgba(255,0,51,.035),transparent 60%);

  /* ── THE TERMINAL'S OWN SURFACE ────────────────────────────────────────
     🚨 IT FLIPS. An earlier version of this file argued the terminal should
     stay a black slab in both themes, the way --media does. Harry overruled it
     on sight: "if you go light mode, it needs to turn it light mode in the
     terminal as well." He is right and the argument was craft talking — a
     black rectangle sitting in a bone-coloured app is the one element that
     announces it was bolted on.

     So the sixteen ANSI colours DO get re-mapped, and they live here rather
     than in app.js, because xterm's theme is JavaScript and the rule that the
     palette is never forked has to survive that. app.js reads these with
     getComputedStyle and hands them to xterm — one source, two consumers.

     Light values are darkened until each carries type on near-white: #36d399
     is a fine green on black and a smear on bone, which is the same reason
     --good is redefined in the light block above. */
  --term-bg:#000; --term-ink:#ededed; --term-cursor:#ff0033;
  --term-sel:rgba(255,255,255,.18);

  /* ═══════════════════════════════════════════════════════════════════════
     🚨 THE CODE PALETTE — FIVE HUES INSIDE A FENCE, AND IT DOES NOT BREAK
     THE ACCENT LAW. Read this before deciding it does.

     The law is that an accent must DISCRIMINATE or not appear, and that three
     orthogonal signals get one channel each and never bleed into one another's.
     What that law protects is the CHROME: --good means a live session,
     --warn a waiting one, --crit an alarm, --volt your own voice, --cyan the
     focus ring. A hue that means two things in the chrome is a hue that means
     nothing.

     A fenced code block is a different MEDIUM, and this file already has the
     precedent: --term-* is its own world, and --t1..--t15 are the ANSI set,
     where red means "the program printed red" and not "an alarm". Nobody
     mistakes a keyword in a listing for a session state, because a listing is
     not a state — it is a picture of a file. So these are their own family,
     named for what they mark rather than for what they mean, and NOTHING
     outside `.ttext code` may wear one.

     ⚠️ THEY ARE TEXT, SO THE FLOOR IS 4.5:1 AND NOT 3:1, on --term-bg, in every
     one of the four appearances. tests/prove-colour.js measures all twenty and
     that is the only reason it is safe to add a palette this size — the whole
     failure this estate keeps paying for is a colour nobody measured.

     ⚠️ AND THE FIFTH IS A GREY ON PURPOSE. A comment is the one thing in a
     listing that is deliberately quieter than the code, so it is the only rung
     here that does not carry a hue. --dim would have been the instinct and is
     wrong: it is below the floor and this file already says nothing carrying a
     fact may use it. */
  --code-com:#7b828d;   /* a comment — quiet, and the only grey here      */
  --code-key:#f0a1ff;   /* const · if · def · SELECT                       */
  --code-str:#4fce93;   /* everything between quotes                       */
  --code-num:#f8d38c;   /* a number, and true/false/null with it           */
  --code-fn:#5aa0e6;    /* a name that LABELS something — a call, a key,
                           a CSS property, an HTML attribute               */
  /* 🚨 THE TERMINAL'S SCROLLBAR IS PAINTED BY xterm, NOT BY CSS — since v6 the
     slider lives inside `.xterm-scrollable-element` and is coloured from
     ITheme.scrollbarSlider*, which app.js reads from here. So it belongs in the
     palette with everything else rather than in a stylesheet that cannot reach
     it; left undeclared the terminal wore xterm's own grey while every other
     scrollbar in the app wore ours.
     ⚠️ TRANSLUCENT ON PURPOSE. It floats OVER the last column of text rather
     than cutting a gutter out of it, so it has to let the characters through. */
  --term-slider:rgba(255,255,255,.14);
  --term-slider-hover:rgba(255,255,255,.24);
  --term-slider-active:rgba(255,255,255,.34);
  --t0:#141414;  --t8:#666666;
  --t1:#f56565;  --t9:#fc8181;
  --t2:#2fbf71;  --t10:#48d88a;
  --t3:#f5a623;  --t11:#f7b955;
  --t4:#7aa2f7;  --t12:#94b4f9;
  --t5:#c39ac9;  --t13:#d7b3dc;
  --t6:#56b6c2;  --t14:#7ccdd8;
  --t7:#ededed;  --t15:#ffffff;

  --ease:cubic-bezier(.2,0,0,1);

  /* ── THE TWO HUD COLOURWAYS, DECLARED ON :root AND THEREFORE TRUE IN EVERY
        APPEARANCE. They are not the skin's palette — that is the
        `html[data-theme="hud"]` block below, which resolves everything from
        --hud. These two exist for one job: the appearance picker has to draw a
        dot in the colour you have NOT chosen, from inside dark, from inside
        light, and from inside the other colourway. A picker that can only show
        you what is already on is not a picker.
        🚨 THE SKIN BLOCK DERIVES FROM THESE RATHER THAN RESTATING THEM. The
        first cut wrote #ff0a2e in both places with an "if either moves, move
        both" warning on it — which is a defect with a comment on it rather than
        a design. There is now one register per literal and nothing to keep in
        step. */
  --hud-red:#ff0a2e;  --hud-red-hi:#ff4d63;  --hud-red-rgb:255,10,46;
  --hud-pink:#ff2bb5; --hud-pink-hi:#ff6ccd; --hud-pink-rgb:255,43,181;

  /* ── 🚨 WHAT THE WINDOW'S OWN FURNITURE WEARS, WHICH IS NOT --bg ──────────
        Harry, 2026-08-23, of WORK.app in VISOR: *"can we get rid of this black
        bar… it needs to match whatever theme you've got on."* The titlebar was
        already following the theme — `<meta name="theme-color">` carries --bg
        to `WKWebView.themeColor` and Chrome.swift dresses the window in it
        (see the-native-shell-follows-the-page-not-a-setting). It was following
        it to the WRONG VALUE, and only in this appearance.

        In dark and light, --bg IS what the top of the page looks like. In VISOR
        it is not: --bg is true #000 and the glass then lays a 118px bloom over
        it, so the page's first 38 rows paint as a dark plum and a titlebar
        holding #000 is a dead slab sitting on a lit edge. Same fault the phone
        had, one surface up — see top-chrome-is-paid-once-by-whatever-is-topmost.

        MEASURED off the painted page, not composed by hand: 1440×900, rows 1–38,
        the middle 60% of the width so the rail and the vignette corners do not
        skew it. Grain and the scanline mask are IN these numbers, because they
        are in what the eye is comparing the bar against.

        ⚠️ IT IS A LITERAL AND IT MUST TRACK ITS HUE. tests/prove-colour.js pins
        the contract rather than the arithmetic: same HUE as --hud, dark enough
        to be furniture, and saturated enough that the shell's own tint test
        fires (Chrome.swift reads the chroma back out of this one colour — that
        is how the titlebar knows to light its top edge without a second
        channel). Move a hue and forget this and the test says so. */
  --chrome-red:#1e070b; --chrome-pink:#1e0a17;
  color-scheme:dark;
}

/* ══════════════════════════════════════════════════════════════════════════
   LIGHT — rebuilt 2026-08-12, on Harry's instruction: *"really massively
   improve the light mode… make it so beautiful and stunning, the most beautiful
   white mode there is."* Measured on the painted page in the app, at 1440×900,
   before and after.

   🚨 WHAT WAS ACTUALLY WRONG, AND IT WAS NOT THE HUES. Four faults, all
   structural, all invisible in a hex list and obvious in a screenshot:

     1. ONE GROUND FOR EVERYTHING. rail, main, transcript, header and composer
        were all `--bg`, so nothing on the page was separated from anything
        else — and then the terminal was a pure-white slab on top of it. See
        `--paper` in the dark block for the fix and the reasoning.
     2. NO DEPTH AT ALL. The seven shadows were 1–2px at 5% alpha. Measured:
        indistinguishable from `none` on a real screen. A dark theme gets depth
        free from luminance; a light theme has only shadow, so a light theme
        with no shadow is a page of flat rectangles. They are two-layer now —
        a tight contact shadow, a wide soft ambient, and a hairline ring — which
        is the whole of what makes a light UI read as expensive.
     3. THE BONE WAS DINGY. #f0eee9 is a mid-warm grey; beside a pure-white
        terminal it read as old paper rather than as a chosen colour. The ladder
        below keeps FERAL's warmth (it is the storefront's, and it is not up for
        grabs) and takes the *muddiness* out by moving the paper up to near-white
        and the rail down, so the warmth reads as intent instead of as dirt.
     4. THE HAIRLINES WERE UNDER THE FLOOR. `--line` at .10 over bone paints
        #d9d7d2, which on a 2× screen you cannot see. The dividing line between
        a sidebar and its content is the single most-looked-at edge in the app.

   ⚠️ AND THE THING THIS BLOCK MUST NOT DO IS CHANGE DARK. Every value here is a
   REDEFINITION of a name declared above; not one selector anywhere is allowed to
   learn which theme it is in. That property is the reason light was fixable at
   all, and it is worth more than any colour in this file.

   ⚠️ THE HEADER OF THIS FILE SAYS THESE VALUES ARE COPIED FROM
   feral-network/apps/inbox/light.css AND THAT THAT FILE WINS. THAT IS NO LONGER
   TRUE OF THE LIGHT BLOCK and pretending otherwise is how this work gets
   reverted by a session "restoring the upstream". `feral-network` is not on this
   estate's servers — only a stub — and the design skill already names
   `/opt/feral-work/web/tokens.css` as "the estate's live reference". So THIS is
   the register for light now. The dark block above is untouched and still is the
   copy it says it is. If inbox's light.css ever turns up, it takes these values,
   not the other way round.
   ══════════════════════════════════════════════════════════════════════════ */
html[data-theme="light"]{
  /* ── the ladder. Five steps, and each one has a JOB, not a brightness ─────
       --elev2   a WELL      a track, a trough, a gutter — below the ground
       --bg      the GROUND  the rail, and whatever the app is standing on
       --paper   the PAPER   what you read and type on           (see dark block)
       --card    a PANEL     an object placed on the paper
       --elev    the TOP     a menu, a popover, a card that floats
     ⚠️ `--card` and `--paper` are the same value TODAY and are not the same
     idea. When a panel next has to be seen against the paper, --card moves and
     --paper does not. */
  --bg:#eae8e3; --card:#fcfbf9; --elev:#ffffff;
  --elev2:#e5e2db;
  --paper:var(--card);
  /* The primary control is INK, and it is the one place in this theme that goes
     dark. Not red — #fff on #ff0033 is 3.96:1 and this family tolerates that in
     exactly one place, which is not here — and not a lighter grey either, which
     is what it was and what made it read as disabled. Ink on paper is the
     strongest, quietest primary a light UI has, it introduces no hue, and it is
     already in the palette twice over. */
  --fill:var(--ink); --on-fill:var(--paper);
  --fill-edge:transparent; --fill-hover:#000000;
  --field:var(--elev);
  --hover:rgba(25,23,19,.055);

  /* The dial, re-weighed for paper. The zone drops to roughly half its alpha,
     the two neutral bands drop a third — and the SEAT goes UP, because the one
     thing that must stay loudest is the part that is actually yours. */
  --g-zone:linear-gradient(90deg,rgba(var(--warn-rgb),.055),rgba(var(--crit-rgb),.11));
  --g-rest:rgba(var(--ink-rgb),.10);
  --g-soft:rgba(var(--ink-rgb),.04);
  --g-seat:rgba(var(--good-rgb),.62);
  --well:rgba(25,23,19,.055);
  /* .12/.20, up from .10/.18. The rail/content divider is the most-looked-at
     edge in the app and at .10 it was not there. Still nowhere near a box. */
  --line:rgba(25,23,19,.12); --line2:rgba(25,23,19,.20);

  /* Ink, one notch darker and one notch cleaner at every rung. `--dim` was
     #837d72 — 3.1:1 on the ground, which is under the floor for anything with a
     shape you are meant to read, and it carries icons. 3.6:1 now, and --mut
     clears AA on all three surfaces (4.8 rail / 5.7 paper / 5.9 white). */
  --ink:#1a1815; --sec:#46423b; --mut:#6a645a; --dim:#7d776c;
  --ink-max:#000;

  --red:#d10026; --red-core:#a8001e;
  --red-deep:#fbe9ec; --red-ink:#fdf4f5;
  --red-glow:rgba(209,0,38,.26); --red-dim:rgba(209,0,38,.07);
  --red-line:rgba(209,0,38,.42);

  /* the voice channel, darkened until it carries type on bone. See the dark
     block for what it means and what may not wear it. */
  --volt:#1d4ed8; --volt-core:#1740b0;
  --volt-deep:#eef2fd;
  --volt-glow:rgba(23,64,176,.26); --volt-dim:rgba(29,78,216,.07);
  --volt-line:rgba(29,78,216,.42);
  --volt-wash:rgba(29,78,216,.16); --volt-wash-soft:rgba(29,78,216,.055);

  /* the app mark, darkened until it holds on bone. 4.65:1 on --bg and 5.51:1 on
     --card, which is this block's own --red to within a rounding error
     (4.59 / 5.43) — so the dot carries the same weight in both themes, exactly
     as the FERAL mark beside it does. */
  --work:#7c3aed;
  --work-glow:rgba(124,58,237,.26); --work-rgb:124,58,237;

  --crit:#b3261e; --good:#097044; --warn:#8f5500;
  --cyan:#0e7490;
  --crit-ink:#b3261e;

  /* ⚠️ TRACKS --ink, WHICH JUST MOVED. Every `rgba(var(--ink-rgb),…)` in
     style.css — hover fills, scrollbar thumbs, dividers drawn by hand — is a
     tint of the ink, so leaving this at the old 25,23,19 would have split the
     one neutral into two that differ by a degree of hue nobody could name and
     everybody could see stacked. */
  --ink-rgb:26,24,21;
  --good-rgb:9,112,68; --warn-rgb:143,85,0; --crit-rgb:179,38,30;
  --red-rgb:209,0,38; --cyan-rgb:14,116,144;
  --volt-rgb:29,78,216;

  --on-accent:#fff; --on-good:#fff; --on-warn:#fff;

  --skel:#e5e2db;
  --media:#0e0e10;
  /* --on-media is DELIBERATELY ABSENT here, exactly as in light.css. It is the
     ink on a ground that does not flip, so it must not flip either. */

  --focus:rgba(14,116,144,.55);

  /* ── DEPTH, WHICH THIS THEME DID NOT HAVE ─────────────────────────────────
     🚨 A DARK THEME GETS DEPTH FROM LUMINANCE; A LIGHT THEME HAS ONLY SHADOW.
     So the seven shadows are not decoration here, they are the entire z-axis —
     and at 1–2px / 5% they were, measured against `none` on a real screen,
     nothing. That is why every panel in the old light mode read as a flat
     rectangle with a faint line round it.

     ⚠️ EVERY ONE IS TWO LAYERS PLUS A RING, and the three parts are not
     interchangeable:
       · a CONTACT shadow — 1–2px, tight, ~7%. It is what says the thing is
         resting on something rather than printed on it.
       · an AMBIENT shadow — wide, far-offset, negative spread. It is the one
         that reads as height, and it must be soft enough to have no edge.
       · a HAIRLINE RING — `0 0 0 1px`, ~5%. On a near-white surface a shadow
         alone leaves the top edge of a white card invisible against white
         paper, because there is no shadow ABOVE an object. The ring is what
         closes the shape. It is not a border: a border changes layout.
     ⚠️ WARM-TINTED (25,23,19), NEVER PURE BLACK. A neutral shadow over a warm
     ground greys it, which is exactly the "dingy" this rebuild exists to remove.
     ⚠️ AND NOT DARKER. Every value here is under 30%: the failure at the other
     end is a page of drop-shadowed boxes, which reads as 2011 rather than as
     expensive. Depth comes from the SPREAD being generous, not the alpha. */
  --sh-card:0 1px 2px rgba(25,23,19,.06),0 0 0 1px rgba(25,23,19,.045);
  --sh-lift:0 1px 2px rgba(25,23,19,.06),0 8px 20px -8px rgba(25,23,19,.15),
            0 0 0 1px rgba(25,23,19,.055);
  --sh-pop:0 2px 4px rgba(25,23,19,.07),0 20px 48px -14px rgba(25,23,19,.26),
           0 0 0 1px rgba(25,23,19,.07);
  --sh-float:0 2px 5px rgba(25,23,19,.07),0 14px 34px -12px rgba(25,23,19,.20),
             0 0 0 1px rgba(25,23,19,.05);
  --sh-hero:0 3px 8px -2px rgba(25,23,19,.08),0 20px 44px -24px rgba(25,23,19,.38);
  --sh-inset:inset 0 1px 2px rgba(25,23,19,.07);
  --sh-btn:0 1px 2px rgba(25,23,19,.08),0 0 0 1px rgba(25,23,19,.05);

  --scrim:rgba(28,25,20,.30); --scrim-strong:rgba(28,25,20,.44);
  /* ⚠️ STILL `none`, AND IT IS A DECISION RATHER THAN AN OVERSIGHT. The dark
     theme's page glow works because a glow ADDS light to a dark ground. The
     same gesture in light can only be a stain, and a stain on white paper is
     the one thing this rebuild is trying to get rid of. Light's ground is flat
     on purpose; its interest comes from the ladder and the shadows above. */
  --page-glow:none;

  /* ── the terminal, in light. See the note in the dark block for why it flips.
     🚨 IT IS `--paper`, NOT `#fff`, AND THAT ONE CHANGE IS HALF OF WHY THE OLD
     LIGHT MODE LOOKED BOLTED TOGETHER. A pure-white terminal on a bone page is
     a white rectangle with a visible edge on three sides — the exact "black slab
     in a bone app" failure the dark block argues against, arriving from the
     other direction. The terminal is not a panel in this app, it IS the reading
     surface, so it takes the reading surface's colour and the seam disappears.
     ⚠️ app.js hands these to xterm through getComputedStyle, which RESOLVES
     var() at computed-value time — so `var(--paper)` arrives as a hex and the
     one-source rule survives the trip into JavaScript. Verified in the engine
     before it was written, because a token that resolves to the literal string
     "var(--paper)" would hand xterm an invalid colour and take the whole
     terminal down. */
  --term-bg:var(--paper); --term-ink:#1a1815; --term-cursor:#d10026;

  /* The code palette, darkened for bone exactly as --good and the ANSI set are
     three hundred lines up: #5fd39a is a fine green on black and a smear on
     paper. Ground here is --paper (#fcfbf9), not #fff, and the floor is still
     4.5:1 because these are letters. */
  --code-com:#6e6a62;
  --code-key:#a411cf;
  --code-str:#046b40;
  --code-num:#6d4b12;
  --code-fn:#0d47a3;
  /* ⚠️ A NEUTRAL INK WASH, NOT A HUE. The obvious move here is the macOS blue,
     and it is wrong in this file: --volt means the PERSON's voice and nothing
     else may wear it (see the dark block). A terminal selection is not somebody
     speaking. .16 rather than .14 because a selection nobody can see is a
     selection that gets made twice. */
  --term-sel:rgba(25,23,19,.16);
  /* Ink on paper, not white on black — the same inversion the whole light block
     is. See the note in the dark block for why this is a token and not a rule. */
  --term-slider:rgba(25,23,19,.16);
  --term-slider-hover:rgba(25,23,19,.28);
  --term-slider-active:rgba(25,23,19,.4);
  /* ── 🚨 IN A LIGHT TERMINAL "BRIGHT" MEANS DARKER, AND THIS RAMP HAD IT
     BACKWARDS FOR EVERY COLOUR. Bright green was #0d8f59 against a base of
     #0a7a4b — i.e. LIGHTER, copied straight from the dark ramp's logic where
     lighter is louder. On white paper lighter is QUIETER, so `\e[92m` — the
     escape a tool reaches for when it wants you to look — painted the one thing
     on the line you could see least. Three of the sixteen (bright black, bright
     green, bright cyan) did not even clear 4.5:1.
     Bright is now MORE SATURATED AND DARKER on every coloured pair. All sixteen
     clear AA on --paper; the numbers are in the commit.
     ⚠️ THE BLACK/GREY PAIR IS THE ONE EXCEPTION AND IT IS NOT AN OVERSIGHT.
     "Bright black" is the comment colour in every palette ever written, in both
     themes — it has to stay the QUIET one, so here alone bright is lighter.
     ⚠️ AND app.js SETS minimumContrastRatio:4.5 IN LIGHT, which would have
     dragged the three failures up on its own — by shifting their LIGHTNESS and
     leaving the hue to fend for itself. A ramp that only reads because the
     engine is correcting it is a ramp nobody chose. */
  --t0:#3f3b35;  --t8:#736d63;
  --t1:#c02a20;  --t9:#a1121a;
  --t2:#0e8553;  --t10:#06663f;
  --t3:#9a5c00;  --t11:#7a4700;
  --t4:#2563eb;  --t12:#1740b0;
  --t5:#8b3ff0;  --t13:#6d28d9;
  --t6:#0e7490;  --t14:#0b5c72;
  --t7:#6a645a;  --t15:#1a1815;

  color-scheme:light;
}

/* ════════════════════════════════════════════════════════════════════════
   HUD — THE THIRD APPEARANCE, AND THE FIRST ONE THAT IS A *SKIN*.

   Dark and light are the same interface in two lightings. HUD is a different
   instrument wearing the same bones: a void ground, every hairline emitting
   the hue, and elevation carried by LIGHT AT THE EDGE rather than by a surface
   getting paler. Opt-in, remembered, and dark stays the default.

   It comes in two colourways — `red` and `pink` — chosen with a second
   attribute, `data-skin`. Everything in this block resolves from --hud /
   --hud-rgb, which is why the pink colourway at the foot is FOUR LINES and not
   a second theme to keep in step.

   ── THE ONE LINE THAT DOES MOST OF THE WORK ───────────────────────────────
   `--line` and `--line2`. Every panel edge, divider, input border, pill and
   chip in this app resolves from those two names — that is what a palette
   that was never forked buys you. Turning them into the hue turns the whole
   console into a drawn instrument in one declaration, without a single
   component knowing a skin exists.

   ── WHAT MAKES THIS A DESIGN AND NOT A NEON FILTER ────────────────────────

   1 · TYPE STAYS BONE. Body text is never the hue. The hue carries EYEBROWS,
       edges, marks, the cursor and one alarm — the things you read at a
       glance and not the things you read. This is the whole difference
       between a HUD and a skin off a 2003 media player, and it is why the
       measured table below has --ink at 19:1 rather than a red at 5:1 doing
       a job it should never be given.

   2 · ELEVATION IS EMISSION. In dark, rising means getting lighter
       (bg → card → elev). On a true-black ground that scale has almost
       nowhere to go, and faking it with grey is how a black UI turns muddy.
       So a raised surface here is still nearly black and is lit at its top
       edge instead: --sh-card and --sh-lift carry an inset hue highlight,
       and --line brightens to --line2 as a thing rises. The ladder is intact;
       it is drawn in light rather than in paint.

   3 · THE ACCENT BUDGET IS DELIBERATELY SPENT, AND ONLY OUTSIDE THE TEXT.
       tokens.css's standing law — one accent, counted per zone, or it is
       wallpaper — governs the DEFAULT console, and it still does. A skin
       whose entire proposition is "the machine draws itself in one hue"
       cannot also ration that hue to five selectors. What does NOT move is
       the reason behind the law: nothing a person has to READ becomes the
       accent, and no bone text is ever given a glow. Legibility never pays
       for the atmosphere.

   4 · GLOW EXISTS HERE, AND IT IS COUNTED. Law 4 in style.css ("no glow, no
       shadow") is a rule about the default console, where a glow can only be
       decoration. Here light IS the medium — but it is only ever emitted by
       something that is ALREADY the hue (an edge, a mark, a cursor). A glow
       under bone type is the cheap version and is not used anywhere.

   ── THE INK SCALE, MEASURED ───────────────────────────────────────────────
   sRGB → linear → relative luminance → (L1+.05)/(L2+.05), same method as the
   dark and light blocks. AA body text is 4.5:1; a non-text mark that carries
   meaning is 3:1.

                     on --bg   on --card  on --elev  on --elev2
     --ink            19.1       18.5       18.0       17.3
     --sec            10.8       10.5       10.2        9.7
     --mut             5.7        5.5        5.3        5.1
     --dim             3.1        3.0        2.9        2.8     marks only
     --hud  (red)      5.3        5.2        5.0        4.8
     --hud  (pink)     6.3        6.1        5.9        5.7
     --good           12.6       12.2       11.8       11.4
     --warn           13.1       12.7       12.3       11.8

   🚨 BOTH HUES CLEAR 4.5:1 ON EVERY SURFACE, and that was a constraint on
   picking them, not a happy result. The obvious poster reds (#e60012 and
   below) land at 3.9:1 and are why neon UIs read cheap: the accent is
   unreadable, so it can only ever be decoration, so it ends up everywhere.
   An accent that PASSES can carry a label, which is what lets it be
   structural.

   ⚠️ --dim FAILS 4.5:1 HERE TOO, exactly as it does in both other themes, and
   the same rule holds: --dim is for marks that carry no information a person
   has to read. Anything carrying a fact is --mut or better.

   ⚠️ THE SKIN IS ON <html>, WHICH IS WHY THE DERIVED TOKENS ARE SAFE.
   `--paper:var(--bg)`, `--fill:var(--elev2)` and friends are declared once, in
   the :root block above, and :root IS this element — so they recompute against
   the values below with nothing restated. 🚨 IF THIS SELECTOR IS EVER MOVED TO
   A DESCENDANT (a skinned pane, a preview frame) THAT STOPS BEING TRUE: a
   `var()` inside a custom property is substituted on the element that DECLARED
   it, so every derived token would freeze at the dark value while the direct
   ones flipped, and half the app would skin. That failure is silent and it has
   already been paid for once on Moxi —
   `feral-parts find "inherited css redeclared on the skin"`.
   ════════════════════════════════════════════════════════════════════════ */
html[data-theme="hud"]{
  /* ── THE HUE. The only thing the second colourway changes. ──────────────
     🚨 GREP THE APP BEFORE NAMING A PROPERTY YOU DECLARE ON <html>. A skin's
     hue lives on the root element, so it INHERITS INTO EVERYTHING — which means
     it does not merely add a name, it silently answers every `var()` of that
     name that was relying on being unset. Two obvious names were tried and both
     were already taken, in two different apps, and both failures are invisible:

       --acc   feral·work's PER-SESSION chat accent, set by `.acc0`–`.acc7` in
               style.css and read in 50 places. Declared here it would have
               killed the `var(--acc,transparent)` fallback on `.srow.mine` and
               painted a bar on every row you own, and tinted every uncoloured
               chat through `color-mix(in srgb,var(--acc) N%,…)`.
       --hue   feral·yap's AVATAR HUE, which is a NUMBER in degrees composed as
               `hsl(var(--hue,0) …)`. Handed a colour that expression is invalid
               at computed-value time, so it does not fall back — it unsets. The
               whole app's avatars would have gone transparent.

     Neither was found by looking at the app. Both were found by grepping.
     `--hud` is free in both, and the same name is used in both on purpose. */
  --hud:var(--hud-red); --hud-hi:var(--hud-red-hi); --hud-rgb:var(--hud-red-rgb);

  /* surfaces — a VOID, and objects defined by their edge rather than their
     fill. --bg is true #000 and not the dark theme's #050505: the hue only
     reads as EMITTED against black, and at #050505 every glow sits on a
     visible grey plate. The three steps above it are barely-there on purpose;
     see note 2 above for where the elevation actually went. */
  --bg:#000000; --card:#050507; --elev:#0a0a0d; --elev2:#101014;
  --well:rgba(0,0,0,.5);
  /* …and what the SHELL wears, which in this appearance is not --bg. See the
     --chrome-* register at the top of the file for why, and for the measurement. */
  --chrome:var(--chrome-red);

  /* 🚨 THE HUD, IN TWO DECLARATIONS. Read the note at the top before touching
     these: every edge in the app is downstream of them. */
  --line:rgba(var(--hud-rgb),.22); --line2:rgba(var(--hud-rgb),.44);

  /* The filled control. In dark this is --elev2 and reads as raised; on black
     that is a dark grey lozenge with no authority at all, so the one primary
     action per screen is a hue-washed plate with a lit edge — the only object
     in the app allowed to be a field of accent. */
  --fill:rgba(var(--hud-rgb),.14); --on-fill:#fff;
  --fill-edge:rgba(var(--hud-rgb),.6); --fill-hover:rgba(var(--hud-rgb),.22);
  --field:#050507;
  /* A hover LIGHTS rather than lifts — same reason as light mode's inversion,
     opposite direction: there is no paler black to move to. */
  --hover:rgba(var(--hud-rgb),.07);

  /* the box gauge — the rest band and the soft band go hue-neutral bone as
     before, but the redline is the skin's own alarm hue so the instrument
     reads as one piece. Same alphas as dark: the ground is darker here, not
     lighter, so nothing needs pulling down the way light did. */
  --g-zone:linear-gradient(90deg,rgba(var(--warn-rgb),.10),rgba(var(--crit-rgb),.26));
  --g-rest:rgba(var(--ink-rgb),.13);
  --g-soft:rgba(var(--ink-rgb),.05);
  --g-seat:rgba(var(--good-rgb),.5);

  /* type — cool bone, one notch colder than dark's neutral greys because on a
     true-black ground a warm grey reads as dirty rather than as quiet. */
  --ink:#f4f4f6; --sec:#b9b9c2; --mut:#84848f; --dim:#5b5b66;
  --ink-max:#fff;
  --ink-rgb:244,244,246;

  /* red — the identity channel, which in this skin IS the hue. Every value is
     derived, so `pink` at the foot inherits all of it. --red-deep/--red-ink
     are gradient STARTS and composite over #000, which makes the alpha form
     exactly equal to the solid one the dark block spells out. */
  --red:var(--hud); --red-core:var(--hud-hi);
  --red-deep:rgba(var(--hud-rgb),.15); --red-ink:rgba(var(--hud-rgb),.08);
  --red-glow:rgba(var(--hud-rgb),.5); --red-dim:rgba(var(--hud-rgb),.14);
  --red-line:rgba(var(--hud-rgb),.55);
  --red-rgb:var(--hud-rgb);

  /* ⚠️ --work IS NOT REDECLARED HERE, AND THAT IS DELIBERATE — SAME CALL AS
     --volt ABOVE. It was briefly set to var(--hud) on the reasoning that a
     violet disc in a red instrument reads as a fault. HARRY, 2026-08-23, looking
     at the painted result: *"not in red. I don't like the red."* He is right and
     the reasoning was backwards: the accent budget at the head of this file
     calls the brand dot EXEMPT, and a mark that changes hue with the appearance
     is not a mark. It inherits the dark block's violet in both colourways, which
     is the only ink on this skin that is not the skin's own. */

  /* ⚠️ --volt STAYS BLUE, IN BOTH COLOURWAYS, AND THAT IS THE POINT.
     It is not a decorative second accent — it is the channel that means YOU
     (your voice while you speak it, your words once sent) against --red, which
     means FERAL and where you are. A skin that repainted it in the skin's own
     hue would collapse two channels into one and lose the distinction the
     split was built for. It is pushed one step colder and brighter for the
     black ground; it is not moved off blue. */
  --volt:#3d8bff; --volt-core:#8ab4ff;
  --volt-deep:#03091a;
  --volt-glow:rgba(138,180,255,.42); --volt-dim:rgba(61,139,255,.15);
  --volt-line:rgba(61,139,255,.52);
  --volt-wash:rgba(61,139,255,.24); --volt-wash-soft:rgba(61,139,255,.085);

  /* status — pushed into a phosphor register: higher chroma, higher
     luminance, because on black a muted status colour reads as switched off
     rather than as calm. All three clear 11:1. */
  --crit:#ff4757; --good:#2fe39a; --warn:#ffc24a;
  --cyan:#3ce7ff;
  --crit-ink:#ff7a86;
  --good-rgb:47,227,154; --warn-rgb:255,194,74; --crit-rgb:255,71,87;
  --cyan-rgb:60,231,255;

  --on-good:#00140c; --on-warn:#1a1204;
  --on-media:#8e8e99;
  --media:#000000;
  --skel:#0d0d11;

  /* ⚠️ FOCUS STAYS CYAN — the one thing on the screen that is NOT the skin's
     hue, which is exactly what makes "the keyboard is here" unmissable on a
     surface where everything else glows. Making it the accent would hide the
     focus ring inside the chrome. */
  --focus:rgba(60,231,255,.6);

  /* Radii tighten. A HUD is drawn with a rule, not moulded — 20px on a panel
     whose edge is a lit hairline reads as a soft app wearing a costume. Not
     square, though: at 0 the corner brackets in skin.css have nothing to sit
     on and the whole thing turns brutalist. */
  --r-xl:10px; --r-lg:8px; --r-md:6px; --r-sm:4px;

  /* ⚠️ SHADOWS BECOME EDGE LIGHT — see note 2. The inset top highlight is the
     hue rather than bone, which is what makes a card read as LIT from its own
     rim rather than as a grey step. The drop half stays, deepened: on a black
     ground a shadow separates a floating thing from the void, and without it a
     popover has no depth at all. */
  --sh-card:inset 0 1px 0 rgba(var(--hud-rgb),.16),0 1px 2px rgba(0,0,0,.6);
  --sh-lift:inset 0 1px 0 rgba(var(--hud-rgb),.2),0 1px 2px rgba(0,0,0,.6),0 14px 34px -16px rgba(0,0,0,.9);
  --sh-pop:0 32px 84px rgba(0,0,0,.92),0 0 0 1px rgba(var(--hud-rgb),.26),inset 0 1px 0 rgba(var(--hud-rgb),.22);
  --sh-float:0 18px 46px rgba(0,0,0,.8);
  --sh-hero:0 14px 36px -18px rgba(0,0,0,.95);
  --sh-inset:inset 0 1px 2px rgba(0,0,0,.6);
  --sh-btn:0 1px 2px rgba(0,0,0,.4);

  --scrim:rgba(0,0,0,.78); --scrim-strong:rgba(0,0,0,.9);
  --page-glow:radial-gradient(96% 62% at 50% 108%,rgba(var(--hud-rgb),.12),transparent 62%);

  /* ── THE TERMINAL, IN HUD ───────────────────────────────────────────────
     🚨 THE SIXTEEN ANSI COLOURS KEEP THEIR MEANINGS. The tempting move is to
     make the whole terminal monochrome in the skin's hue, and it destroys
     information: a diff, a test run and a `systemctl status` all say what they
     say in green and red. So the palette is pushed into a PHOSPHOR register —
     same hues, higher chroma, lifted off the black — and the skin's own colour
     is carried by the cursor and the selection, which are chrome and belong to
     the app rather than to the program running in it.

     ⚠️ --t1 IS A HOT RED IN BOTH COLOURWAYS AND IS NOT WIRED TO --hud. In the
     pink skin an accent-coloured --t1 would paint every error message in the
     chrome colour, and "this line is wrong" would look like furniture. Red
     means error in a pink HUD exactly as it does everywhere else. What the
     pink skin gets instead is --t5, which is genuinely its hue and is
     magenta's job already.

     ⚠️ app.js keeps minimumContrastRatio at 1 here, as in dark — the ramp
     below clears AA on #000 on its own and does not want the engine shifting
     lightness underneath it. */
  --term-bg:#000000; --term-ink:#d9d9e0; --term-cursor:var(--hud);
  --term-sel:rgba(var(--hud-rgb),.3);
  /* The visor's one accent, at the weight the skin uses for its own furniture.
     It follows --hud-rgb, so the pink colourway gets a pink slider for free. */
  --term-slider:rgba(var(--hud-rgb),.22);
  --term-slider-hover:rgba(var(--hud-rgb),.38);
  --term-slider-active:rgba(var(--hud-rgb),.55);
  --t0:#151519;  --t8:#6a6a76;
  --t1:#ff3b4d;  --t9:#ff7b87;
  --t2:#2fe39a;  --t10:#5ef0b6;
  --t3:#ffb224;  --t11:#ffc95c;
  --t4:#5b8cff;  --t12:#8ab0ff;
  --t5:#ff5ecb;  --t13:#ff92da;
  --t6:#3ce7ff;  --t14:#7cf0ff;
  --t7:#d9d9e0;  --t15:#ffffff;

  color-scheme:dark;
}

/* ── THE SECOND COLOURWAY ──────────────────────────────────────────────────
   Neon pink. Four lines, because every rule above resolves from --hud.

   ⚠️ IT IS NOT THE RED WITH ITS HUE ROTATED. Pink sits ~1.2:1 brighter than
   the red at the same alphas, so a hairline at .22 that is a whisper in red is
   a drawn line in pink — which reads as a heavier, busier app rather than a
   pinker one. The two alpha nudges below are what make the two colourways the
   same WEIGHT of instrument, and they are the only structural difference
   between them. */
html[data-theme="hud"][data-skin="pink"]{
  --hud:var(--hud-pink); --hud-hi:var(--hud-pink-hi); --hud-rgb:var(--hud-pink-rgb);
  --line:rgba(var(--hud-rgb),.19); --line2:rgba(var(--hud-rgb),.38);
  --chrome:var(--chrome-pink);
}

*{box-sizing:border-box;margin:0;padding:0}
/* 🚨 THE hidden ATTRIBUTE LOSES TO ANY AUTHOR `display`. The UA stylesheet sets
   [hidden]{display:none}, but .empty{display:grid} and .denied{display:grid}
   are author rules of equal specificity and later origin, so they WIN — and
   every panel marked hidden rendered anyway, stacked on top of each other. A
   screenshot caught it in one look; no test would have. This line is the fix
   and it must stay above every component. */
[hidden]{display:none!important}
/* 🚨 THE PALETTE DOES NOT DECIDE WHETHER A PAGE SCROLLS.
   This rule used to end `overflow:hidden;height:100vh`, which is right for an APP
   SHELL with its own internal scroll panes and catastrophic for a DOCUMENT — and
   this file is inlined by every document the estate renders (`feral-doc` reads it
   live, by design, so a deliverable follows feral·work's palette automatically).

   MEASURED 2026-08-07, with a real wheel gesture against every page on the
   preview door: FIVE of twelve could not be scrolled at all, holding 15,954px of
   content nobody could reach. Harry, twice in one day — "why cant i scroll down i
   need to see info on what i lost", then "there's this bug where you can't
   scroll… make sure that's fixed across everyone's site and server-wide."
   ⚠️ The first report was fixed by hand-writing an override into ONE page. The
   generator kept shipping the bug; that is why he had to say it again.

   ⚠️ REMOVING IT COSTS feral·work NOTHING, and that is why this is the right
   place to fix it rather than in each consumer. style.css:938 already declares
   `html,body{height:100%;overflow:hidden;overscroll-behavior:none}` plus
   `body{position:fixed;inset:0}`, and index.html loads style.css AFTER this file
   — so the app has never been governed by this line. It was pure redundancy here
   and pure poison everywhere else. A document that WANTS to be an app shell says
   so in its own stylesheet, where the reader can see it. */
body{background:var(--bg);color:var(--ink);font-family:var(--sans);font-size:14px;line-height:1.5;
  -webkit-font-smoothing:antialiased}
body::before{content:"";position:fixed;inset:0;z-index:0;pointer-events:none;background:var(--page-glow)}
a{color:inherit;text-decoration:none}
button{font-family:inherit}
::selection{background:var(--red-line);color:var(--on-accent)}

:focus{outline:none}
:focus-visible{outline:2px solid var(--focus);outline-offset:2px;border-radius:var(--r-sm)}

*{scrollbar-width:thin;scrollbar-color:rgba(var(--ink-rgb),.16) transparent}
::-webkit-scrollbar{width:10px;height:10px}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{background:rgba(var(--ink-rgb),.13);border-radius:999px;
  border:3px solid transparent;background-clip:padding-box}
::-webkit-scrollbar-thumb:hover{background:rgba(var(--ink-rgb),.24);border:3px solid transparent;background-clip:padding-box}
::-webkit-scrollbar-corner{background:transparent}

.mono{font-family:var(--mono);font-variant-numeric:tabular-nums}
.kick{font-family:var(--mono);font-size:10px;letter-spacing:.2em;text-transform:uppercase;color:var(--mut)}
kbd{font-family:var(--mono);font-size:10px;background:var(--elev);border:1px solid var(--line);border-radius:5px;padding:1px 6px;color:var(--sec)}
.pill{display:inline-flex;align-items:center;gap:6px;font-family:var(--mono);font-size:9px;letter-spacing:.09em;
  text-transform:uppercase;padding:2px 8px;border-radius:999px;border:1px solid var(--line);color:var(--mut);white-space:nowrap}

@media(prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important}}
