/* ==========================================================================
   365Lab 毒蘑菇测试 — design system
   Light-first, optional dark theme, mobile-adaptive, print friendly.
   ========================================================================== */

:root{
  --brand:#d8455f;        /* fly-agaric red */
  --brand-2:#7c4dcb;      /* night fog violet */
  --brand-3:#2fa38c;      /* moss teal */
  --brand-4:#e0a03a;      /* spore amber */
  --brand-deep:#b32c46;   /* solid brand for text/gradient-backed white text */
  --bg:#f6f4f7;
  --bg-2:#efeaf1;
  --panel:#ffffff;
  --panel-2:#faf8fb;
  --ink:#1c1b22;
  --muted:#5a5764;        /* >=4.5:1 on --panel and --panel-2 */
  --line:#e5e0e9;
  --line-2:#efeaf2;
  --chip:#f2eef5;
  --ok:#177a5d; --warn:#966000; --bad:#c4342f;   /* all >=4.5:1 as text on --panel (--ok was 4.04 before) */
  /* Text-bearing surfaces cannot use --grad-brand: its light stops (--brand-4)
     leave white text at 2.27:1 in light theme and 1.70:1 in dark. These two
     tokens are the solid pair; the gradient stays decorative only. */
  --brand-solid:#b32c46; --on-brand:#ffffff;      /* 6.22:1 */
  --shadow:0 1px 2px rgba(35,20,50,.05),0 10px 28px rgba(35,20,50,.07);
  --shadow-sm:0 1px 2px rgba(35,20,50,.07);
  --radius:14px; --radius-sm:10px;
  --topbar-h:60px;
  --stage-bg:#0c0a12;
  --grad-brand:linear-gradient(120deg,var(--brand),var(--brand-2) 60%,var(--brand-4));
  color-scheme:light;
}
[data-theme="dark"]{
  --brand:#ff6b81;
  --brand-2:#a780ff;
  --brand-3:#4fd0b3;
  --brand-4:#f0bf5e;
  --brand-deep:#ff6b81;
  --bg:#0c0a12;
  --bg-2:#12101a;
  --panel:#16131e;
  --panel-2:#1b1825;
  --ink:#ece9f2;
  --muted:#a8a2b8;
  --line:#292434;
  --line-2:#221e2c;
  --chip:#221e2c;
  --ok:#4fd0b3; --warn:#f0bf5e; --bad:#ff8078;
  /* the dark gradient is made of LIGHT stops, so the readable pair here is
     brand tint + near-black ink (6.83:1), not white text */
  --brand-solid:#ff6b81; --on-brand:#150d13;      /* 6.83:1 */
  --shadow:0 1px 2px rgba(0,0,0,.5),0 12px 32px rgba(0,0,0,.45);
  --shadow-sm:0 1px 3px rgba(0,0,0,.5);
  --stage-bg:#07060b;
  color-scheme:dark;
}

*{box-sizing:border-box}
html{scroll-behavior:smooth}
body{margin:0;font-family:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue","PingFang SC","Microsoft YaHei","Hiragino Sans GB",sans-serif;
  color:var(--ink);background:var(--bg);line-height:1.6;font-size:15px;-webkit-font-smoothing:antialiased;overflow-wrap:break-word}
a{color:inherit;text-decoration:none}
img,svg,canvas{max-width:100%;display:block}
button{font-family:inherit;cursor:pointer;border:none;background:none;color:inherit;font-size:inherit}
input,select,textarea{font-family:inherit;font-size:16px;color:inherit}      /* iOS: >=16px avoids zoom */
h1,h2,h3,h4{line-height:1.25;margin:0;font-weight:800;letter-spacing:-.2px}
h2{font-size:clamp(21px,2.6vw,28px)}
h3{font-size:17px}
p{margin:0 0 12px}
ul,ol{margin:0 0 12px;padding-left:1.25em}
li{margin:4px 0}
code{background:var(--chip);border-radius:5px;padding:1px 6px;font-size:.92em}
table{border-collapse:collapse;width:100%}
.wrap{max-width:1180px;margin:0 auto;padding:0 18px}
/* jump targets must not end up hidden behind the sticky header */
/* <main id="…"> is where the skip links actually land, and it was missing from
   this list, so those jumps parked their target under the sticky bar */
main[id],section[id],div[id],h2[id],h3[id]{scroll-margin-top:calc(var(--topbar-h) + 16px)}
/* Web Interface Guidelines pass: kill the 300ms double-tap zoom delay on
   touch targets, make the mobile tap highlight deliberate rather than the
   browser default blue flash, and stop the lightbox from scroll-chaining
   into the page behind it */
a,button,.btn,.seg button,summary,input[type="checkbox"],input[type="radio"],label{touch-action:manipulation}
html{-webkit-tap-highlight-color:color-mix(in srgb,var(--brand) 18%,transparent)}
.lightbox{overscroll-behavior:contain}
/* display headings read as one balanced block instead of a widow word */
h1,h2,.page-h h2{text-wrap:balance}
::selection{background:color-mix(in srgb,var(--brand) 26%,transparent)}
.hidden,[hidden]{display:none!important}
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
.skip{position:absolute;left:8px;top:-48px;z-index:100;background:var(--panel);padding:8px 14px;border-radius:8px;box-shadow:var(--shadow)}
.skip:focus{top:8px}
/* the no-JS floor: visible only when scripting is off, and it should look
   deliberate rather than like a broken strip of unstyled text */
.ns{margin:0;padding:11px 18px;background:color-mix(in srgb,var(--warn) 12%,var(--panel));
  border-bottom:1px solid color-mix(in srgb,var(--warn) 34%,var(--line));
  color:var(--ink);font-size:13.5px;line-height:1.55;text-align:center}
.ns a{color:var(--brand-deep);font-weight:700;text-decoration:underline;text-underline-offset:2px}
:focus-visible{outline:2.5px solid var(--brand);outline-offset:2px;border-radius:6px}

/* ── top bar ─────────────────────────────────────────────────────────── */
/* 900px was too late: between ~900 and ~1010px the eight nowrap nav items can
   no longer fit, and since the topbar has a FIXED height the squeezed brand
   block wraps and spills over the hero. Collapse before that window opens.
   A flexible top bar keeps it safe even if the nav grows another item. */
.topbar{position:sticky;top:0;z-index:40;min-height:var(--topbar-h);height:auto;padding:6px 0;background:color-mix(in srgb,var(--panel) 86%,transparent);
  backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border-bottom:1px solid var(--line)}
.topbar .wrap{min-height:calc(var(--topbar-h) - 12px);display:flex;align-items:center;gap:14px}
.brand{display:flex;align-items:center;gap:10px;font-weight:900;font-size:17px}
/* single canonical mushroom mark (/assets/favicon.svg) so the header & footer
   brand, the favicons and the PWA icons are literally the same artwork */
.brand .logo{width:30px;height:30px;border-radius:9px;background:url("/assets/favicon.svg") center/30px 30px no-repeat;flex:0 0 auto;box-shadow:var(--shadow-sm)}
.brand small{display:block;font-size:11px;font-weight:600;color:var(--muted);line-height:1.3}
.topnav{margin-left:auto;display:flex;align-items:center;gap:4px}
.topnav a{padding:8px 11px;border-radius:9px;color:var(--muted);font-weight:650;font-size:14px;white-space:nowrap}
.topnav a:hover{background:var(--chip);color:var(--ink)}
.topnav a.on{color:var(--brand-deep);background:color-mix(in srgb,var(--brand) 9%,transparent)}
.tbtns{display:flex;gap:6px;align-items:center;margin-left:6px}
.tbtn{min-width:40px;height:36px;padding:0 12px;border-radius:999px;border:1px solid var(--line);background:var(--panel);font-weight:750;font-size:13px;color:var(--ink)}
.tbtn:hover{border-color:var(--brand)}
/* theme indicator: half-filled disc, readable in both themes, no font dependency */
.tbtn .ti{display:inline-block;width:15px;height:15px;border-radius:50%;border:1.7px solid currentColor;
  background:linear-gradient(90deg,currentColor 50%,transparent 50%);vertical-align:-2px}
[data-theme="dark"] .tbtn .ti{box-shadow:0 0 0 2.5px color-mix(in srgb,var(--brand) 22%,transparent)}
.navtoggle{display:none;width:40px;height:36px;border-radius:9px;border:1px solid var(--line);background:var(--panel);font-size:17px}
@media(max-width:1024px){
  .topnav{position:absolute;left:0;right:0;top:100%;flex-direction:column;align-items:stretch;gap:2px;padding:8px 14px 14px;
    background:var(--panel);border-bottom:1px solid var(--line);box-shadow:var(--shadow);display:none}
  .topnav.open{display:flex}
  .topnav a{padding:11px 10px;font-size:15px}
  .navtoggle{display:inline-flex;align-items:center;justify-content:center;margin-left:auto}
  .tbtns{margin-left:0}
}

/* ── hero / sections ─────────────────────────────────────────────────── */
.hero,.home-hero{padding:38px 0 8px}
.hero h1,.home-hero h1{font-size:clamp(27px,4.6vw,42px);font-weight:900;letter-spacing:-.6px;max-width:24ch}
.hero h1 .g,.home-hero h1 .g{background:var(--grad-brand);-webkit-background-clip:text;background-clip:text;color:transparent}
.hero .lead,.hero p,.home-hero .lead,.home-hero p{margin:14px 0 0;color:var(--muted);font-size:clamp(15px,1.7vw,18px);max-width:72ch}
.hero .badges,.home-hero .badges{display:flex;flex-wrap:wrap;gap:8px;margin-top:18px}
.hero .badges span,.home-hero .badges span{background:var(--panel);border:1px solid var(--line);border-radius:999px;padding:6px 13px;font-size:13px;font-weight:650;color:var(--muted);box-shadow:var(--shadow-sm)}
.hero .actions,.home-hero .actions{display:flex;flex-wrap:wrap;gap:10px;margin-top:22px}

.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;min-height:44px;padding:0 22px;border-radius:11px;
  border:1px solid var(--line);background:var(--panel);font-weight:750;font-size:15px;color:var(--ink);transition:transform .12s,box-shadow .12s,border-color .12s}
.btn:hover{border-color:var(--brand);transform:translateY(-1px)}
.btn:active{transform:translateY(0)}
/* keeps the gradient halo, puts the label on a surface it can actually be read on */
.btn-primary{border-color:transparent;background:var(--brand-solid);color:var(--on-brand);box-shadow:0 6px 18px color-mix(in srgb,var(--brand) 32%,transparent)}
.btn-primary:hover{color:#fff;box-shadow:0 8px 24px color-mix(in srgb,var(--brand) 42%,transparent)}
.btn-ghost{background:transparent;border-color:var(--line)}
.btn-sm{min-height:36px;padding:0 13px;font-size:13.5px;border-radius:9px}
.btn[disabled]{opacity:.5;pointer-events:none}
.btn-danger{border-color:color-mix(in srgb,var(--bad) 40%,var(--line));color:var(--bad)}

section.sec{padding:38px 0}
section.sec:nth-child(even){background:var(--bg-2)}
.sec-h{margin:0 0 20px}
.sec-h .kicker{display:inline-block;font-size:12.5px;font-weight:800;letter-spacing:.08em;text-transform:uppercase;color:var(--brand-deep);margin-bottom:6px}
.sec-h p{margin:8px 0 0;color:var(--muted);max-width:74ch}

/* cards: icon and title share the first row, copy sits below */
.cards{display:grid;gap:14px;grid-template-columns:repeat(auto-fill,minmax(min(250px,100%),1fr))}
#sceneCards{grid-template-columns:repeat(3,1fr)}
@media(max-width:900px){#sceneCards{grid-template-columns:repeat(2,1fr)}}
@media(max-width:600px){#sceneCards{grid-template-columns:1fr}}
.cards.two{grid-template-columns:repeat(auto-fill,minmax(min(320px,100%),1fr))}
.card{position:relative;display:grid;grid-template-columns:auto 1fr;column-gap:11px;align-items:center;
  background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);padding:18px;box-shadow:var(--shadow);overflow:hidden;
  background-image:linear-gradient(180deg,color-mix(in srgb,var(--brand) 4%,transparent),transparent 120px)}
.card:hover{border-color:color-mix(in srgb,var(--brand) 45%,var(--line));box-shadow:0 0 0 3px color-mix(in srgb,var(--brand) 12%,transparent),var(--shadow)}
.card h3{grid-column:2;grid-row:1;margin:0;font-size:16.5px}
.card p{grid-column:1/-1;grid-row:2;margin:10px 0 0;color:var(--muted);font-size:14px}
.card .ico{grid-column:1;grid-row:1;width:38px;height:38px;border-radius:11px;display:grid;place-items:center;background:color-mix(in srgb,var(--brand) 10%,transparent);font-size:19px}
.card .meta{grid-column:1/-1;grid-row:3;margin-top:12px;font-size:12.5px;color:var(--muted);font-weight:650}
a.card{display:grid}

/* feature list, steps, faq */
.feat{display:grid;gap:14px 26px;grid-template-columns:repeat(auto-fit,minmax(280px,1fr))}
.feat div{display:flex;gap:11px;align-items:flex-start}
.feat b{display:block;font-size:15px;margin-bottom:2px}
.feat span{color:var(--muted);font-size:14px}
.dot{flex:0 0 auto;width:24px;height:24px;border-radius:8px;background:var(--brand-solid);color:var(--on-brand);display:grid;place-items:center;font-size:13px;font-weight:800;margin-top:1px}
.steps{counter-reset:s;display:grid;gap:12px}
.steps li{list-style:none;counter-increment:s;position:relative;padding:12px 14px 12px 52px;background:var(--panel);border:1px solid var(--line);border-radius:var(--radius-sm)}
.steps li::before{content:counter(s);position:absolute;left:14px;top:12px;width:26px;height:26px;border-radius:8px;background:var(--brand-solid);color:var(--on-brand);font-weight:800;display:grid;place-items:center;font-size:13px}
.faq{display:grid;gap:10px}
.faq details{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius-sm);padding:0 16px}
.faq summary{list-style:none;cursor:pointer;display:flex;align-items:center;gap:10px;min-height:52px;font-weight:750;font-size:15.5px}
.faq summary:hover{color:var(--brand-deep)}
.faq details:hover{border-color:color-mix(in srgb,var(--brand) 32%,var(--line))}
.faq summary::-webkit-details-marker{display:none}
.faq summary::after{content:"+";margin-left:auto;font-size:20px;color:var(--muted);transition:transform .2s}
.faq details[open] summary::after{transform:rotate(45deg)}
.faq .a{padding:0 0 16px;color:var(--muted);font-size:14.5px}
.faq .a p:last-child{margin-bottom:0}

/* spec / data tables */
.tbl{width:100%;font-size:14px;background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);overflow:hidden}
.tbl th,.tbl td{text-align:left;padding:10px 13px;border-bottom:1px solid var(--line-2);vertical-align:top}
.tbl th{background:var(--panel-2);font-size:13px;color:var(--muted);font-weight:750;white-space:nowrap}
.tbl tr:last-child td{border-bottom:none}
.tbl td:first-child{font-weight:650;white-space:nowrap}
.tbl-scroll{overflow-x:auto;-webkit-overflow-scrolling:touch;max-width:100%}

/* callouts */
.note{border:1px solid var(--line);border-left:4px solid var(--brand-2);background:var(--panel);border-radius:var(--radius-sm);padding:13px 15px;font-size:14px;color:var(--muted);margin-top:14px}
.note:first-child{margin-top:0}
.page-h p{margin-top:10px}
.note.ok{border-left-color:var(--ok)} .note.warn{border-left-color:var(--warn)} .note.bad{border-left-color:var(--bad)}
.note b{color:var(--ink)}
.chipst{display:inline-flex;align-items:center;gap:6px;padding:4px 10px;border-radius:999px;font-size:12.5px;font-weight:750;border:1px solid var(--line)}
.chipst::before{content:"";width:7px;height:7px;border-radius:50%;background:var(--muted)}
.chipst.ok{color:var(--ok);border-color:color-mix(in srgb,var(--ok) 35%,var(--line));background:color-mix(in srgb,var(--ok) 8%,transparent)}
.chipst.ok::before{background:var(--ok)}
.chipst.warn{color:var(--warn);border-color:color-mix(in srgb,var(--warn) 35%,var(--line));background:color-mix(in srgb,var(--warn) 9%,transparent)}
.chipst.warn::before{background:var(--warn)}
.chipst.bad{color:var(--bad);border-color:color-mix(in srgb,var(--bad) 35%,var(--line));background:color-mix(in srgb,var(--bad) 8%,transparent)}
.chipst.bad::before{background:var(--bad)}

/* ── workbench (test page) ───────────────────────────────────────────── */
.wb{display:grid;grid-template-columns:1fr 400px;gap:14px;padding:14px 0 26px;align-items:start}
.wb>*{min-width:0}
@media(max-width:1060px){.wb{grid-template-columns:1fr}}
.stage{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);overflow:hidden;box-shadow:var(--shadow);min-width:0}
/* intentionally NOT sticky: the old desktop sticky stage floated over the
   progress strip and charts below it while scrolling, hiding live status */
.stagebar{display:flex;align-items:center;gap:8px;padding:9px 12px;border-bottom:1px solid var(--line-2);flex-wrap:wrap;background:var(--panel)}
.stagebar .tag{font-size:12px;font-weight:750;color:var(--muted);border:1px solid var(--line);border-radius:7px;padding:3px 8px}
.canvasbox{position:relative;background:var(--stage-bg);aspect-ratio:16/10;min-height:0}
/* a min-height combined with aspect-ratio would make the box grow *wider* than
   its column on narrow screens, so switch to a taller ratio instead */
@media(max-width:600px){.canvasbox{aspect-ratio:4/3}}
@media(max-width:400px){.canvasbox{aspect-ratio:1/1}}
.canvasbox canvas{position:absolute;inset:0;width:100%;height:100%;display:block}
.hud{position:absolute;left:0;right:0;bottom:0;display:flex;flex-wrap:wrap;gap:6px;padding:10px;pointer-events:none}
.hud span{background:rgba(8,6,14,.62);color:#f4f1fb;border:1px solid rgba(255,255,255,.14);border-radius:8px;padding:4px 9px;font-size:12px;font-weight:700;
  font-variant-numeric:tabular-nums;backdrop-filter:blur(4px)}
.hud span b{color:#ffd9a0;font-weight:800}
.hud i{font-style:normal;opacity:.72}
/* .stagebar's action row used to carry half a definition and got the rest from
   an inline style in the tester; give it the same shape as .panel-h's row */
.stagebar .r{margin-left:auto;display:flex;gap:6px;align-items:center;flex-wrap:wrap;min-width:0}
.stagefoot{padding:10px 12px;border-top:1px solid var(--line-2);font-size:12.5px;color:var(--muted);display:flex;gap:12px;flex-wrap:wrap;align-items:center}
.progress{height:8px;border-radius:999px;background:var(--chip);overflow:hidden;flex:1;min-width:120px}
.progress i{display:block;height:100%;width:0;background:var(--grad-brand);transition:width .18s linear}
.chartbox{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);padding:12px;box-shadow:var(--shadow);margin-bottom:14px}
.chartbox canvas{width:100%;height:auto}

.panel{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow);margin-bottom:14px;overflow:hidden}
.panel-h{display:flex;align-items:center;gap:8px;padding:13px 16px;border-bottom:1px solid var(--line-2);font-weight:800;font-size:15px}
.panel-h .r{margin-left:auto;display:flex;gap:6px;align-items:center;flex-wrap:wrap;justify-content:flex-end}
.panel-b{padding:14px 16px}
.fld{margin-bottom:14px}
.fld:last-child{margin-bottom:0}
/* a label that names a <div role=group> is not valid markup — those in the
   tester now use aria-labelledby and need the same styling */
.fld>label,.fld>.lb{display:block;font-size:13.5px;font-weight:750;margin-bottom:6px}
/* .hint is used standalone on the report/reference/guide pages too, so it has
   to work outside .fld — otherwise each usage has to restate itself inline */
.hint,.fs-hint,.fld .hint{font-size:12.5px;color:var(--muted);margin-top:5px;line-height:1.45}
.seg{display:flex;flex-wrap:wrap;gap:4px;background:var(--chip);padding:4px;border-radius:11px;min-width:0}
.seg button{flex:1 1 auto;min-height:38px;padding:0 10px;border-radius:8px;font-weight:700;font-size:13.5px;color:var(--muted);white-space:nowrap}
.seg button.on{background:var(--panel);color:var(--brand-deep);box-shadow:var(--shadow-sm)}
.seg button[disabled]{opacity:.4;cursor:not-allowed}
.seg button:hover:not(.on){color:var(--ink);background:color-mix(in srgb,var(--panel) 55%,transparent)}
.rng{-webkit-appearance:none;appearance:none;width:100%;height:40px;background:transparent}
.rng::-webkit-slider-runnable-track{height:6px;border-radius:999px;background:var(--chip);border:1px solid var(--line)}
.rng::-webkit-slider-thumb{-webkit-appearance:none;width:22px;height:22px;border-radius:50%;background:var(--panel);border:2px solid var(--brand);margin-top:-9px;box-shadow:var(--shadow-sm)}
.rng::-moz-range-track{height:6px;border-radius:999px;background:var(--chip);border:1px solid var(--line)}
.rng::-moz-range-thumb{width:20px;height:20px;border-radius:50%;background:var(--panel);border:2px solid var(--brand)}
.check{display:flex;align-items:center;gap:9px;min-height:40px;font-size:14px;font-weight:650}
.check input{width:19px;height:19px;accent-color:var(--brand)}
.kv{display:grid;grid-template-columns:auto 1fr;gap:5px 12px;font-size:13.5px}
.kv dt{color:var(--muted);font-weight:650;white-space:nowrap}
.kv dd{margin:0;font-weight:650;font-variant-numeric:tabular-nums;overflow-wrap:anywhere}
.metrics{display:grid;gap:8px;grid-template-columns:repeat(auto-fit,minmax(min(96px,100%),1fr))}
.metric{background:var(--panel-2);border:1px solid var(--line-2);border-radius:var(--radius-sm);padding:10px 11px}
.metric b{display:block;font-size:19px;font-weight:900;font-variant-numeric:tabular-nums;letter-spacing:-.3px}
.metric span{font-size:11.5px;color:var(--muted);font-weight:700;letter-spacing:.02em}
.empty{text-align:center;color:var(--muted);font-size:14px;padding:26px 12px}

/* ── report ──────────────────────────────────────────────────────────── */
.score-hero{display:grid;grid-template-columns:auto 1fr;gap:22px;align-items:center;background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);margin-bottom:14px;
  padding:22px;box-shadow:var(--shadow);position:relative;overflow:hidden}
.score-hero::before{content:"";position:absolute;inset:0 0 auto;height:4px;background:var(--grad-brand)}
.recent{display:grid;gap:10px;grid-template-columns:repeat(auto-fill,minmax(260px,1fr))}
.rcard{display:flex;gap:10px;align-items:center;background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:10px;box-shadow:var(--shadow-sm)}
.rcard img,.rcard .noimg{width:78px;height:49px;border-radius:8px;object-fit:cover;flex:0 0 auto;border:1px solid var(--line);background:var(--chip)}
.rcard .noimg{display:grid;place-items:center;font-size:20px}
.rcard .t{min-width:0}
.rcard .t b{font-size:17px;font-weight:900}
.rcard .t span{display:block;font-size:12px;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
a.rcard:hover{border-color:color-mix(in srgb,var(--brand) 45%,var(--line));box-shadow:0 0 0 3px color-mix(in srgb,var(--brand) 12%,transparent),var(--shadow-sm);transform:translateY(-1px)}
a.rcard{transition:border-color .15s ease,box-shadow .15s ease,transform .15s ease}
@media(max-width:640px){.score-hero{grid-template-columns:1fr;gap:12px}}
.score-num{font-size:clamp(46px,9vw,78px);font-weight:900;line-height:1;letter-spacing:-2px;font-variant-numeric:tabular-nums;
  background:var(--grad-brand);-webkit-background-clip:text;background-clip:text;color:transparent}
.score-num small{font-size:.32em;font-weight:800;letter-spacing:0;-webkit-text-fill-color:var(--muted);color:var(--muted)}
.tier{display:inline-flex;align-items:center;gap:8px;padding:7px 14px;border-radius:999px;font-weight:850;font-size:14px;
  background:color-mix(in srgb,var(--brand) 12%,transparent);color:var(--brand-deep);border:1px solid color-mix(in srgb,var(--brand) 32%,transparent)}
.bars{display:grid;gap:13px}
.bar .lab{display:flex;justify-content:space-between;font-size:13.5px;font-weight:700;margin-bottom:5px}
.bar .lab span{color:var(--muted);font-variant-numeric:tabular-nums}
.bar .track{height:11px;border-radius:999px;background:var(--chip);overflow:hidden;border:1px solid var(--line-2)}
.bar .fill{height:100%;border-radius:999px;background:var(--grad-brand)}
.bar .fill.b2{background:linear-gradient(90deg,var(--brand-2),var(--brand))}
.bar .fill.b3{background:linear-gradient(90deg,var(--brand-3),var(--brand-2))}
.bar .fill.b4{background:linear-gradient(90deg,var(--brand-4),var(--brand))}
.shot{border:1px solid var(--line);border-radius:var(--radius-sm);overflow:hidden;background:var(--stage-bg)}
.shot img,.shot canvas{width:100%;height:auto}
.grid-2{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(min(340px,100%),1fr));margin-bottom:14px}
@media(max-width:820px){.grid-2{grid-template-columns:1fr}}

/* ── footer ──────────────────────────────────────────────────────────── */
footer.ft{margin-top:26px;border-top:1px solid var(--line);background:var(--panel);padding:32px 0 26px;font-size:14px}
.ft-grid{display:grid;gap:22px;grid-template-columns:1.4fr repeat(3,1fr)}
@media(max-width:820px){.ft-grid{grid-template-columns:1fr 1fr}}
@media(max-width:520px){.ft-grid{grid-template-columns:1fr}}
.ft h4{font-size:13px;text-transform:uppercase;letter-spacing:.07em;color:var(--muted);margin-bottom:10px}
.ft .col{display:grid;gap:7px;justify-items:start}
.ft .col a{color:var(--muted);font-weight:650}
.ft .col a:hover{color:var(--brand-deep)}
.ft .about{color:var(--muted);max-width:34ch}
.ft-bottom{margin-top:24px;padding-top:16px;border-top:1px solid var(--line-2);color:var(--muted);font-size:13px;display:flex;gap:14px;flex-wrap:wrap;align-items:center}
.ft-bottom a{text-decoration:underline;text-underline-offset:2px}

/* reveal on scroll (progressive; disabled for reduced motion) */
.reveal{opacity:0;transform:translateY(14px);transition:opacity .5s,transform .5s}
.reveal.in{opacity:1;transform:none}
@media(prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  .reveal{opacity:1;transform:none;transition:none}
  /* duration alone is not enough: an `infinite` animation at .001ms still
     re-runs every frame and keeps the compositor busy. Cap the iterations too,
     then exempt the one spinner whose whole job is to look alive. */
  *{animation-duration:.001ms!important;animation-iteration-count:1!important;transition-duration:.001ms!important}
  .overlay .spin{animation:sp 1.2s linear infinite!important}
}

/* ── tier band bar + run note (report) ───────────────────────────────── */
.bandbar-wrap{margin-top:14px;max-width:520px}
.bandbar{position:relative;display:flex;height:10px;border-radius:6px;box-shadow:inset 0 0 0 1px var(--line-2)}
.bandbar i{display:block;height:100%}
.bandbar i:first-child{border-radius:6px 0 0 6px}
.bandbar i:last-child{border-radius:0 6px 6px 0}
.bandbar .bb0{background:color-mix(in srgb,var(--muted) 45%,transparent)}
.bandbar .bb1{background:color-mix(in srgb,var(--brand-3) 60%,transparent)}
.bandbar .bb2{background:color-mix(in srgb,var(--brand-3) 90%,transparent)}
.bandbar .bb3{background:color-mix(in srgb,var(--brand) 55%,transparent)}
.bandbar .bb4{background:color-mix(in srgb,var(--brand) 85%,transparent)}
.bandbar .bb5{background:color-mix(in srgb,var(--brand-2) 85%,transparent)}
.bandmark{position:absolute;top:-4px;width:3px;height:18px;border-radius:2px;background:var(--ink);box-shadow:0 0 0 2px color-mix(in srgb,var(--panel) 70%,transparent)}
.bandlegend{display:flex;justify-content:space-between;font-size:11px;color:var(--muted);margin-top:5px;gap:6px}
.note-edit{display:inline-flex;gap:6px;align-items:center}
.note-edit input{min-width:170px}
.rnote{font-weight:650;color:var(--brand-deep)}
#cmpRadar{display:block;width:min(360px,100%);height:auto;margin:12px auto 0}
.cmp-legend{display:flex;gap:16px;justify-content:center;font-size:12.5px;color:var(--muted)}
.cmp-legend i{display:inline-block;width:10px;height:10px;border-radius:3px;margin-right:5px;vertical-align:-1px}
.cmp-shots{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(240px,100%),1fr));gap:12px;margin-top:12px}
.cmp-shots figure{margin:0;min-width:0}
.cmp-shots figure[hidden]{display:none}
.cmp-shots img{display:block;width:100%;height:auto;border:1px solid var(--line);border-radius:var(--radius-sm)}
.cmp-shots figcaption{font-size:12.5px;color:var(--muted);margin-top:5px;text-align:center}
@media (max-width:560px){.cmp-shots{grid-template-columns:1fr}}
img[data-zoom]{cursor:zoom-in}
.lightbox{position:fixed;inset:0;z-index:90;background:rgba(10,8,14,.88);display:flex;align-items:center;justify-content:center;cursor:zoom-out;padding:18px}
.lightbox[hidden]{display:none}
.lightbox img{max-width:96vw;max-height:92vh;max-height:92dvh;border-radius:10px;box-shadow:0 12px 48px rgba(0,0,0,.6);background:#000}
.totop{position:fixed;right:calc(16px + env(safe-area-inset-right));bottom:calc(16px + env(safe-area-inset-bottom));z-index:60;width:42px;height:42px;border-radius:50%;border:1px solid var(--line);background:var(--panel);color:var(--ink);font-size:19px;font-weight:700;cursor:pointer;box-shadow:0 6px 18px rgba(0,0,0,.18);line-height:1}
.totop[hidden]{display:none}
/* viewport-fit=cover was declared but nothing consumed the insets: on notched
   phones the sticky bar slid under the status area and the footer line under
   the home indicator. env() degrades to 0 where unsupported. */
.topbar{padding-top:calc(6px + env(safe-area-inset-top))}
.wrap{padding-left:max(18px,env(safe-area-inset-left));padding-right:max(18px,env(safe-area-inset-right))}
footer.ft{padding-bottom:calc(26px + env(safe-area-inset-bottom))}
.totop:hover{border-color:color-mix(in srgb,var(--brand) 45%,var(--line));color:var(--brand)}
.toast-act{pointer-events:auto;margin-left:10px;padding:3px 10px;border-radius:8px;border:1px solid rgba(255,255,255,.35);background:rgba(255,255,255,.12);color:#fff;font:inherit;font-weight:700;font-size:12.5px;cursor:pointer}
.toast-act:hover{background:rgba(255,255,255,.24)}
.chtip{position:fixed;z-index:70;background:#1c1b22;color:#f6f4f7;border:1px solid rgba(255,255,255,.16);border-radius:8px;padding:4px 9px;font-size:12px;font-weight:650;pointer-events:none;white-space:nowrap;max-width:220px}
@media print{.chtip{display:none!important}}
@media print{.totop,.lightbox{display:none!important}}

/* ── toasts (shared by every page) ───────────────────────────────────── */
.toasts{position:fixed;left:50%;transform:translateX(-50%);bottom:22px;z-index:80;display:grid;gap:8px;justify-items:center;pointer-events:none}
.toast{background:#1c1b22;color:#f6f4f7;border:1px solid rgba(255,255,255,.14);border-radius:11px;padding:9px 15px;font-size:13.5px;font-weight:650;
  box-shadow:0 8px 28px rgba(0,0,0,.35);opacity:1;transform:none;max-width:min(88vw,520px);animation:tin .24s ease-out}
@keyframes tin{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
.toast.out{opacity:0;transform:translateY(8px);transition:opacity .3s,transform .3s}
/* derive from the status tokens instead of repeating their hex values, and keep
   the variants winning over the dark default below (same specificity → order
   decides, so the dark override must be narrowed to the plain flavour) */
.toast.warn{background:color-mix(in srgb,var(--warn) 26%,#1c1b22);border-color:var(--warn)}
.toast.bad{background:color-mix(in srgb,var(--bad) 26%,#1c1b22);border-color:var(--bad)}
.toast.ok{background:color-mix(in srgb,var(--ok) 30%,#1c1b22);border-color:var(--ok)}
[data-theme="dark"] .toast:not(.ok):not(.warn):not(.bad){background:#221e2c}

/* ── history rows ────────────────────────────────────────────────────── */
.hrow{display:flex;align-items:center;gap:10px;padding:8px 0;border-bottom:1px dashed var(--line-2)}
.hrow:last-child{border-bottom:none}
.hmain{display:flex;align-items:center;gap:10px;flex:1;min-width:0}
.hmain img,.hmain .noimg{width:72px;height:45px;border-radius:8px;object-fit:cover;flex:0 0 auto;border:1px solid var(--line);background:var(--chip)}
.hmain .noimg{display:grid;place-items:center;font-size:20px}
.htxt{min-width:0;display:grid;gap:1px}
.htxt b{font-size:16px;font-weight:900;font-variant-numeric:tabular-nums}
.htxt i{font-style:normal;font-size:12.5px;color:var(--brand-deep);font-weight:750}
.htxt span{font-size:12px;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

/* ── service-worker update banner ───────────────────────────────────── */
.updbar{display:flex;gap:10px;align-items:center;justify-content:space-between;flex-wrap:wrap;
  margin:12px 0 0;padding:11px 14px;border-radius:12px;font-size:14px;font-weight:650;
  background:color-mix(in srgb,var(--brand-4) 14%,var(--panel));border:1px solid color-mix(in srgb,var(--brand-4) 45%,var(--line))}
.updbar button{min-height:36px;padding:0 14px;border-radius:9px;border:1px solid var(--line);background:var(--panel);font-weight:750}
.updbar button:hover{border-color:var(--brand)}

/* print */
@media print{
  /* flip the design tokens themselves, not just body text: a dark-theme user
     would otherwise print dark panels under black text */
  :root,[data-theme="dark"]{
    --bg:#ffffff; --bg-2:#ffffff; --panel:#ffffff; --panel-2:#fafafa;
    --ink:#111111; --muted:#3d3d3d; --line:#c9c9c9; --line-2:#dedede; --chip:#f1f1f1;
    --shadow:none; --shadow-sm:none; --brand-deep:#111; --stage-bg:#f4f4f4; color-scheme:light;
    /* status + brand colours were tuned for dark panels (~1.7:1 on paper); ink
       versions keep every label readable when it lands on white */
    --ok:#14624a; --warn:#7a4e00; --bad:#8f211d;
    --brand:#b32c46; --brand-2:#5b33a0; --brand-3:#1f7a68; --brand-4:#8a5f12;
    --brand-solid:#b32c46; --on-brand:#ffffff}
  body{background:#fff;color:#000;font-size:12px}
  .topbar,footer.ft,.tbtns,.no-print,.wb .panel{display:none!important}
  /* transient layers that would sit on top of the printed frame, plus every
     form control: buttons and selects mean nothing on paper */
  .overlay,.hud,.updbar,.toasts,.seg,.skip,.stagebar .r,#btnFull,.ns,
  .big-actions,button,select,input,.btn,.picker{display:none!important}
  .panel,.card,.chartbox,.stage{box-shadow:none;border-color:#ccc;break-inside:avoid}
  .wb{grid-template-columns:1fr}
  /* paper has no scrollbar: an overflow-x wrapper would silently cut the last
     column off the guide's engine/preset tables and the reference table. The
     clipping ancestors have to let go too, or `visible` just feeds content into
     a parent that crops it with no scrollbar to hint at the loss. */
  .panel,.card,.chartbox,.stage,.guide article,.grid-2{overflow:visible}
  .tbl-scroll{overflow:visible}
  .tbl-scroll table,table.tbl{width:100%;font-size:11px;table-layout:fixed}
  .tbl-scroll td,.tbl-scroll th{white-space:normal;overflow-wrap:anywhere}
  /* gradient-clipped text needs a real fill: print skips background painting by
     default, so the score and accent words would otherwise come out blank */
  .score-num,.hero h1 .g,.home-hero h1 .g,.tier{
    -webkit-text-fill-color:#000;color:#000;background:none!important;box-shadow:none}
  .tier{border:1px solid #999}
  .bar .fill,.bar .track{border:1px solid #bbb}
  a[href^="http"]::after{content:""}
}
