/* Design-system refinement layer — cascades LAST over the base styles.
   Extracted from dashboard.html's inline <style> blocks (Epic P / P3): a strict
   style-src cannot keep 'unsafe-inline' while inline <style> elements exist.
   Load ORDER is the contract — see the <link> sequence in dashboard.html. */
  :root{
    /* Dual-font system: proportional sans for UI chrome & prose; the existing
       --font (data-font switcher) stays the "data" font for numbers/tickers. */
    --font-ui: 'Segoe UI', system-ui, -apple-system, 'Helvetica Neue', Arial, sans-serif;
    --font-num: var(--font);
    /* Spacing scale (4px base) */
    --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-5:20px; --sp-6:24px; --sp-8:32px;
    /* Type scale — tokens hold the values already in use so existing rules can
       reference them without any visual change. Eyebrow = tracked micro-labels;
       2xl = KPI card values. Phone overrides live in the 640px media query. */
    --fs-eyebrow:10px; --fs-xs:11px; --fs-sm:12px; --fs-md:14px;
    --fs-lg:16px; --fs-xl:18px; --fs-2xl:22px;
    --fw-normal:400; --fw-medium:600; --fw-bold:700; --fw-heavy:800;
    --lh-tight:1.15; --lh-normal:1.5;
    /* Radii + elevation + motion */
    --r-sm:6px; --r-md:10px; --r-lg:14px;
    --sh-sm:0 1px 2px rgba(0,0,0,.24), 0 1px 3px rgba(0,0,0,.16);
    --sh-md:0 8px 26px rgba(0,0,0,.34);
    --ease:cubic-bezier(.4,0,.2,1);
  }

  /* ── Contrast fixes (WCAG AA) for the default dark + light themes ─────────── */
  html[data-theme="dark"]{ --dim:#9aa5b1; --dim2:#6b7683; --line:#2a3242; }
  html[data-theme="light"]{ --dim:#57606a; --dim2:#8590a0; --line:#c2c9d1; }

  /* ── Persistent legal disclaimer ───────────────────────────────────────────
     Previously an inline style attribute that hardcoded a DARK background
     (rgba(11,18,32,.92)) while its text colour followed the active theme. In the
     light theme that put #57606a on near-black — 2.4:1 — i.e. the one surface
     that must always be readable was the least readable one. It now takes the
     theme's own panel/line/muted tokens, which clear AA in all five themes.
     The links are also the smallest hit targets on the page (they measured
     31×11 at a 390px viewport), so line-height + padding lift them to the
     2.5.8 AA floor of 24×24 without making the bar noticeably taller. */
  #legal-disclaimer{
    position:fixed; bottom:0; left:0; right:0; z-index:60;
    background:var(--panel); border-top:1px solid var(--line);
    color:var(--muted); font-size:10px; letter-spacing:.3px; text-align:center;
    line-height:24px; padding:2px 8px;
  }
  #legal-disclaimer strong{ color:var(--fg); }
  #legal-disclaimer a{
    color:var(--accent); text-decoration:none;
    display:inline-block; min-width:44px; min-height:24px; padding:0 6px;
  }
  #legal-disclaimer a:hover{ text-decoration:underline; }

  /* ── Typography: sans UI chrome, mono data ────────────────────────────────── */
  body{ font-family: var(--font-ui); }
  .nav-item, .nav-group, .page-sub, .section-title, .table-header h3, .banner,
  .empty, .card-label, .btn, button, input, select, textarea, .badge,
  .login-card p, .field label, .user-chip, .topbar-title, .page-title,
  .md, .md p, .md li, .md h1, .md h2, .md h3, .splash-sub{
    font-family: var(--font-ui);
  }
  /* Data keeps mono + aligned tabular figures */
  .card-value, table, th, td, code, pre, .mono, .md code, .md pre,
  [data-num], .ticker, #cmd-panel, .audit-log, .mp-num{
    font-family: var(--font-num); font-variant-numeric: tabular-nums;
  }

  /* ── Casing rule: sentence-case prose, tasteful eyebrow labels ────────────── */
  .page-sub, .banner, .empty, .error-msg, .login-card p, .md, .splash-sub,
  .user-chip, .config-text, .card-sub{ text-transform:none; letter-spacing:normal; }
  /* Short eyebrow / section labels → refined tracked micro-labels (kept caps) */
  .card-label, .nav-group, th, .field label{
    text-transform:uppercase; letter-spacing:.07em; font-weight:var(--fw-medium);
    font-size:var(--fs-eyebrow); color:var(--dim);
  }
  .section-title, .table-header h3{ text-transform:none; letter-spacing:.005em; font-weight:var(--fw-bold); font-size:var(--fs-sm); }
  .page-title{ text-transform:none; letter-spacing:0; font-weight:var(--fw-bold); font-size:var(--fs-xl); border-bottom-color:var(--line); }
  .page-sub{ text-transform:none; color:var(--dim); font-size:var(--fs-sm); letter-spacing:normal; }
  .nav-item{ text-transform:none; letter-spacing:.005em; font-size:var(--fs-sm); }
  .btn-logout{ text-transform:none; letter-spacing:.02em; }

  /* ── Cards: unified grid (no orphan tracks), accent bar, hover lift ───────── */
  .cards{ grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); }
  .card{ position:relative; transition:transform .16s var(--ease), box-shadow .16s var(--ease), background .16s var(--ease); }
  .card:hover{ transform:translateY(-1px); box-shadow:var(--sh-sm); z-index:1; }
  .card.green::before,.card.red::before,.card.blue::before,.card.yellow::before,.card.orange::before{
    content:''; position:absolute; left:0; top:0; bottom:0; width:2px;
  }
  .card.green::before{ background:var(--pos); }
  .card.red::before{ background:var(--neg); }
  .card.blue::before{ background:var(--accent); }
  .card.yellow::before,.card.orange::before{ background:var(--warn); }
  .card-value{ font-size:var(--fs-2xl); letter-spacing:-.01em; }

  /* ── Buttons / inputs: press + focus states ───────────────────────────────── */
  button, .btn{ transition:transform .1s var(--ease), border-color .15s, background .15s, color .15s; }
  button:active, .btn:active{ transform:translateY(1px); }
  input:focus, select:focus, textarea:focus{ border-color:var(--accent); }
  :focus-visible{ outline:2px solid var(--accent); outline-offset:2px; border-radius:4px; }

  /* ── Tables: prose-legible first cells, hover ─────────────────────────────── */
  td{ letter-spacing:normal; }
  tr:hover td{ background:color-mix(in srgb, var(--panel) 70%, transparent); }

  /* ── Tone the animated background down so data always wins ─────────────────── */
  #bg-fx{ opacity:.45; }

  /* ── Liveliness primitives (used by the enhancement script) ───────────────── */
  @keyframes mpPulseUp   { 0%{ background:color-mix(in srgb,var(--pos) 26%,transparent);} 100%{ background:transparent; } }
  @keyframes mpPulseDown { 0%{ background:color-mix(in srgb,var(--neg) 26%,transparent);} 100%{ background:transparent; } }
  .mp-pulse-up{ animation:mpPulseUp .9s var(--ease); }
  .mp-pulse-down{ animation:mpPulseDown .9s var(--ease); }
  @keyframes mpHeartbeat { 0%,100%{ opacity:1; transform:scale(1);} 50%{ opacity:.45; transform:scale(.82);} }
  .status-dot.green.mp-beat::before{ animation:mpHeartbeat 1.8s var(--ease) infinite; display:inline-block; }
  /* Skeleton shimmer utility */
  @keyframes mpShimmer { 100%{ transform:translateX(100%);} }
  .mp-skel{ position:relative; overflow:hidden; background:var(--panel); border-radius:var(--r-sm);
    display:inline-block; min-width:56px; height:1em; vertical-align:middle; }
  .mp-skel::after{ content:''; position:absolute; inset:0; transform:translateX(-100%);
    background:linear-gradient(90deg,transparent,color-mix(in srgb,var(--fg) 10%,transparent),transparent);
    animation:mpShimmer 1.3s infinite; }
  /* Market open/closed pill */
  .mp-pill{ display:inline-flex; align-items:center; gap:6px; font-family:var(--font-ui);
    font-size:11px; font-weight:600; letter-spacing:.02em; padding:2px 9px; border-radius:999px;
    border:1px solid var(--line); color:var(--dim); text-transform:none; }
  .mp-pill .dot{ width:7px; height:7px; border-radius:50%; background:var(--dim2); }
  .mp-pill.open{ color:var(--pos); border-color:color-mix(in srgb,var(--pos) 40%,var(--line)); }
  .mp-pill.open .dot{ background:var(--pos); box-shadow:0 0 0 0 color-mix(in srgb,var(--pos) 60%,transparent);
    animation:mpBeacon 2s infinite; }
  @keyframes mpBeacon { 0%{ box-shadow:0 0 0 0 color-mix(in srgb,var(--pos) 55%,transparent);} 70%{ box-shadow:0 0 0 6px transparent;} 100%{ box-shadow:0 0 0 0 transparent; } }
  .mp-pill.closed .dot{ background:var(--warn); }

  /* ═══════════════ PHASE 3 — RESPONSIVE HARDENING ═══════════════ */
  /* Center content on wide screens */
  @media (min-width:1440px){
    .page{ max-width:1600px; margin-left:auto; margin-right:auto; }
  }
  /* Tablet drawer: comfortable 44px touch targets */
  @media (max-width:1024px){
    .nav-item{ min-height:44px; display:flex; align-items:center; }
    .btn-logout{ min-height:44px; }
  }
  /* Phones: floor body text at 14px (was 11), inputs at 16px to stop iOS zoom */
  /* WCAG 2.2 AA 2.5.8 applies at every width, not just on phones. A checkbox
     label measured 17.39px tall on tablet and desktop, so the control's whole
     activation area was under the 24x24 floor there too.
     ORDER MATTERS AND COST A CYCLE: this first sat AFTER the phone block below.
     Same specificity, later in the file, so 24px won on source order and the
     phone targets came back at 24 instead of 44 — the gate caught it, which is
     the only reason it is not shipping that way. It belongs above, so the phone
     rule raises the same floor rather than fighting it. */
  label:has(> input[type="checkbox"]), label:has(> input[type="radio"]){ min-height:24px; }

  @media (max-width:640px){
    html, body{ font-size:var(--fs-md); }
    input, select, textarea{ font-size:var(--fs-lg); }
    .card-value{ font-size:20px; }
    .page-title{ font-size:var(--fs-lg); }
    .cards{ grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); }
    button, .btn, .nav-item, .tab, .theme-swatch{ min-height:44px; }
    /* Form controls were never in the line above, so on a phone the reports
       page shipped 28px date and email fields, 35px selects and 16x16
       checkboxes — the checkboxes below WCAG 2.2 AA 2.5.8's 24x24, not just
       below the touch bar. A checkbox is left at its own size and its WRAPPING
       LABEL is floored instead: the label is the activation area (clicking the
       word toggles the box), and a 44px checkbox glyph would be a strange
       thing to look at. Those labels measured 17.4px tall, so the small
       control was not being rescued by a large one. (Epic Q / Q2.) */
    input:not([type="checkbox"]):not([type="radio"]), select, textarea{ min-height:44px; }
    label:has(> input[type="checkbox"]), label:has(> input[type="radio"]){ min-height:44px; }
    .mp-num, .card-value{ overflow-wrap:anywhere; }
  }
  @media (prefers-reduced-motion:reduce){
    .mp-pulse-up,.mp-pulse-down,.status-dot.green.mp-beat::before,.mp-pill.open .dot{ animation:none !important; }
  }

  /* ── Semantic colour tokens for JS-selected swatches (Epic P / P3 step 15) ──
     A template can now pick a KNOWN colour by CLASS instead of interpolating a
     hex into style="", which is the last thing keeping 'unsafe-inline' on
     style-src-attr for these two surfaces. Each class sets custom properties;
     custom properties INHERIT, so one class on a container colours its whole
     subtree and the descendants' own declarations stay static var() references.

     Risk-budget state. This is now the ONLY definition of these three colours —
     MPX.stateColor() was deleted rather than left duplicating them, so there is
     no second source to drift from. The mapping (ACTIVE / SAFE_HOLD|NEEDS_RECON
     / everything else) lives in loadRiskCockpit and is pinned by test. */
  /* Account-state colours. These are not decoration: --mp-st draws the status
     dot and the banner's left rule, AND colours the one button that gets an
     account out of the state it is in ("Review & resolve" on NEEDS_RECON,
     "Re-enable" on SAFE_HOLD / HALTED). That button is TEXT, so it owes WCAG
     1.4.3's 4.5:1 against whatever --bg the active theme sets — and the values
     were fixed while --bg is per-theme, so they could not possibly hold across
     all five. Measured on the risk cockpit (Epic Q / Q4):
         bad  #c0392b  dark 3.48 · bloomberg 3.86 · neon 3.54 · mono 3.86  ✗
         warn #e0952b  light 2.47                                          ✗
     Four of the five themes are dark, so the defaults below are the dark-safe
     values and the light theme overrides the two that need it. `ok` is left
     alone deliberately: ACTIVE renders no button, so it is never text, and the
     dot and rule only owe 1.4.11's 3:1, which it clears everywhere. */
  .mp-state--ok{--mp-st:#0fb9a6}
  .mp-state--warn{--mp-st:#e0952b}   /* dark themes 7.66–8.50 */
  .mp-state--bad{--mp-st:#e74c3c}    /* was #c0392b; dark themes now 4.95–5.50 */
  [data-theme="light"] .mp-state--warn{--mp-st:#9c6210}  /* 5.04 on #fff */
  [data-theme="light"] .mp-state--bad{--mp-st:#c0392b}   /* 5.44 on #fff */

  /* The kill switch paints a FIXED red background but took its text colour from
     var(--fg), which flips with the theme — so the most safety-critical control
     in the product was unreadable on three of five themes: light 2.98,
     bloomberg 2.63, neon 4.41, all against 4.5. A fixed background needs a
     fixed foreground; white clears it everywhere at 5.44. (Epic Q / Q4.) */
  #kill-switch-btn{color:#fff}

  /* Provider-category chips. THREE tokens each, not one: the chip paints the
     colour at three alphas, and 8-digit hex keeps the computed values
     byte-identical to the `${col}22` / `${col}55` string concatenation this
     replaced — a color-mix() approximation would have shifted them and shown up
     as a real diff in the render harness. These DO mirror CAT_COLORS in app.js,
     which still needs the raw values for the SVG donut's stroke="" attribute
     (an attribute style-src-attr does not govern), so the duplication is
     unavoidable and guarded by a drift test instead. */
  .mp-cat--price-feed{--mp-cat:#1f8fd6;--mp-cat-bg:#1f8fd622;--mp-cat-bd:#1f8fd655}
  .mp-cat--technicals{--mp-cat:#27b0c4;--mp-cat-bg:#27b0c422;--mp-cat-bd:#27b0c455}
  .mp-cat--options-flow{--mp-cat:#a371f7;--mp-cat-bg:#a371f722;--mp-cat-bd:#a371f755}
  .mp-cat--fallback{--mp-cat:#3ad36a;--mp-cat-bg:#3ad36a22;--mp-cat-bd:#3ad36a55}
  .mp-cat--ai{--mp-cat:#e3b341;--mp-cat-bg:#e3b34122;--mp-cat-bd:#e3b34155}
  /* Unknown category — mirrors the `|| '#8b949e'` fallback in app.js. */
  .mp-cat--other{--mp-cat:#8b949e;--mp-cat-bg:#8b949e22;--mp-cat-bd:#8b949e55}

  /* Report range pills (js/app.js renderRepRanges). Both branches of what used
     to be two concatenated ternaries in a style attribute — the element already
     carried .active, so the whole thing is expressible here. Doubled selectors
     for (0,2,0), which outranks .btn's (0,1,0) from terminal.css; the inline
     attribute used to win that on its own.
     Note the border-radius: while it lived in the attribute, terminal.css:405's
     [style*="border-radius"]{border-radius:0 !important} matched and SQUARED
     these pills. As a class it escapes that selector, so they are finally round —
     the same latent defect the advisor bell badge had. */
  .rep-range.rep-range{padding:6px 12px;border:1px solid var(--line);background:var(--panel);
    color:var(--fg);border-radius:6px;cursor:pointer;font-size:12px}
  .rep-range.rep-range.active{border-color:var(--accent);
    background:color-mix(in srgb,var(--accent) 16%,transparent)}

  /* Token-keyed colour classes, replacing the JS `style="color:${token}"`
     interpolations. Keyed by the CSS TOKEN, not by meaning: the same green means
     "good" in one panel and the spend-trend map deliberately pairs 'up' with
     --neg (rising cost is bad), so a semantic name would have to lie in one place
     or the other. Supersedes the four .mp-dir--* classes, which were this same
     idea scoped to one card.

     Doubled for (0,2,0) so it ties .card.green .card-value. NOT relying on being
     last: the eight mod-*.css sheets load after this one, so a mod rule at equal
     specificity would win on source order. The utility-effect gate in
     cascade-snapshot.mjs is what actually verifies each of these takes effect on
     the elements that carry it. */
  .mp-c--green.mp-c--green{color:var(--green)}
  .mp-c--orange.mp-c--orange{color:var(--orange)}
  .mp-c--red.mp-c--red{color:var(--red)}
  .mp-c--muted.mp-c--muted{color:var(--muted)}
  .mp-c--dim.mp-c--dim{color:var(--dim)}
  .mp-c--pos.mp-c--pos{color:var(--pos)}
  .mp-c--neg.mp-c--neg{color:var(--neg)}
  .mp-c--warn.mp-c--warn{color:var(--warn)}
  /* Text colour for the fallback case: `color || 'var(--text)'` in the signal
     detail rows. --text is not a token this theme defines, so the fallback was
     already resolving to nothing and the cell inherited; kept as-is rather than
     "fixed", because changing it would be a visual change smuggled into a
     mechanical conversion. */
  .mp-c--text.mp-c--text{color:var(--text)}

  /* Binary left-accent borders, replacing two interpolated border-left colours.
     The hex fallbacks in the original (`var(--green,#3ad36a)`) are preserved
     verbatim: --green is defined on every surface that renders these, so the
     fallback is dead, but dropping it would change the declaration's bytes for
     no reason. */
  .mp-bl--pos.mp-bl--pos{border-left:3px solid var(--green,#3ad36a)}
  .mp-bl--neg.mp-bl--neg{border-left:3px solid var(--red,#f85149)}

  /* The live-graduation card: everything but its left accent was already static. */
  .mp-gradcard.mp-gradcard{background:var(--card,var(--bg));border:1px solid var(--line);
    border-radius:6px;padding:14px}
  .mp-gradcard--eligible.mp-gradcard--eligible{border-left:4px solid #0fb9a6}
  .mp-gradcard--blocked.mp-gradcard--blocked{border-left:4px solid #e0952b}

  /* guardrail-compat status. Hardcoded hexes, not tokens, in the original — kept
     exactly, since this conversion is about WHERE the declaration lives. */
  .mp-gc--passed.mp-gc--passed{color:#0fb9a6}
  .mp-gc--failed.mp-gc--failed{color:#c0392b}
  .mp-gc--other.mp-gc--other{color:var(--muted)}

  /* Bars whose only dynamic part was an INTEGER percentage width. The width now
     comes from a generated u-w-<n>pct class — 0..100, so the match is exact
     rather than rounded and the cascade diff stays at 0. Everything else in
     those attributes was already static, or a finite colour map like the meter
     below.

     Note the border-radius on .mp-costbar: in a style attribute it was being
     squared to 0 by terminal.css's [style*="border-radius"] neutraliser. As a
     class it escapes that, so the bar gets the 2px it always asked for — the
     FOURTH element found squared by that one rule. */
  .mp-costbar.mp-costbar{background:var(--accent,#3fb950);opacity:.7;height:8px;border-radius:2px}
  .mp-gatebar.mp-gatebar{height:100%;background:var(--accent)}
  .mp-meterbar.mp-meterbar{height:100%}
  .mp-meterbar--over.mp-meterbar--over{background:#c0392b}
  .mp-meterbar--near.mp-meterbar--near{background:#e0952b}
  .mp-meterbar--ok.mp-meterbar--ok{background:#0fb9a6}
