/* HSL design tokens — extracted from HSL_Design_System_dc.html (first-declared theme).
   Fonts per design system: display = Fraunces-style display serif fallback, UI = Plus Jakarta Sans, mono = JetBrains Mono-style.
   Color roles: --brand teal (actions/links/selection), --accent green (financial confirmations ONLY),
   warm neutral ink scale for text/surfaces/rules. Status: pend/eval/redy/rejt/paid. */
:root {
  /* Tells the browser which way the *native* furniture should lean —
     scrollbars, <select> popups, date pickers, spin buttons, the form-control
     defaults no stylesheet of ours reaches. Without it those stay light in
     dark mode and the page ends up with a white scrollbar down the side of a
     black window. Declared explicitly as `light` rather than `light dark`
     because the theme here is ours to decide: `light dark` would let the OS
     override the user's explicit "Light" choice for native widgets only, so
     the page and its scrollbar would disagree. The dark blocks below flip it. */
  color-scheme: light;

  --accent: var(--g-500);
  --accent-soft: var(--g-100);
  --brand: var(--b-500);
  --brand-hi: var(--b-400);
  --brand-line: var(--b-200);
  --brand-lo: var(--b-800);
  --brand-soft: var(--b-50);
  --cell-y: 6px;

  /* Motion durations, from the design system (HSL Design System.dc.html:55).
     Nothing consumed them before, so every transition in hirms.css had invented
     its own timing — .12s here, .15s there, .16s a hundred lines later. Three
     steps is the whole vocabulary: fast for a hover or a caret, base for a
     surface arriving, slow for a value bar travelling to a new width. */
  --d-base: 200ms;
  --d-fast: 120ms;
  --d-slow: 320ms;
  --e-1: var(--glass-hi),0 1px 0 var(--rule);
  --e-2: var(--glass-hi),0 1px 2px rgba(8,20,58,.04),0 6px 22px rgba(8,20,58,.07);
  --e-3: var(--glass-hi),0 1px 2px rgba(8,20,58,.04),0 18px 44px rgba(8,20,58,.07);
  --e-4: var(--glass-hi),0 2px 4px rgba(8,20,58,.06),0 28px 64px rgba(8,20,58,.12);

  /* The two easing curves that go with the durations above (dc.html:56).
     --ez-out decelerates into rest, which is what anything arriving or settling
     into a new state wants. --ez-io eases both ends and is for motion that
     loops, where there is no arrival to emphasise. */
  --ez-io: cubic-bezier(.55,0,.28,1);
  --ez-out: cubic-bezier(.2,.9,.28,1);
  /* Three families became two: Inter carries display AND UI. Aliased
     rather than deleted — one line here instead of 15 edits in
     hirms.css, and the distinction stays available if the book ever
     re-splits. */
  --f-disp: var(--f-ui);
  --f-mono: 'JetBrains Mono',ui-monospace,'SFMono-Regular',monospace;
  --f-ui: 'Inter','Helvetica Neue',Arial,system-ui,sans-serif;
  --glass-blur: blur(16px) saturate(1.35);
  --glass-hi: inset 0 1px 0 rgba(255,255,255,.55);

  /* Cards go glass in light mode only — same treatment .hs-card-glass already
     defined but that nothing on any page opted into.

     Literal values, not var(--surface)/var(--glass-blur): a custom property
     is late-bound, so referencing another theme-varying token here would
     silently pick up THAT token's dark-block override the moment
     [data-theme="dark"] was set, even though this declaration itself lives
     only in the light block below — :root and :root[data-theme="dark"] are
     the same element, not separate scopes, so an unresolved reference keeps
     tracking the cascade instead of freezing to the value in force where it
     was written.

     And because they are the same element, declaring these ONLY here does
     not by itself keep them out of dark mode either — cancelled explicitly
     in both dark blocks below (back to plain --surface, no blur), the same
     way every other light/dark-varying token in this file is handled. */
  --card-bg: color-mix(in srgb, rgba(255,255,255,.72) 72%, transparent);
  --card-blur: blur(16px) saturate(1.35);

  /* The graph-paper wash the design paints behind the page (dc.html:28, used at
     :94 as a 24px repeating gradient). Deliberately almost invisible — it gives
     the surfaces something to sit on rather than being a pattern anyone reads.
     Declared here so the value exists when a shell wants it; nothing draws it
     yet, and a token nobody consumes costs nothing. */
  /* Midnight, not the retired warm ink. This token has NO consumer since
     both 24px lattices were removed on 19 Aug; it is kept because tenant
     branding may want a wash back, and it is repainted so that if one
     ever is, it arrives in the current identity rather than the old one. */
  --grid-line: rgba(8,20,58,.045);
  --ink: var(--i-950);
  --ink-2: var(--i-500);
  --ink-3: var(--i-400);
  --lh-1: 1;
  --lh-base: 1.52;
  --lh-snug: 1.3;
  --lh-tight: 1.14;
  --neg: #E0483C;

  /* The clipped corner on the design's cards and panels (dc.html:47). This is
     also the motif's kill switch: it ships as a single token precisely so that
     setting it to 0px flattens every notch in the product at once, without
     hunting down the clip-paths that consume it. Tenant branding may want that;
     so may a printer. */
  --notch: 18px;
  --on-accent: var(--ink);   /* Midnight on Success = 6.57:1. NOT white:
                                white on #12B27E is 2.73:1 and fails even
                                the 3:1 large-text floor. */
  /* The colour that sits ON a --brand fill, and it MUST flip with the theme:
     white is 4.51:1 on light --brand and 3.53:1 on the lifted dark one,
     while Midnight is 5.07:1 dark and 3.98:1 light. Each passes in exactly
     one theme, so neither can be a constant. */
  --on-brand: #fff;

  /* The Pulse button is the exception, and needs its own token because of it.
     --g-pulse is theme-INVARIANT -- the same #2D6BFF -> #1A7CB8 in both
     themes -- so it wants white in both. If it borrowed --on-brand it would
     take Midnight in dark and land at 3.98:1. Defined once here and
     deliberately NOT redefined in the dark block. */
  --on-pulse: #fff;

  /* Same shape as --on-pulse, same reason, and it was found the hard way.
     --g-card is theme-INVARIANT: the member card is the one surface the book
     says stays bright in both themes, so its plate is Purple -> Blue in dark
     exactly as in light. The card was taking --on-brand, which now flips to
     Midnight in dark, so a bright plate got dark navy type:

         Midnight on --g-card    3.60:1 on Purple, 3.98:1 on Blue
         white    on --g-card    4.98:1 on Purple, 4.51:1 on Blue

     The 20px/700 name is large text and survives at 3:1, but the kicker (9px),
     the MSO number (13px) and the detail row (12px) all need 4.5 and got
     3.60-3.98. Measured on a real dark run, not inferred.

     Defined once and never redefined below, which is the whole mechanism: an
     invariant surface needs an invariant on-colour, and a theme-flipping token
     is the wrong tool for it however convenient it looks. */
  --on-card: #fff;

  /* P66f (owner, 3 October: "that's the colour we want, brand book v2"):
     the hero figure stands on the book's SIGNAL ground - Purple, Blue, Cyan,
     Mint, the four stops of --g-signal - re-angled and re-stopped for a card
     that carries white type. It cannot be var(--g-signal) itself: a custom
     property cannot change another gradient's angle or stops, and --g-signal's
     36% Blue / 70% Cyan would put Cyan (about 2:1 under white) beneath the
     sub-line. Here Blue holds to 74% and the Cyan and Mint stops fall in the
     bottom-right corner, where the glyph sits and no text does (the text
     column is 60% of the card, hirms.css .hs-hero-text). White measures
     4.98:1 on Purple and 4.51:1 on Blue; every text box's sampled ground is in
     the hand-in (P66f), both themes, 1440 and 390. Theme-INVARIANT, defined
     once like --g-card / --on-card: the dark block never redefines it. */
  /* The Signal palette RE-STOPPED FOR TYPE. Do not "fix" it back to var(--g-signal):
     that puts Cyan under white text (HsHeroFigureTests pins the Blue stop). */
  --g-hero: linear-gradient(100deg, #6F52F6 0%, #2D6BFF 74%, #20C5E8 90%, #20D6A1 100%);
  --on-hero: #fff;

  /* Same flip as --on-brand, for the same reason: white is 6.86:1 on the
     light danger red and 2.19:1 on the lifted dark one. .hs-btn-danger used
     to hardcode #fff, which the CI guard sanctions as raw hex -- which is
     precisely why nobody noticed it was unreadable in dark. */
  --on-danger: #fff;
  --pad-card: 13px;

  /* Density: compact, always. The design system's [data-density="compact"]
     values, promoted to defaults. HIRMS is read by assessors working a queue of
     hundreds; a comfortable row height costs them screenfuls. The toggle is
     deliberately absent — two densities means every screen has to be right at
     both, and the second one is never the one anybody checks. */
  --row-h: 34px;
  --ctl: 32px;
  --ctl-sm: 27px;
  --paper: var(--i-50);
  --pos: #12B27E;
  --r-full: 999px;
  --r-lg: 14px;
  --r-md: 8px;
  --r-sm: 5px;
  --r-xl: 20px;
  --r-xs: 3px;

  /* The soft brand halo (dc.html:53). Not the same thing as the focus outline,
     which is a hard 2px line and belongs to the keyboard: this is the diffuse
     ring a field or a toggle wears while it is the active one, and it may be
     shown to a mouse user too. Keeping them separate means a designer can
     soften this without weakening the accessibility floor. */
  --ring: 0 0 0 3px rgba(45,107,255,.22);
  --rule: var(--i-100);
  /* A six-step ramp for ORDER along a path (the money bar, 27 Sep 2026): steps of
     the existing Blue scale, light to dark, plus a grey for a stage off the path.
     Sequence, not status: a swatch and a name always sit beside it. Immutable
     (semantic), never a brandable token. */
  --ramp-1: var(--b-100); --ramp-2: var(--b-200); --ramp-3: var(--b-300);
  --ramp-4: var(--b-500); --ramp-5: var(--b-700); --ramp-6: var(--b-900); --ramp-off: var(--i-300);
  --rule-2: var(--i-300);
  /* CONSOLE-3: the sunken cell's hairline — ink at low opacity, inset (tiles, legend). */
  --cell-hairline: color-mix(in srgb, var(--ink) 14%, transparent);
  /* CONSOLE-3c (Kevin, 4 Oct 2026, LOCKED): the seven stage tones of the console's bar and legend —
     graphic only (a dot beside the word, a bar segment), never on text: Cyan and Mint set no type. */
  --stage-notyet: color-mix(in srgb, var(--ink) 35%, transparent);
  --stage-decided-without-claim: color-mix(in srgb, var(--ink) 60%, transparent);
  --stage-awaiting: var(--b-500);
  --stage-pending: var(--st-pend-dot);
  --stage-requisitioned: var(--c-400);
  --stage-paid: var(--g-400);
  --stage-rejected: var(--st-rejt-dot);
  --s1: 4px;
  --s10: 40px;
  --s12: 56px;
  --s2: 8px;
  --s3: 12px;
  --s4: 16px;
  --s5: 20px;
  --s6: 24px;
  --s8: 32px;
  --st-eval: #1B4ACB;
  --st-eval-bg: #EAF0FF;
  --st-eval-line: rgba(45,107,255,.28);
  --st-paid: #4C34C7;
  --st-paid-bg: #F0EDFE;
  --st-paid-line: rgba(111,82,246,.28);
  --st-pend: #8A5A0F;
  --st-pend-bg: #FDF2E3;
  --st-pend-line: rgba(232,163,61,.35);
  --st-redy: #0A7A56;
  --st-redy-bg: #E4F7F0;
  --st-redy-line: rgba(18,178,126,.30);
  --st-rejt: #A82D22;
  --st-rejt-bg: #FDEDEB;
  --st-rejt-line: rgba(224,72,60,.30);

  /* The graphic half of the pairing. Book rule 3: colour is never the only
     signal — roughly 1 in 12 clinical users cannot separate red from green
     reliably, and here that is "Ready to pay" vs "Rejected". */
  --st-eval-dot: #2D6BFF;
  --st-paid-dot: #6F52F6;
  --st-pend-dot: #E8A33D;
  --st-redy-dot: #12B27E;
  --st-rejt-dot: #E0483C;

  /* Functional roles — product UI only, never marketing. */
  --success: #12B27E;
  --warning: #E8A33D;
  /* The one foreground that carries on Warning. 12.1:1 on #E8A33D, and warm
     rather than Midnight because the ground is amber. Tokenised 2026-09-15:
     it shipped as a raw hex in .hs-mast-env and CI's design guard fails the
     build on exactly that - a new hex owes a new token. Same value, so the
     pill is unchanged to the pixel. */
  --on-warning: #1B1200;
  --error: #E0483C;
  --info: #2D6BFF;
  --disabled: #B9C2D8;

  /* Gradients. NOTE the prefix clash: --g-100..--g-700 are the Mint RAMP,
     while --g-signal/pulse/vital/depth are GRADIENTS. Different families,
     same two letters — the map names them this way and the mocks reference
     them, so they are kept, but do not read --g-400 and --g-vital as siblings.
     Pulse stops at #1E8FD4 rather than the book's #20C5E8: white on full Cyan
     is 2.06:1, so a button running the whole way could not carry a white
     label. This holds it above 3:1 across the entire fill. */
  /* Stops are the kit README's, not evenly spaced: 115deg, #6F52F6 0%,
     #2D6BFF 36%, #20C5E8 70%, #20D6A1 100%. Four colours with no positions
     distribute at 0/33/67/100, which drifts the Blue->Cyan handover and lands a
     visibly different ramp from the one the book prints. The positions are the
     spec; carrying the colours alone is only two thirds of it. */
  --g-signal: linear-gradient(115deg,#6F52F6 0%,#2D6BFF 36%,#20C5E8 70%,#20D6A1 100%);
  /* The end stop is #1A7CB8, darker than the handoff's #1E8FD4, and this is
     a threshold correction rather than a taste one. The handoff stopped
     short of full Cyan to clear 3:1, treating the button label as large
     text. It is not: .hs-btn sets --t-sm, 13px semibold, which is below
     every large-text definition, so the label needs 4.5:1. Measured, white
     on #1E8FD4 is 3.54:1 -- it failed. #1A7CB8 is the same hue walked down
     to 4.55:1, so white clears AA across the WHOLE fill rather than only
     its first half.

     SAID PLAINLY, BECAUSE THE OMISSION HAS ALREADY MISLED ONE DESIGN PASS:
     this is NOT the book's Pulse and #1A7CB8 is NOT a palette colour. The
     book (p23) defines Pulse as Blue -> Cyan, and adds "four stops maximum,
     never insert an intermediate hue"; #1A7CB8 is our own darkened Blue and
     the palette (p21) has six colours, none of them this one. The deviation
     is defensible on its own terms -- p24 rules Cyan a graphic colour and
     not a text colour, so a Pulse fill cannot carry a 13px white label and
     the book contradicts itself at this size -- but it must not be quoted
     as book-accurate. docs/html/karine-chat-option-b-aesthetic.html:55 does
     exactly that and is wrong.

     WHERE A PALETTE COLOUR WILL DO, SPEND IT INSTEAD. p24 lists "Blue
     surface . white text" as a SAFE COMBINATION, and --brand is the book's
     Blue #2D6BFF: white on it measures 4.51:1, which clears AA without
     inventing a hue. Anything that only needs a filled primary should take
     solid --brand + --on-brand rather than this gradient -- see
     .hs-karine-send (hirms.css), which does. This token is for the fills
     that genuinely want the Pulse ramp. */
  --g-pulse: linear-gradient(115deg,#2D6BFF,#1A7CB8);
  --g-vital: linear-gradient(115deg,#20C5E8,#20D6A1);
  --g-depth: linear-gradient(150deg,#08143A,#6F52F6);

  /* The member card's plate. Signal's OPENING PAIR only — Purple to Blue —
     and stopping there is the same documented deviation Pulse makes, for the
     same reason and with harder numbers.

     The card carries 12px text across its FULL width (.hs-membercard .row is
     justify-content: space-between, so there is white type at the right edge
     as well as the left), which needs 4.5:1, not the 3:1 large-text floor.
     Sampled every 5% across each candidate ramp:

       full Signal to Mint          worst 1.88:1   fails
       Signal stopped at #1E8FD4    worst 3.54:1   fails at 12px
       Purple -> Blue               worst 4.51:1   passes

     Deliberately NOT redefined in the dark block: the member card is the one
     surface the book says must stay bright in both themes. Leaving it out of
     dark is what keeps it identical, not an omission. */
  --g-card: linear-gradient(115deg,#6F52F6,#2D6BFF);

  --aurora-1: rgba(111,82,246,.30);
  --aurora-2: rgba(45,107,255,.24);
  --aurora-3: rgba(32,197,232,.22);

  /* The mark, as a watermark behind every surface. ONE dial, deliberately, so it
     can be tuned in the browser and in one place rather than hunted through
     rules — the same reason the aurora exposes its hues and its layer opacity
     separately.

     Low, and low on purpose. This sits behind claim grids and money columns, so
     it has to read as texture without lifting the background luminance under
     text — that would quietly erode ratios solved to exactly 4.5:1 (--i-400
     among them, which drove a 29-rule repaint). Verified on /claims before and
     after rather than assumed.

     --i-400 has since been given real headroom (5.02:1 — see its own note
     below), so this dial is no longer the only thing standing between that
     token and a fail. Read that as slack for the aurora, NOT as budget to
     raise this value: the reason the headroom exists is that layered
     decoration was measured spending it.

     Anchored right and bled off the edge instead of centred: text columns start
     at the left, so the densest part of the mark sits where the fewest glyphs
     are. A centred watermark also reads as a stalled loading state, which is
     precisely the wrong association on a screen that has finished loading. */
  --wm-opacity: .045;
  --wm-size: min(52vw, 620px);
  /* The watermarked mark itself. A token so a tenant's published logo can
     replace it from one declaration on .hs-theme-root (BrandStyleBlock,
     Stage 1) and reach the canvas and all four per-surface marks at once.
     Relative to THIS file, which sits beside hirms.css, so both resolve it
     identically. */
  --wm-image: url('../img/hsl-icon.svg');

  --ff-num: 'cv05','ss03','tnum';
  --surface: rgba(255,255,255,.72);
  /* .85, not the .55 this shipped with — and the alpha is the whole change:
     the COLOUR is deliberately untouched.

     --surface-2 is the only surface token tinted to --paper's own colour
     instead of white, which quietly makes it the weakest ground in the
     system: text on it can never beat text on bare paper, because at alpha
     1.0 it IS bare paper. At .55 it also passed 45% of the aurora, and all
     three blobs stack under the filter bar (hirms.css .hs-filters). Measured
     on the running workbench 2026-08-22, --ink-3 on that bar read 3.51:1 and
     3.60:1, and on the grid footer 3.71:1 — the worst --ink-3 nodes on any
     route swept, and the only ones under 4.13:1. Sampled by setting each
     node's colour transparent and reading the pixel its glyphs actually sit
     on, so these are real composites, not the token's ratio against --paper.

     .85 is the minimum with margin: .80 clears 4.5:1 exactly, .85 lands at
     4.62–4.70 in light and 4.82 in dark. Raising alpha rather than darkening
     --i-400 far enough to cover the blob is what keeps that token clear of
     --ink-2 — see its note below, and note that neither move works alone.

     NOT recoloured to white, though white would raise the ceiling further:
     this token's job is to read as a RECESSED tint against the white
     --surface/--surface-3 cards, and whitening it would invert that role
     across all 33 rules that consume it, most of which are hover states. */
  --surface-2: rgba(245,247,252,.85);
  --surface-3: rgba(255,255,255,.86);
  /* Book §05 scale on this repo's nine step names. Six move; --t-xs is HELD at
     12px because the book has no step between 13 and 10 and folding it would
     move table meta text everywhere for no brand gain. --t-2xs 11->10 puts
     every column header and eyebrow at the book's LABEL size — check the claims
     queue at 1024px before signing this off, that is the densest place it
     lands.

     --lh-* and --tr-* are per-step because the book's scale is size PLUS
     line-height PLUS tracking as a set. Taking only the sizes gives smaller
     headings still on the old loose ratios with no negative tracking, which
     reads as generic — the opposite of the point. The older ratio tokens
     (--lh-tight/base/snug/1) stay for body copy. */
  --t-2xl: 28px;  --lh-2xl: 34px;  --tr-2xl: -.024em;
  --t-2xs: 10px;  --lh-2xs: 14px;  --tr-2xs: .180em;
  --t-3xl: 40px;  --lh-3xl: 44px;  --tr-3xl: -.028em;
  --t-4xl: 64px;  --lh-4xl: 60px;  --tr-4xl: -.042em;
  --t-lg: 17px;   --lh-lg: 27px;   --tr-lg: -.010em;
  --t-md: 15px;   --lh-md: 24px;   --tr-md: 0;
  --t-sm: 13px;   --lh-sm: 20px;
  --t-xl: 20px;   --lh-xl: 27px;   --tr-xl: -.020em;
  --t-xs: 12px;   --lh-xs: 18px;
  --w-black: 800;
  --w-bold: 700;
  --w-med: 500;
  --w-reg: 400;
  --w-semi: 600;
}

/* Palette scales. Repainted for Brand Book v2.0 / 2026 — the ramps keep their
   names and their shape, so the 1,614 var() references in hirms.css did not
   have to move.

   READ THIS BEFORE "CORRECTING" A STEP OFF A SCREENSHOT. The previous version
   of this comment argued at length that --b-600 was the brand and that --b-500
   was emphatically NOT the action colour, because in the teal ramp b-500
   (#0089B6) measured 4.0:1 — below AA. That reasoning was correct then and is
   FALSE NOW, because the ramp underneath it changed:

     --b-500 is now #2D6BFF, the book's Blue, measured 4.51:1 on white. It IS
     the action colour, and `--brand: var(--b-500)` above is deliberate.

   It clears AA with almost nothing to spare, though, so the rule that replaces
   the old one is: never darken the surface behind Blue text. On anything but
   white or Mist, step to --b-700 (#1B4ACB, 6.54:1).

   --b-*  interface Blue    actions, links, active states
   --g-*  Mint + Success    CAUTION, see below
   --p-*  Purple            labels, emphasis. Additive — no old ramp to break.
   --c-*  Cyan              GRAPHIC ONLY at every step
   --i-*  Midnight neutrals ink, surfaces, rules

   The --g-* caution: the old --accent (#8CC63F) carried WHITE TEXT on the EFT,
   paid and approve buttons. Mint cannot — it is 1.88:1 on white. So --accent
   maps to --g-500 (Success #12B27E) and Mint lives at --g-400 for FILLS ONLY:
   meter ticks, chart series, the Vital gradient. And white is not safe on
   #12B27E either (2.73:1); --on-accent is Midnight, which is 6.57:1.

   Cyan and Mint never set type and never sit under white text. Both are
   roughly 2:1 on white. They fill, stroke and tick. */
:root {
  --b-50: #EEF3FF;
  --b-100: #DCE7FF;
  --b-200: #B9CEFF;
  --b-300: #8FAEFF;
  --b-400: #5C8CFF;
  --b-500: #2D6BFF;
  --b-600: #1E55DB;
  --b-700: #1B4ACB;
  --b-800: #16327F;
  --b-900: #0E1F52;

  --g-100: #E3FBF3;
  --g-200: #B8F5E1;
  --g-300: #6FE7C4;
  --g-400: #20D6A1;
  --g-500: #12B27E;
  --g-600: #0E9268;
  --g-700: #0A7A56;

  --p-100: #F0EDFE;
  --p-200: #DCD4FD;
  --p-300: #B4A4FA;
  --p-400: #8B72FF;
  --p-500: #6F52F6;
  --p-600: #5A3BE0;
  --p-700: #4C34C7;

  --c-200: #C4F1FA;
  --c-300: #7ADCF1;
  --c-400: #20C5E8;
  --c-500: #1E8FD4;

  /* i-600 and i-800 are filled in rather than left at their old warm greys.
     Nothing consumes them today, so this is coherence — but two warm steps in
     the middle of a Midnight ramp is a trap for whoever reaches for one next. */
  --i-25: #FFFFFF;
  --i-50: #F5F7FC;
  --i-100: #E4E8F2;
  --i-200: #D5DCEB;
  --i-300: #B9C2D8;
  /* Darkened from the book's #8A93AB, which measures 2.86:1 on Mist and
     3.07:1 on white -- under AA, while driving 29 text rules as --ink-3.
     #66718F was the same hue walked down until it cleared 4.5:1 (4.53:1 on
     Mist). The book's DARK --ink-3 was already fine at 5.34:1 and is
     untouched; only the light value was wrong, which is why contrast.md
     called dark 'the tightest value' and never looked at light.

     #606A86 (2026-08-22) walks the same hue down a second time, to 5.02:1 on
     Mist. 4.53:1 was a pass against FLAT --paper and against nothing else --
     0.03 of margin, which is not a solved value but a value sitting on the
     line. Measured on the running workbench, the ground under --ink-3 is
     hardly ever flat paper: it is a translucent surface over the aurora, and
     that composite ran from 4.82:1 down to 3.51:1 across the 46 nodes that
     render this token on /, /claims, /queue and /members. Every node below
     4.13:1 sat on --surface-2; the remaining failures sat on card glass.

     Sized deliberately, and NOT sized to the worst pixel. Covering the 3.51:1
     case with the token ALONE needs #57607A, which measures 5.81:1 and is
     DARKER than --ink-2 (--i-500 #5A6480, 5.49:1): it would invert the ink
     ramp and make dim meta text heavier than the body text above it. #606A86
     buys real headroom and stops well short of --ink-2; --surface-2's alpha
     above carries the rest.

     Neither half works alone, which is why both moved. Fading the aurora
     cannot lift text on --surface-2 past 4.53:1 at ANY opacity, because that
     surface's colour is --paper's own -- at alpha 1.0 it IS bare paper. And
     the token cannot reach the blob without colliding with --ink-2. */
  --i-400: #606A86;
  --i-500: #5A6480;
  --i-600: #4A5570;
  --i-700: #384260;
  --i-800: #1A2450;
  --i-900: #111B44;
  --i-950: #08143A;
}

/* ── Dark theme ──────────────────────────────────────────────────────────────

   Ported, not designed. Every value below is lifted verbatim from the design
   system's own dark block (`docs/HSL Design System.dc.html:61-80`), which
   specifies all 43 slots — palette, surfaces, the five status triads, both
   sentiment colours, four elevations and the focus halo. Nothing here was
   invented. The grouping and the order are the source's too, so the port stays
   auditable line-by-line against it rather than being re-sorted into this
   file's alphabetical house style and becoming a diff nobody can check.

   Note what the design does about elevation, because it is not what a naive
   port would do. The light --e-* shadows are rgba(20,23,25,…) — a dark smudge,
   which is invisible on a dark ground. The design's answer is BOTH halves: the
   drop shadows go near-black and roughly four times heavier (.05 → .40), doing
   the work of separation, and --glass-hi drops from a rgba(255,255,255,.6)
   specular highlight to a .07 hairline that reads as a lit top edge rather
   than a gloss. Surfaces also step up in lightness on their own —
   paper #0C0E10 → surface → surface-2 → surface-3 — so a raised thing is
   lighter *and* casts. Do not simplify one half away.

   The selector is `[data-theme="dark"]`, matching the attribute wherever
   it appears — Blazor renders it on the shell wrapper (.hs-shell on the
   workbench, .hs-app on member and kiosk), NOT on <html>. Nothing sets it
   on the root element any more; hirms.js no longer touches theming at all.

   There is exactly ONE dark block now. See the note where its
   prefers-color-scheme twin used to be for why the second one is gone.
   */

[data-theme="dark"] {
  color-scheme: dark;

  --brand: var(--b-500); --brand-hi: var(--b-400); --brand-lo: var(--b-200);
  --brand-soft: #16204C; --brand-line: #2F3C6E;
  /* Midnight, not white. The dark ramp LIFTS --brand to #4C82FF so it reads
     against the canvas, and white on that is 3.53:1. Midnight is 5.07:1.
     Same for danger: white on the lifted #FF9086 is 2.19:1, Midnight 8.18:1.
     --on-pulse is absent here on purpose -- see its note in the light block. */
  --on-brand: #08143A; --on-danger: #08143A;
  --accent: var(--g-500); --accent-soft: rgba(18,178,126,.16); --on-accent: #08143A;
  /* --surface-2 is .85 here, NOT the design's .58, and the deviation from the
     verbatim port is recorded rather than silent so the line stays auditable
     against the source.

     Dark carries the identical defect to light, for the identical reason: this
     token's colour is rgba(10,18,48) — dark --paper's own value — so like its
     light twin it can never beat bare paper, and .58 passed 42% of the aurora.
     The failure is the MIRROR image, which is why it is easy to miss: the dark
     blobs are RAISED (--aurora-* below, .40/.30/.24), and a bright blob
     LIGHTENS a dark ground, so light --ink-3 text loses contrast exactly where
     dark ink lost it in light. Against the three-blob stack that is 3.79:1 at
     .58 and 4.82:1 at .85.

     Fixing light alone would have left this failing at 3.79:1 with every guard
     green — the half-a-pair defect this repo keeps shipping. Dark --i-400
     itself needs NO change: at 5.34:1 on dark --paper it has the headroom the
     light value did not. */
  --paper: var(--i-25); --surface: rgba(17,27,68,.66); --surface-2: rgba(10,18,48,.85); --surface-3: rgba(22,32,76,.86);
  --card-bg: var(--surface); --card-blur: none;
  --glass-blur: blur(18px) saturate(1.25); --glass-hi: inset 0 1px 0 rgba(255,255,255,.05);
  --rule: var(--i-100); --rule-2: var(--i-200); --grid-line: rgba(255,255,255,.04);
  --ramp-1: var(--i-200); --ramp-2: var(--i-300); --ramp-3: var(--b-500);
  --ramp-4: var(--b-400); --ramp-5: var(--b-200); --ramp-6: var(--i-800); --ramp-off: var(--i-400);
  --ink: var(--i-950); --ink-2: var(--i-500); --ink-3: var(--i-400);
  --st-pend: #F3C275; --st-pend-bg: rgba(232,163,61,.16); --st-pend-line: rgba(239,175,82,.42);
  --st-eval: #8FB0FF; --st-eval-bg: rgba(45,107,255,.18); --st-eval-line: rgba(76,130,255,.42);
  --st-redy: #4EDCA9; --st-redy-bg: rgba(18,178,126,.16); --st-redy-line: rgba(22,198,140,.42);
  --st-rejt: #FF9086; --st-rejt-bg: rgba(224,72,60,.18); --st-rejt-line: rgba(236,91,78,.42);
  --st-paid: #B8A8FF; --st-paid-bg: rgba(111,82,246,.18); --st-paid-line: rgba(139,114,255,.42);
  --st-pend-dot: #EFAF52; --st-eval-dot: #4C82FF; --st-redy-dot: #16C68C;
  --st-rejt-dot: #EC5B4E; --st-paid-dot: #8B72FF;
  --success: #16C68C; --warning: #EFAF52; --error: #EC5B4E; --info: #4C82FF; --disabled: #4A567C;
  --pos: #4EDCA9; --neg: #FF9086;
  --g-depth: linear-gradient(150deg,#0A1230,#4B33C4);
  --aurora-1: rgba(111,82,246,.40); --aurora-2: rgba(45,107,255,.30); --aurora-3: rgba(32,197,232,.24);
  /* MORE than light, not less. The mark's blues and cyans separate less from a
     Midnight ground than from Mist, so the same figure reads fainter in dark —
     matching numbers would not mean matching appearance. The aurora tokens
     directly above are raised in dark for exactly this reason; this follows
     them rather than inventing a different rule. --wm-size is theme-invariant
     and is deliberately NOT repeated here. */
  --wm-opacity: .06;
  --e-1: var(--glass-hi),0 1px 2px rgba(0,0,0,.30);
  --e-2: var(--glass-hi),0 2px 6px rgba(0,0,0,.34);
  --e-3: var(--glass-hi),0 8px 28px rgba(0,0,0,.40);
  --e-4: var(--glass-hi),0 18px 52px rgba(0,0,0,.48);
  --ring: 0 0 0 3px rgba(127,166,255,.30);

  /* The ink ramp inverts wholesale in dark, so --ink/--paper/--rule above can
     keep pointing at the same steps they do in light. Text-bearing accents
     lift until they clear 4.5:1 on the #0A1230 canvas; fills keep the book
     hues. Derived, not from the book — it gives no dark UI ramp — and not yet
     run through axe. */
  --i-25: #0A1230; --i-50: #111B44; --i-100: #24305E; --i-200: #2F3C6E;
  --i-300: #4A567C; --i-400: #7F8AA8; --i-500: #A8B2CC; --i-600: #BFC7DC;
  --i-700: #D5DCEB; --i-800: #E4E9F4; --i-900: #EDF0F8; --i-950: #F5F7FC;
  --b-400: #7FA6FF; --b-500: #4C82FF; --b-200: #B9CEFF;
  --p-400: #A493FF; --p-500: #8B72FF;
}


/* The "System" branch. Byte-identical to the block above — see the note there
   before editing either one alone. */
/* The prefers-color-scheme twin that used to live here is DELETED, not
   moved. It existed only because "System" was implemented by REMOVING
   data-theme, which left an attribute-absent state something had to
   catch. HirmsThemeState now resolves System to a concrete "light" or
   "dark" in C# and Blazor always renders one of the two, so the block
   could never match again.

   That also retires the hazard it carried: two byte-identical blocks
   that had to be edited together by hand, where editing one alone
   silently broke the third theme state for anyone who had chosen it. */

