/* ═══════════════════════════════════════════════════════════════════════════
   SHRADER SEED — theme.css  (2026-09-10)
   Professional, tokenised theme. Loaded AFTER the inline <style> in app.php so
   every rule here wins by source order. Three presets:
     (default)                          "Slate"    — slate neutrals · blue accent
     [data-theme-preset="graphite"]     "Graphite" — near-black nav · warm grey · emerald
     [data-theme-preset="navy"]         "Navy"     — navy nav · cool workspace · amber
   Rules:
     · ONE accent per preset. --grad is FLAT (a two-stop same-colour gradient so
       every existing `background:var(--grad)` consumer keeps working — including
       the text-clipped .grad word in the logo).
     · Categorical chart series live in --s1..--s5, FIXED ORDER, never cycled.
     · Placement/health are STATUS → --st-good/--st-warn/--st-serious/--st-crit,
       always paired with a label or icon (never colour alone).
     · Soft neutral shadows only. No glow, no aurora, no rainbow.
     · Contrast floor (verified numerically): ink ≥ 10:1, --mut ≥ 4.5:1, --mut2 ≥ 3:1
       on the panel in EVERY preset; --accent-ink ≥ 4.5:1 on --accent; --accent-text
       ≥ 4.5:1 on the panel AND on --acc-soft. Focus borders use --accent-text so the
       focus indicator clears 3:1 even when the accent itself is light (emerald/amber).
   WIRING: app.php must load this file AFTER its inline <style>:
       <link rel="stylesheet" href="assets/theme.css?v=YYYYMMDD">
     and a preset is chosen with  document.documentElement.dataset.themePreset='graphite'|'navy'
     (on <html>, NOT <body> — ip_live.js reads tokens from documentElement).
   ═══════════════════════════════════════════════════════════════════════════ */

/* ───────────────────────── 1. TOKENS — default preset "Slate" ───────────── */
:root{
  color-scheme:light;
  /* surfaces */
  --bg:#f5f7fa;--bg2:#eef2f6;--bg3:#e5eaf0;--panel:#ffffff;--tint:rgba(36,112,204,.05);
  /* type */
  --ink:#0f172a;--ink2:#334155;--mut:#5e6b80;--mut2:#7b8698;--on-acc:#ffffff;
  /* lines */
  --bd:#e2e8f0;--bd2:#edf2f7;--bd3:#cbd5e1;--ring:rgba(36,112,204,.24);
  /* the ONE accent — #2470cc, not the #2a78d6 series-1 blue: white on #2a78d6 is only
     4.42:1, white on #2470cc is 4.92:1. Series slot --s1 keeps the validated #2a78d6. */
  --accent:#2470cc;--accent-h:#1c5cab;--accent-d:#164a8a;--acc:var(--accent);
  --accent-ink:#ffffff;            /* ink placed ON the accent (buttons, active pills) */
  --accent-text:#1c5cab;           /* accent used AS text on the panel (≥4.5:1)       */
  --acc-soft:#e8f1fb;--acc-soft2:#d3e4f7;
  /* legacy accent aliases — every old consumer collapses onto the single accent */
  --ind:var(--accent);--ind-h:var(--accent-h);--ind-d:var(--accent-d);
  --vio:var(--accent);--cy:var(--accent);--cy-d:var(--accent-h);
  /* muted semantic colours (UI chrome: banners, dns rows, roadmap chips) */
  --grn:#1e8e4a;--grn-d:#166a37;--grn-soft:#e9f5ee;--grn-bd:#bfe3cc;
  --amb:#b7791f;--amb-d:#8a5a12;--amb-soft:#fbf3e2;--amb-bd:#efd9a6;
  --red:#c9403d;--red-d:#9f2f2c;--red-soft:#fbeaea;--red-bd:#f1c4c3;
  --inf:var(--accent);--inf-d:var(--accent-d);--inf-soft:var(--acc-soft);--inf-bd:var(--acc-soft2);
  /* flat "gradients" — keeps every background:var(--grad) consumer alive, sans rainbow */
  --grad:linear-gradient(0deg,var(--accent),var(--accent));
  --grad-soft:linear-gradient(0deg,var(--acc-soft),var(--acc-soft));
  /* soft neutral shadows */
  --sh:0 1px 2px rgba(15,23,42,.04),0 0 0 1px rgba(15,23,42,.02);
  --sh-md:0 1px 2px rgba(15,23,42,.04),0 4px 12px -4px rgba(15,23,42,.08);
  --sh-lg:0 2px 4px rgba(15,23,42,.04),0 12px 28px -12px rgba(15,23,42,.14);
  --sh-xl:0 4px 8px rgba(15,23,42,.05),0 24px 56px -16px rgba(15,23,42,.22);
  --sh-brand:0 1px 2px rgba(15,23,42,.08);
  --sh-pill:0 1px 2px rgba(15,23,42,.05);
  /* radii */
  --r:12px;--r-sm:8px;--r-lg:14px;--r-pill:999px;
  /* categorical series — FIXED ORDER, never cycled, never re-assigned when hidden */
  --s1:#2a78d6;--s2:#eb6834;--s3:#1baf7a;--s4:#eda100;--s5:#e87ba4;
  /* status (placement inbox/promo/spam, health) — always with a label/icon */
  --st-good:#0ca30c;--st-warn:#fab219;--st-serious:#ec835a;--st-crit:#d03b3b;
  --st-good-soft:#e6f6e6;--st-warn-soft:#fef4dc;--st-serious-soft:#fdeee7;--st-crit-soft:#fbe7e7;
  --st-good-text:#087508;--st-warn-text:#8a5d00;--st-serious-text:#a8441c;--st-crit-text:#a52c2c;
  /* charts */
  --chart-grid:#e8edf3;--chart-axis:#5e6b80;--chart-tip-bg:#0f172a;--chart-tip-ink:#f8fafc;
  /* nav chrome */
  --nav-bg:#0f172a;--nav-ink:#f1f5f9;--nav-mut:#94a3b8;--nav-bd:rgba(255,255,255,.08);
  --nav-hover:rgba(255,255,255,.07);--nav-on-bg:rgba(36,112,204,.26);--nav-on-ink:#93c1f2;
  /* postmaster sparkline colour was undefined → invisible; sane fallback */
  --pm:var(--accent);
  --ease:cubic-bezier(.22,.61,.36,1);--ease-out:cubic-bezier(.2,.8,.2,1);
  /* sender avatars — picked deterministically by FNV-1a over the address, so one sender is
     always one colour. Every value is dark enough for WHITE initials at >=4.5:1. */
  --av1:#1e6fb8;--av2:#b0472c;--av3:#16794f;--av4:#6d45b5;
  --av5:#0f7382;--av6:#b03a72;--av7:#96601b;--av8:#4a5a75;
  --av9:#3f4fb5;--av10:#a83246;--av11:#4a7020;--av12:#1a6a94;
}

/* ───────────────────────── 1b. PRESET "Graphite" ─────────────────────────── */
[data-theme-preset="graphite"]{
  --bg:#f4f3f0;--bg2:#ebe9e5;--bg3:#e1dfda;--panel:#ffffff;--tint:rgba(27,175,122,.05);
  --ink:#19191a;--ink2:#3d3c3a;--mut:#66655f;--mut2:#82817c;--on-acc:#06281b;
  --bd:#e2dfda;--bd2:#edebe7;--bd3:#cbc8c1;--ring:rgba(27,175,122,.24);
  --accent:#1baf7a;--accent-h:#14905f;--accent-d:#0f704a;--acc:var(--accent);
  --accent-ink:#06281b;            /* white on emerald is <3:1 → dark ink on accent */
  --accent-text:#0f704a;
  --acc-soft:#e6f6ef;--acc-soft2:#c8ecda;
  --ind:var(--accent);--ind-h:var(--accent-h);--ind-d:var(--accent-d);
  --vio:var(--accent);--cy:var(--accent);--cy-d:var(--accent-h);
  --grn:#1e8e4a;--grn-d:#166a37;--grn-soft:#e9f5ee;--grn-bd:#bfe3cc;
  --amb:#b7791f;--amb-d:#8a5a12;--amb-soft:#fbf3e2;--amb-bd:#efd9a6;
  --red:#c9403d;--red-d:#9f2f2c;--red-soft:#fbeaea;--red-bd:#f1c4c3;
  --inf:var(--accent);--inf-d:var(--accent-d);--inf-soft:var(--acc-soft);--inf-bd:var(--acc-soft2);
  --grad:linear-gradient(0deg,var(--accent),var(--accent));
  --grad-soft:linear-gradient(0deg,var(--acc-soft),var(--acc-soft));
  --sh:0 1px 2px rgba(25,25,26,.05),0 0 0 1px rgba(25,25,26,.025);
  --sh-md:0 1px 2px rgba(25,25,26,.04),0 4px 12px -4px rgba(25,25,26,.09);
  --sh-lg:0 2px 4px rgba(25,25,26,.04),0 12px 28px -12px rgba(25,25,26,.16);
  --sh-xl:0 4px 8px rgba(25,25,26,.05),0 24px 56px -16px rgba(25,25,26,.24);
  --sh-brand:0 1px 2px rgba(25,25,26,.08);
  --sh-pill:0 1px 2px rgba(25,25,26,.05);
  --r:12px;--r-sm:8px;--r-lg:14px;--r-pill:999px;
  --s1:#2a78d6;--s2:#eb6834;--s3:#1baf7a;--s4:#eda100;--s5:#e87ba4;
  --st-good:#0ca30c;--st-warn:#fab219;--st-serious:#ec835a;--st-crit:#d03b3b;
  --st-good-soft:#e6f6e6;--st-warn-soft:#fef4dc;--st-serious-soft:#fdeee7;--st-crit-soft:#fbe7e7;
  --st-good-text:#087508;--st-warn-text:#8a5d00;--st-serious-text:#a8441c;--st-crit-text:#a52c2c;
  --chart-grid:#e6e3de;--chart-axis:#66655f;--chart-tip-bg:#19191a;--chart-tip-ink:#f7f6f3;
  --nav-bg:#111214;--nav-ink:#f3f2ef;--nav-mut:#9a9893;--nav-bd:rgba(255,255,255,.08);
  --nav-hover:rgba(255,255,255,.07);--nav-on-bg:rgba(27,175,122,.22);--nav-on-ink:#6fdcb1;
  --pm:var(--accent);
  /* avatars — warmer set to sit with graphite's paper; same darkness band, white initials */
  --av1:#2f6f4f;--av2:#8a4b23;--av3:#1f7a5a;--av4:#6b4a9c;
  --av5:#146b74;--av6:#9c3a63;--av7:#8a5a12;--av8:#4f5a52;
  --av9:#3d4f8a;--av10:#9c3340;--av11:#566b1f;--av12:#1f6a8a;
}

/* ───────────────────────── 1c. PRESET "Navy" ─────────────────────────────── */
[data-theme-preset="navy"]{
  --bg:#f3f6fa;--bg2:#eaf0f6;--bg3:#dfe7f0;--panel:#ffffff;--tint:rgba(237,161,0,.06);
  --ink:#0b1f3a;--ink2:#2d4160;--mut:#59698a;--mut2:#75869f;--on-acc:#1a1400;
  --bd:#dde5ee;--bd2:#e8eef5;--bd3:#c3d0de;--ring:rgba(237,161,0,.28);
  --accent:#eda100;--accent-h:#c98500;--accent-d:#8a5d00;--acc:var(--accent);
  --accent-ink:#1a1400;            /* dark ink on amber */
  --accent-text:#8a5d00;
  --acc-soft:#fdf3da;--acc-soft2:#f8e4b0;
  --ind:var(--accent);--ind-h:var(--accent-h);--ind-d:var(--accent-d);
  --vio:var(--accent);--cy:var(--accent);--cy-d:var(--accent-h);
  --grn:#1e8e4a;--grn-d:#166a37;--grn-soft:#e9f5ee;--grn-bd:#bfe3cc;
  --amb:#b7791f;--amb-d:#8a5a12;--amb-soft:#fbf3e2;--amb-bd:#efd9a6;
  --red:#c9403d;--red-d:#9f2f2c;--red-soft:#fbeaea;--red-bd:#f1c4c3;
  --inf:var(--accent);--inf-d:var(--accent-d);--inf-soft:var(--acc-soft);--inf-bd:var(--acc-soft2);
  --grad:linear-gradient(0deg,var(--accent),var(--accent));
  --grad-soft:linear-gradient(0deg,var(--acc-soft),var(--acc-soft));
  --sh:0 1px 2px rgba(11,31,58,.05),0 0 0 1px rgba(11,31,58,.025);
  --sh-md:0 1px 2px rgba(11,31,58,.04),0 4px 12px -4px rgba(11,31,58,.09);
  --sh-lg:0 2px 4px rgba(11,31,58,.04),0 12px 28px -12px rgba(11,31,58,.16);
  --sh-xl:0 4px 8px rgba(11,31,58,.05),0 24px 56px -16px rgba(11,31,58,.24);
  --sh-brand:0 1px 2px rgba(11,31,58,.08);
  --sh-pill:0 1px 2px rgba(11,31,58,.05);
  --r:12px;--r-sm:8px;--r-lg:14px;--r-pill:999px;
  --s1:#2a78d6;--s2:#eb6834;--s3:#1baf7a;--s4:#eda100;--s5:#e87ba4;
  --st-good:#0ca30c;--st-warn:#fab219;--st-serious:#ec835a;--st-crit:#d03b3b;
  --st-good-soft:#e6f6e6;--st-warn-soft:#fef4dc;--st-serious-soft:#fdeee7;--st-crit-soft:#fbe7e7;
  --st-good-text:#087508;--st-warn-text:#8a5d00;--st-serious-text:#a8441c;--st-crit-text:#a52c2c;
  --chart-grid:#e3eaf2;--chart-axis:#59698a;--chart-tip-bg:#0b1f3a;--chart-tip-ink:#f5f8fc;
  --nav-bg:#0b1f3a;--nav-ink:#f3f6fa;--nav-mut:#9db0c8;--nav-bd:rgba(255,255,255,.09);
  --nav-hover:rgba(255,255,255,.07);--nav-on-bg:rgba(237,161,0,.22);--nav-on-ink:#f6c65a;
  --pm:var(--accent);
  /* avatars — cooler set for navy; same darkness band, white initials */
  --av1:#1e5fa8;--av2:#a04a20;--av3:#16705e;--av4:#5a45b0;
  --av5:#0f6a86;--av6:#a3356a;--av7:#8a5d00;--av8:#445a7a;
  --av9:#34489e;--av10:#9c2f46;--av11:#40662a;--av12:#175f92;
}

/* ───────────────────────── 2. BASE / WORKSPACE ───────────────────────────── */
body{background:var(--bg);background-image:none;background-attachment:scroll;color:var(--ink)}
.login-wrap{background:var(--bg);background-image:none}
h1,.topbar h1{color:var(--ink)}
.muted{color:var(--mut)}
::selection{background:var(--acc-soft2);color:var(--ink)}
/* the logo word: no text-clipped gradient, just the accent */
.grad{background:none;-webkit-background-clip:initial;background-clip:initial;color:var(--accent-text);-webkit-text-fill-color:currentColor}
.topnav .grad{color:var(--nav-on-ink)}

/* ───────────────────────── 3. TOP NAV — solid, no pill, no glow ──────────── */
.topnav{background:var(--nav-bg);background-image:none;color:var(--nav-ink);height:60px;
  border-bottom:1px solid var(--nav-bd);box-shadow:none;
  -webkit-backdrop-filter:none;backdrop-filter:none}
.topnav .logo{color:var(--nav-ink)}
.topnav .logo svg,.topnav .logo path{stroke:var(--nav-ink)}
.topnav nav{background:transparent;border:0;box-shadow:none;padding:0;gap:2px;border-radius:0}
.topnav nav a{color:var(--nav-mut);font-weight:600;border-radius:8px;
  box-shadow:none;text-shadow:none;transition:background .12s var(--ease),color .12s var(--ease)}
.topnav nav a span{opacity:.75}
.topnav nav a:hover{background:var(--nav-hover);color:var(--nav-ink)}
.topnav nav a:hover span{opacity:1}
.topnav nav a.on{background:var(--nav-on-bg);color:var(--nav-on-ink);box-shadow:none;text-shadow:none}
.topnav nav a.on span{opacity:1}
/* app.php collapses the nav to two rows ≤900px with height:auto — our fixed 60px must yield there */
@media(max-width:900px){.topnav{height:auto}}
.topnav .who{color:var(--nav-mut)}
.topnav .who .wn{color:var(--nav-ink)}
.topnav .who #logout{color:var(--nav-mut)}
.topnav .who #logout:hover{color:var(--nav-ink)}

/* theme switcher (3 dots) — markup + JS in the spec */
.theme-sw{display:inline-flex;align-items:center;gap:7px;padding:5px 8px;border:1px solid var(--nav-bd);border-radius:var(--r-pill);line-height:0}
.theme-sw button{width:12px;height:12px;border-radius:50%;padding:0;border:2px solid transparent;cursor:pointer;
  background:var(--sw-c,var(--nav-mut));box-shadow:0 0 0 1px rgba(0,0,0,.25);transition:transform .12s var(--ease),border-color .12s var(--ease)}
.theme-sw button[data-preset="slate"]{--sw-c:#2470cc}
.theme-sw button[data-preset="graphite"]{--sw-c:#1baf7a}
.theme-sw button[data-preset="navy"]{--sw-c:#eda100}
.theme-sw button:hover{transform:scale(1.15)}
.theme-sw button.on{border-color:var(--nav-ink);transform:scale(1.15)}
.theme-sw button:focus-visible{outline:2px solid var(--nav-ink);outline-offset:2px}

/* ───────────────────────── 4. BUTTONS — flat accent ──────────────────────── */
.btn{border-radius:9px;letter-spacing:0;transition:background .12s var(--ease),border-color .12s var(--ease),box-shadow .12s var(--ease),transform .08s var(--ease)}
.btn:hover:not(:disabled){transform:none}
.btn-p{background:var(--accent);background-image:none;color:var(--accent-ink);border-color:transparent;box-shadow:var(--sh-brand)}
.btn-p:hover,.btn-p:hover:not(:disabled){background:var(--accent-h);color:var(--accent-ink);transform:none;box-shadow:var(--sh-brand)}
.btn-g{background:var(--panel);border-color:var(--bd);color:var(--ink);box-shadow:var(--sh)}
.btn-g:hover,.btn-g:hover:not(:disabled){background:var(--bg2);border-color:var(--bd3);transform:none;box-shadow:var(--sh)}
.btn:active:not(:disabled),.btn:active,.btn-p:active,.btn-g:active{transform:translateY(1px);box-shadow:none}
.btn-p:focus-visible,.btn-g:focus-visible{outline:none;box-shadow:0 0 0 3px var(--ring)}
.btn-sm{border-radius:8px}

/* inputs */
input,select,textarea{border:1px solid var(--bd);border-radius:9px;background:var(--panel);color:var(--ink);box-shadow:none}
input:focus,select:focus,textarea:focus{border-color:var(--accent-text);box-shadow:0 0 0 3px var(--ring)}
.toggle span{background:var(--bd3)}
.toggle input:checked+span{background:var(--accent);background-image:none}
.seg{background:var(--bg2)}
.seg button.on{background:var(--panel);color:var(--ink);box-shadow:var(--sh)}

/* ───────────────────────── 5. CARDS — 1px border + one soft shadow ───────── */
.card,.ovtile,.mbcard,.rmcard{background:var(--panel);border:1px solid var(--bd);border-radius:var(--r);box-shadow:var(--sh)}
.card.hoverable:hover,.scard:hover,.chartbox:hover,.mbcard:hover,.rmcard:hover,.ovtile:hover{
  transform:none;box-shadow:var(--sh-md)!important;border-color:var(--bd3)}
/* score hero: flat panel, no aurora */
.ov-score,#ovScore,#scWrap{background:var(--panel)!important;background-image:none!important;border-radius:var(--r)}
.gauge-well{background:var(--bg2);border:1px solid var(--bd);box-shadow:none;border-radius:var(--r)}
.gauge-svg{filter:none}
.gauge-svg .track{stroke:var(--bg3)}
/* .arc is NOT restyled: gaugeSvg() paints it with a score-band status gradient (stroke="url(#…)");
   a CSS stroke here would beat that presentation attribute and erase the band meaning. */
/* stat-tile icon chips: quiet neutral, not a gradient */
.ovtile .ic,.scard .ic{background:var(--bg2)!important;background-image:none!important;
  box-shadow:inset 0 0 0 1px var(--bd);border-radius:10px}
.ovtile-v{color:var(--ink)}
.ovtile-l{color:var(--ink2)}
.scard .big{color:var(--ink)}
/* factor / ramp / health mini-bars */
.fbar{background:var(--bg3)}
.fbar>i{background:var(--accent);background-image:none}
.ramp-card::before{background:var(--accent)}
.ramp-bar{background:var(--bg3);box-shadow:none}
.ramp-bar>i{background:var(--accent);background-image:none}
.ramp-bar>i::after{display:none;animation:none}
.mb-hbar{background:var(--bg3)}
.mb-hbar>i{background:var(--accent);background-image:none}   /* quantity, not a status band */
.bar{background:var(--bg3)}

/* ───────────────────────── 6. STATUS — chips, dots, placement bar ────────── */
.chip{border:1px solid transparent}
.chip.inbox{background:var(--st-good-soft);color:var(--st-good-text)}
.chip.promo{background:var(--st-warn-soft);color:var(--st-warn-text)}
.chip.spam{background:var(--st-crit-soft);color:var(--st-crit-text)}
/* stacked placement bar — status hues, 2px gap between segments, rounded ends */
.pbar{height:12px;background:var(--bg3);box-shadow:none;border-radius:var(--r-pill)}
.pbar>i+i{box-shadow:-2px 0 0 0 var(--panel)}   /* 0-width segment → 0-width shadow → no phantom notch */
.pbar .seg-inbox{background:var(--st-good)}
.pbar .seg-promo{background:var(--st-warn)}
.pbar .seg-spam{background:var(--st-crit)}
/* mailbox status */
.mb-dot.active{background:var(--st-good)}
.mb-dot.paused{background:var(--st-warn)}
.mb-dot.blocked{background:var(--st-crit)}
.mb-status{border:1px solid transparent}
.mb-status.active{color:var(--st-good-text);background:var(--st-good-soft)}
.mb-status.paused{color:var(--st-warn-text);background:var(--st-warn-soft)}
.mb-status.blocked{color:var(--st-crit-text);background:var(--st-crit-soft)}
.ovmb{background:var(--panel);border-color:var(--bd)}
.ovmb:hover{background:var(--bg2);border-color:var(--bd3)}
.mb-prov{background:var(--bg2);border-color:var(--bd)}
/* health strip — flat panel + 3px status edge (no gradient wash) */
.hcard{background:var(--panel);border:1px solid var(--bd);border-left-width:3px}
.hcard-ok{background:var(--panel);background-image:none;border-color:var(--bd);border-left-color:var(--st-good)}
.hcard-warn{background:var(--panel);background-image:none;border-color:var(--bd);border-left-color:var(--st-warn)}
.hcard-crit{background:var(--panel);background-image:none;border-color:var(--bd);border-left-color:var(--st-crit)}
.hdot.ok{background:var(--st-good)}
.hdot.warn{background:var(--st-warn)}
.hdot.crit{background:var(--st-crit);animation:pulseCrit 2s ease-out infinite}
@keyframes pulseCrit{0%{box-shadow:0 0 0 0 rgba(208,59,59,.45)}70%{box-shadow:0 0 0 8px rgba(208,59,59,0)}100%{box-shadow:0 0 0 0 rgba(208,59,59,0)}}
.wd-row{background:var(--panel);border:1px solid var(--bd);border-left-width:3px;border-radius:var(--r)}
.wd-row.critical{background:var(--panel);background-image:none;border-left-color:var(--st-crit)}
.wd-row.warn{background:var(--panel);background-image:none;border-left-color:var(--st-warn)}
.wd-row.ok{border-left-color:var(--st-good)}
.wd-fix{background:var(--bg2);border-color:var(--bd2)}
/* DNS rows */
.dns-row{background:var(--panel);border-color:var(--bd)}
.dns-row.is-valid{border-color:var(--bd);background:var(--st-good-soft)}
.dns-row.is-missing{border-color:var(--bd);background:var(--st-warn-soft)}
.dns-row.is-warn,.dns-row.is-error{border-color:var(--bd);background:var(--bg2)}
.is-valid .dns-dot{background:var(--st-good)}
.is-missing .dns-dot{background:var(--st-warn)}
.is-error .dns-dot{background:var(--mut2)}
/* live pill — calm, neutral, the dot carries the status */
.live-pill{background:var(--panel);background-image:none;border:1px solid var(--bd);color:var(--ink2);box-shadow:none;font-weight:600}
.dot-live{background:var(--st-good);box-shadow:0 0 0 3px var(--st-good-soft);animation:pulse 2.4s infinite}
@keyframes pulse{0%,100%{box-shadow:0 0 0 3px var(--st-good-soft)}50%{box-shadow:0 0 0 6px rgba(12,163,12,.12)}}
.live-pill.is-quiet .dot-live{background:var(--mut2);box-shadow:none;animation:none}
/* roadmap / grade chips */
.rm-shipped{color:var(--st-good-text);background:var(--st-good-soft);border-color:transparent}
.rm-building{color:var(--accent-text);background:var(--acc-soft);border-color:transparent}
.rm-planned{color:var(--mut);background:var(--bg2);border-color:var(--bd)}
/* banners */
.banner{background:var(--amb-soft);background-image:none;border-color:var(--amb-bd);color:var(--amb-d);border-radius:var(--r)}
.banner-red{background:var(--red-soft);border-color:var(--red-bd);color:var(--red-d)}
.toast{background:var(--ink);color:var(--panel);box-shadow:var(--sh-xl);border-radius:10px}

/* ───────────────────────── 7. FILTER PILLS / SELECTABLE TILES ────────────── */
.mbf{background:var(--panel);border-color:var(--bd);color:var(--ink2);box-shadow:none}
.mbf:hover{border-color:var(--bd3);transform:none;background:var(--bg2)}
.mbf.on{background:var(--acc-soft);background-image:none;color:var(--accent-text);border-color:var(--acc-soft2);box-shadow:none}
.mbf.on b{color:var(--accent-text)}
.mb-grp{background:var(--acc-soft);color:var(--accent-text);border-color:var(--acc-soft2)}
.mb-grp:hover{background:var(--acc-soft2)}
.mb-grp.none{background:transparent;color:var(--mut2);border-color:var(--bd3)}
.mb-grp.none:hover{color:var(--accent-text);border-color:var(--accent-text)}
.provtile{background:var(--panel);border-color:var(--bd);color:var(--ink2)}
.provtile.on{border-color:var(--accent-text);background:var(--acc-soft);color:var(--accent-text);box-shadow:none}
.pm-chips .chip:hover{transform:none;box-shadow:none}
.pm-chips .chip.inbox{background:var(--acc-soft);color:var(--accent-text);border-color:var(--acc-soft2)}

/* ───────────────────────── 8. TABLES ─────────────────────────────────────── */
th{color:var(--mut);border-bottom:1px solid var(--bd)}
td{border-bottom:1px solid var(--bd2);color:var(--ink)}
.tbl td{border-bottom:1px solid var(--bd2)}
tbody tr:hover td{background:var(--bg2)}
.feedrow:hover{background:var(--bg2)}
@keyframes feedin{from{opacity:0;transform:translateY(-6px);background:var(--acc-soft)}to{opacity:1;transform:none;background:transparent}}

/* ───────────────────────── 9. INBOX CLIENT / MODALS ──────────────────────── */
/* .mc-box stays in the shared selector below — it is a DIFFERENT component (app.php:396, the
   small modal behind mbSetGroup and the message-list popups). Dropping it here would strip
   those modals' panel, border and shadow. */
.mclient{background:rgba(15,23,42,.45)}
.mc-sheet,.mc-box{background:var(--panel);box-shadow:var(--sh-xl);border:1px solid var(--bd);border-radius:var(--r-lg)}
@media(max-width:900px){.mc-sheet{border:0;border-radius:0}}
.mc-em{color:var(--ink)}
.mc-sub{color:var(--mut)}
.mc-x{background:var(--bg2);color:var(--ink2)}
.mc-x:hover{background:var(--bd)}
.mc-live{color:var(--mut)}
.mc-live>i{background:var(--st-good)}
.mc-live.is-retry>i{background:var(--st-warn)}
.mc-live.is-down>i,.mc-live.is-idle>i,.mc-live.is-hidden>i{background:var(--mut2)}
.mc-newpill{background:var(--acc-soft);color:var(--accent-text);box-shadow:var(--sh-pill)}
/* rail */
.mc-rail{background:var(--bg2)}
.mc-rail a{color:var(--ink2)}
.mc-rail a:hover{background:var(--acc-soft)}
.mc-rail a.on{background:var(--panel);color:var(--accent-text);box-shadow:var(--sh)}
.mc-rail a .ct{color:var(--mut)}
.mc-rail a .ct.on{background:var(--acc-soft);color:var(--accent-text)}
.mc-note{color:var(--mut)}
/* list */
.mc-listbar,.mc-foot{background:var(--panel);border-color:var(--bd)}
.mc-foot{color:var(--mut)}
.mc-qic{color:var(--mut)}
.mc-q{background:var(--bg2);border:1px solid transparent;color:var(--ink)}
.mc-q:focus{background:var(--panel);border-color:var(--accent);box-shadow:0 0 0 3px var(--ring)}
.mc-dens{color:var(--mut)}
.mc-dens:hover{background:var(--bg2);color:var(--ink)}
/* row: unread is the accent bar + type weight, never colour alone (the old .dot is gone) */
.mc-row{background:transparent}
.mc-row:not(.seen){background:var(--panel)}
.mc-row:not(.seen)::before{background:var(--accent)}
.mc-row:hover{background:var(--bg2)}
.mc-row.on{background:var(--acc-soft)}
.mc-row.cur{box-shadow:inset 0 0 0 2px var(--accent-text)}
.mc-row .snd,.mc-row .subj{color:var(--ink)}
.mc-row .tm{color:var(--mut)}
.mc-row .star{color:var(--st-warn)}
.mc-row .ans{color:var(--st-good)}
.mc-row.seen .snd{color:var(--ink2)}
.mc-row.seen .subj{color:var(--mut)}
.mc-av{color:#fff}
@keyframes mcGlow{0%{background:var(--acc-soft)}100%{background:transparent}}
/* reading pane */
.mc-read,.mc-read .rd-actions{background:var(--panel)}
.rd-subj,.rd-nm{color:var(--ink)}
.rd-addr,.rd-to,.rd-when{color:var(--mut)}
.rd-fold{background:var(--bg2);border-color:var(--bd);color:var(--mut)}
/* composer */
.mc-comp{background:var(--bg2);border-color:var(--bd)}
.mc-comp .cp-head b{color:var(--ink)}
.cp-from,.cp-f>span{color:var(--mut)}
.cp-f input,.cp-body{background:var(--panel);border:1px solid var(--bd);color:var(--ink)}
.cp-f input:focus,.cp-body:focus{border-color:var(--accent);box-shadow:0 0 0 3px var(--ring)}
.cp-msg{color:var(--mut)}
.cp-msg.bad{color:var(--st-crit-text)}
.mc-comp.is-sent{background:var(--st-good-soft);border-color:transparent;color:var(--st-good-text)}
/* empty states */
.mc-empty{color:var(--mut)}
.mc-empty b{color:var(--ink2)}
.mc-empty kbd{background:var(--bg2);color:var(--ink2);border-color:var(--bd3)}
/* shared message viewer (reader + Live Feed + Email Log) */
.msgseg{background:var(--bg2)}
.msgseg button{color:var(--mut)}
.msgseg button.on{background:var(--panel);color:var(--ink);font-weight:700;box-shadow:var(--sh-pill)}
.msgv-text pre{background:var(--bg2);border-color:var(--bd);color:var(--ink2)}

/* ───────────────────────── 10. EMPTY / IDLE / POSTMASTER — no fake motion ── */
.empty{background:var(--panel);background-image:none;border-radius:var(--r)}
.empty-g{animation:none;opacity:.7}
.pm-hero{background:var(--panel);background-image:none}
.pm-big{text-shadow:none}
.skel{background:linear-gradient(90deg,var(--bg2) 25%,var(--panel) 37%,var(--bg2) 63%);background-size:400% 100%}
.subjbox{background:var(--bg2);border-color:var(--bd)}

/* ───────────────────────── 11. CHART SURFACES ───────────────────────────── */
/* Chart.js reads colours from JS; expose them as tokens (see spec) and keep the
   canvas box quiet. Grid = --chart-grid, axis labels = --chart-axis. */
.chartbox{padding:18px 20px}
.chartbox h3{color:var(--ink);font-size:14px;margin-bottom:12px}
.chart-legend{display:flex;flex-wrap:wrap;gap:6px 14px;font-size:12px;color:var(--ink2);margin-bottom:8px}
.chart-legend i{display:inline-block;width:10px;height:10px;border-radius:3px;margin-right:6px;vertical-align:-1px}
.chart-legend .s1 i{background:var(--s1)}.chart-legend .s2 i{background:var(--s2)}.chart-legend .s3 i{background:var(--s3)}
.chart-legend .s4 i{background:var(--s4)}.chart-legend .s5 i{background:var(--s5)}
.chart-legend .good i{background:var(--st-good)}.chart-legend .warn i{background:var(--st-warn)}
.chart-legend .serious i{background:var(--st-serious)}.chart-legend .crit i{background:var(--st-crit)}
/* stat tile: value + delta + sparkline. Direction (up/down) is NOT a status — a rising spam count
   is bad — so up/down stay in ink; a caller that has judged good/bad uses .good/.bad. */
.stat-delta{font-size:12px;font-weight:600;color:var(--mut)}
.stat-delta.up,.stat-delta.down{color:var(--ink2)}
.stat-delta.good{color:var(--st-good-text)}
.stat-delta.bad{color:var(--st-crit-text)}
/* sparklines (.spark = Postmaster, .lv-spark = live tiles) carry their colour as inline
   stroke/fill attributes chosen per series — CSS must not override them; only the mark weight. */
.spark polyline,.spark path,.lv-spark polyline{fill:none;stroke-width:2}

/* ───────────────────────── 12. MOTION SAFETY ────────────────────────────── */
@media (prefers-reduced-motion:reduce){
  .dot-live,.hdot.crit,.skel,.spark polyline{animation:none}
  .spark polyline{stroke-dasharray:none;stroke-dashoffset:0}   /* app.php draws via dashoffset 600→0 */
  .btn,.card,.ovtile,.topnav nav a{transition:none}
}

/* ══════ seed fleet control (assets/ip_fleet.css) ══════ */
/* ── Mailboxes · fleet view (append to theme.css) — tokens only, no gradients, no glow ── */
.fl-tools{display:flex;flex-wrap:wrap;align-items:center;gap:10px;margin-bottom:12px}
.fl-q{flex:1 1 220px;max-width:320px;padding:8px 12px;font-size:13px}
.fl-sort{padding:8px 10px;font-size:12.5px;margin-left:auto}
.fl-dot{display:inline-block;width:8px;height:8px;border-radius:var(--r-pill);margin-right:6px;background:var(--bd3);vertical-align:0}
.fl-dot.good{background:var(--st-good)}.fl-dot.warn{background:var(--st-warn)}.fl-dot.serious{background:var(--st-serious)}.fl-dot.crit{background:var(--st-crit)}
/* status badge — the state word is the truth, coloured by the --st-* band */
.mb-status.working{color:var(--st-good-text);background:var(--st-good-soft)}
.mb-status.refused{color:var(--st-serious-text);background:var(--st-serious-soft)}
.mb-status.throttled{color:var(--st-warn-text);background:var(--st-warn-soft)}
.mb-status.paused{color:var(--mut);background:var(--bg3)}
.mb-status.dead{color:var(--st-crit-text);background:var(--st-crit-soft)}
.mb-status.flaky{color:var(--st-warn-text);background:var(--st-warn-soft)}
.mb-status.unknown{color:var(--mut);background:var(--bg3)}
.mb-status.unverified{color:var(--ink2);background:var(--bg3);border:1px dashed var(--bd3)}
.fl-card[data-state="dead"] .mb-hbar>i{background:var(--st-crit)}
/* card extras: checkbox top-left, ⋯ top-right, selected ring */
.fl-card{position:relative}
.fl-card.is-sel{border-color:var(--accent-text);box-shadow:0 0 0 2px var(--ring)}
.fl-card[data-state="paused"] .mb-hbar>i{background:var(--bd3)}
.fl-ck{position:absolute;top:14px;left:14px;display:grid;place-items:center;cursor:pointer}
.fl-ck input,.fl-opt input{width:15px;height:15px;margin:0;accent-color:var(--accent);cursor:pointer}
.fl-dots{position:absolute;top:10px;right:10px;width:26px;height:26px;border:1px solid transparent;border-radius:var(--r-sm);background:transparent;color:var(--mut);font-size:16px;line-height:1;cursor:pointer}
.fl-dots:hover{background:var(--bg2);border-color:var(--bd);color:var(--ink)}
.fl-menu{position:absolute;top:38px;right:10px;z-index:30;min-width:150px;padding:5px;background:var(--panel);border:1px solid var(--bd);border-radius:var(--r-sm);box-shadow:var(--sh-md)}
.fl-menu button{display:block;width:100%;text-align:left;padding:7px 10px;border:0;border-radius:6px;background:transparent;color:var(--ink);font:inherit;font-size:13px;cursor:pointer}
.fl-menu button:hover{background:var(--bg2)}
.fl-menu button.danger,.btn.danger{color:var(--st-crit-text)}
.btn-p.danger{background:var(--st-crit);color:#fff}
.btn-p.danger:hover:not(:disabled){background:var(--st-crit-text);color:#fff}
/* bulk bar (sticky bottom) + paced-test progress */
.fl-bulk{position:sticky;bottom:12px;z-index:20;display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-top:16px;padding:10px 14px;background:var(--panel);border:1px solid var(--accent-text);border-radius:var(--r);box-shadow:var(--sh-md)}
.fl-bulk b{margin-right:6px;color:var(--accent-text)}
.fl-prog{margin-bottom:14px;padding:10px 14px;background:var(--panel);border:1px solid var(--bd);border-radius:var(--r)}
.fl-prog-row{display:flex;align-items:center;gap:12px;flex-wrap:wrap;font-size:12.5px;margin-top:8px}
.fl-prog-row .btn{margin-left:auto}
.fl-bar{height:6px;border-radius:var(--r-pill);background:var(--bg3);overflow:hidden}
.fl-bar>i{display:block;height:100%;background:var(--accent);transition:width .3s}
/* modals (Remove / Edit) in the mbProxyModal pattern */
.fl-modal{width:540px;max-width:94vw;margin-top:8vh;padding:0;max-height:88vh;overflow:auto}
.fl-modal-hd{display:flex;align-items:center;justify-content:space-between;padding:16px 22px;border-bottom:1px solid var(--bd)}
.fl-x{border:0;background:var(--bg2);color:var(--ink);width:32px;height:32px;border-radius:9px;cursor:pointer;font-size:15px}
.fl-x:hover{background:var(--bg3)}
.fl-list{margin:0 0 12px;padding:10px 14px 10px 28px;background:var(--bg2);border-radius:var(--r-sm);font-size:12.5px;line-height:1.7}
.fl-opt{display:flex;align-items:center;gap:8px;font-size:12.5px;color:var(--ink2);cursor:pointer;margin-top:4px}
.fl-form{display:grid;gap:10px}
.fl-form label{display:grid;gap:4px;font-size:12px;font-weight:600;color:var(--ink2)}
.fl-form label.fl-opt{display:flex;font-weight:500}
.fl-form input,.fl-form select,.fl-form textarea{font-size:13px;padding:8px 10px;width:100%;box-sizing:border-box}
/* display:flex/grid above would beat the UA [hidden] rule — keep .hidden honest */
.fl-bulk[hidden],.fl-prog[hidden],.fl-form label[hidden]{display:none}

/* fleet toolbar: keep search · state pills · sort · Test all on ONE row.
   (the global input,select{width:100%} rule was stretching the sort select full-width) */
.fl-tools{gap:10px 12px}
.fl-tools .fl-q{width:auto;flex:0 1 240px;min-width:180px}
.fl-tools #flStates{display:flex;flex-wrap:wrap;gap:8px;flex:1 1 auto}
.fl-tools .fl-sort{width:auto;flex:0 0 auto;max-width:250px;margin-left:auto;padding:8px 10px;font-size:13px}
.fl-tools #flTestAll{flex:0 0 auto}
@media(max-width:1200px){.fl-tools .fl-sort{margin-left:0}}

/* ───────────────────────── 13. LIVE WIRE (ip_stream.js) — append to theme.css ─────────────────────────
   Gmail-style real-time stream. Everything in tokens; label colours are Gmail IDENTITY hues (the word is
   always beside the colour), status hues (--st-*) carry the row highlight/kind badge WITH an icon + label. */
:root{--lw-primary:#1a73e8;--lw-social:#1a73e8;--lw-promo:#188038;--lw-updates:#e37400;--lw-forums:#a142f4;--lw-spam:#d93025;--lw-unread:var(--panel);--lw-read:var(--bg)}
.lw-card{padding:0;overflow:hidden;margin-bottom:16px;font-size:14px;font-variant-numeric:tabular-nums}
.lw-hd{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;padding:14px 20px 10px}
.lw-title{display:flex;align-items:center;gap:10px}.lw-title h3{margin:0;font-size:15px}.lw-count{font-size:12.5px}
.lw-livedot{width:9px;height:9px;border-radius:50%;background:var(--st-good);box-shadow:0 0 0 3px var(--st-good-soft);animation:pulse 2.4s infinite;position:relative}
.lw-livedot::after{content:"";position:absolute;left:-2px;right:-2px;bottom:-6px;height:2px;border-radius:2px;background:var(--accent);transform:scaleX(0);transform-origin:left;transition:transform .35s var(--ease)}
.lw-livedot.is-polling::after{transform:scaleX(1)}
.lw-card.is-paused .lw-livedot{background:var(--mut2);box-shadow:none;animation:none}
.lw-tools{display:flex;align-items:center;gap:8px}
.lw-q{width:220px;max-width:50vw;padding:6px 10px;font-size:13px;border-radius:9px}
#lwPause.is-paused{background:var(--acc-soft);color:var(--accent-text);border-color:var(--acc-soft2)}
/* tabs strip (Gmail tabs feel): underline on the active tab, count badge */
.lw-tabs{display:flex;gap:2px;padding:0 12px;border-bottom:1px solid var(--bd);overflow-x:auto;scrollbar-width:none}.lw-tabs::-webkit-scrollbar{display:none}
.lw-tab{display:inline-flex;align-items:center;gap:6px;padding:9px 10px 8px;border:0;border-bottom:2px solid transparent;background:transparent;color:var(--mut);font:600 12.5px/1 Inter,system-ui,sans-serif;cursor:pointer;white-space:nowrap;border-radius:0;transition:color .12s var(--ease),border-color .12s var(--ease)}
.lw-tab:hover{color:var(--ink);background:var(--bg2);border-radius:8px 8px 0 0}
.lw-tab.on{color:var(--accent-text);border-bottom-color:var(--accent)}
.lw-tab:focus-visible{outline:2px solid var(--accent-text);outline-offset:-2px;border-radius:6px}
.lw-tab b{font-size:11px;font-weight:700;padding:1px 6px;border-radius:999px;background:var(--bg3);color:var(--ink2);min-width:18px;text-align:center}
.lw-tab.on b{background:var(--acc-soft);color:var(--accent-text)}
.lw-dot{width:7px;height:7px;border-radius:50%;background:var(--bd3);flex-shrink:0}
.lw-dot.good{background:var(--st-good)}.lw-dot.warn{background:var(--st-warn)}.lw-dot.crit{background:var(--st-crit)}.lw-dot.acc{background:var(--accent)}
/* rows */
.lw-rows{max-height:440px;overflow:auto;background:var(--lw-read)}
.lw-section{display:flex;align-items:center;gap:8px;padding:7px 20px;font-size:11px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--mut);background:var(--bg2);border-bottom:1px solid var(--bd2);position:sticky;top:0;z-index:2}
.lw-section b{font-weight:700;color:var(--ink2);background:var(--bg3);padding:1px 7px;border-radius:999px;letter-spacing:0}
.lw-sec-dot{width:6px;height:6px;border-radius:50%;background:var(--st-good)}.lw-card.is-paused .lw-sec-dot{background:var(--mut2)}
.lw-row{display:flex;align-items:center;gap:12px;min-height:46px;padding:6px 20px;border-bottom:1px solid var(--bd);background:var(--lw-read);cursor:pointer;position:relative;outline:none;transition:background .12s var(--ease)}
.lw-row.is-unread{background:var(--lw-unread);box-shadow:inset 3px 0 0 var(--accent)}
.lw-row.is-unread .lw-from,.lw-row.is-unread .lw-subj-t{font-weight:700;color:var(--ink)}
.lw-row.is-read .lw-from,.lw-row.is-read .lw-subj-t{font-weight:500;color:var(--ink)}
.lw-row.is-new{animation:lwIn .45s var(--ease-out),lwGlow 2s var(--ease) forwards}
.lw-row[data-tone=good]{--lw-c:var(--st-good)}.lw-row[data-tone=warn]{--lw-c:var(--st-warn)}.lw-row[data-tone=crit]{--lw-c:var(--st-crit)}.lw-row[data-tone=acc]{--lw-c:var(--accent)}
@keyframes lwIn{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:none}}
@keyframes lwGlow{from{background:color-mix(in srgb,var(--lw-c) 12%,var(--lw-unread))}to{background:var(--lw-unread)}}
.lw-row:hover,.lw-row:focus-visible,.lw-row:focus-within{background:var(--bg2);z-index:1}
.lw-row:focus-visible{box-shadow:inset 0 0 0 2px var(--accent-text)}
.lw-row.is-unread:focus-visible{box-shadow:inset 3px 0 0 var(--accent),inset 0 0 0 2px var(--accent-text)}
/* avatar: 32px circle, deterministic series tint, darkened slot hue for the letter (legible on the tint) */
.lw-avatar{position:relative;width:32px;height:32px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;font:700 13.5px/1 Inter,system-ui,sans-serif;flex-shrink:0}
.lw-avatar[data-tint=s1]{background:color-mix(in srgb,var(--s1) 14%,transparent);color:color-mix(in srgb,var(--s1) 72%,var(--ink))}
.lw-avatar[data-tint=s2]{background:color-mix(in srgb,var(--s2) 14%,transparent);color:color-mix(in srgb,var(--s2) 72%,var(--ink))}
.lw-avatar[data-tint=s3]{background:color-mix(in srgb,var(--s3) 14%,transparent);color:color-mix(in srgb,var(--s3) 72%,var(--ink))}
.lw-avatar[data-tint=s4]{background:color-mix(in srgb,var(--s4) 14%,transparent);color:color-mix(in srgb,var(--s4) 60%,var(--ink))}
.lw-avatar[data-tint=s5]{background:color-mix(in srgb,var(--s5) 14%,transparent);color:color-mix(in srgb,var(--s5) 72%,var(--ink))}
.lw-kind{position:absolute;right:-3px;bottom:-3px;width:14px;height:14px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;color:var(--panel);box-shadow:0 0 0 2px var(--lw-read)}
.lw-row.is-unread .lw-kind{box-shadow:0 0 0 2px var(--lw-unread)}
.lw-kind.good{background:var(--st-good)}.lw-kind.warn{background:var(--st-warn)}.lw-kind.crit{background:var(--st-crit)}.lw-kind.acc{background:var(--accent)}
/* sender (fixed) · subject–snippet (flex) · label · time / actions */
.lw-sender{width:200px;flex:0 0 200px;min-width:0;display:flex;flex-direction:column;gap:1px}
.lw-from{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--ink)}
.lw-to{font-size:11px;color:var(--mut);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lw-subj{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--ink)}
.lw-snip{color:var(--mut);font-weight:400}
.lw-label{display:inline-flex;align-items:center;gap:5px;padding:2px 8px;border-radius:999px;font-size:11px;font-weight:600;color:var(--ink2);background:var(--bg2);border:1px solid var(--bd);white-space:nowrap;flex-shrink:0}
.lw-label i{width:7px;height:7px;border-radius:50%;background:var(--lw-t,var(--bd3))}
.lw-label small{font-size:10px;font-weight:500;color:var(--mut2);border-left:1px solid var(--bd3);padding-left:5px;margin-left:1px}
.lw-label[data-tab=inbox],.lw-label[data-tab=primary]{--lw-t:var(--lw-primary)}.lw-label[data-tab=social]{--lw-t:var(--lw-social)}.lw-label[data-tab=promotions]{--lw-t:var(--lw-promo)}
.lw-label[data-tab=updates]{--lw-t:var(--lw-updates)}.lw-label[data-tab=forums]{--lw-t:var(--lw-forums)}.lw-label[data-tab=spam]{--lw-t:var(--lw-spam)}
/* "Rescued from Spam" rides alongside the Spam pill on the same row: red dot for where it landed,
   green for what we did about it. Without this rule the new pill falls back to the neutral --bd3
   dot and reads as unstyled rather than as a positive outcome. */
.lw-label[data-tab=rescued]{--lw-t:var(--lw-promo);border-color:var(--lw-promo);color:var(--lw-promo)}
.lw-time{width:72px;flex:0 0 72px;text-align:right;font-size:12px;font-weight:600;color:var(--mut);white-space:nowrap;transition:opacity .12s var(--ease),transform .12s var(--ease)}
.lw-row.is-unread .lw-time{color:var(--accent-text)}
.lw-actions{position:absolute;right:14px;top:50%;transform:translate(8px,-50%);display:flex;gap:6px;opacity:0;pointer-events:none;transition:opacity .12s var(--ease),transform .12s var(--ease)}
.lw-row:hover .lw-actions,.lw-row:focus-within .lw-actions,.lw-row:focus-visible .lw-actions{opacity:1;pointer-events:auto;transform:translate(0,-50%)}
.lw-row:hover .lw-time,.lw-row:focus-within .lw-time,.lw-row:focus-visible .lw-time{opacity:0;transform:translateX(8px)}
.lw-act{border:1px solid var(--bd);background:var(--panel);color:var(--ink2);font:600 11.5px/1 Inter,system-ui,sans-serif;padding:6px 10px;border-radius:8px;cursor:pointer;white-space:nowrap;box-shadow:var(--sh)}
.lw-act:hover{background:var(--bg2);border-color:var(--bd3);color:var(--ink)}.lw-act:disabled{opacity:.5;cursor:default}
.lw-act:focus-visible{outline:none;box-shadow:0 0 0 3px var(--ring)}
/* quiet / empty — Gmail's "No new mail": centred, calm */
.lw-quiet{padding:12px 20px;font-size:13px;color:var(--mut);text-align:center;border-bottom:1px solid var(--bd2);background:var(--lw-read)}.lw-quiet b{color:var(--ink2);font-weight:600}
.lw-empty{padding:42px 20px;text-align:center;font-size:13px;color:var(--mut)}.lw-empty-t{font-size:14px;font-weight:600;color:var(--ink2);margin-bottom:4px}
/* fallback drawer (only when swInbDetail is absent) */
.lw-drawer{position:fixed;inset:0;background:rgba(15,23,42,.42);z-index:240;display:flex;justify-content:flex-end}
.lw-drawer-sheet{width:600px;max-width:94vw;height:100%;overflow-y:auto;background:var(--panel);box-shadow:var(--sh-xl)}
.lw-drawer-hd{display:flex;align-items:center;justify-content:space-between;padding:18px 24px;border-bottom:1px solid var(--bd);position:sticky;top:0;background:var(--panel);font-size:16px}
.lw-drawer-b{padding:20px 24px}.lw-kv{display:grid;grid-template-columns:84px 1fr;gap:8px 12px;font-size:13.5px;margin-bottom:16px}
.lw-drawer-subj{background:var(--bg2);border:1px solid var(--bd);border-radius:10px;padding:12px 14px;margin-bottom:16px;font-weight:500}
.lw-pre{white-space:pre-wrap;word-break:break-word;font-size:12.5px;line-height:1.6;color:var(--ink2);background:var(--bg2);border:1px solid var(--bd);border-radius:10px;padding:14px 16px;max-height:340px;overflow:auto;margin:0}
@media(max-width:820px){.lw-sender{flex-basis:140px;width:140px}.lw-label small{display:none}.lw-q{width:150px}}
@media(max-width:600px){.lw-label{display:none}.lw-sender{flex-basis:110px;width:110px}}
@media (prefers-reduced-motion:reduce){.lw-row.is-new{animation:none}.lw-livedot,.lw-livedot::after{animation:none;transition:none}.lw-row,.lw-time,.lw-actions,.lw-tab{transition:none}}

/* .lw-row/.lw-section are display:flex, which BEATS the browser's default [hidden]{display:none} rule —
   so filtered rows kept painting while JS believed they were hidden (Inbox tab looked broken).
   Make the hidden attribute authoritative for everything inside the wire. */
.lw-card [hidden]{display:none!important}

/* ── section sub-tabs: 13 pages folded into 6 top-level sections ── */
.subnav{display:flex;gap:2px;margin:-8px 0 20px;border-bottom:1px solid var(--bd);overflow-x:auto;scrollbar-width:none}
.subnav::-webkit-scrollbar{display:none}
.subnav a{display:inline-flex;align-items:center;padding:10px 14px 9px;font-weight:600;font-size:13.5px;color:var(--mut);
  border-bottom:2px solid transparent;cursor:pointer;white-space:nowrap;transition:color .15s var(--ease),border-color .15s var(--ease)}
.subnav a:hover{color:var(--ink)}
.subnav a.on{color:var(--accent-text);border-bottom-color:var(--accent)}
.subnav[hidden]{display:none!important}
/* six tabs need no squeezing — restore comfortable spacing */
.topnav nav a{padding:8px 14px;font-size:13.5px}


/* ───────────────────────── PLACEMENT PAGE — tokenised colour ─────────────────────────
   Tab hues themselves come from the existing TABCOL map in app.js (one vocabulary for tabs across
   the whole panel). Everything here is status/chrome, and resolves per preset. Low sample size is a
   WARN state, never a failure — it means "we will not state a percentage", not "something is wrong". */
.pl-hero{background:var(--panel);border-left-color:var(--bd3)}
.pl-hero.tone-good{border-left-color:var(--st-good)}
.pl-hero.tone-warn{border-left-color:var(--st-warn)}
.pl-hero.tone-crit{border-left-color:var(--st-crit)}
.pl-bar{background:var(--bg3)}
.pl-bar i+i{box-shadow:-1.5px 0 0 0 var(--panel)}   /* 0-width segment ⇒ 0-width shadow ⇒ no phantom notch */
.pl-bar.is-empty{background:var(--bg3);opacity:.6}
.pl-n{background:var(--bg3);color:var(--ink2)}
.pl-n.is-low{background:var(--st-warn-soft);color:var(--st-warn-text)}
.pl-tagf{background:var(--acc-soft);color:var(--accent-text)}
.pl-flag{background:var(--st-warn-soft);color:var(--st-warn-text)}
.pl-flag.is-good{background:var(--st-good-soft);color:var(--st-good-text)}
.pl-badge{background:var(--st-warn-soft);color:var(--st-warn-text)}
.pl-card.is-low{box-shadow:inset 3px 0 0 0 var(--st-warn),var(--sh)}
.pl-card.is-nodata{background:var(--bg2)}
.pl-say{background:var(--bg2);border-color:var(--bd)}
.pl-gapnote{background:var(--bg2);border:1px solid var(--bd);color:var(--ink2)}
.pl-day.is-0 .pl-col{background:var(--bd)}
.pl-auth-c{background:var(--bg3);color:var(--ink2)}
.pl-auth-c i{background:var(--bd3)}
.pl-auth-c.tone-good{background:var(--st-good-soft);color:var(--st-good-text)}
.pl-auth-c.tone-good i{background:var(--st-good)}
.pl-auth-c.tone-crit{background:var(--st-crit-soft);color:var(--st-crit-text)}
.pl-auth-c.tone-crit i{background:var(--st-crit)}
.pl-verdict{background:var(--bg3);color:var(--ink2)}
.pl-verdict.tone-good{background:var(--st-good-soft);color:var(--st-good-text)}
.pl-verdict.tone-crit{background:var(--st-crit-soft);color:var(--st-crit-text)}
