/* SessionHub Console — design tokens
   Following the brief exactly. Light mode is the design's primary surface;
   dark mode swaps to near-black + pale sage accent. */

@import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&family=JetBrains+Mono:wght@400;500;600&display=swap");

:root {
  /* TYPE */
  --font-sans: "Inter", ui-sans-serif, system-ui, -apple-system, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;

  /* SPACING (4px base, sticking to brief) */
  --sp-1: 4px;  --sp-2: 8px;  --sp-3: 12px; --sp-4: 16px;
  --sp-5: 24px; --sp-6: 32px; --sp-7: 48px; --sp-8: 64px;

  /* RADIUS */
  --r-sm: 6px;
  --r-md: 10px;   /* secondary buttons, inputs */
  --r-lg: 14px;
  --r-xl: 16px;   /* cards */
  --r-pill: 999px;

  /* MOTION */
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --dur-fast: 140ms;
  --dur-base: 220ms;

  /* STATUS — same in both modes */
  --status-ok:   #10B981;
  --status-warn: #F59E0B;
  --status-err:  #EF4444;
  /* The FOURTH status dot: nothing went wrong and nothing went right — a call
     nobody answered, a call the caller dropped. It lives here with the other
     three, one value for both modes, because it is a DOT and not text: the
     label ink got darker for readability (--fg-4), but a decorative dot that
     followed it would start competing with the three that actually mean
     something. Design ruling: it stays quiet. */
  --status-none: #9A9A9A;

  /* STATUS SURFACES — fg + soft/strong bg variants for chips, banners,
     row highlights, callouts. The flat --status-* above stays as the dot /
     accent color; these pairs are for filled surfaces. High-frequency
     ad-hoc usage across the codebase (audit 2026-05-15); promoted to tokens
     for the design-system cleanup approved by operator 2026-05-15. */
  --status-ok-fg:         #0E7C53;  /* = design getDashTokens okFg light (was #15803D) — mode-by-mode align 2026-06-21 */
  --status-ok-bg-soft:    #DCFCE7;
  --status-ok-bg-strong:  rgba(16,185,129,0.28);  /* design getDashTokens okBorder (was solid #A7F3D0) */
  --status-warn-fg:       #9A6520;  /* = design getDashTokens warnFg light (was #92400E) — mode-by-mode align 2026-06-21 */
  --status-warn-bg-soft:  #FEF3C7;
  --status-warn-bg-strong:rgba(245,158,11,0.30);  /* visible amber border (was #FFFBEB ≈ white) */

  /* Amber WASH — the faintest of the three amber weights, for tinting a whole
     row or panel rather than marking a chip. Design "DIDs Inventory v2" board
     04 paints a number that never rang at rgba(245,158,11,0.05) and the
     current row of the sibling panel at 0.06.

     ADDITIVE token, and it exists because --status-warn-bg-soft (#FEF3C7) is
     a solid amber-100 built for a chip on a white card. Used as a row tint it
     is roughly three times too strong, and on a slice where most numbers have
     never rung the table becomes a wall of amber that hides the very rows it
     is meant to pick out. Caught by rendering board 04 against a real
     allocation whose 95 of 100 numbers had never carried a call.

     The chip fill is a step up from the wash and a step down from the soft
     fill — the design's own rgba(244,147,39,0.08). */
  --status-warn-wash: rgba(245,158,11,0.05);
  --status-warn-chip: rgba(245,158,11,0.09);
  --status-err-fg:        #B91C1C;  /* aligned to design gapFg (was #991B1B) — 2026-05-27 */
  --status-err-bg:        #FEF6F6;  /* design attention-strip fill (frame-accounts.jsx); light = dark in design but theme-flips here */
  --status-err-line:      #F6D9D9;  /* design attention-strip border (frame-accounts.jsx) */
  --status-err-bg-soft:   #FEF2F2;
  --status-err-bg-strong: rgba(239,68,68,0.28);  /* design getDashTokens badBorder (was solid #FECACA) */

  /* Accounts/Customers semantic accents (frame-accounts-kit.jsx acSem) — theme-aware
     so dark mode stays legible (operator color fix 2026-06-20). Dedicated vars
     because our --status-warn/err-fg deliberately flip to yellow/pink in dark,
     which is wrong for these money/quality accents. Light = design's deep shades. */
  --ac-commission:        #7E22CE;  /* purple — commission % / "You owe" */
  --ac-margin:            #0E7C53;  /* green  — wallet / margin markup */
  --ac-amber:             #B45309;  /* amber  — at-risk / low-ASR / abnormal ACD / fair MOS */
  --ac-red:               #B91C1C;  /* red    — overdue / low-balance / poor MOS */

  /* OVERRIDE / inheritance palette — the design's pale-sage "this level wins"
     accent used by the customer auth-rule editor (selected radio cards,
     overridden inherit rows, "✱ Override" pills). From getCustomerTokens:
     overrideBg #C7F0D6 / overrideFg #14532D (light). Distinct from --accent-soft
     so an override reads as a deliberate, calm green — not the primary accent. */
  --override-bg:      #C7F0D6;
  --override-bg-soft: rgba(199,240,214,0.40);
  --override-fg:      #14532D;
  --inherited-bg:     var(--bg-card-soft);

  /* VERDICT — call-quality palette for MOS / ASR scoring. The verdict
     tier escalates good → fair → poor → bad. Used in CDR rows, quality
     summary chips, and the simulator output card. */
  --verdict-good: #166534;   /* MOS 4.0+, ASR >50% */
  --verdict-fair: #92400E;   /* MOS 3.0-4.0, ASR 30-50% */
  --verdict-poor: #991B1B;   /* MOS <3.0, ASR <30% */
  --verdict-bad:  #7F1D1D;   /* dropped, unrouteable */

  /* TERMINAL / SESSION-REPLAY player — a recorded shell is semantically a
     DARK terminal in BOTH modes (it represents a literal asciinema-style
     recording, not a theme-able surface). So these live in :root and do NOT
     theme-flip — fixed dark in light AND dark mode. Values mirror the Claude
     Design "Session replay" artboard player exactly (Access Audit & Roles.dc.html
     artboard 02). Used by frame-cc-access-audit.jsx's CcReplay player. */
  --term-bg:       #1A1A1A;   /* terminal surface */
  --term-scrub-bg: #222222;   /* scrubber tray */
  --term-border:   #2A2A2A;   /* terminal + scrub border */
  --term-text:     #C4C4C4;   /* transcript text + progress fill */
  --term-dim:      #6E6E6E;   /* sys/$ lines, cursor */
  --term-ok:       #5CCB97;   /* read → arrow (allowed reads) */
  --term-bad:      #FCA5A5;   /* blocked write line */
  --term-note:     #9A9A9A;   /* block annotation, scrub timestamps */
  --term-track:    #3A3A3A;   /* scrubber track (unfilled) */
  --term-play-bg:  #F5F5F5;   /* round play button bg (fixed pale, not canvas) */
  --term-play-fg:  #1A1A1A;   /* play glyph */
  --term-marker:   #EF4444;   /* blocked-event marker on the timeline */
  /* CUSTOMER-PORTAL DEPICTION — a FIXED "warm-paper" palette used ONLY by the
     /cc-money dunning-ladder preview (frame-cc-money.jsx) to depict the
     customer's OWN separate portal surface. It is intentionally NOT the console
     theme: it shows the operator exactly what the customer will literally see,
     so it does NOT flip in dark mode (defined once in :root, no .sh-theme-dark
     override). Values come verbatim from the Claude Design "Money Billing &
     Dunning" AB2 customer-preview. See the frame's DESIGN DIVERGENCE note. */
  --portal-paper:   #FAFAF8;  /* warm paper body */
  --portal-chrome:  #ECEAE6;  /* window titlebar */
  --portal-line:    #DAD6CE;  /* titlebar bottom rule */
  --portal-border:  #D4D0C8;  /* secondary-button border */
  --portal-ink:     #1A1815;  /* primary ink / Pay-now bg */
  --portal-mute:    #6B6862;  /* body-mute text */
  --portal-label:   #8A8780;  /* window-title label grey */
  --portal-on-ink:  #FFFFFF;  /* text on the dark Pay-now button */
  --portal-warn-fg: #9A6520;  /* past-due icon (warm-paper warn) */
  --portal-ok-fg:   #0E7C53;  /* "calls still connecting" green */
  --portal-tl-red:   #F2655A; /* macOS traffic-light close */
  --portal-tl-amber: #F5BD4F; /* macOS traffic-light minimise */
  --portal-tl-green: #61C554; /* macOS traffic-light zoom */
}

/* LIGHT (Ledgerix-inspired) */
.theme-light {
  --bg-canvas:  #F5F5F5;
  --bg-surface: #FFFFFF;
  --bg-raised:  #FFFFFF;
  --bg-card:    #FFFFFF;
  --bg-inset:   #F5F5F5;        /* design inset — was #FAFAFA */
  --bg-input:   #FFFFFF;
  --bg-chip:    #FFFFFF;        /* design chipBg — was #F5F5F5 */

  --fg-1: #0A0A0A;              /* primary */
  --fg-2: #404040;              /* secondary */
  --fg-mid: #525252;            /* between --fg-2 and --fg-3 (~150 ad-hoc hits) */
  --fg-3: #737373;              /* muted */
  /* THE LABEL INK — re-picked once, console-wide, by the "Console Greys" canvas
     (2026-08-23) after the old value was measured FAILING WCAG AA in both modes.
     This is the layer that NAMES things: column headings, axis labels,
     sub-labels, eyebrows, placeholders, the muted half of a two-part figure.
     A layer whose whole job is telling you what you are looking at must never
     be the thing you squint at.

       was #A3A3A3 — 2.52:1 on white, 2.42 on --bg-card-soft, 2.31 on the inset.
       now #6E6E6E — 5.10 / 4.89 / 4.68. Verified here, not taken on trust.

     NOT #737373 (our --fg-3): it measures 4.74 / 4.54 / 4.35 — it passes on a
     white card and FAILS on the inset, so the label layer skips past it.
     --fg-3 keeps its own job: quiet PROSE at 12px and up. The two tiers sit
     close now on purpose; size does the layering, not the ink. */
  --fg-4: #6E6E6E;              /* label ink — see above */
  --fg-5: #D4D4D4;              /* faintest tier — design fg5 (separators, off-dots) */
  --fg-on-accent: #FFFFFF;

  --line-0: #EBEBEB;            /* default border (most-used; 362 ad-hoc hits) */
  --line-1: #EBEBEB;            /* = design line / --line-0 (was #E5E5E5 — 1 step dark console-wide) */
  --line-2: #F5F5F5;            /* design lineSoft — was #EFEFEF */
  --line-3: #F0F0F0;
  /* CDR wall band rails only. The design draws the rail edge a full step darker
     and WARMER than --line-0, so it reads as a divider between bands rather than
     another table hairline; it is the same warm family as the frozen pair's edge.
     No existing token carries it — nearest is --term-text, which is the terminal's. */
  --cdr-rail-line: #C9C7C2;
  /* The frozen Time·Customer pair, once the wall scrolls under it. The design
     gives a TINTED row ONE warm wash here — never the row's own amber or red,
     which would drag the failure colour across the calmest part of the wall.
     The row's severity is carried by the dot in the pair instead. */
  --cdr-pair-tint:   #FDF8F0;
  --cdr-pair-line:   #E0DED9;
  --cdr-pair-shadow: 6px 0 12px rgba(0,0,0,0.05);
  /* The wall's row wash — ONE colour, and it does not mean "this failed".
     A failure already announces itself in red in the Verdict column; washing
     the row too doubles the signal, and on a switch having a bad hour it
     turns the entire wall red. The wash is reserved for the rows whose
     problem the verdict does NOT show — a call that answered and lost money,
     a call that connected and carried no audio. Deliberately translucent:
     it is a wash over whatever the row already is. The frozen pair uses the
     OPAQUE --cdr-pair-tint instead, for the reason recorded there. */
  --cdr-row-attention: rgba(245,158,11,0.05);
  /* THE MARK — the operator's own tick, from The Margin, the News, the Fit.
     "The tint is the selected-state amber the console already speaks, quiet
     enough that three marked rows read as emphasis, not alarm."

     ⚠️ IT IS NOT --cdr-row-attention, and the difference is load-bearing. The
     attention wash means "the switch noticed something the verdict does not
     show"; a mark means "I am holding this row". Painting them the same colour
     would make a machine's finding and a human's tick indistinguishable at a
     glance — so the mark is the same amber at roughly twice the weight, and it
     carries a dot in the margin that the attention wash never has. Two anchors,
     one tint, per the ruling: the ground for the mile of columns, the dot for
     the frozen pair. --cdr-pair-marked is its OPAQUE twin, for the same reason
     --cdr-pair-tint is opaque: a translucent wash on the frozen pair lets the
     scrolled columns show straight through it, and only in one theme. */
  --cdr-row-marked:  rgba(244,147,39,0.13);
  --cdr-pair-marked: #FEF1E3;
  --cdr-mark-dot:    #F49327;
  /* The RESTING margin — a hollow ring on every row, not an empty cell.
     ⚠️ Read off CD's drawing, not its prose. The board says "resting, the
     margin is blank", and built to that sentence the gutter had no ink at all:
     nothing to see, nothing to aim at, and the operator opened the page and
     asked whether the feature had shipped. The drawing's own dotS renders an
     8px circle with a 1.5px #C9C7C2 border at 0.55 opacity when UNMARKED —
     "blank" means carries no content, not draws nothing. The ring is the
     target; filling it is the mark. */
  --cdr-mark-ring:   #C9C7C2;
  /* THE SHARED GROUND — the record's surface, and the surface of the row it is
     reading. The Record's Reach ratifies them as ONE:
         const ground = '#F0EFEA';
         panelBg = shared ? ground : '#FFFFFF';
         row bg  = open ? ground : (marked ? tint : '#FFFFFF');
     and The Margin adds the clasp, which is made of the same fact a third time.

     ⚠️ NOT --bg-card-soft, which is what the first build used. That token is
     #FAFAFA — a COOL near-white a hair off the card's #FFFFFF — so the pop-out
     rendered as very nearly the same surface as the wall behind it and the
     operator's own request ("a slightly different background to differentiate
     the pop-out") went unanswered even though the code said it was done. CD's
     ground is a WARM grey, and the warmth is what separates it. A general-
     purpose token cannot carry a per-surface decision. */
  --cdr-record-ground: #F0EFEA;
  /* The record's footer — CD lays 3% black over the ground rather than naming a
     second colour, so the strip stays welded to the panel in either theme. */
  --cdr-record-floor:  rgba(10,10,10,0.03);

  --accent: #0A0A0A;            /* design accent — near-black, was #000000 */
  --accent-hover: #1A1A1A;
  --accent-soft: #FAFAFA;       /* design accentSoft — was #F0F0F0 */

  --spark: #D4D4D4;             /* sparkline gray */
  --spark-strong: #A3A3A3;

  /* Flow topology resting curve colour — design getDashTokens flowLine
     (#C4C4C4 light). ADDITIVE token (2026-06-17 cVerify P1): the dashboard
     flow frame previously mapped its resting bezier curves to var(--fg-1)
     (near-black), darkening every at-rest lane + the footer legend swatch.
     This grey matches the design exactly. Dark-mode value below. */
  --flow-line: #C4C4C4;

  /* DID occupancy-map fill — design "DIDs Inventory.dc.html" board 01, the
     10,000-number strip whose ink is rented-and-ringing, amber is
     rented-and-silent, pale is free. ADDITIVE token: the design paints that
     mass #262626, one step LIFTED off --fg-1 (#0A0A0A) so a large filled area
     reads as a mass rather than a black bar. Mapping it to --fg-1 would be the
     near-black/pure-black drift that cost a fidelity pass before. Free bins use
     --line-1 and silent bins --status-warn, both of which already match the
     design exactly. Dark keeps the same relationship, inverted: one step lifted
     off dark's --fg-1 (#F5F5F5). The design canvas is light-only, so the dark
     value is ours to choose. */
  --occupancy-held: #262626;

  /* Two-series chart inks — design "DIDs Inventory v2" board 04, whose year
     chart pairs a dark outbound bar with a light inbound one and captions
     itself "outbound dark · inbound light — the slope is the finding". The
     pairing IS the reading: one series has to dominate and the other recede,
     or the eye cannot separate them at 12 bars wide.

     ADDITIVE tokens. --series-strong takes the same #262626 as the occupancy
     mass — one step lifted off --fg-1 so a row of bars reads as a mass rather
     than a black fence — and --series-soft is the design's own #C9C7C2. They
     are named for the RELATIONSHIP rather than for out/in, because the same
     pair draws the sibling sparklines, where the quiet ink means "not the row
     you are looking at" rather than "inbound".

     Dark inverts the relationship rather than the values: the strong ink goes
     light and the soft ink goes mid-grey, so outbound still dominates against
     --bg-surface instead of the two swapping places. The design canvas for
     this board is light-only, so the dark values are ours. */
  --series-strong: #262626;
  --series-soft:   #C9C7C2;

  --emphasis-bg: #0A0A0A;       /* inverted card */
  --emphasis-fg: #FFFFFF;

  --shadow-1: 0 1px 0 rgba(10,10,10,0.02), 0 1px 2px rgba(10,10,10,0.04);
  --shadow-2: 0 1px 0 rgba(10,10,10,0.02), 0 4px 12px rgba(10,10,10,0.06);

  /* Wave-2026-05-17 design-fidelity additions — granular tokens from
     /Users/mac/Desktop/sbc-redesign/project/thin-theme.js. Previously a
     handful of frame elements (most visibly the SHQuestionLauncher AI
     bar) used `var(--fg-1)` as background, which auto-inverts to WHITE
     in dark mode instead of staying dark. These tokens give those
     elements an explicit always-dark surface that's parallel to the
     auto-inverting fg/bg pair. */
  /* Delta pills — the "+12% vs prior 24h" chips on the dashboard etc.
     Design's `thin-theme.js` uses MINT (light) + SAGE-translucent (dark)
     greens for positive delta, and red-translucent for negative — NOT
     the emerald (#10B981 family) that --status-ok uses. These tokens
     stay theme-aware so the same chip class works in both modes. */
  --delta-pos-bg:      #C7F0D6;    /* design pillBg light — mint */
  --delta-pos-fg:      #14532D;    /* design pillFg light — deep forest green */
  --delta-neg-bg:      rgba(239,68,68,0.10);  /* design errBg light */
  --delta-neg-fg:      #B91C1C;    /* design errFg light */
  /* Wave-2026-05-18 (C-lite) — text color for the cron-health degraded
     banner. Warm brown on the amber pill (light), lighter amber in dark
     mode override below. Matches the dev-preview banner palette. */
  --cron-banner-fg:    #92400E;

  --bg-card-soft:      #FAFAFA;    /* panel inside card; cardSoft */
  --bg-ai:             #0A0A0A;    /* AI bar / question launcher bg */
  --bg-ai-pill:        #1F1F1F;    /* pill inside AI bar / launcher popover */
  --bg-ai-send:        #FFFFFF;    /* send button circle bg */
  --fg-ai-pill:        #D4D4D4;
  --fg-ai-send:        #0A0A0A;    /* arrow inside send circle */
  --bg-tooltip:        #FFFFFF;
  --line-tooltip:      #EBEBEB;
  --avatar-bg:         #0A0A0A;    /* INVERTED — dark on light bg */
  --avatar-fg:         #FFFFFF;
  --input-line:        #D4D4D4;
  --input-line-active: #0A0A0A;
  --line-soft:         #F5F5F5;
  --line-faint:        #F5F5F5;
  --bar-fg:            #0A0A0A;    /* chart bar/spark foreground */
  --bar-track:         #F5F5F5;
  --histo-bar:         #E5E5E5;    /* CDR distribution "answered" bar (design histo — visible on white, unlike --bar-track) */
  --grid-line:         #EBEBEB;
  /* ── Schedules — time-based control (Claude Design "Schedules.dc.html") ──
     ADDITIVE ONLY: every value below is new; no existing token is touched, so
     no other surface can move.

     The week-ribbon is the surface's shared proof object — seven bars, FILLED
     WHERE OPEN — and it needs a fill that is emphatically NOT body text even
     though light mode happens to share a hex with --fg-2. Keeping it separate
     means a future type change cannot silently repaint every schedule.

     The dots and tone text carry the design's own per-mode values rather than
     leaning on --status-*: the design deliberately brightens them for dark
     (#10B981 → #34D399), and approximating that drift is how a token set
     wanders away from its design. */
  --sch-track:          #F0EFED;   /* ribbon track — the shut hours */
  --sch-band:           #404040;   /* ribbon fill — the open hours */
  --sch-band-disabled:  #C9C7C2;   /* a frozen schedule's week, drained of authority */
  --sch-now:            #F49327;   /* the now-tick. IDENTICAL in both modes, by design —
                                      the only amber on a healthy row. */
  --sch-section:        #F7F7F6;   /* the board's section header bands */
  --sch-hatch-a:        #F0EFED;   /* authoring proof: the hours the engine enforces */
  --sch-hatch-b:        #E9E7E4;
  --sch-dot-ok:         #10B981;
  --sch-dot-neutral:    #525252;   /* shut on purpose — calm, deliberately */
  --sch-dot-err:        #EF4444;
  --sch-dot-warn:       #F59E0B;
  --sch-dot-hollow:     #8A8780;   /* doing nothing at all */
  --sch-fg-ok:          #047857;
  --sch-fg-warn:        #B45309;
  --sch-fg-err:         #B91C1C;

}

/* DARK — "Thin · lighter dark palette" per the 2026-05-17 design canvas
   update. Lighter base (#1C1C1C) than the previous near-black (#0A0A0A) so
   surfaces have more separation; accent flips to WHITE (was pale sage) as
   the Thin variant's signature. Emphasis card returns to a neutral raised
   tone instead of the sage-cream from the previous direction.

   Selector list: applies BOTH when an element directly has `.theme-dark`
   (legacy / explicit usage) AND when the user toggles dark mode via the
   topbar (which sets `body.sh-theme-dark` — this matches `.theme-light`
   roots without forcing edits across 80+ frame files).

   `html.sh-theme-dark` (bare) added 2026-05-27 — ROOT FIX for washed-out dark
   mode: the redesign layout (sessionhub_redesign.html.erb) AND dev-preview.html
   set `sh-theme-dark` on <html> with NO `.theme-light` wrapper in the body, so
   `html.sh-theme-dark .theme-light` never matched → only the hardcoded body bg
   went dark while every --fg, --bg-card, --line var stayed undefined (dim,
   low-contrast text). Matching `html.sh-theme-dark` directly applies the dark
   vars on the <html> root and lets them cascade. Safe: pages that DO have a
   `.theme-light` wrapper still get the more-specific override; light mode
   (no sh-theme-dark) is untouched. */
.theme-dark,
html.sh-theme-dark,
html.sh-theme-dark .theme-light {
  --bg-canvas:  #1C1C1C;
  --bg-surface: #242424;
  --bg-raised:  #2A2A2A;
  --bg-card:    #2A2A2A;
  --bg-inset:   #333333;
  --bg-input:   #2A2A2A;
  --bg-chip:    #2A2A2A;        /* design chipBg dark — was #333333 */

  --fg-1: #F5F5F5;
  --fg-2: #C4C4C4;
  --fg-mid: #B5B5B5;            /* dark equivalent (between --fg-2 and --fg-3) */
  --fg-3: #9A9A9A;
  --fg-4: #9A9A9A;             /* label ink, dark — was #6E6E6E: 2.81:1 on our
                                  card, now 5.10. Same tier as --fg-3 by design. */
  --fg-5: #525252;             /* faintest tier — design fg5 dark */
  --fg-on-accent: #1C1C1C;

  --line-0: #3A3A3A;            /* dark equivalent of default border */
  --line-1: #3A3A3A;
  --line-2: #303030;
  --line-3: #2A2A2A;
  --cdr-rail-line: #525252;    /* = --fg-5; the rail edge stays visible on dark */
  --cdr-pair-tint:   #231F17;
  --cdr-pair-line:   #3A3A3A;
  /* 5% black is invisible on a dark surface — the lift has to be 7x stronger
     for the frozen pair to read as floating above the scrolled columns. */
  --cdr-pair-shadow: 6px 0 12px rgba(0,0,0,0.35);
  --cdr-row-attention: rgba(245,158,11,0.07);
  --cdr-row-marked:  rgba(244,147,39,0.15);
  --cdr-pair-marked: #483A2A;
  --cdr-mark-dot:    #F49327;
  /* ⚠️ NOT #C9C7C2, and not a dim grey either — the same RELATIVE contrast.
     CD's light ring composites to ~#E1E1E1 on #FFFFFF, about 12% below its
     ground. #525252 at 0.55 over the #2A2A2A card landed at ~8%, and a dark
     ground needs MORE separation than a light one, not less — the rings were
     effectively invisible and the operator asked twice where the feature was.
     #737373 composites to ~#525252 on the card: ~16%, visible without
     shouting. Translate the RELATIONSHIP, never the literal. */
  --cdr-mark-ring:   #737373;
  /* Dark: the same MOVE, not the same value — a warm lift off the #2A2A2A card,
     where light warms downward off #FFFFFF. */
  --cdr-record-ground: #37342D;
  --cdr-record-floor:  rgba(255,255,255,0.04);

  --accent: #F5F5F5;            /* white — Thin signature on dark */
  --accent-hover: #FFFFFF;
  --accent-soft: rgba(245,245,245,0.08);

  --spark: #3A3A3A;
  --spark-strong: #5C5C5C;

  /* Flow topology resting curve colour (dark) — design getDashTokens flowLine
     dark = #5C5C5C. ADDITIVE token (2026-06-17 cVerify P1). */
  --flow-line: #5C5C5C;

  /* DID occupancy-map fill (dark) — the light value is #262626, one step
     lifted off light's --fg-1. Dark mirrors that relationship inverted: one
     step lifted off dark's --fg-1 (#F5F5F5), so the rented mass still reads as
     a mass against --bg-surface (#242424) without going pure white. The design
     canvas for this board is light-only, so this value is ours. */
  --occupancy-held: #C4C4C4;

  /* Two-series chart inks (dark). The light pair is #262626 / #C9C7C2 — a
     dominant ink and a recessive one. Dark keeps that ORDER by inverting both:
     strong goes light against --bg-surface (#242424), soft drops to a mid-grey
     that is still legible but plainly secondary. Mapping either to its light
     value would swap which series dominates and invert the chart's meaning. */
  --series-strong: #D4D4D4;
  --series-soft:   #5C5C5C;

  --emphasis-bg: #333333;       /* neutral raised card (was sage cream) */
  --emphasis-fg: #F5F5F5;

  --shadow-1: none;
  --shadow-2: 0 4px 16px rgba(0,0,0,0.4);

  /* Wave-2026-05-17 design-fidelity additions — granular dark tokens
     matched 1:1 with thin-theme.js. These do NOT auto-invert with the
     standard fg/bg pair; they stay dark in dark mode (the design's
     intent for the AI bar etc.) and dark in light mode (always-dark
     surfaces). The "send button circle" stays light in both modes
     because the design intent is a contrasting send affordance. */
  /* Delta pills — design uses SAGE (not emerald) for positive in dark.
     `rgba(181,214,133,0.18)` = sage with 18% alpha so it sits gently
     on the dark canvas; pillFg is #C4DF9A (light sage) for the text. */
  --delta-pos-bg:      rgba(181,214,133,0.18);  /* design pillBg dark */
  --delta-pos-fg:      #C4DF9A;                 /* design pillFg dark */
  --delta-neg-bg:      rgba(239,68,68,0.18);    /* design errBg dark */
  --delta-neg-fg:      #FCA5A5;                 /* design errFg dark */
  --cron-banner-fg:    #FCD34D;                 /* light amber in dark mode */

  --bg-card-soft:      #262626;    /* cardSoft — panel inside card */
  --bg-ai:             #2A2A2A;    /* aiBar — design says #2A2A2A in dark, NOT #F5F5F5 (var(--fg-1)) */
  --bg-ai-pill:        #333333;    /* aiPill — slightly raised pill on AI bar */
  --bg-ai-send:        #F5F5F5;    /* aiSendBg — stays light (contrast affordance) */
  --fg-ai-pill:        #C4C4C4;
  --fg-ai-send:        #1C1C1C;    /* aiSendFg — dark arrow on the light send circle */
  --bg-tooltip:        #333333;
  --line-tooltip:      #404040;
  --avatar-bg:         #F5F5F5;    /* INVERTED — light on dark bg */
  --avatar-fg:         #1C1C1C;
  --input-line:        #404040;
  --input-line-active: #F5F5F5;
  --line-soft:         #303030;
  --line-faint:        #262626;
  --bar-fg:            #F5F5F5;    /* chart bar/spark foreground in dark */
  --bar-track:         #3A3A3A;
  --histo-bar:         #3A3A3A;    /* CDR distribution "answered" bar (design histo, dark) */
  --grid-line:         #303030;

  /* Status surfaces — re-tuned for dark backgrounds so soft-bg variants
     remain visible against #1C1C1C without losing contrast on text. */
  --status-ok-fg:         #5CCB97;  /* = design getDashTokens okFg DARK — re-aligned to regenerated dark artboards (Messaging Omnichannel) 2026-06-27 (was #5EE3B0) */
  --status-ok-bg-soft:    rgba(16,185,129,0.14);
  --status-ok-bg-strong:  rgba(16,185,129,0.32);  /* design dark okBorder (was 0.22) */
  --status-warn-fg:       #E8B765;  /* = design getDashTokens warnFg DARK — re-aligned to regenerated dark artboards (Messaging Omnichannel) 2026-06-27 (was #E6B25E) */
  --status-warn-bg-soft:  rgba(245,158,11,0.14);
  --status-warn-bg-strong:rgba(245,158,11,0.34);  /* design dark warnBorder (was 0.22) */

  /* Amber wash + chip fill (dark). The design canvas for this board is
     light-only, so these are ours. Both sit on --bg-surface (#242424) rather
     than on white, which needs slightly more alpha to register at all while
     staying a tint rather than a fill. */
  --status-warn-wash: rgba(251,191,36,0.07);
  --status-warn-chip: rgba(251,191,36,0.13);
  --status-err-fg:        #FCA5A5;
  --status-err-bg:        rgba(239,68,68,0.08);  /* design attention-strip fill (dark) */
  --status-err-line:      rgba(239,68,68,0.25);  /* design attention-strip border (dark) */
  --status-err-bg-soft:   rgba(239,68,68,0.14);
  --status-err-bg-strong: rgba(239,68,68,0.36);  /* design dark badBorder (was 0.22) */

  /* Accounts/Customers semantic accents — dark tints (acSem dark; operator fix 2026-06-20) */
  --ac-commission:        #D8B4FE;  /* purple (dark) */
  --ac-margin:            #6EE7B7;  /* green  (dark) */
  --ac-amber:             #FBBF24;  /* amber  (dark) */
  --ac-red:               #FCA5A5;  /* red    (dark) */

  /* Override / inheritance palette (dark) — design getCustomerTokens dark:
     overrideBg rgba(181,214,133,.14) / overrideFg #C4DF9A. */
  --override-bg:      rgba(181,214,133,0.22);
  --override-bg-soft: rgba(181,214,133,0.14);
  --override-fg:      #C4DF9A;
  --inherited-bg:     var(--bg-card-soft);

  /* Verdict palette — call-quality scoring also needs dark-mode readjustment
     for legibility on dark surfaces. */
  --verdict-good: #6EE7B7;
  --verdict-fair: #FCD34D;
  --verdict-poor: #FCA5A5;
  --verdict-bad:  #F87171;
  /* Schedules — dark. Same roles, the design's night values. */
  --sch-track:          #2E2E2E;
  --sch-band:           #C4C4C4;
  --sch-band-disabled:  #4A4A4A;
  --sch-now:            #F49327;   /* unchanged across modes, by design */
  --sch-section:        #212121;
  --sch-hatch-a:        #2A2A2A;
  --sch-hatch-b:        #232323;
  --sch-dot-ok:         #34D399;
  --sch-dot-neutral:    #8A8A8A;
  --sch-dot-err:        #F87171;
  --sch-dot-warn:       #FBBF24;
  --sch-dot-hollow:     #9A9A9A;
  --sch-fg-ok:          #34D399;
  --sch-fg-warn:        #FBBF24;
  --sch-fg-err:         #F87171;

}

/* ====== TYPE STYLES ======
   Numbers are tabular; eyebrows are uppercase + tracked. */
.t-hero {
  font-family: var(--font-sans);
  font-weight: 800;
  font-size: 96px;
  line-height: 0.95;
  letter-spacing: -0.025em;
  font-variant-numeric: tabular-nums;
  color: var(--fg-1);
}
.t-hero-mobile {
  font-family: var(--font-sans);
  font-weight: 800;
  font-size: 64px;
  line-height: 0.95;
  letter-spacing: -0.025em;
  font-variant-numeric: tabular-nums;
  color: var(--fg-1);
}
.t-page {
  font-family: var(--font-sans);
  font-weight: 300;
  font-size: 32px;
  line-height: 1.1;
  letter-spacing: -0.02em;
  color: var(--fg-1);
}
.t-section {
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: 20px;
  letter-spacing: -0.01em;
  color: var(--fg-1);
}
.t-eyebrow {
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fg-3);
}
.t-body {
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: 14px;
  line-height: 1.5;
  color: var(--fg-1);
}
.t-body-mute {
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: 14px;
  line-height: 1.5;
  color: var(--fg-3);
}
.t-num-card {
  font-family: var(--font-sans);
  font-weight: 700;
  font-size: 48px;
  line-height: 1;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--fg-1);
}
.t-num-md {
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: 24px;
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
  color: var(--fg-1);
}
.t-mono {
  font-family: var(--font-mono);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: var(--fg-2);
}

.tab-num { font-variant-numeric: tabular-nums; }

/* ====== ROOT FRAME WRAPPER ====== */
.frame {
  font-family: var(--font-sans);
  background: var(--bg-canvas);
  color: var(--fg-1);
  width: 100%;
  height: 100%;
  overflow: hidden;
  position: relative;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* ====== COMMON COMPONENTS ====== */
.card {
  background: var(--bg-card);
  border: 1px solid var(--line-1);
  border-radius: var(--r-xl);
  padding: var(--sp-5);
}
.card-emphasis {
  background: var(--emphasis-bg);
  color: var(--emphasis-fg);
  border-radius: var(--r-xl);
  padding: var(--sp-5);
}
.card-emphasis * { color: inherit; }

/* Buttons */
.btn {
  display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: 14px;
  cursor: pointer;
  border: 1px solid transparent;
  transition: background var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out);
  white-space: nowrap;
  user-select: none;
}
.btn-primary {
  background: var(--accent);
  color: var(--fg-on-accent);
  padding: 10px 18px;
  border-radius: var(--r-pill);
}
.btn-primary:hover { background: var(--accent-hover); }
.btn-secondary {
  background: var(--bg-surface);
  color: var(--fg-1);
  border-color: var(--line-1);
  padding: 9px 14px;
  border-radius: var(--r-md);
}
.btn-secondary:hover { background: var(--bg-inset); }
.btn-ghost {
  background: transparent;
  color: var(--fg-2);
  padding: 8px 12px;
  border-radius: var(--r-md);
}
.btn-ghost:hover { background: var(--bg-inset); color: var(--fg-1); }

/* Pill segmented control */
.seg {
  display: inline-flex;
  background: var(--bg-chip);
  border-radius: var(--r-pill);
  padding: 3px;
  gap: 2px;
}
.theme-light .seg { background: #ECECEC; }
.seg-item {
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: 13px;
  padding: 6px 14px;
  border-radius: var(--r-pill);
  cursor: pointer;
  color: var(--fg-3);
  border: none;
  background: transparent;
  transition: all var(--dur-fast) var(--ease-out);
}
.seg-item.active {
  background: var(--accent);
  color: var(--fg-on-accent);
}
.theme-light .seg-item.active { background: #0A0A0A; color: #FFF; }
.seg-item:not(.active):hover { color: var(--fg-1); }

/* Inputs */
.input {
  font-family: var(--font-sans);
  font-size: 14px;
  background: var(--bg-input);
  color: var(--fg-1);
  border: 1px solid var(--line-1);
  border-radius: var(--r-md);
  padding: 10px 14px;
  outline: none;
  transition: border-color var(--dur-fast) var(--ease-out);
  width: 100%;
}
.input:focus { border-color: var(--accent); }
.input::placeholder { color: var(--fg-4); }

/* Tabs (underline style)
 *
 * Wave 56 — horizontal scroll for medium widths (tab strip no longer
 * silently cuts off when there are >8 tabs on an 1100px window), and a
 * mobile breakpoint <768px that hides the tab row in favor of a
 * <select>-based picker (`.tabs-picker`, rendered inline by the page).
 */
.tabs {
  display: flex;
  gap: 0;
  border-bottom: 1px solid var(--line-1);
  overflow-x: auto;
  flex-wrap: nowrap;
  scrollbar-width: thin;
  -webkit-overflow-scrolling: touch;
}
.tabs::-webkit-scrollbar { height: 4px; }
.tabs::-webkit-scrollbar-thumb { background: var(--line-2); border-radius: 2px; }
.tab {
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: 14px;
  padding: 14px 0;
  margin-right: 28px;
  color: var(--fg-3);
  cursor: pointer;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  transition: color var(--dur-fast) var(--ease-out);
  white-space: nowrap;
  flex-shrink: 0;
}
.tab.active { color: var(--fg-1); border-bottom-color: var(--accent); }
.tab:hover { color: var(--fg-1); }

/* Mobile tab picker (Wave 56). A page that renders BOTH `.tabs` (the
 * horizontal strip) and `.tabs-picker` (a styled <select>) lets the CSS
 * pick which one shows based on viewport. Default: picker hidden, strip
 * shown. <768px: picker shown, strip hidden. */
.tabs-picker {
  display: none;
  width: 100%;
  padding: 12px 14px;
  font-family: var(--font-sans);
  font-size: 14px;
  color: var(--fg-1);
  background: var(--bg-surface);
  border: 1px solid var(--line-1);
  border-radius: var(--r-md);
  outline: none;
}
.tabs-picker:focus { border-color: var(--accent); }
@media (max-width: 768px) {
  .tabs { display: none; }
  .tabs-picker { display: block; }
}

/* Status dot */
.dot {
  display: inline-block;
  width: 8px; height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}
.dot-ok   { background: var(--status-ok); }
.dot-warn { background: var(--status-warn); }
.dot-err  { background: var(--status-err); }
.dot-mute { background: var(--fg-4); }

/* Status indicator (dot + label) */
.status {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  font-weight: 500;
  color: var(--fg-2);
}

/* Pill chip (positive / negative change) — design palette:
   pos: MINT (#C7F0D6 light) / SAGE-translucent (rgba(181,214,133,0.18) dark)
   neg: RED-translucent in both modes (0.10 alpha light, 0.18 alpha dark)
   These were previously emerald-based (#10B981) which is more teal/cyan;
   design uses warmer sage/forest green instead. Driven by --delta-pos-* /
   --delta-neg-* tokens so a single chip class works in both modes. */
.chip-delta {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  font-weight: 500;
  padding: 3px 9px;
  border-radius: var(--r-pill);
  background: var(--delta-pos-bg);
  color: var(--delta-pos-fg);
}
.chip-delta.neg { background: var(--delta-neg-bg); color: var(--delta-neg-fg); }

/* Chip neutral */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  font-weight: 500;
  padding: 4px 10px;
  border-radius: var(--r-pill);
  background: var(--bg-chip);
  color: var(--fg-2);
  border: 1px solid var(--line-1);
}
.theme-light .chip { border-color: var(--line-1); }

/* Tables */
.tbl { width: 100%; border-collapse: collapse; font-size: 14px; }
.tbl th {
  text-align: left;
  font-weight: 500;
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fg-3);
  padding: 12px 0;
  border-bottom: 1px solid var(--line-1);
}
.tbl td {
  padding: 16px 0;
  border-bottom: 1px solid var(--line-2);
  color: var(--fg-1);
  font-variant-numeric: tabular-nums;
}
.tbl tr:last-child td { border-bottom: none; }
/* Wave 2026-05-19 (Issue-carrierPageBugs): scope hover to clickable rows
   only. The bare `.tbl tr:hover` was a false affordance on (a) empty-
   state rows ("No carriers configured…"), (b) read-only data tables
   (translations, account-detail, etc.). Now hover only fires on rows
   that opt in via `data-clickable="true"`. Components that already
   wire inline onMouseEnter/onMouseLeave for hover continue to work; the
   CSS rule below is the primary path for SHListPage-style row navigation. */
.tbl tr[data-clickable="true"]:hover td { background: var(--bg-inset); }

/* Sparkline svg sizing default */
.spark-bg { color: var(--spark); }

/* Connection map node */
.flow-card {
  background: var(--bg-card);
  border: 1px solid var(--line-1);
  border-radius: 14px;
  padding: 14px 16px;
  min-width: 168px;
  position: relative;
}
.flow-card.broken {
  border-style: dashed;
  border-color: var(--status-err);
}

/* Subtle scrollbar hide */
.frame *::-webkit-scrollbar { display: none; }
.frame * { scrollbar-width: none; }

/* ====== HORIZONTAL OVERFLOW GUARD ======
   Belt-and-suspenders for the tooltip-overflow bug. If any frame's
   inner element ever extends past the viewport's right edge (a
   too-wide tooltip, an unflexed table, a runaway absolute-positioned
   popover), browsers add horizontal scroll on body → operator sees
   a white edge (in light) or canvas edge (in dark) when scrolling.
   Clipping at html keeps everything contained without changing the
   layout's intrinsic width. */
html, html body { overflow-x: hidden; }

/* ====== HTML/BODY BG (cascade-independent) ======
   The CSS-var cascade for `--bg-canvas` is rooted in `.theme-light`
   (and its dark-override `html.sh-theme-dark .theme-light`). That
   means the var is set INSIDE each frame's root div — html and body
   themselves have NO `--bg-canvas`, so `body { background: var(--bg-canvas) }`
   in a page layout resolves to UNDEFINED → browser default (white).
   Symptom: any horizontal scroll past the frame's right edge reveals
   the white body bg in dark mode (operator-spotted 2026-05-17).
   Fix: paint html with a fixed hex per theme so any uncovered area
   matches the canvas color. Body inherits via the same selector.
   The fixed values mirror tokens.css's --bg-canvas in each mode. */
html,
html body { background: #F5F5F5; }
html.sh-theme-dark,
html.sh-theme-dark body { background: #1C1C1C; }

/* ====== MOBILE THIN-TEXT (LIGHT MODE) ======
   Per the 2026-05-17 design canvas update — "05 · Mobile dashboard" and
   "06 · Mobile customer detail" both use lighter type weights at mobile
   widths than their desktop equivalents. The mobile artboards (390×844)
   intentionally drop hero/page weights from 800/600 → 300/200 to keep
   the small surface feeling airy rather than crowded.

   Breakpoint matches sh-topnav.css's mobile mode (<768px). Affects ALL
   pages, not just dashboard, so a customer/carrier/etc. detail page on
   a phone gets the same thinner-text treatment automatically. */
@media (max-width: 768px) {
  .t-hero        { font-weight: 200; letter-spacing: -0.03em; font-size: 64px; }
  .t-hero-mobile { font-weight: 200; letter-spacing: -0.03em; }
  .t-page        { font-weight: 300; font-size: 28px; }
  .t-section     { font-weight: 500; font-size: 18px; }
  .t-num-card    { font-weight: 300; font-size: 40px; }
  .t-num-md      { font-weight: 400; font-size: 22px; }
}

/* ====== TOPNAV THEME-TOGGLE BUTTON ======
   Sun/moon icon next to the bell. Same chrome as `sh-topnav-icon-btn`
   so it inherits the topbar's hover + sizing automatically; pair with
   the toggle script in frame-shared.jsx that flips body.sh-theme-dark
   + persists to localStorage('sh-theme'). */
.sh-theme-toggle {
  /* hover/visual state inherited from sh-topnav-icon-btn — only add
     a subtle transition for the icon swap so the change feels smooth
     rather than abrupt. */
  transition: background var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out);
}
.sh-theme-toggle .sh-theme-icon-light,
.sh-theme-toggle .sh-theme-icon-dark { display: none; }
/* In light mode: show the MOON (click → switch to dark). */
html:not(.sh-theme-dark) .sh-theme-toggle .sh-theme-icon-dark { display: inline-flex; }
/* In dark mode: show the SUN (click → switch back to light). */
html.sh-theme-dark .sh-theme-toggle .sh-theme-icon-light { display: inline-flex; }

/* Smooth the cross-mode visual transition on the page chrome itself so
   the toggle feels intentional rather than a hard flash. Limit to
   background/color so layout reflow + sparkline animations are
   unaffected. */
body, .frame, .card, .card-emphasis, .btn, .input, .chip, .flow-card {
  transition: background-color var(--dur-base) var(--ease-out),
              color var(--dur-base) var(--ease-out),
              border-color var(--dur-base) var(--ease-out);
}
