/* © 2026 William C. Chesher. All Rights Reserved.
   admin.css - the sfhsbta admin's one stylesheet: the BTA design system's tokens, the suite shell, the components.

   Values are the BTA Design System's (sfhsbta/content/site/_ds/.../tokens/*.css), restated here because the
   admin image does not ship the site: one yellow, warm neutrals, Montserrat for the voice of the thing,
   Barlow to read, JetBrains Mono for IDs, PINs and numbers. Flat blocks and hard rules, lift used sparingly. */

@font-face{font-family:Montserrat;src:url(/admin/asset/montserrat-var-n-latin.woff2) format("woff2");
  font-weight:100 900;font-style:normal;font-display:swap}
@font-face{font-family:Barlow;src:url(/admin/asset/barlow-400-n-latin.woff2) format("woff2");
  font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:Barlow;src:url(/admin/asset/barlow-600-n-latin.woff2) format("woff2");
  font-weight:600;font-style:normal;font-display:swap}
@font-face{font-family:"JetBrains Mono";src:url(/admin/asset/jetbrains-mono-var-n-latin.woff2) format("woff2");
  font-weight:100 800;font-style:normal;font-display:swap}

/* NO VISIBLE FONT SWAP. The fix sfhsbta.com landed after getting it wrong twice (its fonts.css carries
   the history): swap alone re-lays the page out when the face arrives, optional alone draws a whole page
   view in the fallback when a face misses its window. So: swap, every face the first screen draws is
   preloaded in the page head (shell.py), and the fallback is these metric-matched faces, which put a line
   of Arial in the SAME box the webfont will occupy, so the swap moves nothing. size-adjust is matched on
   advance width (x-height matching still rewraps); the ascent/descent overrides are divided by it. The
   regular faces are the site's own browser-calibrated values (the files are byte-identical); the bold
   faces are matched against Arial Bold, because the admin's headings and sidebar sit at 600-800 and a
   regular-calibrated face synthesised to bold runs wide. Liberation Sans is Arial's metric clone on
   Linux: naming only Arial binds to nothing there and the adjustment silently does nothing. No mono
   fallback on purpose: ui-monospace already measures within half a percent of JetBrains Mono. */
@font-face{font-family:"Montserrat Fallback";src:local("Arial"),local("ArialMT"),local("Liberation Sans"),local("LiberationSans");
  font-weight:100 500;size-adjust:110.40%;ascent-override:87.68%;descent-override:22.74%;line-gap-override:0%}
@font-face{font-family:"Montserrat Fallback";src:local("Arial Bold"),local("Arial-BoldMT"),local("Liberation Sans Bold"),local("LiberationSans-Bold");
  font-weight:600 900;size-adjust:110.28%;ascent-override:87.78%;descent-override:22.76%;line-gap-override:0%}
@font-face{font-family:"Barlow Fallback";src:local("Arial"),local("ArialMT"),local("Liberation Sans"),local("LiberationSans");
  font-weight:100 500;size-adjust:94.20%;ascent-override:106.15%;descent-override:21.23%;line-gap-override:0%}
@font-face{font-family:"Barlow Fallback";src:local("Arial Bold"),local("Arial-BoldMT"),local("Liberation Sans Bold"),local("LiberationSans-Bold");
  font-weight:600 900;size-adjust:91.41%;ascent-override:109.40%;descent-override:21.88%;line-gap-override:0%}

:root{
  color-scheme:light;
  --yellow:#FFDE59;--yellow-tint:#FFF9E6;--yellow-tint-2:#FFF0B1;--yellow-shade:#E0BE3C;--yellow-text:#A8801A;
  --ink:#1B1B1B;--ink2:#2A2A2A;--ink3:#3D3D3D;--paper:#FEFEFE;
  --g50:#F7F7F5;--g100:#EEEEEB;--g200:#DEDEDA;--g300:#C2C2BC;--g400:#91918B;--g500:#6C6C67;--g600:#4A4A46;
  --good:#2E7D32;--good-bg:#E8F3E9;--warn:#9A5C00;--warn-bg:#FDF2DC;--bad:#C62828;--bad-bg:#F9E7E7;
  --info:#1565C0;--info-bg:#E6EEF8;
  /* roles the dark theme moves separately from the ramp: the chrome (the sidebar, the Status hero, ink buttons) stays
     the darkest thing on the page in both themes; text on the yellow is always ink */
  --chrome:#1B1B1B;--chrome-3:#3D3D3D;--on-chrome:#FEFEFE;--on-chrome-soft:#E9E9E4;--on-yellow:#1B1B1B;
  --good-ink:#1C5B34;--bad-ink:#8A1B1B;--warn-mid:#E08A00;
  --note-bg:#FFF8DC;--note-line:#EFDFA0;--err-bg:#FDECEC;--err-line:#E9C3C3;--yellow-line:#F1E4B5;
  --bad-line:#EBC9C9;--warn-line:#F2DDB4;--info-line:#C7D7EE;
  --row-hover:#FCFCFA;--draft-bg:#F1EFE7;--media-ground:#EDEBE5;
  /* the names the existing pages already use */
  --quiet:var(--g500);--line:var(--g200);--sub:var(--g50);--accent:var(--yellow);
  --r:14px;--r-sm:8px;--r-md:10px;
  --shadow-1:0 1px 2px rgba(27,27,27,.06);--shadow-2:0 2px 8px rgba(27,27,27,.08);
  --shadow-hard:4px 4px 0 var(--ink);
  --focus:0 0 0 3px var(--yellow),0 0 0 5px var(--ink);
  --font-core:Montserrat,"Montserrat Fallback","Helvetica Neue",Helvetica,system-ui,sans-serif;
  --font-text:Barlow,"Barlow Fallback","Helvetica Neue",Helvetica,system-ui,sans-serif;
  --font-mono:"JetBrains Mono",ui-monospace,"SF Mono",Menlo,monospace;
  --side:252px;
  --control:44px;--control-sm:38px;
  --fast:140ms;--ease:cubic-bezier(.2,0,.2,1);
}
@media (prefers-reduced-motion:reduce){:root{--fast:0ms}}

/* THE ADMIN IS DARK (wchesher, 2026-10-30: "its time we move sfhsbta.com to dark interface", then "I meant /admin").
   One committed dark theme, on every page shell.py marks data-theme="dark" (every signed-in page and the sign-in);
   the public pages that share this file (/consent for families, /pin for students) stay light. The BTA design
   system's own inverted scope ([data-theme="ink"], tokens/colors.css) is where these start: ink ground, white and
   grey-200 text, the one yellow as the accent; the ramp below walks the same warm neutrals the other way. Screen
   only: a printed slip (.slip) stays black on white. */
@media screen{
  [data-theme="dark"]{
    color-scheme:dark;
    --ink:#EDEDE8;--ink2:#D9D9D3;--ink3:#B8B8B1;--paper:#1E1E1C;
    --g50:#131312;--g100:#272724;--g200:#33332F;--g300:#4A4A45;--g400:#7C7C75;--g500:#A6A69E;--g600:#C9C9C2;
    --yellow-tint:#2B2716;--yellow-tint-2:#463C14;--yellow-text:#FFDE59;--yellow-line:#4F4418;
    --good:#5CC46B;--good-bg:#17301B;--good-ink:#A3E5AC;
    --warn:#F2B451;--warn-bg:#33270F;--warn-mid:#F0A030;--warn-line:#5A4318;
    --bad:#FF6B6B;--bad-bg:#3A1818;--bad-ink:#FFB8B8;--bad-line:#682A2A;
    --info:#7DB1F2;--info-bg:#152536;--info-line:#25456A;
    --chrome:#0B0B0A;--chrome-3:#2B2B28;
    --note-bg:#2B2716;--note-line:#4F4418;--err-bg:#3A1818;--err-line:#682A2A;
    --row-hover:#242422;--draft-bg:#272724;--media-ground:#272724;
    --shadow-1:0 1px 2px rgba(0,0,0,.4);--shadow-2:0 4px 14px rgba(0,0,0,.45);
    --shadow-hard:4px 4px 0 var(--yellow);
    --focus:0 0 0 3px var(--yellow),0 0 0 5px var(--g50);
  }
  [data-theme="dark"] .side{border-right:1px solid var(--chrome-3)}
  [data-theme="dark"] .st-hero{border-top:1px solid var(--chrome-3);border-right:1px solid var(--chrome-3);
    border-bottom:1px solid var(--chrome-3)}
  [data-theme="dark"] img,[data-theme="dark"] video{color-scheme:light}
}

*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{margin:0;background:var(--g50);color:var(--ink);font:16px/1.55 var(--font-text)}
a{color:var(--ink);text-underline-offset:3px}
a:hover{color:var(--yellow-text)}
:focus-visible{outline:none;box-shadow:var(--focus);border-radius:6px}
.mono,code,kbd{font-family:var(--font-mono);font-size:.92em}
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

/* ---- the suite shell -------------------------------------------------------------------------------- */
.band{height:8px;background:var(--yellow)}
.suite{display:grid;grid-template-columns:var(--side) minmax(0,1fr);min-height:100vh;
  background:linear-gradient(to right,var(--chrome) var(--side),transparent var(--side))}
.side{background:var(--chrome);color:var(--on-chrome);position:sticky;top:0;height:100vh;overflow-y:auto;
  display:flex;flex-direction:column;border-top:8px solid var(--yellow)}
.side .brand{display:flex;align-items:center;gap:12px;padding:22px 20px 18px;text-decoration:none;color:var(--on-chrome)}
.side .brand img{width:40px;height:40px;border-radius:50%;display:block;background:var(--on-chrome)}
.side .brand b{display:block;color:var(--on-chrome);font:800 13px/1.1 var(--font-core);letter-spacing:.04em;text-transform:uppercase}
.side .brand span{display:block;font:600 10px/1.4 var(--font-core);letter-spacing:.28em;text-transform:uppercase;
  color:var(--yellow);margin-top:3px}
.side nav{padding:4px 12px 18px;flex:1}
.side .group{font:800 10px/1 var(--font-core);letter-spacing:.2em;text-transform:uppercase;color:var(--g400);
  margin:20px 10px 8px}
.side nav a{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:9px 10px;margin:1px 0;
  border-radius:var(--r-sm);color:var(--on-chrome-soft);text-decoration:none;font:600 14px/1.25 var(--font-core);
  transition:background var(--fast) var(--ease),color var(--fast) var(--ease)}
.side nav a:hover{background:var(--chrome-3);color:var(--on-chrome)}
.side nav a.on{background:var(--yellow);color:var(--on-yellow)}
.side nav a .count{font:700 11px/1 var(--font-mono);padding:3px 7px;border-radius:999px;background:var(--chrome-3);
  color:var(--on-chrome)}
.side nav a.on .count{background:var(--on-yellow);color:var(--yellow)}
.side nav a .count.alert{background:var(--bad);color:var(--on-chrome)}
.side nav a.out::after{content:"\2197";font-size:12px;color:var(--g400)}
.side nav .planned{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:9px 10px;
  margin:1px 0;color:var(--g400);font:600 14px/1.25 var(--font-core);cursor:default}
.side nav .planned .soon{font:700 9px/1 var(--font-mono);letter-spacing:.08em;text-transform:uppercase;
  padding:3px 6px;border:1px solid var(--chrome-3);border-radius:999px}
.side .foot{padding:14px 20px 20px;border-top:1px solid var(--chrome-3);display:flex;align-items:center;
  justify-content:space-between;gap:10px;font-size:12px;color:var(--g400)}
.side .foot a.who{color:var(--on-chrome);text-decoration:none;font-weight:600}
.side .foot a.who:hover{color:var(--yellow)}
.side .foot button{background:transparent;color:var(--on-chrome);border-color:var(--chrome-3)}
.side .foot button:hover{border-color:var(--yellow);color:var(--yellow)}

.main{min-width:0;display:flex;flex-direction:column}
.top{background:var(--paper);border-bottom:1px solid var(--line)}
.top .in,.content{max-width:1180px;margin:0 auto;padding-left:36px;padding-right:36px}
.top .in{padding-top:26px;padding-bottom:22px;display:flex;align-items:flex-end;justify-content:space-between;
  gap:18px;flex-wrap:wrap}
.content{padding-top:28px;padding-bottom:90px;width:100%}
.eyebrow{margin:0 0 8px;font:800 11px/1 var(--font-core);letter-spacing:.2em;text-transform:uppercase;color:var(--g500)}
.eyebrow::before{content:"";display:inline-block;width:18px;height:3px;background:var(--yellow);
  vertical-align:middle;margin:-2px 8px 0 0}
h1{font:800 32px/1.05 var(--font-core);letter-spacing:-.01em;margin:0;text-transform:uppercase}
.top .lede{margin:10px 0 0;color:var(--g600);max-width:70ch;font-size:15px}
.top .actions{display:flex;gap:10px;flex-wrap:wrap}
h2{font:800 13px/1.2 var(--font-core);letter-spacing:.14em;text-transform:uppercase;color:var(--g600);margin:0 0 12px}
h3{font:700 17px/1.3 var(--font-core);margin:0 0 6px}
.section{font:800 12px/1.2 var(--font-core);letter-spacing:.16em;text-transform:uppercase;color:var(--g500);
  margin:34px 0 14px;display:flex;align-items:center;gap:10px}
.section::after{content:"";flex:1;height:1px;background:var(--line)}

/* the public pages (sign-in, the permission form): no sidebar, one column */
.solo .mast{background:var(--paper);border-bottom:1px solid var(--line)}
.solo .mast .in{max-width:880px;margin:0 auto;padding:16px 22px;display:flex;align-items:center;gap:14px}
.solo .mast img{width:38px;height:38px;border-radius:50%;display:block}
.solo .word{display:flex;flex-direction:column;line-height:1.05}
.solo .word b{font:800 15px/1.1 var(--font-core);letter-spacing:.01em;text-transform:uppercase}
.solo .word span{font:600 11px/1.4 var(--font-core);letter-spacing:.18em;text-transform:uppercase;color:var(--g500)}
.solo .wrap{max-width:880px;margin:0 auto;padding:34px 22px 90px}
.solo h1{margin-bottom:22px}

/* ---- components ------------------------------------------------------------------------------------- */
.panel{background:var(--paper);border:1px solid var(--line);border-radius:var(--r);padding:20px 22px;margin:0 0 18px}
.panel.flush{padding:0;overflow:hidden}
.panel > h2:first-child,.panel > h3:first-child{margin-top:0}
/* a panel that folds a reference away until the operator wants it (Students: "How it works") */
details.explainer > summary{cursor:pointer;list-style:none}
details.explainer > summary::-webkit-details-marker{display:none}
details.explainer > summary > h2{display:inline-block;margin:0}
details.explainer > summary::after{content:" \25B8";color:var(--g600)}
details.explainer[open] > summary::after{content:" \25BE"}
.panel .head{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;margin:0 0 12px}
.cols{display:grid;grid-template-columns:repeat(auto-fit,minmax(320px,1fr));gap:18px;align-items:start}
.cols.two{grid-template-columns:minmax(0,2fr) minmax(280px,1fr)}
.muted{color:var(--g500)}
.small{font-size:13px}
.empty{color:var(--g500);font-size:14px}
.empty-state{text-align:center;padding:38px 20px;color:var(--g500)}
.empty-state b{display:block;font:800 15px/1.3 var(--font-core);color:var(--ink);margin-bottom:6px}

/* stat tiles */
.tiles{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:16px;margin:0 0 26px}
.tile{background:var(--paper);border:1px solid var(--line);border-radius:var(--r);padding:18px 18px 16px;
  text-decoration:none;color:var(--ink);display:flex;flex-direction:column;gap:6px;position:relative;
  transition:transform var(--fast) var(--ease),box-shadow var(--fast) var(--ease),border-color var(--fast) var(--ease)}
a.tile:hover{transform:translateY(-1px);box-shadow:var(--shadow-hard);border-color:var(--ink);color:var(--ink)}
.tile .k{font:800 11px/1 var(--font-core);letter-spacing:.18em;text-transform:uppercase;color:var(--g500)}
.tile .v{font:800 34px/1 var(--font-core);letter-spacing:-.02em}
.tile .v small{font:600 14px/1 var(--font-core);color:var(--g500);letter-spacing:0;margin-left:4px}
.tile .d{font-size:13px;color:var(--g600)}
.tile.good{border-left:4px solid var(--good)}
.tile.warn{border-left:4px solid var(--warn-mid)}
.tile.bad{border-left:4px solid var(--bad)}

/* servers (machines.py): one card per machine, a meter per disk, memory and graphics card */
.machines{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:14px;margin:0 0 18px}
.machine{background:var(--sub);border:1px solid var(--line);border-radius:var(--r);padding:14px 16px;min-width:0}
.machine.good{border-left:4px solid var(--good)}
.machine.warn{border-left:4px solid var(--warn-mid)}
.machine.bad{border-left:4px solid var(--bad)}
.machine-head{margin:0 0 10px;line-height:1.6}
.machine dl.kv{font-size:13px;gap:6px 14px}
.machine dd{overflow-wrap:anywhere}
.meter{display:inline-block;width:64px;height:7px;border-radius:4px;background:var(--g200);vertical-align:middle;
  overflow:hidden;margin-right:6px}
.meter>span{display:block;height:100%;background:var(--good)}
.meter.warn>span{background:var(--warn-mid)}
.meter.bad>span{background:var(--bad)}

/* attention list */
.attention{list-style:none;margin:0;padding:0}
.attention li{display:flex;gap:12px;align-items:flex-start;padding:12px 0;border-top:1px solid var(--g100)}
.attention li:first-child{border-top:0}
.attention .dot{flex:none;width:10px;height:10px;border-radius:50%;margin-top:7px;background:var(--g300)}
.attention .warn .dot{background:var(--warn-mid)}.attention .bad .dot{background:var(--bad)}.attention .good .dot{background:var(--good)}
.attention a{font-weight:600}

/* tables */
.table-wrap{overflow-x:auto}
/* a flush panel clips its corners; a table inside one still scrolls sideways (it was clipped on a phone) */
.panel.flush.table-wrap{overflow-x:auto}
table.data{width:100%;border-collapse:collapse;font-size:14px}
table.data th{font:800 10.5px/1.2 var(--font-core);letter-spacing:.14em;text-transform:uppercase;color:var(--g500);
  text-align:left;padding:11px 14px;border-bottom:1px solid var(--line);background:var(--g50);white-space:nowrap}
table.data td{padding:11px 14px;border-bottom:1px solid var(--g100);vertical-align:middle}
table.data tr:last-child td{border-bottom:0}
table.data tbody tr:hover td{background:var(--row-hover)}
table.data td.num,table.data th.num{text-align:right;font-family:var(--font-mono)}
table.data .pin{font:700 15px/1 var(--font-mono);letter-spacing:.12em}
table.data .id{font-family:var(--font-mono);font-size:13px}
table.data .row-actions{display:flex;gap:6px;justify-content:flex-end;flex-wrap:wrap}
tr[hidden]{display:none}

/* key/value */
dl.kv{display:grid;grid-template-columns:max-content 1fr;gap:8px 18px;margin:0;font-size:14px}
dl.kv dt{color:var(--g500);font:700 11px/1.9 var(--font-core);letter-spacing:.12em;text-transform:uppercase}
dl.kv dd{margin:0}
dl.kv.stack{grid-template-columns:1fr;gap:2px}
dl.kv.stack dd{margin:0 0 12px}

/* buttons */
button,.btn{font:800 12px/1 var(--font-core);letter-spacing:.07em;text-transform:uppercase;padding:10px 16px;
  border:1px solid var(--line);border-radius:999px;background:var(--paper);cursor:pointer;color:var(--ink);
  text-decoration:none;display:inline-flex;align-items:center;gap:7px;
  transition:border-color var(--fast) var(--ease),background var(--fast) var(--ease),transform var(--fast) var(--ease)}
button:hover,.btn:hover{border-color:var(--ink);color:var(--ink)}
button:active,.btn:active{transform:scale(.97)}
button.primary,.btn.primary{background:var(--yellow);border-color:var(--yellow-shade);color:var(--on-yellow)}
button.primary:hover,.btn.primary:hover{border-color:var(--ink)}
button.ink,.btn.ink{background:var(--chrome);color:var(--on-chrome);border-color:var(--chrome-3)}
button.ink:hover,.btn.ink:hover{color:var(--yellow)}
button.danger,.btn.danger{color:var(--bad-ink);border-color:var(--bad-line)}
button.danger:hover,.btn.danger:hover{background:var(--bad-bg);border-color:var(--bad)}
button.small,.btn.small{padding:7px 11px;font-size:11px}
/* Products by period: one switch a cell, so the table fits a half-width column without scrolling */
table.data.switches{table-layout:fixed}
table.data.switches th,table.data.switches td{padding:9px 6px}
table.data.switches th[scope=row]{font:700 13px/1.25 var(--font-core);letter-spacing:0;text-transform:none;color:var(--ink)}
table.data.switches th[scope=row] .sub{display:block;font-weight:400;margin-top:2px;white-space:nowrap}
/* the Who column gets the room its "35 students" needs; the switches share the rest, centred under their heads */
table.data.switches col.who{width:31%}
table.data.switches td,table.data.switches thead th:not(:first-child){text-align:center}
table.data.switches td .sub{display:block;margin-top:3px;white-space:nowrap;min-height:1.4em}
button.switch{display:inline-flex;align-items:center;gap:6px;padding:4px 9px 4px 4px;border-radius:999px;
  font:800 10.5px/1 var(--font-core);letter-spacing:.08em;text-transform:uppercase;white-space:nowrap;
  background:var(--bad-bg);color:var(--bad-ink);border:0;box-shadow:none}
button.switch .knob{width:14px;height:14px;border-radius:50%;background:currentColor;flex:none}
button.switch.on{background:var(--good-bg);color:var(--good-ink);flex-direction:row-reverse;padding:4px 4px 4px 9px}
button.switch.some{background:var(--warn-bg);color:var(--warn);letter-spacing:.02em}
button.link{border:0;padding:0;background:none;text-transform:none;letter-spacing:0;font:600 14px/1.4 var(--font-text);
  text-decoration:underline;text-underline-offset:3px}
button[disabled]{opacity:.45;cursor:not-allowed}
form.inline{display:inline}
/* a lone row action (Remove) at the same height as the combos beside it */
button.control,.btn.control{height:var(--control-sm);padding:0 14px;font-size:11px}
table.data td.end{text-align:right;white-space:nowrap}
table.data td.who{min-width:150px;max-width:220px}
table.data td.who .by{display:block;margin-top:2px;line-height:1.35}
table.data .nowrap{white-space:nowrap}

/* forms */
label{display:block;margin:14px 0 6px;font:800 11px/1.2 var(--font-core);letter-spacing:.1em;text-transform:uppercase;
  color:var(--g500)}
input[type=text],input[type=password],input[type=search],input[type=number],input[type=email],input[type=url],
input[type=file],select,textarea{font:inherit;font-size:15px;padding:10px 12px;border:1px solid var(--line);
  border-radius:var(--r-md);width:100%;background:var(--paper);color:var(--ink)}
textarea{min-height:140px;resize:vertical;font-family:var(--font-mono);font-size:13px;line-height:1.5}
select{appearance:none;-webkit-appearance:none;padding-right:34px;
  background-image:linear-gradient(45deg,transparent 50%,var(--g500) 50%),linear-gradient(135deg,var(--g500) 50%,transparent 50%);
  background-position:calc(100% - 18px) 51%,calc(100% - 12px) 51%;background-size:6px 6px,6px 6px;background-repeat:no-repeat}
input:focus,select:focus,textarea:focus{outline:none;border-color:var(--ink);box-shadow:0 0 0 3px var(--yellow)}
.field-row{display:flex;gap:14px;flex-wrap:wrap}
.field-row > *{flex:1 1 180px}
.hint{font-size:13px;color:var(--g500);margin:6px 0 0}
/* the bottom of a form: the submit button at field height, clear of the last hint */
.form-foot{display:flex;gap:12px;align-items:center;flex-wrap:wrap;margin:18px 0 0}
.form-foot button,.form-foot .btn{min-height:var(--control);padding:0 22px}
/* one field and its button read as one control: the inline row edit (a role and Change, a password and Set) */
.combo{display:flex;align-items:stretch;min-width:200px;max-width:280px;margin:0}
.combo > input,.combo > select{flex:1 1 auto;min-width:0;width:auto;height:var(--control-sm);padding-top:0;
  padding-bottom:0;font-size:14px;border-radius:var(--r-md) 0 0 var(--r-md)}
.combo > select{background-position:calc(100% - 18px) 51%,calc(100% - 12px) 51%}
.combo > button{flex:none;height:var(--control-sm);margin-left:-1px;padding:0 14px;font-size:11px;
  border-radius:0 var(--r-md) var(--r-md) 0;background:var(--g50)}
.combo > button:hover{background:var(--yellow);border-color:var(--ink);color:var(--on-yellow)}
.combo > :focus,.combo > button:hover{position:relative;z-index:1}
ul.plain{margin:0 0 10px;padding-left:18px}
.cols.spaced{margin-top:26px}
.toolbar{display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin:0 0 14px}
.toolbar input[type=search]{max-width:340px}
.check{display:flex;gap:9px;align-items:flex-start;margin:12px 0 0;font:400 14px/1.4 var(--font-text);
  text-transform:none;letter-spacing:0;color:var(--ink2)}
.check input{width:auto;margin-top:3px}

/* chips and tags */
.tag,.chip{display:inline-flex;align-items:center;gap:5px;font:800 10px/1 var(--font-core);letter-spacing:.12em;
  text-transform:uppercase;padding:5px 9px;border-radius:999px;background:var(--g100);color:var(--g600);white-space:nowrap}
.tag.published,.chip.good{background:var(--good-bg);color:var(--good-ink)}
.tag.draft{background:var(--draft-bg);color:var(--g500)}
.chip.warn{background:var(--warn-bg);color:var(--warn)}
.chip.bad{background:var(--bad-bg);color:var(--bad-ink)}
.chip.info{background:var(--info-bg);color:var(--info)}
.chip.ink{background:var(--chrome);color:var(--yellow)}
.chip.product{background:var(--yellow-tint);color:var(--ink);box-shadow:inset 0 0 0 1px var(--yellow-shade)}

/* flash */
.note,.err{border-radius:12px;padding:13px 16px;margin:0 0 20px;font-size:14px}
.note{background:var(--note-bg);border:1px solid var(--note-line)}
.err{background:var(--err-bg);border:1px solid var(--err-line)}

/* media cards (the existing library) */
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:18px}
.card{background:var(--paper);border:1px solid var(--line);border-radius:var(--r);overflow:hidden;display:flex;flex-direction:column}
.card img,.card video{width:100%;aspect-ratio:3/2;object-fit:cover;display:block;background:var(--media-ground)}
.card .meta{padding:13px 14px;display:flex;flex-direction:column;gap:9px;flex:1}
.card .name{font-weight:600;font-size:14px;word-break:break-word}

/* PIN slips: a sheet a teacher cuts up */
.slips{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px}
.slip{border:1.5px dashed var(--g400);border-radius:var(--r-sm);padding:14px 16px;background:var(--paper);break-inside:avoid}
.slip .who{font:800 15px/1.2 var(--font-core)}
.slip .where{font-size:12px;color:var(--g500);margin:2px 0 10px}
.slip .line{display:flex;justify-content:space-between;font:600 13px/1.6 var(--font-text)}
.slip .line b{font:700 16px/1.6 var(--font-mono);letter-spacing:.1em}
.slip .url{font-size:11px;color:var(--g500);margin-top:8px}

/* ---- narrow screens: the sidebar becomes a top bar ---------------------------------------------- */
@media (max-width:900px){
  .suite{grid-template-columns:1fr;background:none;align-content:start}
  .side{position:static;height:auto;border-top-width:6px}
  .side .brand{padding:14px 16px}
  .side nav{display:flex;gap:4px;overflow-x:auto;padding:0 10px 12px;scrollbar-width:none}
  .side nav::-webkit-scrollbar{display:none}
  .side .group{display:none}
  .side nav a,.side nav .planned{white-space:nowrap;flex:none}
  /* the brand and the account (name, sign out) share the first row; the sections scroll beneath them */
  .side{display:grid;grid-template-columns:minmax(0,1fr) auto;grid-template-areas:"brand foot" "nav nav"}
  .side .brand{grid-area:brand}
  .side .foot{grid-area:foot;border-top:0;padding:0 14px 0 0;gap:8px}
  .side nav{grid-area:nav;-webkit-mask-image:linear-gradient(to right,#000 82%,transparent);
    mask-image:linear-gradient(to right,#000 82%,transparent);padding-right:48px}
  .top .in,.content{padding-left:16px;padding-right:16px}
  h1{font-size:26px}
  .cols.two{grid-template-columns:1fr}
  dl.kv{grid-template-columns:1fr}
}

@media (max-width:600px){
  .tiles{grid-template-columns:1fr 1fr;gap:10px}
  .tile{padding:14px}
  .tile .v{font-size:26px}
}

/* ---- print: a slip sheet or a list, nothing else --------------------------------------------------- */
@media print{
  body{background:#fff}
  .side,.top .actions,.toolbar,.no-print,.band,form{display:none!important}
  .suite{display:block}
  .top{border:0}
  .content,.top .in{padding:0;max-width:none}
  .panel{border:0;padding:0}
  .slip{border-color:#000}
}

/* THE REPORT CARD (reports_views._report; wchesher, 2026-10-22: "also redo the interface of individual feedback").
   Who and where on one quiet line, the words lead, the facts under them, the screenshot beside, one outcome bar at the
   foot (a segmented pick, the line to them, the feature), Delete and the trail last. */
.rc{margin:0 0 20px}
.rc-top{display:flex;justify-content:space-between;align-items:center;gap:10px 16px;flex-wrap:wrap;padding:16px 24px;border-bottom:1px solid var(--g100)}
.rc-who{display:flex;align-items:center;gap:8px 10px;flex-wrap:wrap;min-width:0;font-size:16px}
.rc-who > b{font:700 17px/1.2 var(--font-core)}
.rc-who .small{font-size:14px}
.rc .chip{font-size:12px;padding:6px 11px}
.rc-id{font:600 15px/1 var(--font-mono);color:var(--g500)}
.rc-when{font-size:15px;color:var(--g500)}
.rc-body{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:22px;padding:22px 24px 24px}
.rc-main{display:grid;gap:14px;min-width:0;align-content:start}
.rc-words{margin:0;font:500 21px/1.5 var(--font-text);white-space:pre-wrap;overflow-wrap:anywhere;max-width:72ch}
.rc-meta{display:flex;flex-wrap:wrap;gap:6px 24px;margin:0;padding:0;list-style:none;font-size:15px;color:var(--g600)}
.rc-meta li{min-width:0;overflow-wrap:anywhere}
.rc-meta b{font:800 11px/1 var(--font-core);letter-spacing:.12em;text-transform:uppercase;color:var(--g500);margin-right:8px}
.rc-shot img{display:block;width:150px;max-width:100%;max-height:120px;object-fit:cover;object-position:top;border:1px solid var(--line);border-radius:var(--r-sm)}
.rc-shots{display:grid;gap:6px;align-content:start}
.rc-shots.many{grid-template-columns:repeat(2,96px)}
.rc-shots.many .rc-shot img{width:96px;max-height:80px}
.rc-outcome{display:grid;gap:14px;padding:18px 24px;background:var(--yellow-tint);border-top:1px solid var(--yellow-line)}
.rc-closed{background:var(--g50);border-top-color:var(--g100)}
.rc-row{display:flex;align-items:center;gap:10px 12px;flex-wrap:wrap}
.rc-status{display:inline-flex;align-items:center;gap:8px;flex-wrap:wrap;margin-right:auto;min-width:0}
.rc-said{font-size:16px;color:var(--g600)}
.rc-seg{display:inline-flex;flex-wrap:wrap;border:1px solid var(--g300);border-radius:var(--r-sm);overflow:hidden;background:var(--paper)}
.rc-seg label{position:relative;cursor:pointer}
.rc-seg input{position:absolute;opacity:0;width:1px;height:1px}
.rc-seg span{display:block;font:700 13px/1 var(--font-core);letter-spacing:.06em;text-transform:uppercase;padding:13px 18px;color:var(--ink3);border-right:1px solid var(--g200)}
.rc-seg label:last-child span{border-right:0}
.rc-seg input:checked + span{background:var(--chrome);color:var(--yellow)}
.rc-seg input:focus-visible + span{box-shadow:var(--focus)}
.rc-hint{font-size:15px;color:var(--g600);display:none}
.rc-outcome:has(input[value="fixed"]:checked) .rc-for-fixed,
.rc-outcome:has(input[value="implemented"]:checked) .rc-for-implemented,
.rc-outcome:has(input[value="wontfix"]:checked) .rc-for-wontfix,
.rc-outcome:has(input[value="declined"]:checked) .rc-for-declined,
.rc-outcome:has(input[value="done"]:checked) .rc-for-done,
.rc-outcome:has(input[value="duplicate"]:checked) .rc-for-duplicate{display:inline}
.rc-line{flex:1 1 260px;min-width:0}
.rc-area{flex:0 1 160px;min-width:0}
.rc-by,.rc-of{flex:0 1 130px;min-width:0;display:none}
.rc-see{flex:0 1 180px;min-width:0;display:none}
.rc-outcome:has(input[value="fixed"]:checked) .rc-by,
.rc-outcome:has(input[value="fixed"]:checked) .rc-see,
.rc-outcome:has(input[value="implemented"]:checked) .rc-see,
.rc-outcome:has(input[value="duplicate"]:checked) .rc-of{display:block}
.rc-outcome:has(input[value="done"]:checked) .rc-line,
.rc-outcome:has(input[value="duplicate"]:checked) .rc-line,
.rc-outcome:has(input[value="new"]:checked) .rc-line{display:none}
/* the bulk bar: out of the way until a report is ticked, then held at the top while the cards scroll */
.rc-tick{width:20px;height:20px;margin:0 4px 0 0}
.rc-bulk{display:none;position:sticky;top:8px;z-index:5;margin:0 0 16px;border:1px solid var(--yellow-line)}
body:has(.rc-tick:checked) .rc-bulk{display:grid}
.rc-foot{display:flex;justify-content:space-between;align-items:flex-start;gap:10px;padding:12px 24px 14px;border-top:1px solid var(--g100)}
.rc-trail{font-size:15px}
.rc-trail summary{cursor:pointer;color:var(--g600);font-weight:600}
.rc-trail ul{margin:6px 0 0;padding-left:18px}
button.rc-delete{border-color:transparent;background:transparent;color:var(--g500)}
button.rc-delete:hover{color:var(--bad);border-color:var(--bad);background:var(--bad-bg)}
.rc.rc-done .rc-words{color:var(--g600)}
/* The inbox's filters: one labelled row per thing they narrow, pills big enough to read and hit. */
.rc-filters{display:grid;gap:12px;margin:0 0 24px;padding:18px 24px;border:1px solid var(--line);border-radius:var(--r);background:var(--paper)}
.rc-filter{display:grid;grid-template-columns:96px minmax(0,1fr);align-items:center;gap:12px}
.rc-filter-k{font:800 11px/1 var(--font-core);letter-spacing:.14em;text-transform:uppercase;color:var(--g500)}
.rc-pills{display:flex;flex-wrap:wrap;gap:8px}
.rc-pill{display:inline-flex;align-items:center;min-height:36px;padding:0 16px;border-radius:999px;border:1px solid var(--g200);
  font:600 15px/1 var(--font-text);color:var(--ink2);text-decoration:none;white-space:nowrap;
  transition:background var(--fast) var(--ease),border-color var(--fast) var(--ease),color var(--fast) var(--ease)}
.rc-outcome button.primary{font-size:13px;min-height:var(--control-sm);padding:0 22px}
#implemented,#implemented ~ .hint,.hint:has(+ .rc-filters){font-size:15px}
a.rc-pill:hover{border-color:var(--ink3);color:var(--ink)}
a.rc-pill:focus-visible{outline:0;box-shadow:var(--focus)}
.rc-pill.on{background:var(--yellow);border-color:var(--yellow);color:var(--on-yellow);font-weight:700}
@media (max-width:640px){.rc-filter{grid-template-columns:1fr;gap:8px}.rc-filters{padding:16px}
  .rc-top,.rc-body,.rc-outcome,.rc-foot{padding-left:16px;padding-right:16px}.rc-words{font-size:19px}}
/* The model's read on a card, and the look-over panel (feedback_reader.py): quiet, and plainly a suggestion. */
.rc-ai{display:grid;gap:6px;padding:10px 18px;background:var(--g50);border-top:1px solid var(--g100)}
.rc-ai-tag{font:800 10px/1 var(--font-core);letter-spacing:.14em;text-transform:uppercase;color:var(--g500)}
.rc-ai-gist{margin:0;font-size:15px;color:var(--ink3);max-width:72ch}
.rc-ai-fill{margin:0;font-size:13px;color:var(--g600)}
.chip.rc-ai-high{background:var(--bad-bg);color:var(--bad);border-color:var(--bad-line)}
.chip.rc-ai-medium{background:var(--warn-bg);color:var(--warn);border-color:var(--warn-line)}
.chip.rc-ai-low{background:var(--g100);color:var(--g600)}
.chip.rc-ai-verdict{background:var(--info-bg);color:var(--info);border-color:var(--info-line)}
.lo{display:grid;gap:14px;margin:0 0 16px}
.lo-head{display:flex;justify-content:space-between;align-items:flex-start;gap:10px 16px;flex-wrap:wrap}
.lo-head h2{margin:0 0 4px}
.lo-head .hint{margin:0;max-width:64ch}
.lo-themes{list-style:none;margin:0;padding:0;display:grid;gap:10px}
.lo-themes li{display:grid;grid-template-columns:40px minmax(0,1fr);gap:10px;align-items:baseline}
.lo-n{font:700 20px/1 var(--font-core);text-align:right}
.lo-themes small{display:block;color:var(--g600);font-size:13px}
.lo-ids a{margin-right:6px;font-family:var(--font-mono);font-size:12px}
@media (max-width:600px){.rc-body{grid-template-columns:1fr}.rc-shot img,.rc-shots.many .rc-shot img{width:100%;max-height:200px}.rc-shots.many{grid-template-columns:1fr 1fr}}

/* ---- the Status page and the overview's strip (status.py, status.js) ----
   Five tones, one meaning each across the board: good (well), busy (at work, the yellow), warn, bad, quiet (never
   heard from). Live readings pulse; nothing else moves. */
.st-dot{flex:none;display:inline-block;width:9px;height:9px;border-radius:50%;background:var(--g300)}
.st-dot.good{background:var(--good)}.st-dot.busy{background:var(--yellow-shade)}.st-dot.warn{background:var(--warn-mid)}
.st-dot.bad{background:var(--bad)}
.st-chip{display:inline-flex;align-items:center;gap:7px;padding:4px 10px;border-radius:999px;white-space:nowrap;
  font:700 12px/1.2 var(--font-core);letter-spacing:.02em;background:var(--g100);color:var(--g600)}
.st-chip.good{background:var(--good-bg);color:var(--good)}.st-chip.busy{background:var(--yellow-tint-2);color:var(--ink)}
.st-chip.warn{background:var(--warn-bg);color:var(--warn)}.st-chip.bad{background:var(--bad-bg);color:var(--bad-ink)}
.st-muted{color:var(--g500);font-size:13px}
.st-mono{font-family:var(--font-mono);font-size:.92em;font-weight:600}
.st-pulse{position:relative;flex:none;display:inline-block;width:14px;height:14px}
.st-pulse span,.st-pulse::after{position:absolute;inset:0;border-radius:50%;background:var(--good)}
.st-pulse::after{content:"";animation:st-ping 2s var(--ease) infinite;opacity:.55}
.st-pulse.bad span,.st-pulse.bad::after{background:var(--bad)}
.st-pulse.warn span,.st-pulse.warn::after{background:var(--warn-mid)}
@keyframes st-ping{0%{transform:scale(1);opacity:.55}80%,100%{transform:scale(2.6);opacity:0}}
@media (prefers-reduced-motion:reduce){.st-pulse::after{animation:none;opacity:0}}

.st-hero{background:var(--chrome);color:var(--on-chrome);border-radius:var(--r);padding:22px 24px;margin:0 0 22px;
  box-shadow:var(--shadow-2);border-left:6px solid var(--good)}
.st-hero.bad{border-left-color:var(--bad)}
.st-hero-head{display:flex;align-items:center;gap:16px}
.st-hero h2{margin:0;font:800 26px/1.15 var(--font-core);letter-spacing:-.01em;color:var(--yellow)}
.st-hero .st-muted{margin:4px 0 0;color:rgba(254,254,254,.62)}
.st-problems{list-style:none;margin:16px 0 0;padding:14px 0 0;border-top:1px solid var(--chrome-3);display:grid;gap:8px}
.st-problems li{display:flex;gap:10px;align-items:baseline;font-size:15px}
.st-problems .st-dot{transform:translateY(-1px)}

/* THE RACK (status.js): one row per machine, the same four columns down the page -- who and its state, what it is
   doing now, three gauges (compute, memory, disk), when it last said. Its tone is a rule down the left edge. What
   needs a person sits under the row, the rack's full width. */
.st-rack{display:grid;gap:12px;margin:0 0 26px}
.st-row{display:grid;grid-template-columns:minmax(170px,1.1fr) minmax(0,2fr) auto 84px;gap:14px 24px;align-items:center;
  background:var(--paper);border:1px solid var(--line);border-left:5px solid var(--g300);border-radius:var(--r);
  padding:16px 20px;box-shadow:var(--shadow-1)}
.st-row.good{border-left-color:var(--good)}.st-row.busy{border-left-color:var(--yellow)}
.st-row.warn{border-left-color:var(--warn-mid)}.st-row.bad{border-left-color:var(--bad)}
.st-who{display:grid;gap:6px;justify-items:start;min-width:0}
.st-who-name{display:flex;align-items:center;gap:9px}
.st-row h3{margin:0;font:800 17px/1.2 var(--font-core)}
.st-does{margin:0;font-size:13px;color:var(--g500);line-height:1.35}
.st-now{display:grid;gap:8px;min-width:0}
.st-now p{margin:0}
.st-now-head{font:600 15px/1.35 var(--font-text);color:var(--ink);overflow-wrap:anywhere}
.st-now-sub{font-size:13px;color:var(--g500)}
.st-heard{display:grid;gap:4px;justify-items:end;text-align:right}
.st-heard-v{font:600 13px/1.2 var(--font-mono);color:var(--g600);white-space:nowrap}
.st-k{font:800 10px/1 var(--font-core);letter-spacing:.16em;text-transform:uppercase;color:var(--g500);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* THE ARC GAUGE (teenyverse design system, "arc gauge" + "gauge law-line"): the ring fills with what is in use, the
   number sits in it, a second tick marks where the line is. Ink while well, yellow while at work, red past the line;
   a dashed empty ring is a resource the machine does not report. */
.st-gauges{display:grid;grid-template-columns:repeat(3,136px);gap:10px}
.st-gauge{display:grid;justify-items:center;align-content:start;gap:8px;text-align:center}
.st-dial{position:relative;width:104px;height:104px}
.st-dial svg{width:104px;height:104px;transform:rotate(-90deg);overflow:visible}
.st-track{fill:none;stroke:var(--g100);stroke-width:5}
.st-gauge.none .st-track{stroke:var(--g200);stroke-dasharray:3 4}
.st-arc{fill:none;stroke:var(--ink);stroke-width:5;stroke-linecap:round;transition:stroke-dashoffset .6s var(--ease)}
.st-gauge.busy .st-arc{stroke:var(--yellow-shade)}.st-gauge.warn .st-arc{stroke:var(--warn-mid)}
.st-gauge.bad .st-arc{stroke:var(--bad)}
.st-law{stroke:var(--bad);stroke-width:2.5;stroke-linecap:round}
.st-dial-v{position:absolute;inset:0;display:flex;flex-wrap:wrap;align-content:center;justify-content:center;
  align-items:baseline;column-gap:1px;font-family:var(--font-mono);font-variant-numeric:tabular-nums}
.st-dial-v b{font-size:26px;font-weight:700;line-height:1;letter-spacing:-.03em}
.st-dial-v small{font-size:13px;font-weight:600;color:var(--g500)}
.st-dial-v i{flex-basis:100%;text-align:center;margin-top:3px;font:700 9px/1 var(--font-core);letter-spacing:.14em;
  text-transform:uppercase;font-style:normal;color:var(--g500)}
.st-gauge.none .st-dial-v b{color:var(--g300)}
.st-gauge-k{display:grid;gap:4px;justify-items:center;max-width:136px}
.st-gauge-sub{font:500 12px/1.3 var(--font-mono);color:var(--g600);text-wrap:balance}
.st-gauge.bad .st-gauge-sub{color:var(--bad)}

/* the budget meter (teenyverse "budget meter"): a job's frames */
.st-meter{display:grid;gap:6px}
.st-meter-head{display:flex;flex-wrap:wrap;justify-content:space-between;gap:4px 12px;align-items:baseline;min-width:0}
.st-meter-head .st-k{white-space:normal;overflow:visible}
.st-bar{display:block;height:10px;border-radius:999px;background:var(--g100);border:1px solid var(--line);overflow:hidden}
.st-fill{display:block;height:100%;border-radius:999px;background:var(--ink);transition:width .6s var(--ease)}
.st-meter.busy .st-fill{background:var(--yellow-shade)}.st-meter.warn .st-fill{background:var(--warn-mid)}
.st-meter.bad .st-fill{background:var(--bad)}
.st-meter .st-v{font:500 12.5px/1.3 var(--font-mono);color:var(--g600)}
.st-facts{display:grid;grid-template-columns:auto 1fr;gap:4px 14px;margin:0;font-size:14px}
.st-facts dt{color:var(--g500)}.st-facts dd{margin:0;font-family:var(--font-mono);font-size:13px;text-align:right}

/* the two-plane grid (teenyverse "planes"): cells that share their rules */
.st-planes{display:grid;grid-template-columns:repeat(3,1fr);gap:1px;background:var(--line);border:1px solid var(--line);
  border-radius:var(--r-sm);overflow:hidden}
.st-plane{display:grid;gap:5px;padding:10px 12px;background:var(--paper)}
.st-plane b{font:700 22px/1 var(--font-mono);font-variant-numeric:tabular-nums}
.st-plane.warn b{color:var(--warn-mid)}.st-plane.zero b{color:var(--g400)}
.st-plane span{font:800 10px/1.25 var(--font-core);letter-spacing:.12em;text-transform:uppercase;color:var(--g500)}
.st-queues{list-style:none;margin:0;padding:0;display:grid;gap:5px;font-size:14px}
.st-queues li{display:flex;align-items:center;gap:8px}.st-queues .st-muted{margin-left:auto;text-align:right}

.st-tray{grid-column:1 / -1;display:grid;gap:10px;padding-top:12px;border-top:1px solid var(--g100)}
.st-foot{margin:0;font-size:12px;line-height:1.4;color:var(--g500)}
.st-why{margin:0;font-size:14px;line-height:1.4;padding:10px 12px;border-radius:var(--r-sm);background:var(--g50);
  border-left:3px solid var(--g300)}
.st-why.warn{background:var(--warn-bg);border-left-color:var(--warn-mid);color:var(--ink)}
.st-why.bad{background:var(--bad-bg);border-left-color:var(--bad);color:var(--bad-ink)}
.st-detail{font-size:13px}
.st-detail summary{cursor:pointer;color:var(--g600);font-weight:600;width:max-content}
.st-detail-lines{margin:6px 0 0;padding-left:18px;line-height:1.5;font-family:var(--font-mono);font-size:12.5px;
  overflow-wrap:anywhere;columns:2 320px;column-gap:28px}

@media (max-width:1100px){
  .st-row{grid-template-columns:minmax(0,1fr) auto;grid-template-areas:"who heard" "now now" "gauges gauges"}
  .st-who{grid-area:who}.st-heard{grid-area:heard;align-self:start}.st-now{grid-area:now}
  .st-gauges{grid-area:gauges;justify-content:start}
}
.st-specs{display:flex;flex-wrap:wrap;gap:6px 18px;margin:2px 0 0;padding-top:10px;border-top:1px dashed var(--g200)}
.st-specs div{display:grid;gap:3px}
.st-specs dt{font:800 9.5px/1 var(--font-core);letter-spacing:.14em;text-transform:uppercase;color:var(--g500)}
.st-specs dd{margin:0;font:600 13px/1.25 var(--font-mono);color:var(--ink)}
@media (max-width:600px){.st-row{padding:14px 16px}.st-gauges{grid-template-columns:repeat(3,minmax(0,1fr));width:100%}
  .st-dial,.st-dial svg{width:84px;height:84px}.st-dial-v b{font-size:21px}}

.st-list ul{list-style:none;margin:0;padding:0}
.st-list li{display:grid;grid-template-columns:auto minmax(0,1fr) auto 64px;gap:12px;align-items:center;
  padding:11px 0;border-top:1px solid var(--g100)}
.st-list li:first-child{border-top:0}
.st-list h2{margin:0}
.st-name{display:flex;flex-direction:column;min-width:0}
.st-name b,.st-name span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.st-said{font-size:13px;color:var(--g600);text-align:right}
.st-ms{font:500 12px/1 var(--font-mono);color:var(--g500);text-align:right}

.st-strip{padding:14px 18px}
.st-strip-top{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;margin:0 0 10px}
.st-strip-head{display:inline-flex;align-items:center;gap:10px;text-decoration:none;font:800 15px/1.2 var(--font-core)}
.st-strip-head .st-muted{font:600 12px/1 var(--font-core);text-decoration:underline;text-underline-offset:3px}
.st-pills{display:flex;flex-wrap:wrap;gap:8px}
.st-pill{display:inline-flex;align-items:center;gap:7px;padding:6px 11px;border-radius:999px;font-size:13px;
  background:var(--g50);border:1px solid var(--g100)}
.st-pill b{font:700 12px/1 var(--font-core)}
.st-pill.bad{background:var(--bad-bg);border-color:var(--bad-line)}.st-pill.warn{background:var(--warn-bg);border-color:var(--warn-line)}
@media (max-width:600px){.st-list li{grid-template-columns:auto minmax(0,1fr) auto}.st-ms{display:none}
  .st-hero h2{font-size:21px}}

/* ---- the overview's hero (overview._hero) ----
   wchesher, 2026-10-30: "We need a hero on the dashboard, the dashboard needs to be funal but not boring. WORLD CLASS
   UX. I spend a lot of time here. Be kind". The darkest surface on the page in both themes (the chrome), lit by one
   soft yellow glow and the seal as a watermark; the platform live on the right. Everything in it is a way somewhere. */
.hero{position:relative;overflow:hidden;display:grid;grid-template-columns:minmax(0,1.35fr) minmax(280px,1fr);gap:28px;
  align-items:stretch;margin:0 0 30px;padding:34px 34px 30px;border-radius:calc(var(--r) + 6px);
  background:radial-gradient(900px 420px at 92% -20%,rgba(255,222,89,.20),transparent 60%),
             radial-gradient(600px 300px at -10% 120%,rgba(255,222,89,.07),transparent 60%),var(--chrome);
  color:var(--on-chrome);border:1px solid var(--chrome-3);box-shadow:var(--shadow-2);
  animation:hero-in .5s var(--ease) both}
.hero::after{content:"";position:absolute;left:0;right:0;bottom:0;height:3px;
  background:linear-gradient(90deg,var(--yellow),rgba(255,222,89,.25) 55%,transparent)}
.hero.bad::after{background:linear-gradient(90deg,var(--bad),rgba(255,107,107,.25) 55%,transparent)}
.hero-seal{position:absolute;right:-60px;bottom:-120px;width:320px;height:320px;opacity:.035;pointer-events:none;
  filter:grayscale(1) brightness(2)}
.hero-main{position:relative;display:flex;flex-direction:column;gap:12px;min-width:0}
.hero-date{margin:0;font:800 11px/1 var(--font-core);letter-spacing:.22em;text-transform:uppercase;color:var(--yellow)}
.hero-hi{margin:0;font:800 clamp(30px,3.6vw,46px)/1.05 var(--font-core);letter-spacing:-.02em;text-transform:none;
  color:var(--on-chrome)}
.hero-hi em{font-style:normal;color:var(--yellow)}
.hero-say{margin:0;max-width:56ch;font-size:17px;line-height:1.5;color:rgba(254,254,254,.82)}
.hero-say a{color:var(--yellow);font-weight:600}
.hero-doors{display:flex;flex-wrap:wrap;gap:10px;margin-top:10px}
.hero-door{display:inline-flex;align-items:center;gap:10px;padding:10px 16px;border-radius:999px;text-decoration:none;
  font:700 13px/1 var(--font-core);color:var(--on-chrome);background:rgba(254,254,254,.06);
  border:1px solid rgba(254,254,254,.14);transition:background var(--fast) var(--ease),border-color var(--fast) var(--ease),
  transform var(--fast) var(--ease)}
.hero-door:first-child{background:var(--yellow);color:var(--on-yellow);border-color:var(--yellow)}
.hero-door:hover{color:var(--on-chrome);border-color:var(--yellow);transform:translateY(-1px)}
.hero-door:first-child:hover{color:var(--on-yellow);background:#FFE77F}
.hero-door span[aria-hidden]{transition:transform var(--fast) var(--ease)}
.hero-door:hover span[aria-hidden]{transform:translateX(3px)}
.hero-live{position:relative;align-self:stretch;padding:18px;border-radius:var(--r);background:rgba(254,254,254,.04);
  border:1px solid rgba(254,254,254,.10);backdrop-filter:blur(2px);min-width:0}
.hero-live .st-strip-top{margin:0 0 14px;flex-direction:column;align-items:flex-start;gap:6px}
.hero-live .st-strip-head{color:var(--on-chrome);font-size:17px;flex-wrap:wrap;row-gap:8px}
.hero-live .st-strip-head .st-muted{color:rgba(254,254,254,.6);text-decoration:none;font-weight:600;
  letter-spacing:.14em;text-transform:uppercase;font-size:10px;order:-1;flex-basis:100%}
.hero-live .st-muted{color:rgba(254,254,254,.55)}
.hero-live .st-pills{display:grid;grid-template-columns:1fr;gap:6px}
.hero-live .st-pill{justify-content:flex-start;background:rgba(254,254,254,.05);border-color:rgba(254,254,254,.08);
  color:var(--on-chrome);text-decoration:none;border-radius:var(--r-sm);padding:8px 11px}
.hero-live .st-pill b{min-width:84px;color:rgba(254,254,254,.66);font-weight:700;letter-spacing:.04em}
.hero-live .st-pill:hover{border-color:var(--yellow)}
.hero-live .st-pill.bad{background:rgba(255,107,107,.13);border-color:rgba(255,107,107,.35)}
.hero-live .st-pill.warn{background:rgba(240,160,48,.12);border-color:rgba(240,160,48,.32)}
.hero-counts{display:flex;gap:26px;margin-top:auto;padding-top:22px;text-decoration:none;color:var(--on-chrome)}
.hero-count{display:flex;align-items:baseline;gap:9px}
.hero-count b{font:800 34px/1 var(--font-core);letter-spacing:-.02em}
.hero-count span{font:700 11px/1.2 var(--font-core);letter-spacing:.14em;text-transform:uppercase;color:rgba(254,254,254,.6)}
.hero-count.bad b{color:var(--bad)}.hero-count.warn b{color:var(--warn-mid)}.hero-count.good b{color:var(--good)}
.hero-counts:hover span{color:var(--on-chrome)}
@keyframes hero-in{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion:reduce){.hero{animation:none}}
@media (max-width:900px){.hero{grid-template-columns:1fr;padding:26px 22px}.hero-seal{width:240px;height:240px}}
@media print{.hero{display:none}}

/* the Students list's Last signed in: when, then where, one format down the column (students_views.seen_of) */
.seen{display:flex;flex-direction:column;gap:2px;line-height:1.2;white-space:nowrap}
.seen .when{font:500 13px/1.2 var(--font-mono);color:var(--ink);font-variant-numeric:tabular-nums}
.seen .where{font:700 10px/1.2 var(--font-core);letter-spacing:.1em;text-transform:uppercase;color:var(--g500)}

/* ---- voice (/admin/voice): the page is the lab (voice_lab.py styles it). wchesher, 2026-10-31: "it is too complicated,
   does not display well, and is anything but elegant AF"; 2026-11-01: "another deeper pass for usability and elegance".
   Above it, only a note that needs the operator. ----------------------------------------------------------------- */
.vx-note{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin:0 0 22px;padding:12px 16px;font-size:14px;
  border:1px solid var(--warn-line);border-radius:var(--r-md);background:var(--warn-bg);color:var(--ink2)}
.vx-note span:nth-child(2){flex:1 1 260px}
.vx-note a{font-weight:600;white-space:nowrap}
.rc-rec{margin:0 0 8px;padding:8px 12px;border-left:4px solid var(--warn-mid);background:var(--warn-bg);border-radius:4px;font-size:15px}
.rc-rec span{color:var(--g600)}
