/* ===========================================================================
   Ntiva / OneSpot design system — tokens from DESIGN-SYSTEM.md
   Written as plain CSS (no Tailwind dependency) so the app renders identically
   if the CDN is unreachable from the Static Web App. Token values are verbatim.
   ========================================================================= */
:root{
  --navy:#0f172a;
  --ocean:#0c4a6e;
  --teal:#0e7490;
  --orange:#f97316;
  --error:#f87171;
  --ok:#2dd4bf;
  --s-30:rgba(255,255,255,0.30);

  --s-05:rgba(255,255,255,0.05);
  --s-10:rgba(255,255,255,0.10);
  --s-15:rgba(255,255,255,0.15);
  --s-65:rgba(255,255,255,0.65);
  --s-70:rgba(255,255,255,0.70);

  --sora:'Sora',sans-serif;
  --inter:'Inter',sans-serif;
  --mono:ui-monospace,'SF Mono',Menlo,Consolas,monospace;

  color-scheme:dark;
}
*{box-sizing:border-box}
body{
  margin:0;padding:0;min-height:100vh;
  background:linear-gradient(135deg,#0f172a 0%,#0c4a6e 60%,#0e7490 100%);
  background-attachment:fixed;
  font-family:var(--inter);font-size:14px;color:#fff;
  -webkit-font-smoothing:antialiased;
}
h1,h2,h3{margin:0;font-family:var(--sora);letter-spacing:-0.03em;line-height:1.2}
button{font-family:var(--inter);font-size:inherit;cursor:pointer}
code{font-family:var(--mono);font-size:.85em;background:var(--s-10);padding:1px 5px;border-radius:4px}

/* ---- focus contract ---- */
:focus-visible{outline:3px solid var(--orange);outline-offset:3px;box-shadow:0 0 0 6px rgba(0,0,0,.5)}

/* ---- buttons ---- */
@keyframes statsGlow{
  0%,100%{box-shadow:0 0 0 0 rgba(249,115,22,.7),0 4px 14px -2px rgba(249,115,22,.45);transform:scale(1)}
  50%{box-shadow:0 0 0 8px rgba(249,115,22,0),0 4px 20px 0 rgba(249,115,22,.2);transform:scale(1.03)}
}
.btn-cta{
  font-family:var(--sora);font-weight:600;color:#fff;border:none;
  border-radius:.5rem;padding:.55rem 1.15rem;font-size:.8125rem;background-color:var(--orange);
  animation:statsGlow 2.4s cubic-bezier(.4,0,.6,1) infinite;
  transition:filter 150ms ease,transform 100ms ease;outline-offset:2px;
}
.btn-cta:hover{filter:brightness(1.12)}
.btn-cta:active{transform:scale(.97)!important;animation:none}
.btn-ghost{
  font-family:var(--inter);font-weight:500;color:#fff;font-size:.8125rem;
  padding:.5rem .9rem;border-radius:.5rem;border:1.5px solid var(--s-65);background:transparent;
  transition:background-color 150ms ease,color 150ms ease,transform 100ms ease;outline-offset:2px;
}
.btn-ghost:hover{background-color:#fff;color:var(--navy)}
.btn-ghost:active{transform:scale(.97)}
.btn-ghost.btn-active{background:rgba(249,115,22,.15);border-color:var(--orange);color:var(--orange)}
.btn-ghost.btn-active:hover{background:rgba(249,115,22,.25);color:var(--orange)}

/* ---- forms ---- */
.form-label{font-family:var(--inter);font-weight:500;font-size:.6875rem;text-transform:uppercase;
  letter-spacing:.06em;color:var(--s-70);display:block;margin-bottom:.375rem}
.form-input{
  width:100%;background:var(--s-05);border:1px solid var(--s-15);border-radius:.5rem;
  padding:.5rem .75rem;color:#fff;font-family:var(--inter);font-size:.8125rem;
  outline:none;display:block;transition:border-color 150ms ease;
}
.form-input:focus{border-color:var(--orange)}
.form-input::placeholder{color:rgba(255,255,255,.3)}
select.form-input option{background:var(--navy);color:#fff}
textarea.form-input{min-height:60px;resize:vertical;line-height:1.6}
.form-input.inline{width:auto;min-width:150px}

/* ---- surfaces ---- */
.card{
  background:var(--s-05);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);
  border:1px solid var(--s-10);border-radius:.75rem;
  box-shadow:0 1px 2px rgba(15,23,42,.45),0 8px 24px -8px rgba(14,116,144,.35);
  transition:box-shadow 200ms ease,border-color 150ms ease;
}
.card:hover{box-shadow:0 4px 12px rgba(15,23,42,.55),0 16px 40px -8px rgba(249,115,22,.45)}
.card.open{border-color:rgba(249,115,22,.35)}

.toolbar{
  display:flex;align-items:center;gap:.65rem;flex-wrap:wrap;justify-content:space-between;
  padding:.75rem 1.5rem;background:rgba(15,23,42,.82);
  backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);
  border:1px solid var(--s-10);border-left:none;border-right:none;
}

/* ---- header ---- */
header.mast{position:relative;z-index:10;padding:1rem 1.5rem 0}
.mast-in{max-width:1560px;margin:0 auto}
.mast-row{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:1rem}
.wordmark{display:flex;align-items:center;gap:1.1rem;flex-shrink:0}
.logo-n{width:38px;height:38px;border-radius:8px;background:var(--navy);display:grid;place-items:center;
  font-family:var(--sora);font-weight:800;font-size:20px;color:var(--orange);flex-shrink:0;
  border:1px solid var(--s-10)}
.rule{width:1px;height:32px;background:rgba(255,255,255,.25)}
.wordmark .t{font-family:var(--sora);font-weight:700;font-size:1.2rem;letter-spacing:-.03em;line-height:1.2;display:block}
.wordmark .s{font-family:var(--inter);font-weight:500;font-size:.72rem;color:var(--s-70);display:block}

.counters{display:flex;gap:1.75rem;flex-wrap:wrap}
.counter .n{font-family:var(--sora);font-weight:700;font-size:1.7rem;line-height:1;
  font-variant-numeric:tabular-nums;letter-spacing:-.03em}
.counter .l{font-family:var(--inter);font-size:.65rem;text-transform:uppercase;letter-spacing:.09em;
  color:var(--s-70);margin-top:.35rem}
.counter.alarm .n{color:var(--orange)}

/* ---- runway ---- */
.runway{max-width:1560px;margin:1.15rem auto 0;padding-bottom:1.15rem;position:relative;z-index:10}
.runway-head{display:flex;justify-content:space-between;font-size:.65rem;
  letter-spacing:.09em;text-transform:uppercase;color:var(--s-70);margin-bottom:.5rem}
.runway-track{display:flex;gap:2px;height:34px;align-items:flex-end}
.rw{flex:1 1 0;min-width:2px;border-radius:2px 2px 0 0;background:var(--s-10)}
.rw.decided{background:rgba(255,255,255,.42)}
.rw.now{background:var(--orange);box-shadow:0 0 12px rgba(249,115,22,.6)}
.runway-note{font-size:.75rem;color:var(--s-70);margin-top:.55rem}

/* ---- layout ---- */
.bar-wrap{position:sticky;top:0;z-index:20}
main{max-width:1560px;margin:0 auto;padding:1.35rem 1.5rem 5rem;position:relative;z-index:10}
.filters{display:flex;align-items:center;gap:.65rem;flex-wrap:wrap;flex:1 1 auto}
.actions{display:flex;align-items:center;gap:.65rem;flex-wrap:nowrap;flex-shrink:0}
.count-note{font-size:.75rem;color:var(--s-70);font-variant-numeric:tabular-nums}

/* ---- client card ---- */
.client{margin-bottom:.9rem;overflow:hidden}
.client-head{display:grid;grid-template-columns:minmax(230px,2.2fr) repeat(4,minmax(88px,1fr)) auto;
  gap:1rem;align-items:center;padding:1rem 1.25rem;cursor:pointer;background:transparent;border:none;
  width:100%;text-align:left;color:inherit;border-radius:.75rem;
  transition:background-color 150ms ease,transform 100ms ease}
.client-head:hover{background:var(--s-05)}
.client-head:active{transform:scale(.995)}
.cname{font-family:var(--sora);font-weight:600;font-size:.95rem;letter-spacing:-.02em}
.cmeta{font-size:.7rem;color:var(--s-70);margin-top:.2rem}
.kv .k{font-size:.6rem;text-transform:uppercase;letter-spacing:.08em;color:var(--s-70)}
.kv .v{font-family:var(--sora);font-weight:600;font-size:.9rem;font-variant-numeric:tabular-nums;margin-top:.15rem}
.chev{color:var(--s-70);font-size:.7rem;transition:transform 150ms ease}
.client.open .chev{transform:rotate(90deg)}
.client-body{display:none;border-top:1px solid var(--s-10)}
.client.open .client-body{display:block}

/* ---- play banner ---- */
.play{padding:.95rem 1.25rem;background:rgba(249,115,22,.10);border-bottom:1px solid var(--s-10);
  display:flex;gap:1rem;align-items:flex-start}
.play-k{font-size:.6rem;text-transform:uppercase;letter-spacing:.08em;color:var(--orange);
  white-space:nowrap;padding-top:.25rem;font-weight:600}
.play-v{font-family:var(--sora);font-weight:600;font-size:.9rem}
.play-why{font-size:.78rem;color:var(--s-70);margin-top:.2rem;line-height:1.6}
.platform-note{padding:.8rem 1.25rem;font-size:.78rem;color:var(--s-70);line-height:1.7;
  background:var(--s-05);border-bottom:1px solid var(--s-10)}

/* ---- table ---- */
table{width:100%;border-collapse:collapse;font-size:.8125rem}
th{text-align:left;font-size:.6rem;text-transform:uppercase;letter-spacing:.08em;color:var(--s-70);
  padding:.6rem .75rem;border-bottom:1px solid var(--s-10);font-weight:600;white-space:nowrap}
td{padding:.7rem .75rem;border-bottom:1px solid rgba(255,255,255,.06);vertical-align:top}
tbody tr{transition:background-color 150ms ease}
tbody tr:hover{background:rgba(255,255,255,.03)}
tr:last-child td{border-bottom:none}
.srv-name{font-family:var(--mono);font-size:.75rem;font-weight:600}
.srv-sub{font-size:.7rem;color:var(--s-70);margin-top:.15rem;line-height:1.55}

/* ---- pills ---- */
.pill{display:inline-block;background:var(--s-10);border-radius:9999px;padding:.125rem .55rem;
  font-size:.7rem;line-height:1.15rem;font-weight:500;white-space:nowrap}
.pill.ok{background:rgba(45,212,191,.16);color:#5eead4}
.pill.warn{background:rgba(249,115,22,.16);color:#fdba74}
.pill.bad{background:rgba(248,113,113,.16);color:var(--error)}
.pill.idle{background:var(--s-10);color:var(--s-70)}
.pill.opt{background:var(--orange);color:#fff;font-family:var(--sora);font-weight:600}
/* No recommendation yet: evidence gaps are open. Deliberately reads as pending,
   not as a fifth option and not as an error. */
.pill.opt.opt-none{background:var(--s-10);color:var(--s-70);border:1px dashed var(--s-15)}

.ev{display:inline-block;font-size:.575rem;text-transform:uppercase;letter-spacing:.07em;
  color:var(--s-70);border:1px solid var(--s-15);border-radius:9999px;padding:0 .4rem;
  margin-left:.35rem;vertical-align:1px}
.ev.inferred{color:#fdba74;border-color:rgba(249,115,22,.4)}
.ev.pending{color:var(--error);border-color:rgba(248,113,113,.4)}

.applist{margin:.2rem 0 0;padding:0;list-style:none;font-size:.72rem}
.applist li{padding:.05rem 0;color:var(--s-70)}
.appflag{font-size:.72rem;margin-top:.4rem;padding:.4rem .55rem;border-radius:.5rem;line-height:1.55;
  background:rgba(248,113,113,.12);color:#fca5a5;border:1px solid rgba(248,113,113,.25)}
/* An application whose OWN support ends before Windows Server 2016's does.
   Deliberately the loudest thing on a server row, because it is the one finding
   whose deadline is earlier than the deadline this whole tool is organised
   around - an AM planning for 12 Jan 2027 would otherwise arrive months late. */
.appflag.earlier{background:rgba(248,113,113,.22);border-color:#f87171;border-width:2px}

/* Machines ITGlue lists as Server 2016 that the RMM does not carry. They are
   deliberately NOT counted in the estate - the standing rule is that the RMM is
   the source of truth - but an AM quoting this client needs to know the number
   might be low, so it is surfaced rather than buried in a note nobody reads. */
.delta.serverfree{background:rgba(94,234,212,.14);border-left:3px solid var(--teal);
  border-radius:.4rem;padding:.45rem .6rem}

.review-note{margin:0 1.25rem .9rem;padding:.7rem .85rem;font-size:.76rem;line-height:1.6;
  background:rgba(249,115,22,.12);border-left:3px solid var(--orange);border-radius:.4rem;
  color:var(--s-70)}
.review-note b{color:#fff;font-weight:600}
.review-note .why{display:block;margin-top:.35rem;color:var(--s-65)}
.appflag.earlier b{display:block;margin-bottom:.2rem}
.appflag.caution{background:rgba(249,115,22,.12);color:#fdba74;border-color:rgba(249,115,22,.25)}
.appflag.unknown{background:var(--s-05);color:var(--s-70);border-color:var(--s-10)}
.appflag b{font-weight:600;color:#fff}
.notes-inline{font-size:.72rem;color:#fdba74;margin-top:.3rem;line-height:1.55}

/* ---- decision panel ---- */
.decision{padding:1.1rem 1.25rem;background:var(--s-05);border-top:1px solid var(--s-10)}
.decision h3{font-family:var(--inter);font-size:.65rem;text-transform:uppercase;
  color:var(--orange);margin-bottom:.8rem;font-weight:600;letter-spacing:.09em}
.dgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:.8rem}
.dnotes{margin-top:.8rem}
.saved{font-size:.72rem;color:#5eead4;margin-top:.6rem;min-height:1rem}
.saved.bad{color:#fca5a5}

/* Toolbar save receipt. Auto-save with no visible state is indistinguishable
   from a tool that quietly does nothing, so this is never decoration. */
.savestate{font-size:.75rem;color:var(--s-70);font-variant-numeric:tabular-nums;
  white-space:nowrap}
.savestate.ok{color:#5eead4}
.savestate.warn{color:#fdba74}
.savestate.bad{color:#fca5a5;font-weight:600}

.notice{padding:.9rem 1.1rem;font-size:.78rem;line-height:1.7;color:var(--s-70);
  border-left:3px solid var(--orange);margin-bottom:1rem}
.notice b{color:#fff;font-weight:600}
.legend{font-size:.75rem;color:var(--s-70);line-height:1.8;margin-bottom:1.1rem;padding:0 .2rem}
.legend b{color:#fff;font-weight:600}
.empty{text-align:center;padding:4rem 1rem;color:var(--s-70)}

@media(max-width:900px){
  .client-head{grid-template-columns:1fr auto;gap:.6rem}
  .client-head .kv{display:none}
  .counters{gap:1.1rem}
  .counter .n{font-size:1.35rem}
}
@media (prefers-reduced-motion:reduce){
  *{animation:none!important;transition:none!important}
}

/* ===========================================================================
   ANALYTICS OUTPUT — the four-option matrix, target OS, gaps and overrides.
   Added when the recommendation stopped being a single verdict.
   ========================================================================= */

/* Every option is shown, always. A blocked Option 1 is the reason to pitch
   another one, so hiding the losers would hide the argument. */
.optmatrix{display:flex;gap:.25rem;margin:.4rem 0 .35rem}
.ochip{
  display:inline-flex;align-items:center;justify-content:center;
  width:1.45rem;height:1.45rem;border-radius:6px;
  font-family:var(--sora);font-size:.72rem;font-weight:600;
  border:1px solid var(--s-15);cursor:help;
}
.ochip.eligible{background:rgba(45,212,191,.16);color:var(--ok);border-color:rgba(45,212,191,.34)}
.ochip.blocked {background:rgba(248,113,113,.16);color:var(--error);border-color:rgba(248,113,113,.34)}
.ochip.unknown {background:var(--s-05);color:var(--s-65)}

.target-os{
  display:inline-block;margin-left:.4rem;font-family:var(--sora);
  font-size:.74rem;font-weight:600;color:var(--ok);letter-spacing:-.01em;
}

.srv-why{margin:.35rem 0;font-size:.74rem;line-height:1.55;color:var(--s-65)}
.srv-why div{margin-bottom:.15rem}

/* Gaps are collapsed by default: they are the worklist, not the headline. */
.gaps{margin:.35rem 0}
.gaps summary{
  font-size:.72rem;color:var(--orange);cursor:pointer;
  font-family:var(--sora);font-weight:600;letter-spacing:-.01em;
}
.gaps summary:focus-visible{
  outline:3px solid var(--orange);outline-offset:3px;
  box-shadow:0 0 0 6px rgba(0,0,0,.5);border-radius:4px;
}
.gaps ul{margin:.3rem 0 0 .9rem;padding:0;font-size:.72rem;line-height:1.6;color:var(--s-65)}

/* Per-server override. Deliberately quieter than the client-level control —
   the client play is the primary record, this is the exception. */
.form-input.mini{
  margin-top:.4rem;padding:.28rem .45rem;font-size:.74rem;
  max-width:11rem;background:var(--s-05);
}

.delta{
  margin-top:.4rem;padding:.32rem .5rem;border-radius:6px;
  background:rgba(249,115,22,.12);border:1px solid rgba(249,115,22,.28);
  font-size:.72rem;line-height:1.5;color:#fdba74;
}
.delta b{color:#fff;font-family:var(--sora)}

.client-flags{
  margin:0 0 .9rem;padding:.5rem .7rem;border-radius:8px;
  background:var(--s-05);border:1px solid var(--s-10);
  font-size:.76rem;line-height:1.6;color:var(--s-65);
}
.client-flags b{color:var(--s-70);font-family:var(--sora)}

/* Visually hidden but present for screen readers — the mini override selects
   need a label and the column header is not specific enough. */
.sr-only{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0;
}

/* ===========================================================================
   LIGHT CONTENT ZONE
   The masthead keeps the Ntiva gradient and its grain. Everything below it —
   the toolbar and all the data — sits on white paper.

   Implemented by re-scoping the surface tokens rather than rewriting every
   rule: --s-05..--s-70 are white-alpha at :root (correct over the gradient) and
   are redefined here as ink-alpha (correct over paper). Any rule using a token
   therefore inverts on its own, and only hard-coded #fff needs touching.

   Every colour pair below is asserted by scripts/check-contrast.js at 4.5:1.
   Do not hand-pick a new accent here without adding it to that file — the
   accents that read well on navy (#5eead4, #fdba74, #fca5a5) all fail on white.
   ========================================================================= */
:root{
  --ink:#0f172a;
  --ink-70:rgba(15,23,42,.72);
  --ink-62:rgba(15,23,42,.62);
  --paper:#ffffff;
  --paper-2:#f8fafc;

  /* Light-surface accents. 700-weight for text on paper, 800 where the text
     sits on its own colour tint and needs the extra headroom. */
  --accent-ink:#c2410c;
  --ok-ink:#0f766e;
  --warn-ink:#b45309;
  --warn-ink-2:#92400e;
  --bad-ink:#b91c1c;
  --delta-ink:#9a3412;
}

/* Body fills the viewport so the paper reaches the bottom on short pages;
   the horizontal bleed is the box-shadow trick below, so no extra markup. */
body{min-height:100vh;display:flex;flex-direction:column}

.bar-wrap,
main{
  --s-05:rgba(15,23,42,0.04);
  --s-10:rgba(15,23,42,0.10);
  --s-15:rgba(15,23,42,0.14);
  --s-30:rgba(15,23,42,0.26);
  --s-65:rgba(15,23,42,0.62);
  --s-70:rgba(15,23,42,0.72);
  color:var(--ink);
}

main{
  flex:1 1 auto;
  background:var(--paper);
  /* Full-bleed white without wrapping main in another element. */
  box-shadow:0 0 0 100vmax var(--paper);
  clip-path:inset(0 -100vmax);
}

/* Sticky control bar reads as paper floating over paper, so it needs an edge
   rather than the frosted-dark treatment it had over the gradient. */
.toolbar{
  background:var(--paper);
  border-bottom:1px solid var(--s-10);
  box-shadow:0 1px 2px rgba(15,23,42,.05),0 8px 20px -12px rgba(12,74,110,.28);
}

/* ---- surfaces ---- */
main .card{
  background:var(--paper);
  backdrop-filter:none;-webkit-backdrop-filter:none;
  border:1px solid rgba(15,23,42,.12);
  /* Layered and colour-tinted, per the design system — ocean and orange, not
     a flat grey drop. */
  box-shadow:0 1px 2px rgba(15,23,42,.06),0 10px 24px -12px rgba(12,74,110,.22);
}
main .card:hover{
  box-shadow:0 2px 6px rgba(15,23,42,.09),0 18px 40px -14px rgba(249,115,22,.30);
}
main .card.open{border-color:rgba(249,115,22,.45)}
main .client-head:hover{background:var(--s-05)}

/* ---- type ---- */
main .srv-name{color:var(--ink)}
main .cname,
main .kv .v{color:var(--ink)}
main .legend b,
main .notice b,
main .appflag b,
main .delta b,
main .client-flags b{color:var(--ink)}
main .notes-inline{color:var(--warn-ink)}

/* ---- tables ---- */
main th{border-bottom:1px solid var(--s-15)}
main td{border-bottom:1px solid rgba(15,23,42,.08)}
main tbody tr:hover{background:rgba(15,23,42,.025)}

/* ---- the recommendation banner ---- */
main .play{background:rgba(249,115,22,.10);border-bottom:1px solid var(--s-10)}
main .play-k{color:var(--accent-ink)}
main .play-v{color:var(--ink)}
main .platform-note{background:var(--paper-2);border-bottom:1px solid var(--s-10)}

/* ---- pills ---- */
main .pill.ok{background:rgba(45,212,191,.16);color:var(--ok-ink)}
main .pill.warn{background:rgba(249,115,22,.16);color:var(--warn-ink-2)}
main .pill.bad{background:rgba(248,113,113,.16);color:var(--bad-ink)}
main .pill.idle{background:rgba(15,23,42,.08);color:var(--ink-70)}
main .pill.opt{background:var(--accent-ink);color:#fff}
main .pill.opt.opt-none{background:rgba(15,23,42,.06);color:var(--ink-70);
  border:1px dashed var(--s-30)}

/* ---- option matrix ---- */
main .ochip{border-color:var(--s-15)}
main .ochip.eligible{background:rgba(45,212,191,.16);color:var(--ok-ink);
  border-color:rgba(15,118,110,.35)}
main .ochip.blocked{background:rgba(248,113,113,.16);color:var(--bad-ink);
  border-color:rgba(185,28,28,.35)}
main .ochip.unknown{background:rgba(15,23,42,.05);color:var(--ink-70)}
main .target-os{color:var(--ok-ink)}
main .srv-why{color:var(--ink-70)}
main .gaps summary{color:var(--accent-ink)}
main .gaps ul{color:var(--ink-70)}

/* ---- application flags ---- */
main .appflag{background:rgba(248,113,113,.10);color:var(--bad-ink);
  border-color:rgba(185,28,28,.22)}
main .delta.serverfree{background:rgba(15,118,110,.10);color:var(--ink-70)}
main .delta.serverfree b{color:var(--ok-ink)}
main .review-note{color:var(--ink-70)}
main .review-note b{color:var(--warn-ink-2)}
main .review-note .why{color:var(--ink-62)}
main .appflag.earlier{background:rgba(248,113,113,.16);color:var(--bad-ink);border-color:var(--bad-ink)}
main .appflag.earlier b{color:var(--bad-ink)}
main .appflag.caution{background:rgba(249,115,22,.10);color:var(--warn-ink-2);
  border-color:rgba(146,64,14,.22)}
main .appflag.unknown{background:rgba(15,23,42,.04);color:var(--ink-70);
  border-color:var(--s-10)}
main .applist li{color:var(--ink-70)}

/* ---- evidence tags ---- */
main .ev{color:var(--ink-70);border-color:var(--s-30)}
main .ev.inferred{color:var(--warn-ink);border-color:rgba(180,83,9,.45)}
main .ev.pending{color:var(--bad-ink);border-color:rgba(185,28,28,.45)}

/* ---- decision panel: recessed against the card ---- */
main .decision{background:var(--paper-2);border-top:1px solid var(--s-10)}
main .decision h3{color:var(--accent-ink)}
main .saved{color:var(--ok-ink)}
/* On paper the navy-zone accents all fail 4.5:1 - see the note at the top of
   this block. 700-weight inks on white, 800-weight where the text sits on its
   own colour tint. Asserted by scripts/check-contrast.js, not eyeballed. */
main .saved.bad{color:var(--bad-ink);font-weight:600}
.bar-wrap .savestate{color:var(--ink-62)}
.bar-wrap .savestate.ok{color:var(--ok-ink)}
.bar-wrap .savestate.warn{color:var(--warn-ink)}
.bar-wrap .savestate.bad{color:var(--bad-ink)}
main .delta{background:rgba(249,115,22,.12);border-color:rgba(194,65,12,.30);
  color:var(--delta-ink)}
main .client-flags{background:var(--paper-2);border:1px solid var(--s-10);
  color:var(--ink-70)}

/* ---- notices ---- */
main .notice{color:var(--ink-70)}
main .legend{color:var(--ink-70)}
main .empty{color:var(--ink-70)}

/* ---- controls ---- */
.bar-wrap .form-input,
main .form-input{
  background:rgba(15,23,42,.04);
  border:1px solid var(--s-15);
  color:var(--ink);
}
.bar-wrap .form-input::placeholder,
main .form-input::placeholder{color:rgba(15,23,42,.64)}
.bar-wrap .form-input:focus,
main .form-input:focus{border-color:var(--accent-ink)}
.bar-wrap select.form-input option,
main select.form-input option{background:var(--paper);color:var(--ink)}
.bar-wrap .form-label,
main .form-label{color:var(--ink-70)}

.bar-wrap .btn-ghost,
main .btn-ghost{color:var(--ink);border-color:var(--s-30)}
.bar-wrap .btn-ghost:hover,
main .btn-ghost:hover{background-color:var(--ink);color:var(--paper)}
.bar-wrap .btn-ghost.btn-active,
main .btn-ghost.btn-active{background:rgba(249,115,22,.14);
  border-color:var(--accent-ink);color:var(--accent-ink)}
.bar-wrap .btn-ghost.btn-active:hover,
main .btn-ghost.btn-active:hover{background:rgba(249,115,22,.22);color:var(--accent-ink)}
.bar-wrap .btn-cta,
main .btn-cta{background-color:var(--accent-ink)}
.bar-wrap .count-note{color:var(--ink-70)}
main code{background:rgba(15,23,42,.07);color:var(--ink)}

/* The design system's focus halo is rgba(0,0,0,.5), which is correct on navy
   and far too heavy on paper. The orange ring is the load-bearing part and is
   unchanged; only the halo is lightened inside the light zone. */
.bar-wrap :focus-visible,
main :focus-visible{
  outline:3px solid var(--accent-ink);outline-offset:3px;
  box-shadow:0 0 0 6px rgba(194,65,12,.18);
}

/* Stale snapshot warning in the masthead. Lives on the gradient, so it keeps
   the light-on-dark amber rather than the paper-zone accent. */
.wordmark .s .stale,
#data-as-of.stale{color:#fdba74;font-weight:600}

/* ===========================================================================
   PRE-DELIVERY CHECKLIST FIXES (ui-ux-pro-max)
   Three failures the checklist caught in the light-zone change. Listed with
   causes so they are not reintroduced.
   ========================================================================= */

/* 1. Horizontal overflow at narrow widths — 377px of it at a 390px viewport.
      Cause: body became `display:flex` to let the paper fill short pages, which
      made main a flex item. A flex item defaults to `min-width:auto`, so it
      sizes to its content's min-content width — the widest table — instead of
      the viewport. min-width:0 lets it shrink and hands scrolling back to the
      table's own overflow-x container. min-width:0 alone was not enough: as a
      column flex item main was still cross-axis content-sizing (child 719 +
      48 padding = 767), so it needs an explicit width:100% to fill the
      container instead of its content. */
main{min-width:0;width:100%}

/* 2. backdrop-filter left on an opaque surface. The toolbar went from
      rgba(15,23,42,.82) to solid white but kept blur(12px) — a blur sampling a
      backdrop that is no longer visible through it. Pure compositing cost. */
.toolbar{backdrop-filter:none;-webkit-backdrop-filter:none}

/* 3. Target sizes. WCAG 2.5.8 (AA) wants 24x24 everywhere; 44x44 is the touch
      figure. The evidence-gap disclosure was 14px tall, which fails both, so it
      is fixed unconditionally. The rest keep desktop density and grow only
      where the pointer is coarse — a 44px-tall filter row would waste a third
      of the toolbar on a mouse-driven screen. */
main .gaps summary{min-height:24px;display:flex;align-items:center;gap:.3rem}

@media (pointer:coarse){
  .bar-wrap .form-input, main .form-input,
  .bar-wrap .btn-ghost,  main .btn-ghost,
  .bar-wrap .btn-cta,    main .btn-cta,
  main .form-input.mini{min-height:44px}
  main .gaps summary{min-height:44px}
  main .client-head{min-height:44px}
}

/* 4. Horizontal overflow below ~900px, from two base rules that predate the
      light zone and were never caught because the screenshot pass only ever
      rendered at 1600px wide:
        .actions  is flex-wrap:nowrap AND flex-shrink:0 — four buttons plus the
                  count that can neither wrap nor shrink, so they force 644px.
        .wordmark is flex-shrink:0, so the masthead subtitle keeps its
                  max-content width instead of wrapping.
      A flex item also needs min-width:0 before its text will wrap at all. */
@media(max-width:900px){
  .actions{flex-wrap:wrap;flex-shrink:1;justify-content:flex-start}
  .filters{min-width:0}
  .wordmark{flex-shrink:1;min-width:0}
  .wordmark .t,.wordmark .s{white-space:normal;overflow-wrap:anywhere}
  .toolbar{padding:.75rem 1rem}
  main{padding-left:1rem;padding-right:1rem}
}

/* 5. The real cause of the remaining 216px of mobile overflow. Setting
      display:block + overflow-x:auto on a <table> does not reliably contain the
      anonymous table box Chrome generates for the table-internal children, so
      the internals still leaked into the document scroll width even with the
      card at overflow:hidden and the table's own clientWidth inside its parent.
      The table now scrolls inside a dedicated wrapper, which is the pattern
      ui-ux-pro-max prescribes for any wide content. tabindex and role make the
      scroll region focusable and announced — without them a keyboard user
      cannot scroll it at all.

      contain:paint is the part that actually stops the leak. overflow-x:auto on
      the wrapper scrolls correctly (clientWidth 356 inside scrollWidth 717) but
      Chrome still counted the table internals in the DOCUMENT scroll width, so
      the page scrolled sideways while the table also scrolled. Containment says
      the descendants do not paint outside the wrapper, which is true and which
      fixes the reporting. Rejected alternatives: table{width:100%;table-layout:
      fixed} fixes the number by squashing five columns into 356px and destroying
      readability, and overflow-x:clip on main clips the card hover shadows. */
.tablewrap{overflow-x:auto;-webkit-overflow-scrolling:touch;contain:paint}
.tablewrap:focus-visible{outline:3px solid var(--accent-ink);outline-offset:-3px}
.tablewrap table{min-width:100%}

/* "3 of 6" on a filtered client card — the total is context, not the number. */
.kv .of{ color:var(--ink-62); font-size:.82em; }

/* ===========================================================================
   AUTH CHROME — Pattern E

   The gate is a full-page takeover, not a banner: when auth fails there is
   nothing safe to render behind it, and a dismissible warning over a broken
   auth state invites someone to dismiss it.

   Every colour and measure here is stated outright rather than taken from a
   token. Two reasons, both learned the hard way on 25 Aug 2026:
     - `main` re-scopes the surface tokens to ink-on-white for the light content
       zone, so a gate rendered inside it came out white-on-white.
     - This stylesheet has no spacing or radius tokens (--sp-*, --r-* and
       friends do not exist). An undefined custom property fails silently, so
       the card rendered with no padding and nobody noticed until it was on
       screen. This is the one screen that shows up when something is already
       broken; it must not depend on anything that can be re-scoped or missing.
   ========================================================================= */
.whoami-wrap{ display:flex; align-items:center; gap:.65rem; margin-left:auto; }
.whoami{ font-size:.78rem; color:var(--s-70); letter-spacing:.01em; white-space:nowrap; }
.btn-signout{
  font:inherit; font-size:.75rem; font-weight:600; letter-spacing:.02em;
  color:var(--s-70); background:var(--s-10); border:1px solid var(--s-15);
  border-radius:.5rem; padding:.4rem .65rem; cursor:pointer;
  transition:background-color 140ms ease, color 140ms ease, transform 100ms ease;
}
.btn-signout:hover{ background:var(--s-15); color:#fff; }
.btn-signout:active{ transform:scale(.97); }
.btn-signout:focus-visible{ outline:3px solid var(--orange); outline-offset:3px; }

.gate{
  min-height:100vh; display:grid; place-items:center; padding:1.5rem;
  background:linear-gradient(135deg,#0f172a 0%,#0c4a6e 60%,#0e7490 100%);
  color:#fff;
}
.gate-card{
  max-width:34rem; text-align:left; padding:2rem 2.25rem 2.25rem;
  background:rgba(255,255,255,0.06);
  border:1px solid rgba(255,255,255,0.12);
  border-radius:.9rem;
  box-shadow:0 18px 40px -18px rgba(0,0,0,.55), 0 2px 8px -2px rgba(12,74,110,.35);
}
.gate-card h1{
  font-family:var(--sora); font-weight:800; letter-spacing:-.03em;
  font-size:clamp(1.4rem,3vw,1.9rem); color:#fff; margin:0 0 .9rem;
}
.gate-card p{
  color:rgba(255,255,255,0.82); line-height:1.7; margin:0 0 1.5rem; font-size:.9rem;
}
.gate-card button{
  font-family:var(--inter); font-size:.85rem; font-weight:600;
  border-radius:.5rem; padding:.7rem 1.15rem; border:1px solid transparent;
  transition:background-color 140ms ease, transform 100ms ease;
}
.gate-card button:active{ transform:scale(.98); }
.gate-card button:focus-visible{ outline:3px solid var(--orange); outline-offset:3px; }
.gate-card .btn-cta{ background:var(--orange); color:#0f172a; }
.gate-card .btn-cta:hover{ background:#fb8c3c; }
.gate-card .btn-ghost{
  background:rgba(255,255,255,0.08); color:#fff; border-color:rgba(255,255,255,0.18);
}
.gate-card .btn-ghost:hover{ background:rgba(255,255,255,0.14); }
.gate-card button + button{ margin-left:.65rem; }
