/* Meter Watch — shared design system (macOS glass).
   Both pages link this file; neither carries an inline <style>.

   CANVAS CONTRACT — the dashboard's chart code reads custom properties at draw
   time. --signal / --we / --anomaly go through a hex-only parser: keep them
   6-digit hex in EVERY theme block. --line/--line-soft/--faint/--muted/--txt/
   --ink/--panel are used as canvas colors directly: keep them defined in every
   theme block. CSS-only accents (--accent*, --danger, --plan) are never read
   by canvas and are the only ones the P3 block may upgrade.

   THEME API — :root[data-theme="light"|"dark"] pins a theme (set pre-paint by
   the head snippet); no attribute = Auto (OS media query decides).
   :root[data-pace="overpacing"|"underusing"] retints the ambient layer. */

:root{
  color-scheme: light dark;
  /* ---- light tokens (default) ---- */
  --ink:#f5f5f7; --txt:#1d1d1f; --muted:#6e6e73; --faint:#aeaeb2;
  --panel:#ffffff;                    /* opaque surface: fallbacks + canvas label chip */
  --panel-2:rgba(120,120,128,.08);    /* inset fields, track bars */
  --material:rgba(255,255,255,.62);   /* glass card fill */
  --line:rgba(0,0,0,.10); --line-soft:rgba(0,0,0,.055);
  --signal:#c25200; --signal-dim:#9c4200; --signal-vivid:#ff9500;
  --signal-soft:rgba(194,82,0,.10);
  --anomaly:#d70015; --anomaly-soft:rgba(215,0,21,.08);
  --we:#8944ab;
  --tipbg:rgba(30,30,32,.94);
  --ambient-a:rgba(255,149,0,.11); --ambient-b:rgba(137,68,171,.08);
  --shimmer:rgba(255,255,255,.75);
  --card-shadow:0 1px 2px rgba(0,0,0,.06),0 8px 24px rgba(0,0,0,.07),
                inset 0 .5px 0 rgba(255,255,255,.65);
  --font-ui:-apple-system,BlinkMacSystemFont,"SF Pro Text",system-ui,"Segoe UI",Roboto,sans-serif;
  --font-round:ui-rounded,"SF Pro Rounded",-apple-system,system-ui,sans-serif;
  --mono:ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  --r-card:16px; --r-tile:12px; --r-ctl:8px;
  /* CSS-only aliases (P3-upgradable) */
  --accent:var(--signal); --accent-vivid:var(--signal-vivid);
  --danger:var(--anomaly); --plan:var(--we);
}
/* ---- dark tokens: keep this block and the [data-theme="dark"] copy in sync ---- */
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]){
    --ink:#161619; --txt:#f5f5f7; --muted:#98989f; --faint:#636366;
    --panel:#1d1d20; --panel-2:rgba(120,120,128,.14);
    --material:rgba(255,255,255,.055);
    --line:rgba(255,255,255,.10); --line-soft:rgba(255,255,255,.06);
    --signal:#ff9f0a; --signal-dim:#c77700; --signal-vivid:#ffb340;
    --signal-soft:rgba(255,159,10,.12);
    --anomaly:#ff453a; --anomaly-soft:rgba(255,69,58,.12);
    --we:#bf5af2;
    --tipbg:rgba(20,20,22,.94);
    --ambient-a:rgba(255,159,10,.09); --ambient-b:rgba(191,90,242,.06);
    --shimmer:rgba(255,255,255,.10);
    --card-shadow:inset 0 .5px 0 rgba(255,255,255,.12);
  }
}
:root[data-theme="dark"]{
  --ink:#161619; --txt:#f5f5f7; --muted:#98989f; --faint:#636366;
  --panel:#1d1d20; --panel-2:rgba(120,120,128,.14);
  --material:rgba(255,255,255,.055);
  --line:rgba(255,255,255,.10); --line-soft:rgba(255,255,255,.06);
  --signal:#ff9f0a; --signal-dim:#c77700; --signal-vivid:#ffb340;
  --signal-soft:rgba(255,159,10,.12);
  --anomaly:#ff453a; --anomaly-soft:rgba(255,69,58,.12);
  --we:#bf5af2;
  --tipbg:rgba(20,20,22,.94);
  --ambient-a:rgba(255,159,10,.09); --ambient-b:rgba(191,90,242,.06);
  --shimmer:rgba(255,255,255,.10);
  --card-shadow:inset 0 .5px 0 rgba(255,255,255,.12);
}
/* Wide gamut: only CSS-only aliases upgrade; canvas-parsed hex never changes. */
@supports (color: color(display-p3 1 1 1)){
  :root{ --accent-vivid:color(display-p3 1 .61 .05); --danger:color(display-p3 .86 .05 .1);
         --plan:color(display-p3 .55 .27 .68); }
  @media (prefers-color-scheme: dark){
    :root:not([data-theme="light"]){ --accent-vivid:color(display-p3 1 .72 .3);
      --danger:color(display-p3 1 .3 .26); --plan:color(display-p3 .77 .41 .95); }
  }
  :root[data-theme="dark"]{ --accent-vivid:color(display-p3 1 .72 .3);
    --danger:color(display-p3 1 .3 .26); --plan:color(display-p3 .77 .41 .95); }
}
/* Signature: pace verdict tints the ambient light (set on <html> by renderPace) */
:root[data-pace="overpacing"]{ --ambient-a:rgba(255,59,48,.11); }
:root[data-pace="underusing"]{ --ambient-a:rgba(94,92,230,.09); }

/* ---------- base ---------- */
*{box-sizing:border-box}
html,body{margin:0}
/* `hidden` is enforced only by the UA stylesheet, which ANY author `display`
   rule outranks by origin — not by specificity, so no amount of reordering
   below would help. .scope-load and .plegend both set display:flex and so
   silently ignored el.hidden: every chart skeleton stayed painted on top of
   its own finished chart. Re-assert the attribute in the author origin. */
[hidden]{display:none !important}
body{
  background:var(--ink); color:var(--txt); font-family:var(--font-ui);
  -webkit-font-smoothing:antialiased; -webkit-tap-highlight-color:transparent;
  min-height:100vh; transition:background-color .3s,color .3s;
  padding-left:env(safe-area-inset-left); padding-right:env(safe-area-inset-right);
}
::selection{background:var(--signal-soft)}
:focus-visible{outline:2px solid var(--accent); outline-offset:2px}
.num{font-variant-numeric:tabular-nums}
.eyebrow{font-size:13px; color:var(--muted); font-weight:400}

/* ambient light behind the glass — the blur needs something to frost */
.ambient{position:fixed; inset:0; z-index:-1; pointer-events:none;
  background:
    radial-gradient(900px 620px at 82% -8%, var(--ambient-a), transparent 62%),
    radial-gradient(1000px 700px at -12% 108%, var(--ambient-b), transparent 60%);
  transition:background 1.2s ease}

/* ---------- card recipe ---------- */
.card{background:var(--panel); border:1px solid var(--line);
  border-radius:var(--r-card); box-shadow:var(--card-shadow)}
@supports ((backdrop-filter:blur(4px)) or (-webkit-backdrop-filter:blur(4px))){
  .card{background:var(--material);
    -webkit-backdrop-filter:blur(24px) saturate(1.6); backdrop-filter:blur(24px) saturate(1.6)}
}

/* ---------- toolbar ---------- */
.top{position:sticky; top:0; z-index:10; display:flex; align-items:center;
  justify-content:space-between; gap:14px; padding:12px 22px;
  padding-top:calc(12px + env(safe-area-inset-top));
  background:var(--material); border-bottom:1px solid var(--line);
  -webkit-backdrop-filter:blur(24px) saturate(1.6); backdrop-filter:blur(24px) saturate(1.6)}
.brand{display:flex; align-items:center; gap:10px}
.dot-we{width:26px; height:26px; border-radius:8px; background:linear-gradient(160deg,var(--accent-vivid),var(--signal-dim));
  display:grid; place-items:center; font-size:10px; font-weight:700; color:#fff}
.brand b{font-size:14px; font-weight:600; letter-spacing:-.01em; display:block}
.brand span{display:block; font-size:11px; color:var(--muted)}
.live{display:flex; align-items:center; gap:12px; font-size:12px; color:var(--muted)}
.stat-live{display:flex; align-items:center; gap:8px; padding:5px 11px;
  border-radius:999px; background:var(--panel-2)}
.pulse{width:8px; height:8px; border-radius:50%; background:var(--accent-vivid);
  box-shadow:0 0 0 0 var(--signal-soft); animation:pulse 2s infinite}
.pulse.warn{background:var(--danger); animation:pulse-warn 1.4s infinite}
@keyframes pulse{0%{box-shadow:0 0 0 0 rgba(255,159,10,.5)}70%{box-shadow:0 0 0 7px rgba(255,159,10,0)}100%{box-shadow:0 0 0 0 rgba(255,159,10,0)}}
@keyframes pulse-warn{0%{box-shadow:0 0 0 0 rgba(255,69,58,.5)}70%{box-shadow:0 0 0 7px rgba(255,69,58,0)}100%{box-shadow:0 0 0 0 rgba(255,69,58,0)}}

/* macOS-style segmented control (theme switch + range switches) */
.seg,.range{display:inline-flex; gap:2px; padding:2px; border-radius:9px; background:var(--panel-2)}
.seg button,.range button{border:0; background:transparent; color:var(--muted);
  font:inherit; font-size:12px; padding:4px 11px; border-radius:7px; cursor:pointer;
  transition:background .15s,color .15s}
.seg button[aria-pressed="true"],.range button[aria-pressed="true"]{
  background:var(--panel); color:var(--txt); box-shadow:0 1px 3px rgba(0,0,0,.12)}
@supports ((backdrop-filter:blur(4px)) or (-webkit-backdrop-filter:blur(4px))){
  .seg button[aria-pressed="true"],.range button[aria-pressed="true"]{background:var(--material)}
}

/* ---------- page scaffold ---------- */
.wrap{max-width:1080px; margin:0 auto; padding:22px 22px calc(64px + env(safe-area-inset-bottom))}
.sec{margin-top:28px}
.sechead{display:flex; align-items:center; justify-content:space-between; gap:12px; margin-bottom:10px}
.sechead h2{margin:0; font-size:13px; font-weight:600; color:var(--muted)}

/* ---------- alerts ---------- */
.alert{border:1px solid var(--danger); background:var(--anomaly-soft);
  border-radius:var(--r-tile); padding:14px 16px; margin-top:18px}
.alert .eyebrow{color:var(--danger); font-weight:600}
.alert-row{display:flex; align-items:center; gap:12px; flex-wrap:wrap; margin-top:8px; font-size:13px}
.alert button{border:0; border-radius:var(--r-ctl); background:var(--danger); color:#fff;
  font:inherit; font-size:13px; font-weight:600; padding:7px 14px; cursor:pointer}
.alert button:hover{filter:brightness(1.08)}
.captcha-img{background:#fff; padding:5px; border-radius:6px; height:44px}
.alert-msg{margin-top:8px; font-size:13px; color:var(--danger)}
input[type=text]{font:inherit; background:var(--panel-2); border:1px solid var(--line);
  color:var(--txt); padding:8px 10px; border-radius:var(--r-ctl); width:130px}
input[type=text]:focus{outline:2px solid var(--accent); outline-offset:1px}

/* ---------- hero ---------- */
.hero{display:grid; grid-template-columns:1fr auto; gap:24px; align-items:center;
  margin-top:22px; padding:28px}
.readout .eyebrow{margin-bottom:6px}
.odo{font-family:var(--font-round); font-size:clamp(52px,11vw,104px); font-weight:700;
  line-height:.95; letter-spacing:-.02em; color:var(--txt)}
.odo small{font-size:.32em; color:var(--muted); font-weight:600}
.subline{margin-top:12px; font-size:13px; color:var(--muted); display:flex; gap:8px;
  align-items:center; flex-wrap:wrap}
.chip{border-radius:999px; padding:4px 11px; font-size:12px; background:var(--panel-2); color:var(--txt)}
.chip.we{color:var(--plan); background:transparent; border:1px solid var(--plan)}
/* Widths approximate the text each chip will hold ("of 1,500.00 GB", an offer
   name). They are not cosmetic: below 720px the chips wrap to their own row,
   so a placeholder narrower than the real text would fit on line one and drop
   the whole page 34px the moment it was filled in. */
#totalChip .sk-text{width:7.4em}
#planChip .sk-text{width:5.2em}
.usebar{margin-top:16px; height:10px; background:var(--panel-2); border-radius:999px;
  overflow:hidden; max-width:360px}
.usebar>i{display:block; height:100%; border-radius:999px;
  background:linear-gradient(90deg,var(--signal-dim),var(--accent-vivid)); transition:width .6s ease}

/* sampling ring */
.beat{text-align:center; min-width:132px}
.ring{position:relative; width:104px; height:104px; margin:0 auto}
.ring svg{transform:rotate(-90deg)}
.ring .track{stroke:var(--panel-2); fill:none}
.ring .fill{stroke:var(--accent-vivid); fill:none; stroke-linecap:round;
  transition:stroke-dashoffset .9s linear}
.ring .cap{position:absolute; inset:0; display:grid; place-content:center; text-align:center}
.ring .cap b{font-family:var(--font-round); font-size:24px; color:var(--txt)}
.ring .cap span{font-size:10px; color:var(--muted)}
.beat>.eyebrow{margin-top:12px}
.beat small{display:block; font-size:12px; color:var(--faint); margin-top:4px}

/* ---------- stat tiles ---------- */
.stats{display:grid; grid-template-columns:repeat(3,1fr); gap:12px; margin-top:16px}
.stat{padding:16px 18px; border-radius:var(--r-tile)}
.stat .eyebrow{margin-bottom:8px}
.stat .v{font-family:var(--font-round); font-size:22px; font-weight:600}
.stat .v small{font-size:13px; color:var(--muted); font-weight:400}
.stat .sub{font-size:12px; color:var(--faint); margin-top:4px}
.stat.flag .v{color:var(--danger)}

/* ---------- pace ---------- */
.pacecard{padding:18px 20px}
.verdict{display:flex; align-items:flex-start; gap:10px; font-size:14px; margin-bottom:16px; line-height:1.45}
/* flex:1 so the slot is the same width whether it holds prose or placeholder
   bars — a shrink-to-fit flex item would collapse a block-level .sk-line to
   nothing, and the real text already fills this width anyway. */
.verdict>span:last-child{flex:1; text-wrap:balance}
/* The verdict prose is the one pace slot that can't just render an em-dash.
   Two bars under 720px, one above: the measured line count of all three real
   verdicts at each width. No margin between them — text lines have none. */
.verdict .sk-line + .sk-line{width:62%}
@media (min-width:721px){ .verdict .sk-line + .sk-line{display:none} }
.vdot{width:10px; height:10px; border-radius:50%; background:var(--accent-vivid); flex:none; margin-top:4px}
.verdict.over .vdot{background:var(--danger)} .verdict.under .vdot{background:var(--muted)}
.verdict b{color:var(--accent)} .verdict.over b{color:var(--danger)}
.meter-track{position:relative; height:12px; border-radius:999px; overflow:visible;
  background:linear-gradient(90deg,var(--muted) 0%,var(--accent-vivid) 50%,var(--danger) 100%); opacity:.9}
.ideal-band{position:absolute; top:-3px; bottom:-3px; left:44%; width:12%;
  border:1px dashed var(--faint); border-radius:999px}
.marker{position:absolute; top:50%; width:18px; height:18px; border-radius:50%;
  background:#fff; border:1px solid rgba(0,0,0,.15); transform:translate(-50%,-50%);
  transition:left .5s ease; box-shadow:0 1px 4px rgba(0,0,0,.3)}
.meter-labels{display:flex; justify-content:space-between; margin-top:9px; font-size:11px; color:var(--faint)}
.pacestats{display:grid; grid-template-columns:repeat(4,1fr); gap:1px; background:var(--line);
  border:1px solid var(--line); border-radius:var(--r-tile); overflow:hidden; margin-top:18px}
.pacestats>div{background:var(--panel); padding:12px 14px}
@supports ((backdrop-filter:blur(4px)) or (-webkit-backdrop-filter:blur(4px))){
  .pacestats>div{background:var(--material)}
}
.pacestats .eyebrow{display:block; font-size:12px; margin-bottom:6px}
.pacestats b{display:block; font-family:var(--font-round); font-size:17px;
  font-weight:600; line-height:1.18}
.pacestats b small{font-size:12px; color:var(--muted); font-weight:400}

/* ---------- chart cards ---------- */
.scope{position:relative; padding:10px; border-radius:var(--r-card)}
canvas{display:block; width:100%; height:300px}
/* The tape captures horizontal drag to scrub its tooltip; pan-y keeps the page
   scrollable vertically from on top of it. #punch is untouched — it lives in a
   horizontal scroller and must keep both axes. */
#chart{touch-action:pan-y}
.tip{position:absolute; pointer-events:none; background:var(--tipbg); color:#f5f5f7;
  border-radius:9px; padding:8px 11px; font-size:12px; opacity:0; transition:opacity .1s;
  transform:translate(-50%,-115%); white-space:nowrap; z-index:3;
  box-shadow:0 4px 16px rgba(0,0,0,.25)}
.tip b{color:var(--accent-vivid)} .tip .d{color:#ff6b61}
.tip .t{color:rgba(245,245,247,.6); display:block; margin-bottom:3px}
.scope-empty{position:absolute; inset:0; display:grid; place-content:center;
  text-align:center; color:var(--faint); font-size:13px}

/* ---------- loading skeleton ----------
   A card with no data yet is NOT a card with no history. Before the first
   response lands, every scope used to assert "not enough history yet", which is
   alarming and untrue. The shimmer says "fetching"; the empty text is reserved
   for a response that genuinely came back empty.

   One shimmer recipe, three shapes: .sk fills a canvas overlay, .sk-line is a
   block the height of one line of its parent's text, .sk-text is an inline run
   sized in em so it reserves a real text box inside a chip or table cell. */
.sk,.sk-line,.sk-text{background:var(--panel-2); border-radius:var(--r-ctl);
  position:relative; overflow:hidden}
.sk::after,.sk-line::after,.sk-text::after{content:''; position:absolute; inset:0;
  transform:translateX(-100%);
  background:linear-gradient(90deg,transparent,var(--shimmer),transparent);
  animation:sk-shimmer 1.5s ease-in-out infinite}
@keyframes sk-shimmer{100%{transform:translateX(100%)}}
@media (prefers-reduced-motion: reduce){
  .sk::after,.sk-line::after,.sk-text::after{animation:none}
}
/* Sized in em against the line-height of whatever it stands in for, so one
   rule holds at every breakpoint where that text changes size. */
.sk-line{display:block; height:1.45em}
.sk-text{display:inline-block; height:1em; vertical-align:-.15em; border-radius:4px}

.scope-load{position:absolute; inset:10px; display:flex; flex-direction:column;
  gap:6px; pointer-events:none}
/* Ragged widths and staggered sweeps on a 7-bar cycle, so #calLoad — whose bar
   count follows the week rows and can run past seven — keeps the pattern
   instead of falling off the end of a fixed list into flat full-width bars. */
.scope-load .sk{flex:1; width:96%}
.scope-load .sk:nth-child(7n+2){width:82%} .scope-load .sk:nth-child(7n+3){width:90%}
.scope-load .sk:nth-child(7n+4){width:74%} .scope-load .sk:nth-child(7n+5){width:88%}
.scope-load .sk:nth-child(7n+6){width:79%} .scope-load .sk:nth-child(7n){width:93%}
.scope-load .sk:nth-child(7n+2)::after{animation-delay:.10s}
.scope-load .sk:nth-child(7n+3)::after{animation-delay:.20s}
.scope-load .sk:nth-child(7n+4)::after{animation-delay:.30s}
.scope-load .sk:nth-child(7n+5)::after{animation-delay:.40s}
.scope-load .sk:nth-child(7n+6)::after{animation-delay:.50s}
.scope-load .sk:nth-child(7n)::after{animation-delay:.60s}

/* patterns */
.pgrid{display:grid; gap:14px}
.ptitle{font-size:13px; font-weight:600; color:var(--muted); margin:0 0 8px}
.ptitle .psub{color:var(--faint); font-weight:400; margin-left:8px}
.pcard{position:relative; min-width:0}
.pscroll{overflow-x:auto; overscroll-behavior-x:contain}
#punch{height:190px; min-width:560px}
#cal{height:90px}
#cad{height:150px}
.plegend{display:flex; flex-wrap:wrap; gap:4px 6px; align-items:center; margin-top:8px;
  font-size:11px; color:var(--faint)}
/* Reserved, not removed. The markup ships this class so the legend holds its row
   from the first paint; legendState resolves it once the response lands. Without
   it each legend appearing shoves the cards below it down 21px. */
.plegend.pending{visibility:hidden}
.plegend .sw{width:10px; height:10px; border-radius:3px; display:inline-block; margin-left:10px}
.plegend .sw:first-child{margin-left:0}
.plegend .sw.peak{border:1.5px solid var(--anomaly); background:transparent; margin-left:14px}
#punchLegend .sw{margin-left:0}
#punchLegend .sw.peak{margin-left:14px}
#punchLegend span:not(.sw){margin:0 6px}

/* ---------- ledger ---------- */
.tablecard{padding:6px 16px; border-radius:var(--r-card)}
table{width:100%; border-collapse:collapse; font-size:13px}
thead th{text-align:right; font-weight:600; color:var(--muted); font-size:12px;
  padding:10px 12px 9px; border-bottom:1px solid var(--line)}
thead th:first-child{text-align:left}
tbody td{padding:8px 12px; border-bottom:1px solid var(--line-soft); text-align:right;
  color:var(--txt); font-family:var(--mono); font-size:12.5px}
tbody td:first-child{text-align:left; color:var(--muted)}
tbody tr:last-child td{border-bottom:0}
tbody tr{transition:background .1s}
tbody tr:hover,tbody tr.hot-hover{background:var(--signal-soft)}
tbody tr.flag td:first-child{color:var(--danger)}
.dcell{display:inline-flex; align-items:center; gap:8px; justify-content:flex-end}
.dbar{height:6px; width:60px; background:var(--panel-2); border-radius:999px; overflow:hidden}
.dbar>i{display:block; height:100%; background:var(--accent-vivid)}
.flag .dbar>i{background:var(--danger)}
.zero{color:var(--faint)}
/* Placeholder rows carry the real td padding and font, so the body starts near
   the height it will settle at. renderLedger's innerHTML assignment wipes them
   on the first render — including the failed-response render, so they can't
   get stuck. Exact reservation is impossible here: the row count depends on how
   many readings arrived and how buildGroups collapses them. */
.sk-row td .sk-text{width:70%}
.sk-row td:first-child .sk-text{width:58%}
.sk-row td:last-child .sk-text{width:34%}
tbody tr.grp{cursor:pointer}
tbody tr.grp td:first-child{color:var(--faint)}
.tw{display:inline-block; width:12px; color:var(--accent); transition:transform .15s}
tr.grp[aria-expanded="true"] .tw{transform:rotate(90deg)}
.grpn{color:var(--muted); font-family:var(--font-ui)}
tbody tr.child td{color:var(--faint); font-size:11.5px}
tbody tr.child td:first-child{padding-left:26px}
.more{margin-top:14px; margin-bottom:8px; text-align:center}
.more button{border:1px solid var(--line); background:transparent; color:var(--muted);
  font:inherit; font-size:12px; padding:6px 14px; border-radius:var(--r-ctl); cursor:pointer}
.more button:hover{color:var(--txt); border-color:var(--muted)}
.foot{margin-top:26px; font-size:12px; color:var(--faint); line-height:1.7}
.foot b{font-weight:600}

/* ---------- login ---------- */
.auth{min-height:100dvh; display:grid; place-items:center; padding:24px}
form.login{width:min(380px,100%); padding:32px 28px}
form.login h1{margin:0 0 4px; font-size:20px; font-weight:700; letter-spacing:-.01em}
form.login p.sub{margin:0 0 22px; font-size:13px; color:var(--muted)}
form.login label{display:block; font-size:13px; color:var(--muted); margin:14px 0 6px}
form.login input[type=text],form.login input[type=password]{width:100%; padding:10px 12px;
  background:var(--panel-2); color:var(--txt); border:1px solid var(--line);
  border-radius:var(--r-ctl); font:inherit; font-size:14px}
form.login input:focus{outline:none; border-color:var(--accent);
  box-shadow:0 0 0 3px var(--signal-soft)}
form.login .row{display:flex; align-items:center; gap:8px; margin:18px 0 20px;
  font-size:13px; color:var(--muted)}
form.login input[type=checkbox]{accent-color:var(--accent)}
form.login button{width:100%; padding:11px; border:0; border-radius:10px;
  background:var(--accent); color:#fff; font:inherit; font-size:14px; font-weight:600; cursor:pointer}
form.login button:hover{filter:brightness(1.08)}
form.login button[disabled]{opacity:.6; cursor:default}
#err{display:none; margin-top:16px; padding:9px 11px; font-size:13px;
  border-radius:var(--r-ctl); background:var(--anomaly-soft); color:var(--danger);
  border:1px solid var(--danger)}
#err.on{display:block}

/* ---------- responsive ---------- */
@media (max-width:720px){
  .wrap{padding:16px 14px calc(48px + env(safe-area-inset-bottom))}
  .top{flex-wrap:wrap; gap:10px; padding:10px 14px}
  .hero{grid-template-columns:1fr; align-items:start; padding:20px}
  .odo{font-size:clamp(46px,16vw,80px)}
  .beat{margin-top:14px; text-align:left; display:grid; grid-template-columns:auto 1fr;
    column-gap:16px; align-items:center}
  .ring{grid-row:1 / span 2; margin:0}
  .beat>.eyebrow{margin-top:0; align-self:end} .beat small{margin-top:3px; align-self:start}
  .stats{grid-template-columns:1fr}
  .pacestats{grid-template-columns:1fr 1fr}
  /* Two columns are narrow enough that the longest projected-use value
     ("2,130.00 GB · 142%") wrapped to a second line while the other three tiles
     stayed at one — so the card was 20px taller for overpacing accounts only,
     after the placeholder had already reserved the one-line height. Breaking
     the unit onto its own line gives every tile the same two, whatever the
     value, and min-height holds those two for the em-dash placeholder too. */
  .pacestats b{min-height:2.36em}
  .pacestats b small{display:block}
  .verdict{font-size:13px}
  .meter-labels{font-size:9.5px}
  canvas{height:230px}
  .sechead{flex-wrap:wrap}
  .dbar{display:none}
  thead th,tbody td{padding:7px 8px; font-size:12px}
  .grpn{font-size:11px}
}

/* ---------- system preferences ---------- */
@media (display-mode: standalone){
  /* the Dock-app window has its own title bar; tighten our toolbar */
  .top{padding-top:8px; padding-bottom:8px}
}
@media (prefers-reduced-transparency: reduce){
  .card,.top,.pacestats>div,.seg button[aria-pressed="true"],.range button[aria-pressed="true"]{
    background:var(--panel); -webkit-backdrop-filter:none; backdrop-filter:none}
  .ambient{display:none}
}
@media (prefers-contrast: more){
  :root{--line:rgba(0,0,0,.28); --line-soft:rgba(0,0,0,.18); --muted:#3c3c43}
  :root[data-theme="dark"]{--line:rgba(255,255,255,.32); --line-soft:rgba(255,255,255,.2); --muted:#c7c7cc}
}
@media (prefers-contrast: more) and (prefers-color-scheme: dark){
  :root:not([data-theme="light"]){--line:rgba(255,255,255,.32); --line-soft:rgba(255,255,255,.2); --muted:#c7c7cc}
}
@media (prefers-reduced-motion: reduce){
  .pulse,.pulse.warn{animation:none}
  .ring .fill{transition:none}
  .usebar>i,.marker{transition:none}
  .ambient{transition:none}
}
