:root {
  color-scheme: dark;
  --sdscpa-green: #7AC143; --sdscpa-orange: #F7941E; --sdscpa-red: #ED1C45;
  --sdscpa-magenta: #EC008C; --sdscpa-violet: #92278F;
  --sdscpa-indigo: #2E3192; --sdscpa-cyan: #00AEEF;
  --sdscpa-rainbow: linear-gradient(90deg,#7AC143,#F7941E,#ED1C45,#EC008C,#92278F,#2E3192,#00AEEF);
  --bg: #0A0A0A; --panel: #1A1A1D; --panel2: #222227; --panel-raised: #222227;
  --input: #111115; --surface: rgba(27,27,31,.84);
  --text: #F0F0F2; --muted: #96969F;
  --line: rgba(255,255,255,.11); --line-strong: rgba(255,255,255,.19);
  --good: #7AC143; --warn: #F7941E; --bad: #ED1C45; --info: #3B82F6;
  --accent: #3B82F6; --accent-hover: #4B8CF7; --violet: #92278F;
  /* Ink that sits on top of a filled --accent / --info surface. Themes that
     make those fills light (the contrast theme paints --accent white) flip
     these to dark, so a selected control never renders white-on-white. */
  --on-accent: #ffffff; --on-info: #ffffff;
  /* The rainbow gradient is the fixed brand anchor — used sparingly as the
     wordmark fill, header underline, and footer strip. */
  --rainbow: var(--sdscpa-rainbow);
  --mono: 'SF Mono','Cascadia Mono','Consolas',ui-monospace,monospace;
  --radius: 18px; --control-radius: 11px;
  --shadow: 0 12px 32px rgba(0,0,0,.28);
  --shadow-float: 0 22px 64px rgba(0,0,0,.48);
  --ease-fluid: cubic-bezier(.2,.8,.2,1);
}
/* Light theme */
html[data-theme="light"] {
  color-scheme: light;
  --bg: #f3f4f6; --panel: #ffffff; --panel2: #eceef1; --panel-raised: #fff;
  --input: #fff; --surface: rgba(255,255,255,.88); --text: #15171a;
  --muted: #5a6069; --line: rgba(21,23,26,.13); --line-strong: rgba(21,23,26,.24);
  --shadow: 0 8px 24px rgba(15,23,42,.09); --shadow-float: 0 20px 52px rgba(15,23,42,.18);
}
html[data-theme="light"] .brand-main {
  background: none; -webkit-text-fill-color: currentColor; color: var(--text);
}
html[data-theme="light"] code { background: #eceef1; }

/* High-contrast theme (black/white, thick borders) */
html[data-theme="contrast"] {
  color-scheme: dark;
  --bg: #000; --panel: #000; --panel2: #000; --panel-raised: #000;
  --input: #000; --surface: #000; --text: #fff;
  --muted: #e6e6e6; --line: #ffffff; --line-strong: #fff;
  --good: #00e000; --warn: #ffd400; --bad: #ff4d4d; --info: #4dd2ff; --accent: #ffffff;
  /* --accent and --info are near-white here, so anything filled with them
     takes dark ink instead of the default white. */
  --on-accent: #000000; --on-info: #000000;
  --shadow: none;
}
html[data-theme="contrast"] .brand-main {
  background: none; -webkit-text-fill-color: #fff; color: #fff;
}
/* No blanket `button` override here: the base button rule already fills with
   --accent and inks with --on-accent, which this theme flips to white-on-black.
   A blanket rule also repainted tabs, ghost and toggle buttons, whose own
   .active/.selected rules kept white text — leaving them white-on-white. */
html[data-theme="contrast"] a { color: #4dd2ff; }
html[data-theme="contrast"] .card, html[data-theme="contrast"] .count,
html[data-theme="contrast"] input, html[data-theme="contrast"] select,
html[data-theme="contrast"] textarea { border-width: 2px; }

* { box-sizing: border-box; }
body {
  margin: 0; background-color: var(--bg); color: var(--text);
  background-image:
    radial-gradient(circle at 8% -10%, rgba(0,174,239,.12), transparent 34rem),
    radial-gradient(circle at 92% -15%, rgba(146,39,143,.11), transparent 36rem),
    linear-gradient(180deg, rgba(255,255,255,.018), transparent 32rem);
  background-attachment: fixed;
  font: 16px/1.5 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
  font-optical-sizing: auto;
}
a { color: var(--info); text-decoration: none; transition: color 180ms var(--ease-fluid); }
a:hover { text-decoration: underline; }
h1, h2, h3 { line-height: 1.2; }
/* Page titles are solid text at heading weight — the guide gives headings
   700–900 and no added letter-spacing, and reserves gradient text for the
   wordmark. The rainbow returns underneath as a short rule, which the guide
   lists as a sanctioned use of the brand anchor ("the underline beneath a
   header"). */
h1 { font-weight: 800; color: var(--text); }
h1::after {
  content: ""; display: block; width: 64px; height: 3px; border-radius: 3px;
  background: var(--rainbow); margin: .5rem 0 0;
}
/* Centred layouts centre the rule with their title. */
.kiosk-prompt h1::after, .lb-head h1::after, .card.login h1::after { margin-inline: auto; }
/* Not page titles: the IMIN board's section label, and the projector title,
   which is a live class name on a wall display rather than a document head. */
.imin-next h1::after, .projector-body .seating-live-head h1::after { display: none; }
/* House icon set (templates/_icons.html): inline SVG, one stroke style, colour
   inherited from the surrounding text so an icon picks up its context's theme
   or section colour automatically. */
.icon { display: inline-block; vertical-align: -.18em; flex: none; }
.imin-event-meta .icon { vertical-align: -.12em; opacity: .8; }

.muted { color: var(--muted); }
code { background: #0b1220; padding: .1em .35em; border-radius: 4px; font-size: .9em; }
hr { border: none; border-top: 1px solid var(--line); margin: 1.25rem 0; }

.topbar {
  display: flex; align-items: center; justify-content: space-between;
  gap: .5rem 1rem; flex-wrap: wrap;
  padding: .72rem clamp(.9rem, 2.2vw, 1.65rem); background: var(--surface);
  border-bottom: 1px solid var(--line);
  /* 2px rainbow brand strip along the header's bottom edge. */
  box-shadow: inset 0 -2px 0 0 transparent;
  position: sticky; top: 0; z-index: 1000;
  -webkit-backdrop-filter: blur(20px) saturate(1.25);
  backdrop-filter: blur(20px) saturate(1.25);
}
.topbar::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 2px;
  background: var(--rainbow);
}
.topbar .links { display: flex; align-items: center; flex-wrap: wrap; gap: .35rem .9rem; }
.brand { display: inline-flex; flex-direction: column; line-height: 1.1; color: var(--text); gap: .12rem; }
.brand:hover { text-decoration: none; }
/* The rainbow "SDSCPA" wordmark (static/logo.png — see templates/_brand.html
   for why the artwork is a PNG rather than live SVG text). Everything else on
   the page re-colours with the theme; the wordmark is the fixed brand mark.
   Height comes from each call site's height attribute, so it is not set here. */
.sdscpa-wordmark { display: block; width: auto; max-width: min(248px, 58vw); object-fit: contain; }
/* Legacy CSS-gradient wordmark, kept for any page still using the text span. */
.brand-main { font-weight: 900; font-size: 1.15rem; letter-spacing: -.5px;
  background: var(--rainbow);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent; }
.brand-sub { font-size: .66rem; text-transform: uppercase; letter-spacing: .18em; color: var(--muted); }

/* App footer: centered rainbow strip above one line of dim monospace text. */
.app-footer { text-align: center; color: var(--muted); font-size: .78rem;
  padding: 1.5rem 1rem 2rem; display: flex; flex-direction: column; align-items: center; gap: .55rem; }
.footer-strip { display: block; width: 120px; height: 2px; border-radius: 99px; background: var(--rainbow); }
.footer-text { font-family: var(--mono); letter-spacing: .02em; }
/* The version doubles as the way in to the release notes. */
.footer-version { color: inherit; }
.footer-version:hover { color: var(--text); }

/* Sign-in card wordmark. */
.login-wordmark { width: min(260px, 70vw); height: auto; margin: 0 auto .1rem; }
.topbar .links a { color: var(--muted); white-space: nowrap; padding: .32rem .15rem; }
.topbar .links a:hover { color: var(--text); text-decoration: none; }
/* A button in the bar (the sign-in link a signed-out student sees on the 3D
   printing board) keeps its filled ink rather than the muted nav colour. */
.topbar .links a.btn-link, .topbar .links a.btn-link:hover { color: var(--on-accent); }
/* Active nav link indicator (issue 3.14) */
.topbar .links a[aria-current="page"] { color: var(--text); font-weight: 700; }
/* Current-class "Now" pill in the nav (issue 2.1) */
.nav-now-pill {
  display: inline-block; background: rgba(74,222,128,.18); color: var(--good);
  border: 1px solid rgba(74,222,128,.35); border-radius: 999px;
  padding: .18rem .7rem; font-size: .82rem; font-weight: 700; white-space: nowrap;
}
.nav-now-pill:hover { background: rgba(74,222,128,.28); text-decoration: none; }

/* Topbar student quick-search (a combobox; see static/quick_search.js). */
.nav-search { position: relative; }
.nav-search-input { width: 11.5rem; padding: .38rem .65rem; font-size: .85rem;
  background: var(--input); color: var(--text); border: 1px solid var(--line);
  border-radius: 999px; transition: width 180ms var(--ease-fluid), border-color 180ms var(--ease-fluid); }
.nav-search-input:focus { width: 15rem; outline: none; border-color: var(--accent); }
.nav-search-input::placeholder { color: var(--muted); }
.nav-search-results { position: absolute; top: calc(100% + .4rem); right: 0;
  min-width: 17rem; max-height: 21rem; overflow-y: auto; margin: 0; padding: .3rem;
  list-style: none; background: var(--panel-raised); border: 1px solid var(--line-strong);
  border-radius: var(--control-radius); box-shadow: var(--shadow-float); z-index: 1200; }
.nav-search-results.hidden { display: none; }
.nav-search-results [role="option"] { display: flex; flex-direction: column; gap: .05rem;
  padding: .45rem .6rem; border-radius: 8px; cursor: pointer; }
.nav-search-results [role="option"] strong { font-size: .9rem; }
.nav-search-results [role="option"] span { font-size: .74rem; color: var(--muted); }
.nav-search-results [role="option"]:hover,
.nav-search-results [role="option"].active { background: var(--accent); }
.nav-search-results [role="option"]:hover strong, .nav-search-results [role="option"].active strong,
.nav-search-results [role="option"]:hover span, .nav-search-results [role="option"].active span {
  color: var(--on-accent); }
.nav-search-empty { padding: .45rem .6rem; color: var(--muted); font-size: .82rem; }
.ab-day-bar { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 1rem;
  padding: .65rem max(1rem, calc((100vw - 1180px) / 2)); background: rgba(0,174,239,.13);
  border-bottom: 1px solid rgba(0,174,239,.35); }
.ab-day-bar.needs-choice { background: rgba(245,158,11,.15); border-bottom-color: rgba(245,158,11,.4); }
.ab-day-bar > div { display: flex; flex-direction: column; gap: .1rem; }
.ab-day-bar span { color: var(--muted); font-size: .82rem; }

.container { max-width: 1240px; margin: 0 auto; padding: clamp(1rem, 2.5vw, 1.8rem) clamp(.9rem, 2.5vw, 1.5rem); }
.center-card { min-height: 100vh; display: grid; place-items: center; }

.card { background: linear-gradient(145deg, rgba(255,255,255,.025), transparent 45%), var(--panel);
  border: 1px solid var(--line); border-radius: var(--radius);
  padding: 1.25rem; box-shadow: var(--shadow); }
/* Sections stacked down a page separate by the same 1rem a .grid puts between
   its columns, so the vertical and horizontal rhythm match. A .card carries no
   margin of its own, so without this two in a row meet at the border and read
   as one long section.
   A top margin on each rather than a gap between adjacent siblings, because
   templates put <script> and other zero-height elements between two sections
   and an adjacent-sibling rule silently stops matching when they do. Scoped to
   the page's own children: cards side by side inside a .grid are grid items,
   take the grid's own gap, and would be pushed out of line with each other by
   a margin as well. */
main > .card, main > .grid { margin-top: 1rem; }
main > :first-child { margin-top: 0; }
.grid { display: grid; gap: 1rem; }
.grid.two { grid-template-columns: 1fr 1fr; }
.grid:not(.two) { grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); }
@media (max-width: 800px) { .grid.two { grid-template-columns: 1fr; } }
.link-card { transition: border-color 200ms var(--ease-fluid), transform 200ms var(--ease-fluid), box-shadow 200ms var(--ease-fluid); }
.link-card:hover { border-color: var(--line-strong); text-decoration: none; }
/* Lift-on-hover, only where a real pointer is hovering (not touch). */
@media (hover: hover) and (pointer: fine) {
  .link-card:hover, .board-item:hover, .proj-row:hover {
    transform: translateY(-2px); border-color: var(--line-strong);
    box-shadow: 0 14px 34px rgba(0,0,0,.24);
  }
}
.class-card { position: relative; }
.class-card .class-open { display: block; }
.class-card .class-open:hover { text-decoration: none; }
/* NOW badge on class cards (issue 2.1) */
.class-card--now { border-color: var(--good); }
/* "No period" pill in class cards uses warn colour (issue 3.15) */
.class-open .pill.warn a.pill-link { color: inherit; text-decoration: underline; }
/* Gear icon with "Manage" text label + larger tap target (issue 2.7) */
.class-cog {
  position: absolute; top: .45rem; right: .6rem; z-index: 2;
  color: var(--muted); display: flex; align-items: center; gap: .2rem;
  padding: .35rem .5rem; border-radius: 6px; font-size: .78rem; line-height: 1;
  min-width: 44px; min-height: 44px; justify-content: flex-end;
}
.class-cog:hover { color: var(--text); background: var(--panel2); text-decoration: none; }
.class-cog-icon { font-size: 1rem; }
.class-cog-label { font-weight: 600; font-size: .78rem; }
.link-card h3 { margin: .4rem 0 .2rem; }
.teacher-section { margin-bottom: 1.75rem; }
.teacher-section > h2 { border-bottom: 1px solid var(--line); padding-bottom: .35rem; margin-bottom: .8rem; }

.stack { display: flex; flex-direction: column; gap: .6rem; }
.row { display: flex; gap: .6rem; align-items: end; flex-wrap: wrap; }
/* Layout utilities for the form templates (extracted from what used to be
   repeated inline style="" attributes — same computed styles). */
.row.align-center { align-items: center; }
.row.justify-end { justify-content: flex-end; }
.row > .grow { flex: 1; }
.row > .grow-2 { flex: 2; }
.stack.tight { gap: .4rem; }
.input-w-5 { width: 5rem; }
.input-w-6 { width: 6rem; }
.input-w-8 { width: 8rem; }
.input-w-10 { width: 10rem; }
/* A checkbox beside its text instead of the stacked field layout. */
label.check-row { flex-direction: row; align-items: center; gap: .6rem; }
label.check-row--emph { font-size: 1rem; color: var(--text); }
input.check-box { width: 1.1rem; height: 1.1rem; }
/* Muted explainer sitting beside a field, aligned near its baseline. */
.field-note { padding-bottom: .6rem; font-size: .85rem; }
input, select, button, textarea {
  font: inherit; min-height: 40px; padding: .55rem .72rem; border-radius: var(--control-radius);
  border: 1px solid var(--line); background: var(--input); color: var(--text);
  transition: border-color 180ms var(--ease-fluid), box-shadow 180ms var(--ease-fluid),
    background-color 180ms var(--ease-fluid), transform 180ms var(--ease-fluid);
}
input, select, textarea { box-shadow: inset 0 1px 2px rgba(0,0,0,.32); }
textarea { resize: vertical; width: 100%; }
input:focus, select:focus, textarea:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 4px rgba(59,130,246,.2), inset 0 1px 2px rgba(0,0,0,.32); }
button { background: var(--accent); border-color: var(--accent); color: var(--on-accent); cursor: pointer; font-weight: 600; }
button:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
button:active, .btn-link:active { transform: scale(.97); }
button:focus-visible, .btn-link:focus-visible, a:focus-visible, summary:focus-visible {
  outline: 3px solid var(--accent); outline-offset: 3px;
}
button.danger { background: transparent; color: var(--bad); border-color: var(--bad); }
button.sm { min-height: 34px; padding: .25rem .55rem; font-size: .85rem; }
button.ghost { background: rgba(255,255,255,.035); color: var(--text); border-color: var(--line-strong); }
/* A pass the teacher issued past the class limit: the kiosk stays shut for
   the rest of the class until this button is pressed. */
button.override-pass { background: rgba(245,158,11,.18); color: var(--warn); border-color: var(--warn); }
button.override-pass:hover { background: rgba(245,158,11,.28); border-color: var(--warn); }
.btn-link { display: inline-flex; min-height: 40px; align-items: center; justify-content: center;
  background: var(--accent); color: var(--on-accent); padding: .5rem .9rem;
  border: 1px solid var(--accent); border-radius: var(--control-radius); font-weight: 700;
  transition: background-color 180ms var(--ease-fluid), border-color 180ms var(--ease-fluid), transform 180ms var(--ease-fluid); }
.btn-link:hover { background: var(--accent-hover); border-color: var(--accent-hover); text-decoration: none; }
/* Inline link button (replaces <a href="#">) (issue 4.3) */
.btn-inline-link {
  background: none; border: none; color: var(--info); padding: 0;
  font: inherit; cursor: pointer; text-decoration: none; font-size: inherit;
}
.btn-inline-link:hover { text-decoration: underline; }
label { display: flex; flex-direction: column; gap: .2rem; font-size: .85rem; color: var(--muted); }

.flash { padding: .7rem 1rem; border: 1px solid var(--line); border-radius: var(--control-radius); margin-bottom: 1rem; }
.flash.ok { background: #052e16; color: #86efac; }
.flash.error { background: #450a0a; color: #fca5a5; }
.flash.warn { background: rgba(245,158,11,.15); color: var(--warn); border: 1px solid rgba(245,158,11,.35); }

/* Auto-jump banner (shown when the dashboard auto-routes to the live class) */
.auto-jump-banner { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; }
.auto-jump-banner a { font-weight: 600; }
.flash-dismiss { margin-left: auto; background: none; border: none; color: inherit;
  opacity: .7; cursor: pointer; font-size: 1rem; line-height: 1; padding: 0 .2rem; }
.flash-dismiss:hover { opacity: 1; }

/* Auto-advance pause toggle on the live class view */
.auto-advance-toggle { white-space: nowrap; }
.auto-advance-toggle--off { color: var(--warn); border-color: var(--warn); }

/* Auto-advance countdown banner (issue 2.2) */
.advance-countdown-bar {
  position: fixed; bottom: 0; left: 0; right: 0; z-index: 900;
  background: var(--panel2); border-top: 1px solid var(--line);
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; padding: .7rem 1.25rem; box-shadow: 0 -4px 12px rgba(0,0,0,.2);
}
.advance-countdown-bar .advance-msg { font-weight: 600; color: var(--warn); }
.advance-countdown-bar .advance-stay { background: transparent; color: var(--text);
  border: 1px solid var(--line); }

/* Schedule strip — daily period timeline on live views */
.schedule-strip {
  display: flex; flex-wrap: nowrap; overflow-x: auto; gap: .5rem;
  padding: .5rem 0 .6rem; margin-bottom: .75rem;
  scrollbar-width: thin;
}
.sched-chip {
  flex: 0 0 auto;
  display: flex; flex-direction: column; align-items: center; gap: .15rem;
  padding: .4rem .75rem; border-radius: var(--radius);
  background: var(--panel2); border: 1px solid var(--line);
  min-width: 7rem; text-align: center;
}
.sched-chip--now {
  background: rgba(74,222,128,.12); border-color: var(--good); color: var(--good);
}
.sched-chip--past { opacity: .4; }
.sched-name { font-weight: 700; font-size: .82rem; }
.sched-time { font-size: .75rem; color: var(--muted); font-variant-numeric: tabular-nums; }
.sched-chip--now .sched-time { color: inherit; }
.sched-countdown {
  font-size: .72rem; font-weight: 700; color: var(--good);
  background: rgba(74,222,128,.15); border-radius: 999px;
  padding: .05rem .4rem; margin-top: .1rem;
}
.sched-countdown--soon { color: var(--warn); background: rgba(245,158,11,.15); }

/* Live-view header row with Modified Bell button */
.live-header {
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: 1rem; margin-bottom: .25rem;
}
.live-header h1 { margin: 0; }
#modified-bell-wrap { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; padding-top: .25rem; }
button.warn { color: var(--warn); border-color: rgba(245,158,11,.4); }

/* Modified bell schedule modal form rows */
.modified-bell-card { max-height: 85vh; overflow-y: auto; }
.modified-bell-row { align-items: flex-end; gap: .75rem; }
.modified-bell-row label { display: flex; flex-direction: column; gap: .2rem;
  font-size: .82rem; color: var(--muted); }
.modified-bell-row input[type="time"] { margin-top: .2rem; }

.login { width: min(390px, 92vw); text-align: center; gap: .8rem; display: flex; flex-direction: column; }
.login label { text-align: left; }
/* "Stay signed in" sits beside its box rather than above it, and gets a
   finger-sized target: this form is used on a phone more than anywhere else. */
.login label.stay-signed-in { flex-direction: row; align-items: center; gap: .55rem;
  min-height: 44px; cursor: pointer; }
/* Shed the app's text-field chrome — the border and inset shadow draw a second
   empty box behind the native tick. */
.login label.stay-signed-in input {
  width: 1.2rem; height: 1.2rem; flex: 0 0 auto; margin: 0; padding: 0;
  border: none; background: none; box-shadow: none; accent-color: var(--accent);
}

/* Tables */
table.roster { width: 100%; border-collapse: collapse; margin: .5rem 0 1rem; }
.roster th, .roster td { text-align: left; padding: .55rem .5rem; border-bottom: 1px solid var(--line); }
.roster th { color: var(--muted); font-size: .8rem; text-transform: uppercase; letter-spacing: .04em;
  position: sticky; top: 0; background: var(--bg); z-index: 1; }
.roster.compact td, .roster.compact th { padding: .4rem .4rem; font-size: .92rem; }
.roster tr.tardy td { background: rgba(245, 158, 11, .08); }
/* Absent students stay readable but visibly recede, so a glance down the live
   board separates who is in the room from who is not. */
.roster tr.absent td { color: var(--muted); background: rgba(120, 120, 130, .10); }
.roster tr.absent td a, .roster tr.absent td strong { color: var(--muted); font-weight: 600; }
.roster tr.absent td .muted, .roster tr.absent td .sub { opacity: .8; }
.roster tr.absent td select, .roster tr.absent td button { opacity: .75; }
.roster tr.absent:hover td select, .roster tr.absent:hover td button,
.roster tr.absent td select:focus, .roster tr.absent td button:focus-visible { opacity: 1; }

/* Inline tag-assignment form in a roster cell (class detail, show roster). */
.row.card-scan-form { gap: .3rem; flex-wrap: nowrap; align-items: center; }

.chips { list-style: none; padding: 0; display: flex; flex-wrap: wrap; gap: .4rem; }
.chips li { background: var(--panel2); padding: .25rem .6rem; border-radius: 999px; font-size: .85rem; }
.list { list-style: none; padding: 0; }
.list li { display: flex; justify-content: space-between; padding: .4rem 0; border-bottom: 1px solid var(--line); }

.pill { display: inline-block; padding: .12rem .55rem; border-radius: 999px; font-size: .78rem; font-weight: 700; background: var(--panel2); color: var(--muted); }
.pill.good { background: rgba(34,197,94,.18); color: var(--good); }
.pill.warn { background: rgba(245,158,11,.18); color: var(--warn); }
.pill.bad  { background: rgba(239,68,68,.18); color: var(--bad); }
.pill.info { background: rgba(56,189,248,.18); color: var(--info); }
.pill.nurse { background: rgba(139,92,246,.18); color: #a78bfa; }
/* NOW badge on class cards (issue 2.1) */
.now-badge { background: rgba(74,222,128,.25); color: var(--good); margin-right: .3rem; }

/* Dashboard */
.dash-head { display: flex; justify-content: space-between; align-items: center; gap: 1rem; }
.dash-head-right { display: flex; flex-direction: column; align-items: flex-end; gap: .5rem; }
.clock { font-variant-numeric: tabular-nums; color: var(--muted); }
.clock.big { font-size: 2rem; font-weight: 700; color: var(--text); }
.counts { display: flex; gap: 1rem; margin: 1rem 0; }
.count { flex: 1; background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); padding: 1rem; text-align: center; box-shadow: var(--shadow); }
.count > span { font-size: 2.4rem; font-weight: 800; display: block; }
.count label { color: var(--muted); }
.count.good span { color: var(--good); } .count.warn span { color: var(--warn); } .count.bad span { color: var(--bad); } .count.info span { color: var(--info); }

/* Period countdown on the class dashboard (issue 3.8) */
.period-countdown {
  font-size: .85rem; color: var(--muted); font-weight: 600;
  padding: .2rem .6rem; border-radius: 999px; background: var(--panel2);
  border: 1px solid var(--line);
}
.period-countdown--soon { color: var(--warn); border-color: rgba(245,158,11,.4); background: rgba(245,158,11,.1); }
/* Before the bell: today's in/out times for the period, then the countdown. */
.period-status { display: flex; flex-direction: column; align-items: center; gap: .2rem; }
.period-times { color: var(--muted); font-size: .72rem; font-weight: 800;
  letter-spacing: .04em; text-transform: uppercase; white-space: nowrap; }
.period-countdown--before { color: var(--info); border-color: rgba(56,189,248,.4);
  background: rgba(56,189,248,.1); }

/* Prominent "currently in the restroom" banner, above the counts */
.restroom-banner { margin: 1rem 0; border: 1px solid var(--info);
  background: rgba(56,189,248,.12); border-radius: var(--radius); padding: .6rem 1rem;
  box-shadow: var(--shadow); }
.rb-row { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; padding: .25rem 0; }
.rb-icon { font-size: 1.5rem; }
.rb-name { font-size: 1.3rem; font-weight: 800; color: var(--info); }
.restroom-banner:has(.rb-row.nurse) { border-color: #8b5cf6; background: rgba(139,92,246,.12); }
.rb-row.nurse .rb-name { color: #a78bfa; }
.restroom-banner .timer { font-size: 1.3rem; margin-left: auto; }
.restroom-banner button { margin-left: .5rem; }

/* Full-screen red flash on the teacher dashboard when a sign-out is blocked */
.screen-flash { position: fixed; inset: 0; z-index: 100; display: flex;
  align-items: center; justify-content: center; text-align: center; padding: 2rem;
  font-size: 2.4rem; font-weight: 800; color: #fff; background: rgba(239,68,68,.92); }
.screen-flash.active { animation: flashpulse .6s steps(1) 6; }
@keyframes flashpulse { 0%,100% { background: rgba(239,68,68,.92); } 50% { background: rgba(239,68,68,.45); } }

/* Clickable attendance-override dropdown on the class dashboard */
.status-select { padding: .25rem 1.6rem .25rem .6rem; border-radius: 999px;
  font-size: .78rem; font-weight: 700; cursor: pointer; border: 1px solid var(--line);
  -webkit-appearance: none; appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath fill='%23888' d='M0 0l5 6 5-6z'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right .55rem center; }
.status-select.on_time { background-color: rgba(74,222,128,.18); color: var(--good); border-color: transparent; }
.status-select.tardy   { background-color: rgba(251,191,36,.18); color: var(--warn); border-color: transparent; }
.status-select.absent  { background-color: rgba(239,68,68,.18); color: var(--bad); border-color: transparent; }
.status-select.excused { background-color: rgba(56,189,248,.18); color: var(--info); border-color: transparent; }
.status-select:focus { outline: 2px solid var(--accent); }
.status-select option { background: var(--panel); color: var(--text); font-weight: 600; }

/* Restroom (away) status on the class dashboard */
.roster tr.out td { background: rgba(56,189,248,.10); }
.roster td.actions { text-align: right; white-space: nowrap; }
.timer { font-variant-numeric: tabular-nums; font-weight: 700; color: var(--info); }
.timer.alert { color: var(--bad); }
/* Restroom timer for a student with an extended-time accommodation */
.timer.acc-timer { color: var(--warn); }
.timer.acc-timer.alert { color: var(--bad); }
.roster tr.alert td { animation: flashred 1s steps(1) infinite; }
@keyframes flashred {
  0%, 100% { background: rgba(239,68,68,.12); }
  50%      { background: rgba(239,68,68,.42); }
}

/* Modal (disruption logging) */
.modal { position: fixed; inset: 0; background: rgba(0,0,0,.68);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  display: flex; align-items: center; justify-content: center; padding: 1rem; z-index: 1200; }
.modal-card { background: var(--panel-raised); border: 1px solid var(--line-strong); border-radius: var(--radius);
  padding: 1.5rem; width: min(520px, 94vw); display: flex; flex-direction: column; gap: 1rem;
  box-shadow: var(--shadow-float); animation: modal-in 200ms var(--ease-fluid);
  /* If the screen is too short for the whole form, scroll inside the card
     instead of letting the Save/Cancel buttons fall off-screen. */
  max-height: 90vh; overflow-y: auto; overscroll-behavior: contain; }
.modal-card h2 { margin: 0; }
.weekly-report-card { border-top: 4px solid var(--accent); }
.weekly-report-card .eyebrow { margin-bottom: -.65rem; }
/* What's-new popup: the release notes for the version just installed. */
.whats-new-card { border-top: 4px solid var(--accent); width: min(640px, 94vw); }
.whats-new-card .eyebrow { margin-bottom: -.65rem; }
.whats-new-version { margin: .2rem 0 -.4rem; font-size: .95rem; color: var(--muted);
  font-family: var(--mono); }
.whats-new-list, .changelog-list { margin: 0; padding-left: 1.1rem;
  display: flex; flex-direction: column; gap: .6rem; }
.whats-new-list li, .changelog-list li { line-height: 1.5; }
.whats-new-list code, .changelog-list code { font-family: var(--mono); font-size: .88em;
  background: var(--panel2); border: 1px solid var(--line); border-radius: 5px;
  padding: .05rem .3rem; }
@keyframes modal-in { from { opacity: 0; transform: translateY(8px) scale(.985); } }
/* Disruption / Recognition toggle in the behavior modal */
.seg { display: flex; gap: .5rem; }
.seg-btn { flex: 1; background: var(--panel2); border: 1px solid var(--line);
  color: var(--muted); border-radius: 8px; padding: .55rem; font-weight: 700; }
.seg-btn.active[data-cat="negative"] { background: rgba(239,68,68,.18);
  border-color: var(--bad); color: var(--bad); }
.seg-btn.active[data-cat="positive"] { background: rgba(34,197,94,.18);
  border-color: var(--good); color: var(--good); }
/* Disruption/Recognition toggle — faint color hint on inactive buttons */
.seg-btn[data-cat="negative"]:not(.active) { color: rgba(239,68,68,.6); }
.seg-btn[data-cat="positive"]:not(.active) { color: rgba(74,222,128,.6); }

.chip-select { display: flex; flex-wrap: wrap; gap: .5rem; }
.chip-toggle { background: var(--panel2); border: 1px solid var(--line); color: var(--text);
  border-radius: 999px; padding: .4rem .8rem; font-weight: 500; font-size: .9rem; }
.chip-toggle.selected { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }

/* Quick-log section in behavior modal (issue 2.4) */
.quick-log-wrap { background: var(--panel2); border-radius: 10px; padding: .7rem .9rem;
  border: 1px dashed var(--line); }
.quick-log-wrap .field-label { margin-bottom: .4rem; }
/* One-tap chips look distinct from the build-an-entry chips below so it's clear
   they save instantly rather than being part of the form selection. */
/* The section heading above these chips already carries the bolt icon, so the
   chip itself needs no repeated glyph — its solid accent border is the cue. */
.quick-chip { border-style: solid; border-color: var(--accent); font-weight: 600; }
.quick-chip:hover { background: var(--accent); color: var(--on-accent); }

/* Inline validation message in behavior modal (issue 1.5) */
.behavior-inline-error { margin: 0; }

/* Read-only "Logged by" field in behavior modal — looks like a label, not an input */
.readonly-display {
  opacity: .6; cursor: default;
  background: var(--panel); border-color: transparent;
  pointer-events: none;
}
.readonly-display:focus { outline: none; box-shadow: none; }

/* Kiosk */
.kiosk-body { background: radial-gradient(circle at 50% 30%, #1e293b, #0f172a);
  /* A kiosk page never scrolls, so a downward swipe on a tablet is always the
     accidental one that reloads it. `none` refuses the pull-to-refresh gesture
     rather than letting a stray finger restart the station. */
  overscroll-behavior-y: none; }
.kiosk { max-width: none; min-height: 100vh; display: flex; flex-direction: column;
  align-items: center; justify-content: center; text-align: center; padding: 2rem; }
.kiosk-header { position: fixed; top: 0; left: 0; right: 0; display: flex; justify-content: space-between;
  align-items: center; padding: 1rem 1.5rem; color: var(--muted); }
.kiosk-brand { display: flex; flex-direction: column; line-height: 1.15; gap: .25rem; }
.kiosk-logo { height: 34px; width: auto; }
/* Whole-screen red flash when a second student tries to leave for the restroom */
.kiosk-body.flash-red { animation: kioskflash .5s steps(1) 6; }
@keyframes kioskflash {
  0%, 100% { background: radial-gradient(circle at 50% 30%, #1e293b, #0f172a); }
  50%      { background: #b91c1c; }
}
.station-mode { font-weight: 700; letter-spacing: .05em; }
.station-mode.shop { color: var(--info); }
.station-mode.universal { color: var(--warn); }
/* Teacher-pairing banner for universal kiosks */
.teacher-banner { position: fixed; top: 4rem; left: 0; right: 0; text-align: center;
  font-size: 1.1rem; font-weight: 700; padding: .35rem 1rem; z-index: 5; }
.teacher-banner.unpaired { background: rgba(251,191,36,.15); color: var(--warn); }
.teacher-banner.paired    { background: rgba(34,197,94,.15);  color: var(--good); }
.kiosk-code { font-size: 1.3rem; letter-spacing: .18em; }
/* A universal kiosk borrowed for a rehearsal by a show's five-digit code. */
.teacher-banner.show-mode { background: rgba(236,0,140,.15); color: #f472b6; }
/* Which course the attendance kiosk is checking in for right now */
.current-course { position: fixed; top: 4.2rem; left: 0; right: 0; text-align: center;
  font-size: 1.5rem; font-weight: 700; color: var(--good); padding: 0 1rem; }
.current-course.none { color: var(--muted); font-weight: 500; }
/* Universal kiosk: push current-course below the teacher banner */
.kiosk-universal .current-course { top: 6.4rem; }
/* Live echo of a typed-in student ID */
.typed-id { margin-top: 1rem; font-size: 2.6rem; font-weight: 800;
  font-variant-numeric: tabular-nums; letter-spacing: .12em; color: var(--text); }
.kiosk-prompt h1 { font-size: 3rem; margin: .3rem 0; }
.tap-icon { font-size: 6rem; line-height: 1; animation: pulse 2s infinite; }
@keyframes pulse { 0%,100% { opacity: .4; transform: scale(1); } 50% { opacity: 1; transform: scale(1.06); } }
#reader { position: fixed; opacity: 0; pointer-events: none; bottom: 0; }
.kiosk .clock { position: fixed; bottom: 1.2rem; font-size: 1.4rem; }

.kiosk-result { padding: 2rem 3rem; border-radius: 20px; min-width: min(560px, 90vw); border: 3px solid var(--line); }
.kiosk-result.good { border-color: var(--good); background: rgba(34,197,94,.12); }
.kiosk-result.warn { border-color: var(--warn); background: rgba(245,158,11,.12); }
.kiosk-result.bad  { border-color: var(--bad);  background: rgba(239,68,68,.12); }
.kiosk-result.info { border-color: var(--info); background: rgba(56,189,248,.12); }
.result-icon { font-size: 4.5rem; line-height: 1; margin-bottom: .3rem; }
.result-name { font-size: 2.6rem; font-weight: 700; margin: .2rem 0; }
.result-big { font-size: 3.5rem; font-weight: 800; letter-spacing: .03em; }
.result-msg { color: var(--muted); font-size: 1.15rem; margin-top: .3rem; }

/* --- On-screen number pad (static/keypad.js) ------------------------------
   Fixed to the bottom of every kiosk so a student with no card can key their
   ID in on a tablet. --keypad-h is what the kiosk shells reserve above it. */
:root { --keypad-h: 20rem; }   /* replaced with the pad's measured height by keypad.js */
.keypad { position: fixed; left: 0; right: 0; bottom: 0; z-index: 20;
  display: flex; flex-direction: column; align-items: center; gap: .5rem;
  padding: .6rem 1rem calc(.6rem + env(safe-area-inset-bottom));
  background: var(--surface); border-top: 1px solid var(--line);
  backdrop-filter: blur(12px); }
.keypad-readout { min-height: 2.6rem; font-size: 2.2rem; font-weight: 800;
  letter-spacing: .14em; font-variant-numeric: tabular-nums; color: var(--text);
  line-height: 1.2; text-align: center; word-break: break-all; }
/* The prompt, shown in place of the digits until something is typed. */
.keypad-readout.empty { font-size: 1rem; font-weight: 600; letter-spacing: .04em;
  color: var(--muted); text-transform: uppercase; }
.keypad-keys { display: grid; grid-template-columns: repeat(3, 1fr); gap: .5rem;
  width: min(30rem, 100%); }
.keypad-key { min-height: 3.4rem; font-size: 1.8rem; font-weight: 700;
  background: var(--panel2); color: var(--text); border: 1px solid var(--line-strong);
  border-radius: var(--control-radius); font-variant-numeric: tabular-nums;
  /* A kiosk is tapped, never selected or long-pressed for a context menu. */
  user-select: none; -webkit-user-select: none; -webkit-touch-callout: none;
  touch-action: manipulation; }
/* Hover is sticky after a tap on a touchscreen, so each key holds its own
   colour rather than taking the global button:hover fill. */
.keypad-key:hover { background: var(--panel2); border-color: var(--line-strong); }
.keypad-key.pressed { background: var(--accent); border-color: var(--accent);
  color: var(--on-accent); transform: scale(.97); }
.keypad-key svg { display: block; margin: 0 auto; }
.keypad-enter, .keypad-enter:hover { background: var(--accent);
  border-color: var(--accent); color: var(--on-accent); }
.keypad-enter { font-size: 1.15rem; letter-spacing: .04em; }

/* Keep the page's own content clear of the pad. The kiosk shell keeps its full
   100vh and centres inside the space the padding leaves, so anything taller
   than that scrolls rather than disappearing under the keys. */
/* pad + the fixed clock that sits just above it, so neither is overlapped. */
body.has-keypad .kiosk { padding-bottom: calc(var(--keypad-h) + 2.75rem); }
/* The two-tap overlays are the tallest thing a kiosk draws, so they give back
   the room the pad takes rather than pushing the page into a scroll. */
body.has-keypad .brain-break-prompt,
body.has-keypad .work-pass-panel { padding: 1.4rem 2rem; gap: .5rem; }
body.has-keypad .bbp-icon { font-size: 3rem; }
body.has-keypad .wpp-icon { font-size: 2.6rem; }
body.has-keypad .bbp-name { font-size: 1.8rem; }
body.has-keypad .kiosk .clock { bottom: calc(var(--keypad-h) + .6rem); }
/* The pad's readout is the live echo of a typed ID, and it stays visible even
   while a result is on screen, so the prompt's own echo would just be a second
   copy of the same digits. It comes back if the pad is ever taken off a page. */
body.has-keypad .typed-id { display: none; }
body.has-keypad .ci { padding-bottom: var(--keypad-h); }
body.has-keypad .offline-badge { bottom: calc(var(--keypad-h) + 1rem); }

@media (max-height: 700px) {
  .keypad-readout { min-height: 2rem; font-size: 1.6rem; }
  .keypad-key { min-height: 2.5rem; font-size: 1.4rem; }
}

/* "Install on this tablet" — only ever rendered by static/pwa_install.js when
   the browser says the page is installable and not already installed. */
.pwa-install { position: fixed; top: 1rem; right: 1rem; z-index: 30;
  min-height: 34px; padding: .3rem .7rem; font-size: .85rem;
  background: rgba(255,255,255,.06); color: var(--text);
  border: 1px solid var(--line-strong); }

/* The shop kiosk's sign-up form takes over the screen and wants the tablet's
   real keyboard for a name, so the number pad steps out of the way. */
body:has(.ci-modal:not(.hidden)) .keypad { display: none; }

/* --- The Activities tab: a teacher's own after-school clubs -------------- */
.af-group { border: 1px solid var(--line); border-radius: var(--control-radius);
  padding: .7rem .9rem; display: flex; flex-direction: column; gap: .5rem; }
.af-group legend { padding: 0 .35rem; font-size: .8rem; font-weight: 700;
  color: var(--muted); text-transform: uppercase; letter-spacing: .05em; }
.af-note { font-size: .82rem; margin: 0; }
.act-today { list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: .45rem; }
.act-today li { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; }
/* Edit and Archive sit side by side. Deliberately not display:flex — that would
   take the cell out of the table layout and let it escape its column. */
.act-actions { white-space: nowrap; }
.act-actions form { display: inline-block; margin-left: .4rem; }
/* The activity form carries two date fields and a day-of-week row, so it gets
   more room than the default modal. */
.activity-card { width: min(40rem, 94vw); }

/* The hall-pass register lists every tag and what it is doing right now, so it
   takes the full width of the admin page rather than one grid column. */
.admin-passes { grid-column: 1 / -1; }

/* Bell schedule */
.bell-day { margin-bottom: 1rem; }
.bell-day-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
.bell-table input[type=time] { width: 100%; }

/* Kiosk manual entry */
.kiosk-link { position: fixed; bottom: 1.2rem; right: 1.5rem; background: none;
  border: 1px solid var(--line); color: var(--muted); font-size: .95rem; }
.manual-box { display: flex; flex-direction: column; gap: 1rem; align-items: center;
  background: var(--panel); border: 1px solid var(--line); border-radius: 16px; padding: 2rem; }
.manual-box input { font-size: 2rem; text-align: center; width: min(360px, 80vw); letter-spacing: .1em; }
.manual-box .row { gap: 1rem; }

/* Student history: flags, summary, inline action forms */
.alert-banner { background: rgba(239,68,68,.12); border: 1px solid var(--bad);
  border-radius: 10px; padding: .7rem 1rem; margin: 1rem 0; display: flex;
  align-items: center; gap: .5rem; flex-wrap: wrap; }
.behavior-summary { margin-bottom: 1rem; }
.summary-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 1rem; margin-top: .5rem; }
.summary-grid > div { background: var(--panel2); border: 1px solid var(--line); border-radius: 10px; padding: .8rem 1rem; }
.summary-grid .big { font-size: 1.8rem; font-weight: 800; display: block; }
.summary-grid .big.good { color: var(--good); }
.summary-grid .big.bad { color: var(--bad); }
.summary-grid label { margin-top: .3rem; }
.trend { font-weight: 700; }
.trend.up { color: var(--bad); }
.trend.up.good { color: var(--good); }
.trend.down { color: var(--good); }
.trend.down.bad { color: var(--bad); }

/* Student history in-page navigation (issue 3.6) */
.history-page-nav {
  display: flex; flex-wrap: wrap; gap: .35rem; margin: 1rem 0 1.25rem;
  padding: .5rem .75rem; background: var(--panel2);
  border-radius: var(--radius); border: 1px solid var(--line);
}
.history-page-nav a {
  color: var(--muted); font-size: .82rem; font-weight: 600;
  padding: .2rem .45rem; border-radius: 5px;
}
.history-page-nav a:hover { color: var(--text); background: var(--panel); text-decoration: none; }

/* Possible-abuse flag dismiss button (issue 3.10) */
.abuse-flag { cursor: default; display: inline-flex; align-items: center; gap: .3rem; }
.abuse-dismiss {
  background: none; border: none; color: inherit; padding: 0 .1rem;
  font-size: .85rem; cursor: pointer; line-height: 1; border-radius: 3px;
  min-width: unset; min-height: unset;
}
.abuse-dismiss:hover { background: rgba(239,68,68,.25); }

/* Student accommodations card */
.accommodation-card { border-color: var(--accent); }
.accommodation-card h2 { color: var(--accent); }

/* Analytics tooltip (issue 4.5) */
.analytics-tooltip {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.1rem; height: 1.1rem; background: var(--panel2); border: 1px solid var(--line);
  border-radius: 50%; font-size: .68rem; cursor: help; vertical-align: middle;
  color: var(--muted); font-weight: 700;
}

/* Inline SVG charts (charts.js): the analytics page's full-width panels and
   the small sparklines on the student/class history pages. */
.chart-region { margin: .6rem 0 .2rem; }
.chart-region svg text { font-family: inherit; }
.trend-spark { display: block; margin-bottom: .35rem; }
.trend-spark svg text { font-family: inherit; }
.class-trend-strip { display: flex; align-items: center; gap: .8rem; flex-wrap: wrap;
  margin: .5rem 0 0; color: var(--muted); }
.class-trend-strip .trend-spark { margin-bottom: 0; }
.trend.flat { color: var(--muted); font-weight: 500; }
.muted.sm, .sm { font-size: .8rem; }
form.inline { display: inline; }
.contact-form { margin-bottom: 1rem; }
.field-label { display: block; font-size: .85rem; color: var(--muted); margin-bottom: .3rem; }
.chip-toggle.radio.selected { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
/* Banner that splits a settings form into clear groups (e.g. "Your live
   dashboard" vs "Alert thresholds"). */
.settings-group-label {
  margin: .55rem 0 0; padding-top: 1.15rem; border-top: 1px solid var(--line);
  font-size: .75rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--accent);
}
.settings-group-label:first-of-type { border-top: none; padding-top: 0; margin-top: 0; }

/* One vertical rhythm for every settings and admin card.
   These cards lay their children out with the flex gap on .stack, and leaving
   the browser's default heading and paragraph margins stacked on top of that
   gap is what made the space between one section and the next uneven — a
   heading after a paragraph got the gap plus two margins, one after a field row
   got the gap alone. Margins off, gap in charge, and one deliberate step down
   before a heading that starts a new section. */
.settings-card-section > h2, .settings-card-section > p,
.admin-card-section > h2, .admin-card-section > p,
.settings-resources .card > h2, .settings-resources .card > p { margin: 0; }
.settings-card-section > h2:not(:first-child),
.admin-card-section > h2:not(:first-child) { margin-top: .85rem; }
/* A heading immediately under a group banner belongs to it, so it stays close. */
.settings-group-label + h2, .settings-group-label + p + h2 { margin-top: .15rem !important; }
.settings-card-section > button[type="submit"] { margin-top: .5rem; align-self: flex-start; }

/* Alert thresholds: four settings that are all "how many, and how recently".
   One row each, so the shape they share is visible instead of being spelled out
   four times under four headings. */
.threshold-grid { display: flex; flex-direction: column; }
.threshold-row {
  display: grid; grid-template-columns: minmax(8rem, 11rem) 1fr; gap: .35rem 1.1rem;
  align-items: start; padding: .8rem 0; border-top: 1px solid var(--line);
}
.threshold-row:first-child { border-top: none; padding-top: .25rem; }
.threshold-name { font-weight: 600; padding-top: 1.35rem; }
.threshold-name .muted { display: block; font-weight: 400; font-size: .8rem; margin-top: .1rem; }
.threshold-fields { display: flex; flex-wrap: wrap; gap: .5rem .9rem; align-items: end; }
.threshold-fields label { display: flex; flex-direction: column; gap: .25rem;
  font-size: .85rem; color: var(--muted); }
.threshold-fields input { width: 6.5rem; }
@media (max-width: 640px) {
  .threshold-row { grid-template-columns: 1fr; padding: .7rem 0; }
  .threshold-name { padding-top: 0; }
}
.quick-flag-picker { display: flex; flex-wrap: wrap; gap: .5rem; }
.quick-flag-choice { display: inline-flex; align-items: center; cursor: pointer; }
.quick-flag-choice input { position: absolute; opacity: 0; pointer-events: none; }
.quick-flag-choice span { padding: .45rem .7rem; border: 1px solid var(--line); border-radius: 999px;
  background: var(--panel2); color: var(--text); }
.quick-flag-choice input:checked + span { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.quick-flag-choice input:focus-visible + span { outline: 2px solid var(--accent); outline-offset: 2px; }
.quick-flag-choice input:disabled + span { cursor: not-allowed; opacity: .5; }

.hidden { display: none !important; }

/* "Other" hall-pass picker popover */
.pass-menu { position: absolute; z-index: 1200; display: flex; flex-direction: column;
  gap: .3rem; background: var(--panel); border: 1px solid var(--line);
  border-radius: 10px; padding: .4rem; box-shadow: var(--shadow); min-width: 9rem; }
.pass-menu .pass-opt { text-align: left; }

/* Concerns cards */
.concern.alert { border-left: 4px solid var(--bad); }
.concern.approaching { border-left: 4px solid var(--warn); }
.concern-head { display: flex; align-items: center; justify-content: space-between; gap: .5rem; }
.concern-head a { font-size: 1.1rem; font-weight: 700; }
.concern-classes { display: flex; flex-wrap: wrap; gap: .3rem; margin: .5rem 0; }
.concern-reasons { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: .3rem; font-size: .9rem; }

/* Tab bar (e.g. dashboard My classes / + New class) */
.tabs { display: flex; gap: .4rem; border-bottom: 1px solid var(--line); margin: 1rem 0; }
.tab-btn { background: transparent; border: none; color: var(--muted); font-weight: 600;
  padding: .5rem .9rem; border-bottom: 2px solid transparent; border-radius: 0; cursor: pointer; }
.tab-btn:hover { color: var(--text); }
.tab-btn.active { color: var(--text); border-bottom-color: var(--accent); }

/* Public shop-hours leaderboard */
.lb-head { text-align: center; margin: 1.5rem 0 1.2rem; }
.lb-head .sdscpa-wordmark { margin: 0 auto .35rem; }
.lb-head .brand-sub { margin: 0 0 .5rem; }
.lb-head h1 { margin: .3rem 0; font-size: 2.2rem; }
.leaderboard { list-style: none; margin: 0 auto; padding: 0; max-width: 1000px;
  display: flex; flex-direction: column; gap: .6rem; }
.lb-row { display: flex; align-items: center; gap: 1rem; background: var(--panel);
  border: 1px solid var(--line); border-radius: var(--radius); padding: .9rem 1.2rem; }
/* Podium places carry rainbow stops in gradient order (the house way of
   colour-coding a small ordered set) rather than the reserved --warn/--good
   semantic tokens, which have to keep meaning "warning" and "success". */
.lb-row.top { border-color: var(--line-strong); box-shadow: var(--shadow); }
.lb-row.top-1 { border-color: var(--sdscpa-green); }
.lb-row.top-2 { border-color: var(--sdscpa-orange); }
.lb-row.top-3 { border-color: var(--sdscpa-red); }
.lb-rank { font-size: 1.6rem; font-weight: 800; color: var(--muted);
  min-width: 2.2rem; text-align: center; }
.lb-row.top-1 .lb-rank { color: var(--sdscpa-green); }
.lb-row.top-2 .lb-rank { color: var(--sdscpa-orange); }
.lb-row.top-3 .lb-rank { color: var(--sdscpa-red); }
.lb-name { flex: 1; font-size: 1.3rem; font-weight: 600; display: flex;
  align-items: center; gap: .6rem; flex-wrap: wrap; }
.lb-in { font-size: .7rem; }
/* Hours are a measurement, not a success state — plain text, not --good. */
.lb-hours { font-size: 1.6rem; font-weight: 800; color: var(--text); }
.lb-hours small { font-size: .8rem; font-weight: 600; color: var(--muted); margin-left: .2rem; }
.muted.sub { font-size: .75rem; }

/* Search / filter boxes (admin student list, class dashboard) */
.search {
  width: 100%; margin: .5rem 0 1rem; padding: .6rem .8rem;
  background: var(--input); border: 1px solid var(--line); border-radius: var(--control-radius);
  color: var(--text); font-size: 1rem;
}
.search:focus { outline: none; border-color: var(--accent); }

/* Logged-in user name in the top nav */
.who { color: var(--muted); font-size: .85rem; white-space: nowrap; }

/* Account dropdown in the nav */
.account { position: relative; }
.account-btn { background: rgba(255,255,255,.045); color: var(--text); border: 1px solid var(--line);
  font-size: .85rem; padding: .3rem .7rem; border-radius: 999px; cursor: pointer; font-weight: 600; }
.account-btn:hover { filter: brightness(1.12); }
.account-dropdown { position: absolute; right: 0; top: calc(100% + .4rem); z-index: 1100;
  background: var(--surface); border: 1px solid var(--line-strong); border-radius: var(--control-radius);
  -webkit-backdrop-filter: blur(22px) saturate(1.2); backdrop-filter: blur(22px) saturate(1.2);
  box-shadow: var(--shadow-float); min-width: 12rem; padding: .35rem; display: flex; flex-direction: column; }
.account-dropdown a { color: var(--text); padding: .55rem .7rem; border-radius: 7px; white-space: nowrap; }
.account-dropdown a:hover { background: var(--panel2); text-decoration: none; }
/* Theme picker inside account dropdown (issue 3.13) */
.dropdown-divider { border: none; border-top: 1px solid var(--line); margin: .25rem 0; }
.dropdown-theme { display: flex; align-items: center; gap: .5rem;
  padding: .4rem .7rem; font-size: .85rem; color: var(--muted); }
.dropdown-label { white-space: nowrap; }
.theme-select-inline {
  flex: 1; padding: .2rem .4rem; font-size: .8rem; border-radius: 6px;
  background: var(--panel2); color: var(--muted); border: 1px solid var(--line);
}
label.inline { display: inline-flex; flex-direction: row; align-items: center;
  gap: .25rem; font-size: .85rem; }

/* Dashboard notification toasts */
.toast-stack {
  position: fixed; top: 1rem; right: 1rem; z-index: 1000;
  display: flex; flex-direction: column; gap: .5rem; max-width: 360px;
}
.toast {
  display: flex; align-items: center; gap: .6rem;
  background: var(--panel2); border: 1px solid var(--line);
  border-left: 4px solid var(--bad); border-radius: 10px;
  padding: .7rem .9rem; box-shadow: var(--shadow);
  animation: toast-in .25s ease-out;
}
.toast.warn { border-left-color: var(--warn); }
.toast.ok { border-left-color: var(--good); }
.toast.ok .toast-icon { color: var(--good); }
.toast.fade { opacity: 0; transition: opacity .6s ease; }
.toast-icon { font-size: 1.1rem; }
.toast-close {
  margin-left: auto; background: none; border: none; color: var(--muted);
  cursor: pointer; font-size: 1rem; padding: 0 .2rem;
}
.toast-close:hover { color: var(--text); }
@keyframes toast-in { from { transform: translateX(20px); opacity: 0; } to { transform: none; opacity: 1; } }

/* -----------------------------------------------------------------------
   Refused hall passes (class view)
   -----------------------------------------------------------------------
   A pass turns a student away at the kiosk; this is where the teacher finds
   out. Bigger and longer-lived than a toast — it is read from across a room,
   often while the teacher is mid-sentence — and it sits top-centre rather than
   in the toast corner so the two never stack on top of one another. */
.pass-alerts {
  /* Clear of the sticky top bar rather than over it — the alert is loud, but
     it must not swallow the nav for the 45 seconds it is up. --topbar-h is
     measured by now_bar.js; the fallback covers the moment before it runs. */
  position: fixed; top: calc(var(--topbar-h, 58px) + .6rem);
  left: 50%; transform: translateX(-50%);
  z-index: 1001; display: flex; flex-direction: column; gap: .5rem;
  width: min(30rem, calc(100vw - 2rem)); pointer-events: none;
}
.pass-alert {
  pointer-events: auto;
  display: flex; align-items: flex-start; gap: .7rem;
  background: var(--panel2); border: 1px solid var(--warn);
  border-left: 5px solid var(--warn); border-radius: 12px;
  padding: .8rem 1rem; box-shadow: var(--shadow);
  animation: pass-alert-in .25s ease-out;
}
.pass-alert.fade { opacity: 0; transition: opacity .4s ease; }
.pass-alert-icon { color: var(--warn); flex: 0 0 auto; line-height: 1; }
.pass-alert-body { display: flex; flex-direction: column; gap: .15rem; min-width: 0; }
.pass-alert-body strong { font-size: 1.02rem; }
.pass-alert-why { color: var(--warn); font-weight: 700; font-size: .92rem; }
.pass-alert-detail { color: var(--muted); font-size: .85rem; }
.pass-alert-when { color: var(--muted); font-size: .78rem; }
/* The teacher's answer to the refusal: let the student go anyway. */
.pass-alert-actions { display: flex; flex-wrap: wrap; gap: .4rem; margin-top: .35rem; }
.pass-alert-actions:empty { display: none; }
.pass-alert-actions button { border-color: var(--warn); }
.pass-alert.allowed { border-color: var(--good); border-left-color: var(--good); }
.pass-alert.allowed .pass-alert-icon, .pass-alert.allowed .pass-alert-why { color: var(--good); }
.pass-alert-allowed {
  display: inline-flex; align-items: center; gap: .3rem;
  color: var(--good); font-weight: 700; font-size: .9rem;
}
.pass-alert-close {
  margin-left: auto; flex: 0 0 auto; background: none; border: none;
  color: var(--muted); cursor: pointer; font-size: 1.2rem; padding: 0 .2rem;
}
.pass-alert-close:hover { color: var(--text); background: none; }
@keyframes pass-alert-in { from { transform: translateY(-12px); opacity: 0; } to { transform: none; opacity: 1; } }

@media (max-width: 760px) {
  .pass-alerts { width: calc(100vw - 1rem); }
}

/* Collapsible create/add forms */
details > summary { cursor: pointer; padding: .25rem 0; user-select: none; }
details[open] > summary { margin-bottom: .5rem; }
.card-actions { margin: .5rem 0 0; font-size: .85rem; }

/* ----------------------------------------------------------------------- */
/* Mobile / tablet layout                                                   */
/* ----------------------------------------------------------------------- */
@media (max-width: 760px) {
  .topbar { flex-wrap: wrap; gap: .5rem .75rem; padding: .6rem .9rem; }
  .topbar .links { display: flex; flex-wrap: wrap; gap: .2rem .7rem; width: 100%; }
  .topbar .links a { margin-left: 0; min-height: 36px; display: inline-flex; align-items: center; }
  .brand-logo { height: 24px; }
  .sdscpa-wordmark { height: 27px; }
  .brand-sub { font-size: .58rem; letter-spacing: .14em; }
  .container { padding: 1rem .9rem; }
  .center-card { padding: 1rem; }

  /* Attendance count tiles: 2-up instead of a cramped single row */
  .counts { flex-wrap: wrap; gap: .6rem; }
  .count { flex: 1 1 40%; padding: .7rem; }
  .count span { font-size: 1.9rem; }

  .dash-head { flex-wrap: wrap; gap: .5rem; align-items: flex-start; }
  .clock.big { font-size: 1.5rem; }

  /* Wide tables scroll sideways rather than overflowing the screen */
  table.roster { display: block; overflow-x: auto; -webkit-overflow-scrolling: touch; }

  .row { gap: .5rem; }
  .row > label, .row > input, .row > select { flex: 1 1 100%; }
  .modal-card { padding: 1rem; width: 96vw; }

  .lb-name { font-size: 1.1rem; } .lb-hours { font-size: 1.35rem; }
  .toast-stack { left: 1rem; right: 1rem; max-width: none; }

  /* Kiosk text scales down so it fits a phone/small tablet */
  .kiosk-prompt h1 { font-size: 2.2rem; }
  .tap-icon { font-size: 4.5rem; }
  .result-big { font-size: 2.4rem; }
  .result-name { font-size: 1.8rem; }
  .result-icon { font-size: 3.2rem; }
}

/* Phone view (compact live class with big touch buttons) */
.phone-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
.phone-list { display: flex; flex-direction: column; gap: .6rem; }
.pcard { background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  padding: .8rem 1rem; }
.pcard.out { border-color: var(--info); background: rgba(56,189,248,.10); }
.pcard.out.nurse { border-color: #8b5cf6; background: rgba(139,92,246,.10); }
.pname { font-size: 1.25rem; font-weight: 700; display: flex; align-items: center;
  gap: .5rem; flex-wrap: wrap; margin-bottom: .5rem; }
.pname .timer { margin-left: auto; }
.pbtns { display: flex; gap: .6rem; }
button.big { flex: 1; padding: 1rem; font-size: 1.1rem; border-radius: 12px; }
button.big.restroom { background: var(--info); border-color: var(--info); }
button.big.nurse { background: #8b5cf6; border-color: #8b5cf6; }
button.big.ghost { width: 100%; }

/* Kiosk offline indicator */
.offline-badge {
  position: fixed; bottom: 1rem; left: 50%; transform: translateX(-50%);
  background: var(--warn); color: #1a1a1a; font-weight: 700;
  padding: .5rem 1rem; border-radius: var(--radius); box-shadow: var(--shadow);
  z-index: 1000;
}

/* -----------------------------------------------------------------------
   Brain Break feature
   ----------------------------------------------------------------------- */

/* Brain break colour token — purple, distinct from nurse/restroom */
:root { --brain-break: #a78bfa; --brain-break-bg: rgba(167,139,250,.18); }

.pill.brain-break { background: var(--brain-break-bg); color: var(--brain-break); }

/* Stat badge on student history */
.count.brain-break span { color: var(--brain-break); }

/* Brain break timer in dashboard roster */
.timer.brain-break-timer { color: var(--brain-break); }
.timer.brain-break-timer.alert { color: var(--bad); }

/* Banner row for brain-break student */
.rb-row.brain-break .rb-name { color: var(--brain-break); }
.restroom-banner:has(.rb-row.brain-break) { border-color: var(--brain-break);
  background: var(--brain-break-bg); }

/* Phone card */
.pcard.out.brain-break { border-color: var(--brain-break); background: var(--brain-break-bg); }


/* Kiosk brain break confirmation overlay */
.brain-break-prompt {
  display: flex; flex-direction: column; align-items: center; gap: .75rem;
  padding: 2.5rem 3rem; border-radius: 20px; border: 3px solid var(--brain-break);
  background: var(--brain-break-bg); min-width: min(560px, 90vw); text-align: center;
}
.bbp-icon { font-size: 5rem; line-height: 1; }
.bbp-name { font-size: 2.4rem; font-weight: 700; color: var(--brain-break); }
.bbp-msg { font-size: 1.4rem; }
.bbp-action { font-size: 1.2rem; line-height: 1.5; }
.bbp-timer {
  font-size: 3rem; font-weight: 800; font-variant-numeric: tabular-nums;
  color: var(--brain-break); min-width: 2.5rem; text-align: center;
}

/* Kiosk work-pass group checkout panel: stays open across many scans. */
.work-pass-panel {
  display: flex; flex-direction: column; align-items: center; gap: .6rem;
  padding: 2.5rem 3rem; border-radius: 20px; border: 3px solid var(--accent);
  background: var(--panel2); min-width: min(560px, 90vw); max-width: 90vw;
  text-align: center;
}
.wpp-icon { font-size: 4rem; line-height: 1; }
.wpp-title { font-size: 1.8rem; font-weight: 700; color: var(--accent); }
.wpp-roster {
  list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap;
  gap: .5rem; justify-content: center; max-height: 30vh; overflow-y: auto;
}
.wpp-roster li {
  font-size: 1.1rem; padding: .3rem .8rem; border-radius: 999px;
  background: var(--panel); border: 1px solid var(--line);
}
.wpp-msg { font-size: 1.2rem; }

/* ========================================================================= */
/* Production project-management board (/management)                         */
/* ========================================================================= */
.mgmt-head { display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: .6rem 1rem; margin-bottom: .5rem; }
.mgmt-head h1 { margin: 0; }
.mgmt-monthnav { display: flex; align-items: center; gap: .5rem; }
.mgmt-month { font-weight: 700; font-size: 1.05rem; min-width: 9rem; text-align: center; }
.mgmt-actions { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.btn-link.ghost-link { background: rgba(255,255,255,.035); color: var(--text); border: 1px solid var(--line-strong); }
.btn-link.ghost-link:hover { background: rgba(255,255,255,.075); border-color: var(--line-strong); }
.crumb { margin: 0 0 .5rem; }
.proj-desc { margin: .2rem 0 1rem; }
.mgmt-sec { border-bottom: 1px solid var(--line); padding-bottom: .35rem; margin: 1.6rem 0 .9rem; }
/* The date heading inside .mgmt-head carries no rule or margins of its own. */
.mgmt-sec.bare { border: 0; margin: 0; }
.mgmt-legend { display: flex; align-items: center; flex-wrap: wrap; gap: .6rem; margin: .3rem 0 1rem; }

/* Open-shop tags (calendar + legend) */
.shopchip { display: inline-flex; align-items: center; gap: .25rem; font-size: .64rem;
  padding: .06rem .32rem; border-radius: 5px; line-height: 1.35; white-space: nowrap;
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; font-weight: 600; }
.shopchip.free { background: rgba(34,197,94,.16); color: var(--good); }
.shopchip.help { background: rgba(251,191,36,.18); color: var(--warn); }
.shopchip.club { background: rgba(139,92,246,.20); color: var(--violet); }
.shopchip-time { opacity: .8; font-weight: 500; }
.shopdot { display: inline-block; width: .55rem; height: .55rem; border-radius: 50%; flex-shrink: 0; }

/* Month calendar grid */
.cal { margin: .4rem 0 1rem; }
.cal-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 4px; }
/* Sat/Sun revealed by the board's toggle, or by a weekend that has a call. */
.cal-with-weekend .cal-grid { grid-template-columns: repeat(7, 1fr); }
.cal-cell.cal-weekend { background: var(--input); }
.cal-weekhead { margin-bottom: 4px; }
.cal-hd { text-align: center; color: var(--muted); font-size: .7rem; text-transform: uppercase;
  letter-spacing: .04em; padding: .2rem 0; }
.cal-cell { background: var(--panel); border: 1px solid var(--line); border-radius: 8px;
  min-height: 94px; padding: .3rem; display: flex; flex-direction: column; gap: .2rem; overflow: hidden; }
.cal-cell.cal-editable { cursor: pointer; }
.cal-cell.cal-editable:hover, .cal-cell.cal-editable:focus { border-color: var(--accent); outline: none; }
.cal-out { opacity: .45; }
.cal-today { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
.cal-daynum { font-size: .8rem; color: var(--muted); font-weight: 700; }
.cal-today .cal-daynum { color: var(--accent); }
.cal-chips { display: flex; flex-direction: column; gap: 2px; overflow: hidden; }

/* Active-work board (grouped by shop). align-items:start lets a shop with no
   active work shrink to its own height instead of stretching to match the
   busiest column, which left tall empty panels down the row. */
.board { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: 1rem; margin-bottom: 1rem; align-items: start; }
.board-col { background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  padding: .9rem; }
.board-col-h { display: flex; align-items: center; gap: .4rem; font-size: 1rem; margin: 0 0 .6rem;
  border-bottom: 1px solid var(--line); padding-bottom: .4rem; }
.board-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .6rem; }
.board-item { background: var(--panel2); border: 1px solid var(--line); border-left: 3px solid transparent;
  border-radius: 10px; padding: .55rem .65rem; display: flex; flex-direction: column; gap: .35rem; }
.board-item.overdue { border-left-color: var(--bad); }
.board-item-title { font-weight: 600; font-size: .92rem; }
.board-item-meta { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; font-size: .78rem; }
.board-empty { font-size: .85rem; }
.due { color: var(--warn); font-size: .8rem; font-weight: 600; white-space: nowrap; }
.overdue .due, .due.overdue { color: var(--bad); }

/* Project list */
.proj-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .4rem; }
.proj-row { display: flex; align-items: center; gap: .6rem; padding: .5rem .7rem;
  background: var(--panel); border: 1px solid var(--line); border-left: 3px solid transparent;
  border-radius: 10px; }
.proj-row.overdue { border-left-color: var(--bad); }

/* Day editor + form fields */
.day-row { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.day-row-name { min-width: 8rem; }
.field { display: flex; flex-direction: column; gap: .25rem; font-size: .85rem; color: var(--muted); }
.modal-actions { display: flex; gap: .6rem; align-items: center; justify-content: flex-end; flex-wrap: wrap; }
.modal-delete { margin-top: -.2rem; }

/* Task pipeline */
.pipeline { display: flex; flex-wrap: wrap; align-items: center; gap: .3rem; margin: .5rem 0; }
.stage { display: inline-flex; align-items: center; gap: .3rem; font-size: .8rem; padding: .2rem .55rem;
  border-radius: 999px; border: 1px solid var(--line); background: var(--panel2); color: var(--muted); }
.stage-done { color: var(--good); border-color: rgba(34,197,94,.45); }
.stage-active { color: var(--text); background: rgba(59,130,246,.14); border-color: var(--accent); font-weight: 700; }
.stage-pending { opacity: .65; }
.stage-arrow { color: var(--muted); }

.task-card.task-done { opacity: .72; }
.task-head { display: flex; align-items: baseline; justify-content: space-between; gap: .6rem; flex-wrap: wrap; }
.task-head h3 { margin: 0; }
.task-actions { display: flex; gap: .5rem; flex-wrap: wrap; align-items: center; margin-top: .6rem; }
.file-list { list-style: none; margin: .4rem 0; padding: 0; display: flex; flex-direction: column; gap: .3rem; }
.file-list li { display: flex; align-items: center; gap: .5rem; font-size: .9rem; }
.upload-row { margin-top: .6rem; }

/* Ordered team-sequence builder */
.seq-builder { background: var(--panel2); border: 1px solid var(--line); border-radius: 10px;
  padding: .7rem; display: flex; flex-direction: column; gap: .5rem; }
.seq-label { font-weight: 600; font-size: .85rem; }
.seq-add { align-items: center; }
.seq-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .35rem; }
.seq-step { display: flex; align-items: center; gap: .5rem; background: var(--panel);
  border: 1px solid var(--line); border-radius: 8px; padding: .3rem .5rem; }
.seq-step-name { flex: 1; font-size: .9rem; }
.seq-step-btns { display: flex; gap: .25rem; }
.seq-empty { font-size: .82rem; margin: .1rem 0 0; }
button.xs { padding: .12rem .42rem; font-size: .74rem; line-height: 1; }
button.xs:disabled { opacity: .4; cursor: default; }

@media (max-width: 640px) {
  .cal-cell { min-height: 66px; padding: .2rem; }
  .cal-daynum { font-size: .7rem; }
  .shopchip { font-size: .55rem; padding: .04rem .25rem; }
  .mgmt-head { align-items: flex-start; }
  .day-row-name { min-width: 100%; }
}

/* Student-facing board (/pm): branded header shown in place of the staff nav */
.pm-header { display: flex; align-items: center; gap: .75rem; flex-wrap: wrap;
  position: relative; padding-bottom: .8rem; margin-bottom: 1.1rem; }
.pm-header::after { content: ""; position: absolute; left: 0; bottom: 0;
  height: 2px; width: 160px; border-radius: 99px; background: var(--rainbow); }
.pm-header-title { font-size: .72rem; text-transform: uppercase; letter-spacing: .16em;
  color: var(--muted); }

/* Part quantity (×N) */
.qty { display: inline-block; font-size: .72rem; font-weight: 700; color: var(--accent);
  background: rgba(59,130,246,.14); padding: .02rem .34rem; border-radius: 5px; }
.qty-input { width: 5rem; }

/* Day templates modal */
.modal-section { border-top: 1px solid var(--line); padding-top: .9rem; margin-top: .2rem; }
.modal-section:first-of-type { border-top: none; padding-top: 0; }
.modal-section h3 { margin: 0 0 .3rem; }
.tpl-head { display: flex; align-items: center; justify-content: space-between; gap: .5rem; }
.tpl-list { list-style: none; margin: .5rem 0 0; padding: 0; display: flex; flex-direction: column; gap: .4rem; }
.tpl-row { display: flex; align-items: center; justify-content: space-between; gap: .5rem;
  background: var(--panel2); border: 1px solid var(--line); border-radius: 8px; padding: .4rem .6rem; }
.tpl-row-name { font-weight: 600; }
.tpl-row-btns { display: flex; align-items: center; gap: .35rem; }
.weekday-row { display: flex; flex-wrap: wrap; gap: .35rem .9rem; }

/* Send-one / send-all advance controls */
.advance-btns { display: flex; flex-wrap: wrap; gap: .4rem; }
.advance-count { width: 4.25rem; padding: .35rem .45rem; }
.advance-form.is-busy { opacity: .6; pointer-events: none; }
.stage-count { font-weight: 700; font-size: .78rem; background: rgba(0,0,0,.25);
  border-radius: 5px; padding: 0 .35rem; }
html[data-theme="light"] .stage-count { background: rgba(0,0,0,.08); }
.stage-advance { display: flex; align-items: center; flex-wrap: wrap; gap: .4rem;
  width: 100%; }
.stage-advance .muted { min-width: 8rem; }

/* Production account shop-approval checkboxes (Admin) */
.shop-approve { display: flex; flex-wrap: wrap; gap: .2rem .8rem; align-items: center;
  background: var(--panel2); border: 1px solid var(--line); border-radius: 8px; padding: .4rem .6rem; }

/* Project start-date / dependency status */
.proj-blocked { color: var(--violet); font-size: .8rem; font-weight: 600; white-space: nowrap; }
.proj-row.blocked, .board-item.blocked { opacity: .85; }
.day-times { display: flex; gap: .4rem; align-items: center; flex-wrap: wrap; }
.day-times.hidden { display: none; }

/* Announcement banner */
.mgmt-announce { background: rgba(139,92,246,.12); border: 1px solid var(--violet);
  border-radius: 10px; padding: .5rem .8rem; margin: .3rem 0 .8rem; font-weight: 600;
  display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; }
.mgmt-announce.muted { background: var(--panel2); border-color: var(--line); font-weight: 400; }

/* "Today" strip */
.today-strip { display: flex; align-items: center; flex-wrap: wrap; gap: .4rem .6rem;
  background: var(--panel); border: 1px solid var(--line); border-radius: 10px;
  padding: .55rem .75rem; margin-bottom: .8rem; }
.today-chip { display: inline-flex; align-items: center; gap: .3rem; font-size: .82rem;
  padding: .15rem .55rem; border-radius: 999px; }
.today-chip.free { background: rgba(34,197,94,.16); color: var(--good); }
.today-chip.help { background: rgba(251,191,36,.18); color: var(--warn); }
.today-chip.club { background: rgba(139,92,246,.20); color: var(--violet); }

/* "My shop" filter dimming */
.shop-filter { font-size: .82rem; color: var(--muted); }
[data-dept].dimmed { opacity: .18; }
.board-col[data-dept].dimmed { opacity: .32; }
.mode-ico { font-size: .9em; }

/* Progress bar + step line on board items */
.board-item-step { font-size: .76rem; color: var(--muted); }
.progress-bar { height: 6px; background: var(--panel); border: 1px solid var(--line);
  border-radius: 99px; overflow: hidden; }
.progress-bar > span { display: block; height: 100%; background: var(--rainbow); border-radius: 99px; }
.proj-progress { margin: .2rem 0 1rem; max-width: 340px; display: flex; flex-direction: column; gap: .25rem; }

/* TV / hallway display (/tv) */
.tv { max-width: 1400px; margin: 0 auto; padding: 1.5rem 2rem; }
.tv-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding-bottom: .7rem; margin-bottom: 1rem; position: relative; }
.tv-head::after { content: ""; position: absolute; left: 0; bottom: -1px; height: 3px;
  width: 220px; background: var(--rainbow); border-radius: 99px; }
.tv-date { font-size: 2rem; font-weight: 800; }
.tv-announce { background: rgba(139,92,246,.16); border: 2px solid var(--violet);
  border-radius: 12px; padding: .8rem 1.1rem; font-size: 1.6rem; font-weight: 700; margin-bottom: 1.2rem; }
.tv-h { font-size: 1.2rem; text-transform: uppercase; letter-spacing: .12em; color: var(--muted);
  margin: 1.2rem 0 .6rem; }
.tv-shops { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 1rem; }
.tv-shop { background: var(--panel); border: 1px solid var(--line); border-left: 8px solid var(--sc);
  border-radius: 14px; padding: 1rem 1.2rem; display: flex; flex-direction: column; gap: .15rem; }
.tv-shop-icon { font-size: 2.4rem; line-height: 1; }
.tv-shop-name { font-size: 1.55rem; font-weight: 800; }
.tv-shop-mode { font-size: 1.15rem; font-weight: 600; }
.tv-shop-time { font-size: 1.25rem; color: var(--muted); font-family: var(--mono); }
.tv-work { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 1rem; }
.tv-work-col { background: var(--panel); border: 1px solid var(--line); border-radius: 12px; padding: .8rem 1rem; }
.tv-work-shop { font-size: 1.3rem; font-weight: 800; margin-bottom: .4rem; }
.tv-work-item { font-size: 1.1rem; padding: .25rem 0; border-top: 1px solid var(--line); }
.tv-none { font-size: 1.3rem; color: var(--muted); }

/* Shop check-in kiosk (/shopcheck) */
.reader-hidden { position: fixed; top: 0; left: 0; width: 1px; height: 1px; opacity: 0; border: 0; padding: 0; }
.ci { max-width: 1100px; margin: 0 auto; padding: 1.2rem 1.5rem; text-align: center; }
.ci-head { display: flex; align-items: baseline; justify-content: center; gap: 1rem; flex-wrap: wrap; margin-bottom: .8rem; }
.ci-title { font-size: 1.8rem; font-weight: 800; }
.ci-date { font-size: 1.1rem; color: var(--muted); font-family: var(--mono); }
/* When the shop's sign-in window is limited, the kiosk says when it opens. */
.ci-opens { font-size: 1.1rem; font-weight: 700; color: var(--warn); }
/* A universal kiosk standing in the shop: the way back to its classroom. */
.ci-back { text-align: center; font-size: 1.1rem; font-weight: 700; padding: .35rem 1rem;
  background: rgba(56,189,248,.15); color: var(--info); }
.ci-universal { padding-top: .8rem; }
.ci-prompt { font-size: 1.4rem; font-weight: 600; padding: 1rem; background: var(--panel);
  border: 1px solid var(--line); border-radius: 12px; margin-bottom: 1rem; }
.ci-pick { font-size: 1.5rem; font-weight: 700; padding: 1rem; background: rgba(59,130,246,.14);
  border: 2px solid var(--accent); border-radius: 12px; margin-bottom: 1rem; }
.ci-result { padding: 1.4rem; border-radius: 14px; margin-bottom: 1rem; border: 2px solid var(--line); }
.ci-result.good { background: rgba(34,197,94,.16); border-color: var(--good); }
.ci-result.warn { background: rgba(251,191,36,.18); border-color: var(--warn); }
.ci-result.info { background: rgba(59,130,246,.14); border-color: var(--accent); }
.ci-result.bad  { background: rgba(239,68,68,.16); border-color: var(--bad); }
.ci-name { font-size: 1.6rem; font-weight: 800; }
.ci-big { font-size: 2.2rem; font-weight: 900; letter-spacing: .04em; }
.ci-shopname { font-size: 1.4rem; font-weight: 700; }
.ci-msg { font-size: 1.1rem; color: var(--muted); }
.ci-shops { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 1rem; }
.ci-shop { text-align: left; background: var(--panel); border: 1px solid var(--line);
  border-left: 8px solid var(--sc); border-radius: 14px; padding: 1rem 1.1rem; cursor: pointer;
  color: var(--text); display: flex; flex-direction: column; gap: .25rem; }
.ci-shop:hover { border-color: var(--accent); }
.ci-shop.pickable { box-shadow: 0 0 0 2px var(--accent); }
.ci-shop.armed { box-shadow: 0 0 0 3px var(--good); }
.ci-shop-top { display: flex; align-items: center; gap: .5rem; }
.ci-num { display: inline-flex; align-items: center; justify-content: center; width: 2rem; height: 2rem;
  border-radius: 8px; background: var(--sc); color: #fff; font-weight: 900; font-size: 1.1rem; }
.ci-icon { font-size: 1.8rem; }
.ci-shop-name { font-size: 1.3rem; font-weight: 800; }
.ci-shop-mode { font-size: .9rem; color: var(--muted); }
.ci-work { list-style: none; margin: .3rem 0 0; padding: 0; font-size: .92rem; display: flex; flex-direction: column; gap: .15rem; }
.ci-work li { border-top: 1px solid var(--line); padding-top: .2rem; }
.ci-nowork { font-size: .85rem; }
.ci-none { font-size: 1.3rem; color: var(--muted); grid-column: 1 / -1; }
/* Sign-up popup for a student the system doesn't know yet. Sized for a
   touchscreen: the type is kiosk-sized and every target clears 44px. */
.ci-modal { position: fixed; inset: 0; z-index: 60; display: flex; align-items: center;
  justify-content: center; padding: 1.5rem; background: rgba(0,0,0,.72); }
.ci-modal-card { width: min(640px, 100%); max-height: 92vh; overflow-y: auto; padding: 1.6rem;
  background: var(--panel); border: 2px solid var(--accent); border-radius: 16px;
  box-shadow: var(--shadow-float); }
.ci-modal-card h2 { margin: 0 0 .5rem; font-size: 1.7rem; }
.ci-modal-card p { font-size: 1.05rem; }
.ci-reg-code { margin: .4rem 0 1rem; padding: .7rem 1rem; font-family: var(--mono);
  font-size: 2rem; font-weight: 800; text-align: center; letter-spacing: .06em;
  background: var(--panel2); border: 1px solid var(--line-strong); border-radius: 12px; }
.ci-reg-field { display: flex; flex-direction: column; gap: .3rem; margin-bottom: .9rem;
  font-size: 1rem; font-weight: 700; }
.ci-reg-field input { padding: .8rem; font-size: 1.3rem; }
.ci-reg-label { margin: 0 0 .4rem; font-weight: 700; }
.ci-reg-grades { display: flex; flex-wrap: wrap; gap: .5rem; margin-bottom: 1rem; }
/* Unpicked grades read as outlines so the chosen one is the only filled key. */
.ci-reg-grade { min-width: 3.6rem; min-height: 3.2rem; font-size: 1.3rem; font-weight: 800;
  color: var(--text); background: rgba(255,255,255,.035); border-color: var(--line-strong); }
.ci-reg-grade:hover { background: rgba(255,255,255,.09); border-color: var(--accent); }
.ci-reg-grade.selected { color: var(--on-accent); background: var(--accent); border-color: var(--accent); }
.ci-reg-grade.selected:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
.ci-reg-actions { display: flex; justify-content: flex-end; gap: .6rem; }
.ci-reg-actions button { min-height: 3rem; padding: .7rem 1.2rem; font-size: 1.05rem; }
.ci-reg-error { margin: 0 0 .8rem; padding: .6rem .8rem; color: var(--bad); font-weight: 700;
  background: rgba(237,28,69,.12); border: 1px solid var(--bad); border-radius: 10px; }
/* Kiosk sign-ups waiting for staff to check them: amber, not alarming — the
   student is already checked in, this is a to-do rather than a failure. */
.card.needs-review { border-color: var(--warn); background:
  linear-gradient(145deg, rgba(247,148,30,.09), transparent 45%), var(--panel); }
.card.needs-review h2 { display: flex; align-items: center; gap: .45rem; color: var(--warn); }

/* IMIN after-school activities: 1080p TV display + isolated editor. */
.imin-tv-body, .imin-admin-body { --imin-cyan: #00AEEF; --imin-orange: #F7941E; }
.imin-tv-body { overflow: hidden; background-color: var(--bg); background-image:
  radial-gradient(circle at 5% -5%, rgba(0,174,239,.14), transparent 36rem),
  radial-gradient(circle at 95% -10%, rgba(146,39,143,.13), transparent 38rem); }
.imin-screen { width: 100vw; height: 100vh; padding: 1.1rem 1.5rem; display: grid;
  grid-template-rows: auto minmax(0, 1.08fr) minmax(0, .92fr); gap: .65rem; }
.imin-tv-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  border-bottom: 3px solid transparent; border-image: var(--rainbow) 1; padding-bottom: .55rem; }
.imin-title-lockup { display: flex; align-items: center; gap: .8rem; }
.imin-title-lockup > div { display: flex; flex-direction: column; }
.imin-title-lockup strong { font-size: 1.55rem; line-height: 1.1; }
.imin-title-lockup span { color: var(--muted); text-transform: uppercase; letter-spacing: .14em; font-size: .64rem; }
.imin-today { font-size: 1.25rem; font-weight: 800; }
.imin-next, .imin-month { min-height: 0; display: flex; flex-direction: column; }
.imin-next h1, .imin-month h2 { font-size: .88rem; line-height: 1; text-transform: uppercase;
  letter-spacing: .16em; color: var(--muted); margin: .2rem 0 .45rem;
  background: none; -webkit-text-fill-color: currentColor; }
.imin-month h2 span { font-weight: 400; }
.imin-ten-grid { min-height: 0; flex: 1; display: grid; grid-template-columns: repeat(5, 1fr);
  grid-template-rows: repeat(2, minmax(0, 1fr)); gap: .45rem; }
.imin-day-card { min-width: 0; min-height: 0; overflow: hidden;
  background: linear-gradient(145deg, rgba(255,255,255,.025), transparent 50%), var(--panel);
  border: 1px solid var(--line); border-radius: var(--control-radius); padding: .42rem .52rem;
  box-shadow: 0 8px 22px rgba(0,0,0,.18); }
.imin-day-card.is-today { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
.imin-day-card > header { display: flex; justify-content: space-between; align-items: baseline;
  border-bottom: 1px solid var(--line); padding-bottom: .2rem; margin-bottom: .25rem; }
.imin-day-card > header span { text-transform: uppercase; letter-spacing: .11em; color: var(--muted); font-size: .72rem; }
.imin-day-card > header strong { font-size: 1rem; }
.imin-day-events { display: flex; flex-direction: column; gap: .25rem; }
.imin-event { border-left: 3px solid var(--imin-cyan); padding-left: .38rem; min-width: 0; }
.imin-event.production { border-left-color: var(--imin-orange); }
.imin-event-top { display: flex; align-items: baseline; justify-content: space-between; gap: .3rem; }
/* Wrap to two lines rather than truncating on one: the activity name is the
   whole point of a wall display, and single-line clipping cut the most common
   entries ("Production Shop Open") down to "Production S…". */
.imin-event-top strong { font-size: .94rem; min-width: 0; overflow: hidden;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow-wrap: anywhere; }
.imin-event-top time { color: var(--imin-cyan); font: 700 .76rem var(--mono); white-space: nowrap; }
.imin-event.production time { color: var(--imin-orange); }
.imin-event-meta { display: flex; gap: .45rem; color: var(--muted); font-size: .7rem; white-space: nowrap; overflow: hidden; }
/* One line of description, so the space the two-line activity name needs comes
   back out of the least important text rather than pushing a whole event off
   the bottom of a fixed-height day card. */
.imin-event p { font-size: .7rem; line-height: 1.2; margin: .12rem 0 0; color: var(--text);
  display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden; }
.imin-no-events { color: var(--muted); font-size: .78rem; padding-top: .35rem; text-align: center; }
.imin-cal-weekhead, .imin-cal-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 3px; }
.imin-cal-weekhead div { text-align: center; color: var(--muted); text-transform: uppercase; font-size: .58rem; }
.imin-cal-grid { min-height: 0; flex: 1; grid-auto-rows: minmax(0, 1fr); }
.imin-cal-day { min-width: 0; overflow: hidden; background: var(--panel); border: 1px solid var(--line);
  border-radius: 8px; padding: .18rem .28rem; }
.imin-cal-blank { border: 1px dashed rgba(136,136,136,.12); border-radius: 6px; }
.imin-cal-num { display: block; color: var(--muted); font-size: .62rem; font-weight: 800;
  text-transform: uppercase; letter-spacing: .04em; border-bottom: 1px solid var(--line); margin-bottom: .08rem; }
.imin-cal-event { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; border-left: 2px solid var(--imin-cyan);
  padding-left: .22rem; font-size: .58rem; line-height: 1.35; }
.imin-cal-event.production { border-left-color: var(--imin-orange); }
.imin-cal-event time { font-family: var(--mono); color: var(--muted); }
.imin-cal-more { color: var(--muted); font-size: .54rem; }

/* Portrait-mounted TV (for example, a 1080x1920 display). Keep the same
   top/bottom information split, but give the detailed cards two wide columns
   instead of squeezing ten cards across five narrow columns. */
@media (orientation: portrait) {
  .imin-screen { padding: 1.35rem 1.5rem; grid-template-rows: auto minmax(0, 1fr) minmax(0, 1fr);
    gap: .8rem; }
  .imin-tv-head { padding-bottom: .7rem; }
  .imin-title-lockup strong { font-size: 1.65rem; }
  .imin-title-lockup span { font-size: .7rem; }
  .imin-today { font-size: 1.25rem; text-align: right; }
  .imin-next h1, .imin-month h2 { font-size: .98rem; margin-bottom: .55rem; }
  .imin-ten-grid { grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-rows: repeat(5, minmax(0, 1fr)); gap: .55rem; }
  .imin-day-card { padding: .52rem .68rem; border-radius: 12px; }
  .imin-day-card > header span { font-size: .8rem; }
  .imin-day-card > header strong { font-size: 1.08rem; }
  .imin-day-events { gap: .35rem; }
  .imin-event { padding-left: .48rem; }
  .imin-event-top strong { font-size: 1rem; }
  .imin-event-top time { font-size: .8rem; }
  .imin-event-meta { font-size: .75rem; gap: .65rem; }
  .imin-event p { font-size: .75rem; }
  .imin-no-events { font-size: .88rem; }
  .imin-cal-weekhead div { font-size: .7rem; }
  .imin-cal-day { padding: .3rem .42rem; border-radius: 8px; }
  .imin-cal-num { font-size: .72rem; margin-bottom: .18rem; }
  .imin-cal-event { font-size: .67rem; line-height: 1.45; padding-left: .3rem; }
  .imin-cal-more { font-size: .64rem; }
}

.imin-admin-body { min-height: 100vh; }
.imin-admin-head { display: flex; justify-content: space-between; align-items: center; gap: 1rem;
  margin-bottom: 1.25rem; border-bottom: 2px solid var(--line); padding-bottom: .7rem; }
.imin-admin-head > div { display: flex; align-items: center; gap: .8rem; }
.imin-admin-head h1 { margin: 0; font-size: 1.45rem; }
.imin-admin-head nav { display: flex; align-items: center; gap: 1rem; }
.imin-admin-grid { display: grid; grid-template-columns: minmax(320px,.9fr) minmax(420px,1.1fr); gap: 1rem; }
.imin-admin-grid h2 { margin-top: 0; }
.imin-form-pair > label { flex: 1; min-width: 180px; }
.imin-repeat-row > label { flex: 1; min-width: 210px; }
.imin-occurrence-note { margin: 0; font-size: .82rem; }
.imin-production-note { background: rgba(247,148,30,.1); border-left: 4px solid var(--imin-orange);
  padding: .65rem .8rem; border-radius: 6px; color: var(--muted); font-size: .85rem; margin-bottom: 0; }
.imin-admin-list { display: flex; flex-direction: column; gap: .55rem; max-height: 65vh; overflow-y: auto; }
.imin-admin-list article { display: grid; grid-template-columns: 120px 1fr auto; align-items: start; gap: .65rem;
  padding: .65rem; border: 1px solid var(--line); border-radius: 9px; background: var(--panel2); }
.imin-admin-date, .imin-admin-info { display: flex; flex-direction: column; }
.imin-admin-date span, .imin-admin-info span { color: var(--muted); font-size: .78rem; }
.imin-admin-info p { margin: .25rem 0 0; font-size: .82rem; }
.imin-admin-actions { display: flex; gap: .35rem; }
.imin-password-card { margin-top: 1rem; }
.imin-password-card summary { cursor: pointer; font-weight: 700; }
.imin-password-card form { margin-top: .8rem; }
.imin-history-card { margin-top: 1rem; }
.imin-history-head { display: flex; align-items: end; justify-content: space-between; gap: 1rem;
  flex-wrap: wrap; margin-bottom: .8rem; }
.imin-history-head h2, .imin-history-head p { margin: 0; }
.imin-history-search { display: flex; align-items: end; gap: .45rem; flex-wrap: wrap; }
.imin-history-search label { min-width: min(330px, 70vw); }
.imin-history-list { max-height: 32rem; }
@media (max-width: 850px) {
  .imin-admin-grid { grid-template-columns: 1fr; }
  .imin-admin-list { max-height: none; }
  .imin-admin-head { align-items: flex-start; flex-direction: column; }
  .imin-history-search, .imin-history-search label { width: 100%; }
}
@media (max-width: 760px) {
  .imin-admin-grid, .imin-admin-grid > *, .imin-history-card { min-width: 0; }
  .imin-form-pair > label, .imin-repeat-row > label { flex: 1 1 100%; min-width: 0; }
  .imin-admin-list article { grid-template-columns: minmax(86px, .7fr) minmax(0, 1.3fr); }
  .imin-admin-actions { grid-column: 1 / -1; justify-content: flex-end; flex-wrap: wrap; }
}

/* "Somebody still has the pass" notes, on the dashboard and the class view. */
.pass-notes { display: flex; flex-direction: column; gap: .5rem; margin-bottom: 1rem; }
.pass-note { display: flex; align-items: center; justify-content: space-between;
  gap: .75rem; margin-bottom: 0; }
.pass-note form { margin: 0; }
.pass-note button { white-space: nowrap; }
@media (max-width: 560px) {
  .pass-note { align-items: flex-start; flex-direction: column; }
}

/* Teacher-owned RFID passes and kiosks on Settings. */
/* Cards sit at their natural height rather than stretching to match the tallest
   in the row: a short card padded out to a tall neighbour reads as a section
   with something missing from the bottom of it. */
.settings-resources, .grid.two.admin-card-section { align-items: start; }
.settings-resources { margin-bottom: 0; }
.admin-card-section + .admin-card-section,
.settings-card-section + .settings-card-section { margin-top: 1rem; }

/* The edit cell in an admin list holds two forms — change it, and delete it.
   Left as siblings they stack, which doubled the height of every row in
   Production shops, Shop tools and Staff accounts and left the name column
   floating in the middle of the space. One flex row, wrapping together. */
.admin-edit-cell { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem .5rem; }
/* The three export groups sat stacked down one narrow column with a tall empty
   space beside them. Side by side they fit the card they are already in. */
.export-groups { display: grid; gap: 1.25rem 1.5rem;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); align-items: start; }
.export-groups > div { display: flex; flex-direction: column; gap: .55rem; }
.export-groups h3 { margin: 0; }
/* Says which way the production board is being looked at, next to the month
   links that page away from it. */
/* The save bar: comes up at the bottom of the window as soon as a settings
   field differs from what it was, so Save is never a scroll away and a pending
   change cannot sit unnoticed. Fixed to the viewport rather than the page,
   because the point is that it reaches you wherever you are in a long form. */
.save-bar { position: fixed; left: 0; right: 0; bottom: 0; z-index: 120;
  background: var(--panel); border-top: 1px solid var(--line-strong, var(--line));
  box-shadow: 0 -10px 30px rgba(0,0,0,.45);
  animation: save-bar-in 160ms var(--ease-fluid, ease-out); }
.save-bar[hidden] { display: none; }
.save-bar::before { content: ""; position: absolute; left: 0; right: 0; top: -2px; height: 2px;
  background: linear-gradient(90deg,#7AC143,#F7941E,#ED1C45,#EC008C,#92278F,#2E3192,#00AEEF); }
@keyframes save-bar-in { from { transform: translateY(100%); } to { transform: none; } }
@media (prefers-reduced-motion: reduce) { .save-bar { animation: none; } }
.save-bar-inner { max-width: 1240px; margin: 0 auto; display: flex; align-items: center;
  flex-wrap: wrap; gap: .6rem 1rem; padding: .8rem clamp(.9rem, 2.5vw, 1.5rem); }
.save-bar-text { display: flex; flex-direction: column; gap: .1rem; min-width: 0; }
.save-bar-label { font-size: .95rem; }
.save-bar-note { color: var(--muted); font-size: .8rem; }
.save-bar-actions { display: flex; gap: .5rem; margin-left: auto; }
.save-bar-save { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
/* Room for the bar, so it never covers the last control on the page. */
body.has-save-bar { padding-bottom: 5.5rem; }
@media (max-width: 560px) {
  .save-bar-actions { margin-left: 0; width: 100%; }
  .save-bar-actions button { flex: 1; }
  body.has-save-bar { padding-bottom: 8rem; }
}

/* With the bar running, a section's own Save button is a second copy of a
   control that is now always on screen. Hidden rather than removed: the bar
   submits through it, and Enter in a text field submits against it too. Gated
   on the class settings_dirty.js sets, so a page where that script failed to
   load keeps the buttons rather than losing every way to save. */
.save-bar-active form[data-save-bar] > button[type="submit"],
.save-bar-active form[data-save-bar] > button:not([type]) { display: none; }

/* The fields that differ, so "2 unsaved changes" says which two. */
.field-dirty { border-color: var(--accent) !important;
  box-shadow: 0 0 0 3px rgba(59,130,246,.18), inset 0 1px 2px rgba(0,0,0,.32) !important; }
.field-dirty-label { position: relative; }
.field-dirty-label > :first-child { color: var(--accent); }

.mgmt-scope { font-size: .78rem; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--accent); padding: .2rem .5rem;
  border: 1px solid var(--line); border-radius: 999px; white-space: nowrap; }
/* Explanatory prose in a full-width settings card would otherwise run the whole
   1240px of the container, which is well past a comfortable line to read. The
   controls under it still use the full width. */
.settings-card-section > p, .admin-card-section > p { max-width: 76ch; }
.export-groups form { margin: 0; }
.admin-edit-cell > form { display: flex; flex-wrap: wrap; align-items: center;
  gap: .4rem .5rem; margin: 0; }
.admin-resource-list li,
.admin-class-item { align-items: center; gap: .75rem; }
.admin-class-summary { flex: 1; min-width: 0; }
.admin-class-summary .muted { display: block; margin-top: .15rem; }
.admin-list-actions { display: flex; align-items: center; gap: .4rem; margin-left: auto; }
@media (max-width: 700px) {
  .admin-class-item { align-items: flex-start; flex-direction: column; }
  .admin-list-actions { flex-wrap: wrap; margin-left: 0; width: 100%; }
}
.table-scroll { max-width: 100%; overflow-x: auto; }
.resource-table { margin-bottom: 0; }
.resource-empty { padding: .8rem; border: 1px dashed var(--line); border-radius: var(--control-radius); }
.station-list { display: flex; flex-direction: column; gap: .5rem; }
.station-item { display: flex; align-items: center; justify-content: space-between; gap: .75rem;
  padding: .7rem; border: 1px solid var(--line); border-radius: var(--control-radius); background: var(--panel2); }
.station-actions { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; justify-content: flex-end; }
.station-actions form { margin: 0; }

@media (max-width: 560px) {
  .station-item { align-items: flex-start; flex-direction: column; }
  .station-actions { width: 100%; justify-content: flex-start; }
}

/* -----------------------------------------------------------------------
   Accessibility preference layers
   ----------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    scroll-behavior: auto !important;
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}

@media (prefers-reduced-transparency: reduce) {
  .topbar, .account-dropdown { background: var(--panel); -webkit-backdrop-filter: none; backdrop-filter: none; }
  .modal { -webkit-backdrop-filter: none; backdrop-filter: none; }
}

@media (prefers-contrast: more) {
  :root { --line: rgba(255,255,255,.38); --line-strong: rgba(255,255,255,.68); }
  input, select, textarea, button, .card { border-width: 2px; }
  .muted, label { color: #c7c7cc; }
}

/* ----------------------------------------------------------------------- */
/* Seating charts and attendance-aware classroom tools                     */
/* ----------------------------------------------------------------------- */
.eyebrow { margin: 0 0 .25rem; color: var(--accent); font-size: .72rem; font-weight: 850;
  letter-spacing: .14em; text-transform: uppercase; }
.seating-page-head, .seating-live-head { display: flex; align-items: center;
  justify-content: space-between; gap: 1rem; }
.seating-page-head { margin-bottom: 1.15rem; }
.seating-page-head h1, .seating-live-head h1 { margin: 0; }
.seating-setup-grid { display: grid; grid-template-columns: minmax(255px,.72fr) minmax(480px,1.6fr);
  gap: 1rem; align-items: start; }
.seating-template-panel { position: sticky; top: 1rem; }
.seating-template-panel h2, .workspace-title h2, .assignment-head h2 { margin: .2rem 0 .75rem; }
.step-kicker { color: var(--muted); font-size: .7rem; font-weight: 800; letter-spacing: .12em;
  text-transform: uppercase; }
.or-divider { display: flex; align-items: center; gap: .5rem; margin: 1rem 0; color: var(--muted); }
.or-divider::before, .or-divider::after { content: ""; height: 1px; flex: 1; background: var(--line); }
.seating-new-template { margin-top: .8rem; }
.template-tip { margin: 1rem 0 0; padding: .75rem; border-radius: var(--control-radius);
  color: var(--muted); background: rgba(0,174,239,.08); border: 1px solid rgba(0,174,239,.18);
  font-size: .78rem; line-height: 1.45; }
.workspace-title, .assignment-head, .workspace-actions, .assignment-footer { display: flex;
  align-items: center; justify-content: space-between; gap: 1rem; }
.room-size-controls { display: flex; align-items: end; gap: .5rem; }
.room-size-controls label { width: 74px; }
.room-size-controls input { min-width: 0; }
.room-help { margin-top: 0; }
.room-shell { padding: 1rem; border: 1px solid var(--line); border-radius: calc(var(--radius) + 2px);
  background-color: var(--bg); background-image: radial-gradient(circle at 1px 1px, var(--line) 1px, transparent 0);
  background-size: 18px 18px; overflow: auto; }
.room-front { width: min(72%, 520px); margin: 0 auto 1.25rem; padding: .38rem .8rem;
  display: flex; align-items: center; justify-content: space-between; gap: .5rem;
  background: var(--panel-raised); border: 1px solid var(--line-strong); border-top: 4px solid var(--accent);
  border-radius: 0 0 9px 9px; box-shadow: 0 8px 24px rgba(0,0,0,.15); }
.room-front span { color: var(--muted); font-size: .68rem; }
.room-front strong { color: var(--text); font-size: .7rem; letter-spacing: .12em; }
.layout-editor-grid, .assignment-grid, .live-seat-grid { display: grid;
  grid-template-columns: repeat(var(--seat-columns), minmax(72px, 1fr)); gap: .65rem;
  min-width: calc(var(--seat-columns) * 82px); }
.layout-cell { aspect-ratio: 1.35; min-height: 58px; padding: .35rem; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: .1rem; color: var(--muted); background: rgba(255,255,255,.025);
  border: 1px dashed var(--line-strong); border-radius: 9px; }
.layout-cell:hover { color: var(--text); background: rgba(255,255,255,.055); border-style: solid; }
.layout-cell.is-seat { color: var(--text); background: linear-gradient(145deg, rgba(122,193,67,.18), rgba(122,193,67,.06));
  border: 1px solid rgba(122,193,67,.62); box-shadow: inset 0 -5px 0 rgba(122,193,67,.12); }
.layout-cell span { font-size: .9rem; font-weight: 850; }
.layout-cell small { font-size: .55rem; letter-spacing: .13em; color: var(--muted); }
.workspace-actions { margin-top: .9rem; }
.save-status { font-size: .82rem; }
.save-status.is-unsaved { color: var(--warn); }
.seating-empty-state { min-height: 330px; display: flex; flex-direction: column; align-items: center;
  justify-content: center; text-align: center; }
.empty-state-icon { display: grid; place-items: center; width: 64px; height: 64px; margin-bottom: .4rem;
  border-radius: 18px; color: var(--accent); background: rgba(122,193,67,.1); font-size: 2rem; }
.seating-empty-state h2 { margin: .35rem 0; }
.assignment-card { margin-top: 1rem; }
.assignment-head { margin-bottom: 1rem; }
.assignment-head p { margin: .2rem 0; }
.assignment-room { padding-bottom: 1.25rem; }
.assignment-grid { grid-template-rows: repeat(var(--seat-rows), minmax(74px, auto)); }
.assignment-desk { min-width: 0; padding: .45rem; align-self: stretch; justify-content: center;
  border: 1px solid var(--line-strong); border-radius: 9px; background: var(--panel-raised);
  box-shadow: 0 5px 14px rgba(0,0,0,.15); }
.assignment-desk.has-student { cursor: grab; }
.assignment-desk.has-student:active { cursor: grabbing; }
.assignment-desk.is-drag-over { border-color: var(--accent); background: rgba(122,193,67,.16); }
.assignment-desk > span { color: var(--muted); font-size: .62rem; font-weight: 800;
  letter-spacing: .08em; text-transform: uppercase; }
.assignment-desk select { width: 100%; min-width: 0; padding: .38rem .3rem; font-size: .77rem; }
.assignment-desk option.is-unseated { color: var(--warn); font-weight: 800; }
.unseated-panel { margin-top: .85rem; padding: .8rem; border: 2px solid var(--warn);
  border-radius: var(--control-radius); background: rgba(245,158,11,.09); }
.unseated-panel > div:first-child { display: flex; align-items: baseline; justify-content: space-between;
  flex-wrap: wrap; gap: .35rem 1rem; }
.unseated-panel.is-empty { border-color: var(--good); background: rgba(122,193,67,.08); }
.unseated-students { display: flex; flex-wrap: wrap; gap: .45rem; margin-top: .65rem; min-height: 2rem; }
.unseated-student { padding: .42rem .65rem; color: var(--warn); background: var(--panel-raised);
  border-color: var(--warn); cursor: grab; font-size: .78rem; }
.unseated-student:active { cursor: grabbing; }
.unseated-panel.is-drag-over { box-shadow: 0 0 0 3px rgba(245,158,11,.25); }
.assignment-footer { margin-top: .8rem; color: var(--muted); font-size: .84rem; }

.seating-live-head { margin-bottom: 1rem; }
.seating-live-head .crumb { margin-bottom: .45rem; }
.class-tools-panel { position: fixed; z-index: 61; top: 50%; left: .65rem; width: 58px; padding: .45rem;
  display: grid; gap: .4rem; transform: translateY(-50%); border: 1px solid var(--line-strong);
  border-radius: 16px; background: var(--panel-raised); box-shadow: var(--shadow-float);
  transition: width .22s var(--ease-fluid); }
.class-tools-panel.expanded { width: min(360px,calc(100vw - 1.3rem)); grid-template-columns: 48px 1fr; }
.class-tools-expand { min-height: 44px; padding: .25rem; display: flex; align-items: center;
  justify-content: center; gap: .18rem; color: var(--muted); background: var(--panel2); border-color: var(--line); }
.class-tools-expand:hover, .class-tools-expand[aria-expanded="true"] { color: var(--text); border-color: var(--accent); }
.class-tools-icon { font-size: 1.05rem; }
.class-tools-chevron { font-size: 1.05rem; transition: transform .2s ease; }
.class-tools-panel.expanded .class-tools-chevron { transform: rotate(180deg); }
.class-tools-details { display: none; min-width: 0; max-height: min(78vh,680px); padding: .2rem .25rem .2rem .6rem;
  overflow-y: auto; border-left: 1px solid var(--line); }
.class-tools-panel.expanded .class-tools-details { display: grid; gap: .7rem; }
.class-tools-head > div { display: flex; align-items: baseline; justify-content: space-between; gap: .7rem; }
.class-tools-head span { color: var(--muted); font-size: .78rem; font-variant-numeric: tabular-nums; }
.class-tool-block { padding: .65rem; display: grid; gap: .55rem; border: 1px solid var(--line);
  border-radius: var(--control-radius); background: var(--panel2); }
.class-tool-title { display: flex; align-items: center; justify-content: space-between; gap: .6rem; }
.class-tool-title output { color: var(--accent); font-size: 1.25rem; font-weight: 900;
  font-variant-numeric: tabular-nums; letter-spacing: .04em; }
.class-tool-block.timer-finished { border-color: var(--bad); box-shadow: 0 0 0 2px rgba(237,28,69,.18); }
.class-tool-block.timer-finished output { color: var(--bad); }
.class-timer-inputs { display: grid; grid-template-columns: 1fr 1fr; gap: .5rem; }
.class-timer-inputs label { display: grid; grid-template-columns: auto 1fr; align-items: center; gap: .4rem; }
.class-timer-inputs span { color: var(--muted); font-size: .72rem; }
.class-timer-inputs input { min-width: 0; min-height: 34px; padding: .3rem .4rem; text-align: center; }
.class-tool-actions, .class-timer-presets, .class-signal-actions { display: flex; flex-wrap: wrap; gap: .35rem; }
.class-tool-actions button { flex: 1; }
.class-timer-presets button { flex: 1; padding-inline: .35rem; }
.class-signal-actions button { flex: 1 1 42%; }
.signal-go { color: #fff; background: #16803a; border-color: #22c55e; }
.signal-warn { color: #211700; background: #fbbf24; border-color: #f59e0b; }
.signal-stop { color: #fff; background: #c81e3a; border-color: #ed1c45; }
.class-fullscreen { width: 100%; }
.class-signal-overlay { position: fixed; inset: 0; z-index: 89; display: grid; place-items: center;
  pointer-events: none; visibility: hidden; opacity: 0; transition: opacity .18s ease; }
.class-signal-overlay strong { padding: .85rem 1.25rem; border-radius: 999px; color: #fff;
  background: rgba(0,0,0,.78); font-size: clamp(1.15rem,3vw,2rem); letter-spacing: .04em;
  text-transform: uppercase; box-shadow: var(--shadow-float); }
.class-signal-overlay.active { visibility: visible; opacity: 1; }
.class-signal-overlay.go { background: rgba(22,128,58,.28); }
.class-signal-overlay.warn { background: rgba(245,158,11,.3); }
.class-signal-overlay.stop { background: rgba(200,30,58,.38); }
.sound-meter-panel { position: fixed; z-index: 60; top: 50%; right: .65rem; width: 58px; padding: .45rem;
  display: grid; grid-template-rows: auto minmax(130px,32vh) auto; gap: .4rem; transform: translateY(-50%);
  border: 1px solid var(--line-strong); border-radius: 16px; background: var(--panel-raised);
  box-shadow: var(--shadow-float); transition: width .22s var(--ease-fluid); }
.sound-meter-panel.expanded { width: min(340px,calc(100vw - 1.3rem)); grid-template-columns: 48px 1fr;
  grid-template-rows: auto minmax(130px,32vh) auto; }
.sound-meter-expand { min-height: 42px; padding: .25rem; display: flex; align-items: center; justify-content: center;
  gap: .2rem; color: var(--muted); background: var(--panel2); border-color: var(--line); }
.sound-meter-expand:hover { color: var(--text); }
.sound-meter-icon { font-size: .72rem; font-weight: 900; }
.sound-meter-chevron { font-size: 1.05rem; transition: transform .2s ease; }
.sound-meter-panel.expanded .sound-meter-chevron { transform: rotate(180deg); }
.sound-meter-copy { min-width: 0; }
.sound-meter-copy > div { display: flex; flex-direction: column; }
.sound-meter-panel.active .sound-meter-icon { color: var(--good); }
.sound-meter-readout { min-height: 0; display: flex; flex-direction: column; align-items: center; gap: .35rem; }
.sound-meter-track { position: relative; width: 1rem; height: 100%; overflow: hidden; border: 1px solid var(--line-strong);
  border-radius: 999px; background: linear-gradient(0deg, rgba(122,193,67,.16) 0 60%, rgba(245,158,11,.18) 60% 80%, rgba(237,28,69,.2) 80%); }
.sound-meter-fill { position: absolute; inset: auto 0 0; display: block; width: 100%; height: 0; border-radius: inherit;
  background: var(--good); transition: height .08s linear, background .15s ease; }
.sound-meter-panel.near-limit .sound-meter-fill { background: var(--warn); }
.sound-meter-panel.over-limit .sound-meter-fill { background: var(--bad); }
.sound-meter-panel.sound-meter-error { border-color: rgba(237,28,69,.55); }
.sound-meter-panel.sound-meter-error #sound-meter-status { color: var(--bad); max-width: 48rem; }
.sound-meter-limit { position: absolute; left: -3px; right: -3px; height: 3px; transform: translateY(1px);
  border-radius: 3px; background: #fff; box-shadow: 0 0 0 1px rgba(0,0,0,.45); }
.sound-meter-readout output { color: var(--muted); font-size: .75rem; font-variant-numeric: tabular-nums; font-weight: 800; }
.sound-meter-details { grid-column: 2; grid-row: 1 / 4; min-width: 0; padding: .3rem .35rem .3rem .55rem;
  display: none; align-content: center; gap: .8rem; border-left: 1px solid var(--line); }
.sound-meter-panel.expanded .sound-meter-details { display: grid; }
.sound-settings-button { grid-row: 3; min-height: 40px; padding: .25rem; color: var(--muted);
  background: var(--panel2); border-color: var(--line); font-size: 1rem; }
.sound-settings-button:hover, .sound-settings-button[aria-expanded="true"] { color: var(--text); border-color: var(--accent); }
.sound-settings-menu { position: absolute; right: calc(100% + .55rem); bottom: 0; width: min(270px,calc(100vw - 5rem));
  padding: .85rem; display: grid; gap: .85rem; border: 1px solid var(--line-strong); border-radius: 14px;
  background: var(--panel-raised); box-shadow: var(--shadow-float); }
.sound-settings-menu[hidden] { display: none; }
.sound-limit-control { gap: .25rem; min-width: 160px; }
.sound-limit-control > span { display: flex; justify-content: space-between; color: var(--muted); font-size: .78rem; }
.sound-limit-value-row { display: grid; grid-template-columns: 1fr 4rem; align-items: center; gap: .55rem; }
.sound-limit-value-row input[type="range"] { width: 100%; padding: 0; accent-color: var(--accent); }
.sound-limit-value-row input[type="number"] { min-height: 34px; padding: .3rem .4rem; text-align: center; }
.sound-beep-control { padding-top: .7rem; flex-direction: row; align-items: flex-start; gap: .55rem;
  border-top: 1px solid var(--line); cursor: pointer; }
.sound-beep-control input { width: 1.1rem; height: 1.1rem; margin-top: .1rem; accent-color: var(--accent); }
.sound-beep-control span { display: flex; flex-direction: column; gap: .15rem; }
.sound-beep-control small { color: var(--muted); line-height: 1.3; }
.sound-beep-volume-control { gap: .3rem; }
.sound-beep-volume-control > span { display: flex; justify-content: space-between; color: var(--muted); font-size: .78rem; }
.sound-beep-volume-control output { color: var(--text); font-weight: 800; }
.sound-beep-volume-control input { width: 100%; padding: 0; accent-color: var(--accent); }
.sound-privacy-note { color: var(--muted); font-size: .68rem; }
.sound-alert-overlay { position: fixed; inset: 0; z-index: 90; display: grid; place-items: center;
  pointer-events: none; visibility: hidden; opacity: 0; background: rgba(220,38,38,.58); color: #fff; }
.sound-alert-overlay strong { padding: .7rem 1rem; border-radius: 999px; background: rgba(69,10,10,.88);
  font-size: clamp(1rem,2.2vw,1.5rem); letter-spacing: .03em; text-transform: uppercase; }
.sound-alert-overlay.active { visibility: visible; animation: sound-alert-pulse .8s ease-in-out infinite; }
@keyframes sound-alert-pulse { 0%,100% { opacity: .26; } 50% { opacity: .72; } }
@media (prefers-reduced-motion: reduce) { .sound-alert-overlay.active { animation: none; opacity: .55; } }
.live-head-actions { display: flex; align-items: center; gap: .75rem; }
.presence-summary { min-width: 94px; padding: .55rem .8rem; display: flex; flex-direction: column;
  text-align: center; background: rgba(122,193,67,.1); border: 1px solid rgba(122,193,67,.38);
  border-radius: var(--radius); }
.presence-summary strong { color: var(--good); font-size: 1.5rem; line-height: 1; }
.presence-summary span { color: var(--muted); font-size: .65rem; text-transform: uppercase; letter-spacing: .08em; }
/* --tab-count is set inline when an optional tab (Shop) is present. */
.seating-mode-tabs { display: grid; grid-template-columns: repeat(var(--tab-count, 5), 1fr); gap: .5rem; margin-bottom: 1rem;
  padding: .35rem; border: 1px solid var(--line); background: var(--panel); border-radius: var(--radius); }
.seating-mode-tabs.projector-tabs { grid-template-columns: repeat(3, 1fr); }
.seating-tab { color: var(--muted); background: transparent; border-color: transparent; }
.seating-tab span { margin-right: .3rem; }
.seating-tab:hover { color: var(--text); background: rgba(255,255,255,.045); border-color: transparent; }
.seating-tab.active { color: var(--on-accent); background: var(--accent); border-color: var(--accent); box-shadow: 0 5px 16px rgba(0,0,0,.2); }
.seating-tool-panel { min-height: 58vh; padding: 1rem; border: 1px solid var(--line); border-radius: var(--radius);
  background: linear-gradient(145deg, rgba(255,255,255,.02), transparent 40%), var(--panel); box-shadow: var(--shadow); }
.seat-toolbar { display: flex; align-items: center; justify-content: space-between; gap: .75rem; margin-bottom: .8rem; }
.status-legend { display: flex; align-items: center; flex-wrap: wrap; gap: .45rem .9rem; color: var(--muted); font-size: .76rem; }
.status-legend span { display: inline-flex; align-items: center; gap: .35rem; }
.legend-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--muted); }
.legend-dot.here { background: var(--good); }.legend-dot.tardy { background: var(--warn); }
.legend-dot.away { background: var(--info); }.legend-dot.excused { background: #a78bfa; }
.legend-dot.left-early { background: var(--info); }
.legend-dot.absent { background: var(--bad); }
.live-room { min-height: 50vh; }
.live-seat-grid { grid-template-rows: repeat(var(--seat-rows), minmax(92px, 1fr)); }
.live-desk { position: relative; min-width: 0; min-height: 84px; padding: .6rem; display: flex;
  flex-direction: column; align-items: flex-start; justify-content: center; overflow: hidden;
  background: var(--panel-raised); border: 1px solid var(--line-strong); border-radius: 11px;
  box-shadow: 0 7px 20px rgba(0,0,0,.17); }
.live-desk::before { content: ""; position: absolute; inset: 0 auto 0 0; width: 5px; background: var(--muted); }
.live-desk small { color: var(--muted); font-size: .57rem; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; }
.live-desk strong { width: 100%; margin: .18rem 0; overflow: hidden; text-overflow: ellipsis;
  font-size: clamp(.75rem, 1.2vw, .98rem); white-space: nowrap; }
.live-desk span { padding: .12rem .4rem; font-size: .63rem; font-weight: 800; border-radius: 999px; background: rgba(255,255,255,.07); }
.live-desk.here::before { background: var(--good); }.live-desk.here span { color: var(--good); background: rgba(34,197,94,.12); }
.live-desk.tardy::before { background: var(--warn); }.live-desk.tardy span { color: var(--warn); background: rgba(245,158,11,.12); }
.live-desk.away::before { background: var(--info); }.live-desk.away span { color: var(--info); background: rgba(56,189,248,.12); }
.live-desk.excused::before { background: #a78bfa; }.live-desk.excused span { color: #a78bfa; background: rgba(167,139,250,.12); }
.live-desk.absent { opacity: .62; }.live-desk.absent::before { background: var(--bad); }.live-desk.absent span { color: var(--bad); background: rgba(239,68,68,.12); }
.live-desk.empty { opacity: .35; border-style: dashed; background: transparent; }
.live-desk.empty::before { display: none; }.live-desk.empty strong { color: var(--muted); font-weight: 600; }
.live-desk[role="button"] { cursor: pointer; }
.live-desk[role="button"]:hover { border-color: var(--info); transform: translateY(-2px); }
.live-desk[role="button"]:focus-visible { outline: 3px solid var(--info); outline-offset: 2px; }
.live-desk.display::before { background: var(--accent); }
.undo-banner { margin: 0 0 1rem; padding: .7rem .85rem; display: flex; align-items: center;
  justify-content: space-between; gap: .75rem; border: 1px solid rgba(0,174,239,.35);
  border-radius: var(--control-radius); background: rgba(0,174,239,.08); }
.undo-banner span { font-weight: 700; }
.attendance-review-head { display: flex; align-items: end; justify-content: space-between; gap: 1rem; }
.attendance-review-head h2, .attendance-review-head p { margin: .25rem 0; }
.bulk-attendance-actions { display: flex; align-items: center; justify-content: flex-end; flex-wrap: wrap; gap: .4rem; }
/* Roster multi-select: the pick-then-mark bar above the roster list. */
.roster-selection-bar { display: flex; align-items: center; flex-wrap: wrap; gap: .6rem;
  margin: .6rem 0 0; padding: .5rem .7rem; border: 1px solid var(--line);
  border-radius: var(--control-radius); background: var(--panel2); }
.roster-selection-bar .inline { display: flex; align-items: center; gap: .4rem; font-weight: 700; }
.roster-selection-actions { display: flex; align-items: center; flex-wrap: wrap; gap: .3rem; margin-left: auto; }
.roster-select { display: flex; align-items: center; }
.roster-select input, .roster-selection-bar input[type="checkbox"] {
  width: 1.05rem; height: 1.05rem; accent-color: var(--accent); }
.attendance-control-row.has-select { grid-template-columns: auto minmax(150px,1fr) auto minmax(210px,auto) auto; }
/* Fix a day: the per-class attendance history / correction screen. */
.fix-day-picker { align-items: end; gap: .8rem; flex-wrap: wrap; }
.fix-day-note { display: block; margin: .6rem 0 0; font-weight: 700; }
.fix-day-note input { width: 100%; max-width: 34rem; }
.fix-day-note .muted { font-weight: 400; }
.fix-day-actions { white-space: nowrap; }
.fix-day-actions button.active { border-color: var(--accent); color: var(--accent);
  font-weight: 800; }
/* A soft-deleted history row: still visible for a while so it can be restored. */
tr.deleted-row td { opacity: .55; text-decoration: line-through; }
tr.deleted-row td.actions { text-decoration: none; opacity: 1; }
tr.deleted-row td.actions .muted { font-style: italic; }
/* Teacher-view offline queue: "N changes waiting to sync". */
.pending-sync-badge { font-weight: 600; font-size: .85rem; }
.attendance-review-counts { display: grid; grid-template-columns: repeat(6, 1fr); gap: .55rem; margin: 1rem 0; }
.attendance-review-counts article { padding: .7rem; text-align: center; border: 1px solid var(--line);
  border-radius: var(--control-radius); background: var(--panel2); }
.attendance-review-counts strong { display: block; color: var(--text); font-size: 1.45rem; }
.attendance-review-counts span { color: var(--muted); font-size: .68rem; font-weight: 800;
  letter-spacing: .07em; text-transform: uppercase; }
.attendance-control-list { display: flex; flex-direction: column; gap: .45rem; }
/* Divider above the personal-leadership block at the foot of the roster. */
.roster-group-heading { margin: .9rem 0 0; padding-top: .7rem; border-top: 1px solid var(--line);
  color: var(--muted); font-size: .68rem; font-weight: 800; letter-spacing: .07em;
  text-transform: uppercase; }
.attendance-control-row { padding: .55rem .7rem; display: grid; grid-template-columns: minmax(150px,1fr) auto minmax(210px,auto) auto;
  align-items: center; gap: .65rem; border: 1px solid var(--line); border-radius: var(--control-radius); background: var(--panel2); }
.attendance-control-row.is-focused { border-color: var(--info); box-shadow: 0 0 0 3px rgba(0,174,239,.18); }
.attendance-student strong, .attendance-student span { display: block; }
.attendance-student span { color: var(--muted); font-size: .72rem; }
/* Preferred name leads; the legal name sits under it for attendance transfer. */
.attendance-student .legal-name { color: var(--muted); font-size: .68rem; font-style: italic; }
.attendance-student .timer { display: inline; font-size: .72rem; }
.attendance-control-row.away { border-color: rgba(56,189,248,.45); background: rgba(56,189,248,.07); }
/* Out of the room at personal leadership: on the list to be seen, not to be marked. */
.attendance-control-row.leadership { border-style: dashed; background: transparent; }
.attendance-control-row.is-overtime { border-color: var(--bad); }
.attendance-control-row.is-overtime .attendance-student strong,
.attendance-control-row.is-overtime .attendance-student .timer {
  animation: overtime-flash 1s steps(1) infinite;
}
@keyframes overtime-flash {
  0%, 100% { color: var(--bad); }
  50%      { color: var(--text); }
}
@media (prefers-reduced-motion: reduce) {
  .attendance-control-row.is-overtime .attendance-student strong,
  .attendance-control-row.is-overtime .attendance-student .timer {
    animation: none; color: var(--bad);
  }
}
.attendance-status-buttons, .pass-quick-control, .behavior-quick-control { display: flex; align-items: center; gap: .3rem; }
.behavior-quick-control button { border-color: var(--accent); }
/* Seat panel: the same controls as a roster row, stacked for a dialog. */
.seat-actions-controls { display: flex; flex-direction: column; gap: .6rem; }
.seat-actions-controls .attendance-status-buttons,
.seat-actions-controls .pass-quick-control { flex-wrap: wrap; }
.seat-actions-controls .attendance-status-buttons button { flex: 1 1 auto; }
.seat-actions-controls .pass-quick-control:empty,
.seat-actions-controls .behavior-quick-control:empty { display: none; }
.seat-actions-controls .pass-quick-control select { flex: 1 1 8rem; }
#seat-actions .modal-card h2 { font-size: 1.35rem; }
/* Seat-corner behavior log: sits above the desk's own click target. */
.desk-log { position: absolute; top: .25rem; right: .25rem; z-index: 1; padding: 0;
  width: 1.5rem; height: 1.4rem; min-height: 0; display: flex; align-items: center; justify-content: center;
  line-height: 1; font-size: .74rem; color: var(--muted); background: rgba(255,255,255,.06);
  border: 1px solid var(--line-strong); border-radius: 7px; }
.desk-log:hover, .desk-log:focus-visible { color: var(--on-accent); background: var(--accent); border-color: var(--accent); }
.attendance-status-buttons button.selected { color: var(--on-accent); background: var(--accent); border-color: var(--accent); }
.attendance-status-buttons .left-early-button { border-color: rgba(56,189,248,.55); }
.attendance-status-buttons .left-early-button.selected { color: var(--on-info); background: var(--info); border-color: var(--info); }
.live-desk.left-early::before { background: var(--info); }
.live-desk.left-early span { color: var(--info); background: rgba(56,189,248,.12); }
.pass-quick-control select { min-width: 120px; padding: .35rem; font-size: .75rem; }
.random-rules-card { margin: 0 0 1rem; padding: .8rem; border: 1px solid var(--line); border-radius: var(--radius); background: var(--panel2); }
.random-rules-card summary { display: flex; align-items: center; justify-content: space-between; gap: 1rem; cursor: pointer; }
.random-rule-options { display: flex; flex-wrap: wrap; gap: .65rem 1rem; margin: 1rem 0; }
.random-rule-options label, .copy-options label { flex-direction: row; align-items: center; gap: .4rem; }
.pair-rule-builders { display: grid; grid-template-columns: repeat(2,1fr); gap: 1rem; }
.pair-rule-builders h3 { margin-bottom: .4rem; }
.rule-chip-list { min-height: 32px; margin-top: .45rem; display: flex; flex-wrap: wrap; gap: .35rem; }
.rule-chip { padding: .28rem .5rem; color: var(--text); background: rgba(0,174,239,.1); border-color: rgba(0,174,239,.3); font-size: .7rem; }
.student-rule-grid { display: grid; grid-template-columns: repeat(auto-fit,minmax(260px,1fr)); gap: .45rem; }
.student-rule-grid label { padding: .5rem; display: grid; grid-template-columns: 1fr 1fr; align-items: center;
  gap: .45rem; border: 1px solid var(--line); border-radius: var(--control-radius); background: var(--panel); }
.student-rule-grid label span { display: flex; align-items: center; gap: .35rem; font-size: .75rem; }
.student-rule-grid input { min-width: 0; padding: .38rem; font-size: .75rem; }
.seating-version-card { margin-top: 1rem; }
.seating-version-list { display: grid; grid-template-columns: repeat(auto-fit,minmax(240px,1fr)); gap: .55rem; }
.seating-version-list article { padding: .65rem; display: flex; align-items: center; justify-content: space-between;
  gap: .6rem; border: 1px solid var(--line); border-radius: var(--control-radius); background: var(--panel2); }
.seating-version-list article span { display: block; font-size: .7rem; }
.privacy-note { color: var(--muted); font-weight: 700; }
.projector-body .main { max-width: 1600px; }
.projector-body .seating-live-head h1 { font-size: clamp(2rem,4vw,4rem); }
.copy-options { padding: .75rem; display: grid; grid-template-columns: repeat(2,1fr); gap: .5rem;
  border: 1px solid var(--line); border-radius: var(--control-radius); }
.copy-options p { grid-column: 1/-1; margin: 0; }
.class-start-label { display: inline-block; margin-top: .45rem; color: var(--accent); font-size: .75rem; font-weight: 800; }
.tool-intro { display: flex; align-items: end; justify-content: space-between; gap: 1rem; margin-bottom: 1.2rem; }
.tool-intro h2, .tool-intro p { margin: .25rem 0; }
.group-controls { display: flex; align-items: end; gap: .5rem; }
.random-group-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: .8rem; }
.random-group-card { overflow: hidden; border: 1px solid var(--line); border-radius: var(--radius); background: var(--panel2); }
.random-group-card header { display: flex; justify-content: space-between; align-items: center; padding: .5rem .75rem;
  background: rgba(122,193,67,.1); border-bottom: 1px solid rgba(122,193,67,.22); }
.random-group-card header span { color: var(--accent); font-size: .68rem; font-weight: 850; letter-spacing: .13em; }
.random-group-card header strong { display: grid; place-items: center; width: 25px; height: 25px; color: var(--good);
  background: rgba(122,193,67,.13); border-radius: 50%; font-size: .75rem; }
.random-group-card ol { list-style: none; margin: 0; padding: .3rem .75rem .65rem; counter-reset: member; }
.random-group-card li { display: flex; align-items: center; gap: .45rem; padding: .6rem .1rem;
  border-bottom: 1px solid var(--line); font-weight: 700; }
.random-group-card li:last-child { border-bottom: 0; }
.random-group-card li::before { counter-increment: member; content: counter(member); color: var(--muted); font: 700 .7rem var(--mono); }
.mini-status { margin-left: auto; color: var(--warn); font-size: .62rem; }
.tool-empty { grid-column: 1/-1; min-height: 260px; display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: .3rem; color: var(--muted); border: 1px dashed var(--line); border-radius: var(--radius); }
.wheel-layout { min-height: 56vh; display: grid; grid-template-columns: minmax(260px,.72fr) minmax(390px,1.28fr);
  align-items: center; gap: 1.5rem; }
.wheel-copy { padding: 1rem 1.5rem; }
.wheel-copy h2 { margin: .2rem 0; font-size: clamp(2rem, 4vw, 3.5rem); }
.spin-button { width: 100%; min-height: 56px; margin-top: 1rem; font-size: 1.1rem; }
.wheel-touch-hint { margin: .9rem 0 0; padding: .7rem .8rem; display: flex; align-items: center; gap: .4rem;
  color: var(--text); background: rgba(0,174,239,.08); border: 1px solid rgba(0,174,239,.24);
  border-radius: var(--control-radius); font-size: .82rem; }
.wheel-touch-hint span { font-size: 1.2rem; }.wheel-touch-hint strong { color: var(--info); }
.wheel-result { min-height: 78px; margin-top: .8rem; padding: .8rem; display: flex; flex-direction: column;
  justify-content: center; text-align: center; color: var(--muted); border: 1px solid var(--line); border-radius: var(--radius); background: var(--panel2); }
.wheel-result strong { color: var(--text); font-size: 1.45rem; }.wheel-result.has-winner { border-color: rgba(122,193,67,.55); background: rgba(122,193,67,.08); }
.wheel-stage { position: relative; width: min(58vh, 620px, 100%); aspect-ratio: 1; margin: auto; }
#student-wheel { width: 100%; height: 100%; display: block; filter: drop-shadow(0 18px 24px rgba(0,0,0,.28));
  transition: transform 4.6s cubic-bezier(.12,.7,.12,1); touch-action: none; user-select: none;
  -webkit-user-select: none; cursor: grab; }
#student-wheel.is-dragging { cursor: grabbing; filter: drop-shadow(0 22px 28px rgba(0,0,0,.36)); }
#student-wheel:focus-visible { outline: 4px solid var(--info); outline-offset: 5px; border-radius: 50%; }
.wheel-pointer { position: absolute; z-index: 4; top: -5px; left: 50%; width: 0; height: 0; transform: translateX(-50%);
  border-left: 20px solid transparent; border-right: 20px solid transparent; border-top: 46px solid #fff;
  filter: drop-shadow(0 4px 4px rgba(0,0,0,.35)); }
.wheel-hub { position: absolute; z-index: 3; top: 50%; left: 50%; width: 82px; height: 82px; transform: translate(-50%,-50%);
  display: grid; place-items: center; color: #fff; background: var(--panel-raised); border: 7px solid rgba(255,255,255,.9);
  border-radius: 50%; box-shadow: 0 7px 20px rgba(0,0,0,.35); font-size: .62rem; font-weight: 900; letter-spacing: .08em; }
.wheel-pointer, .wheel-hub, .wheel-gesture-label { pointer-events: none; }
.wheel-gesture-label { position: absolute; z-index: 4; left: 50%; bottom: 5%; transform: translateX(-50%);
  padding: .3rem .58rem; color: rgba(255,255,255,.9); background: rgba(20,20,24,.72);
  border: 1px solid rgba(255,255,255,.32); border-radius: 999px; font-size: .58rem;
  font-weight: 850; letter-spacing: .13em; white-space: nowrap; backdrop-filter: blur(5px); }

@media (max-width: 900px) {
  .seating-setup-grid, .wheel-layout { grid-template-columns: 1fr; }
  .seating-template-panel { position: static; }
  .wheel-copy { text-align: center; }.wheel-stage { width: min(70vw, 540px); }
  .attendance-control-row { grid-template-columns: 1fr; }
  /* Stacked rows: the checkbox sits beside the student instead of a column. */
  .attendance-control-row.has-select { grid-template-columns: auto 1fr; }
  .attendance-control-row.has-select > :not(.roster-select):not(.attendance-student) { grid-column: 1 / -1; }
  .attendance-review-counts { grid-template-columns: repeat(3,1fr); }
}
@media (max-width: 650px) {
  .seating-page-head, .seating-live-head, .workspace-title,
  .assignment-head, .tool-intro, .attendance-review-head { align-items: stretch; flex-direction: column; }
  .live-head-actions, .assignment-actions { align-items: stretch; flex-direction: column; }
  .seating-mode-tabs { grid-template-columns: 1fr; }
  .seat-toolbar { align-items: flex-start; flex-direction: column; }
  .room-size-controls, .room-size-controls label, .group-controls, .group-controls label { width: 100%; }
  .room-front { width: 90%; }
  .wheel-stage { width: min(88vw, 480px); }
  .wheel-copy { padding: .5rem; }
  .attendance-review-counts { grid-template-columns: repeat(2,1fr); }
  .pair-rule-builders, .copy-options { grid-template-columns: 1fr; }
  .student-rule-grid label { grid-template-columns: 1fr; }
}

/* Preferred seating accommodations and room-zone painter. */
.pass-limit-mode { margin: .25rem 0; padding: .8rem; display: grid; grid-template-columns: repeat(2,minmax(0,1fr));
  gap: .65rem; border: 1px solid var(--line); border-radius: var(--control-radius); }
.pass-limit-mode legend { padding: 0 .35rem; color: var(--muted); font-size: .8rem; font-weight: 800; }
.pass-limit-mode label { padding: .7rem; flex-direction: row; align-items: flex-start; gap: .55rem;
  border: 1px solid var(--line); border-radius: var(--control-radius); background: var(--panel2); cursor: pointer; }
.pass-limit-mode label:has(input:checked) { border-color: var(--accent); background: rgba(122,193,67,.08); }
.pass-limit-mode input { width: 1.1rem; height: 1.1rem; margin-top: .12rem; accent-color: var(--accent); }
.pass-limit-mode span { display: flex; flex-direction: column; gap: .15rem; }
.pass-limit-mode small { color: var(--muted); line-height: 1.35; }
@media (max-width: 650px) { .pass-limit-mode { grid-template-columns: 1fr; } }

.seating-preference-field { padding: 1rem; border: 1px solid rgba(0,174,239,.28);
  border-radius: var(--radius); background: rgba(0,174,239,.065); }
.seating-preference-field > label { max-width: 360px; }
.seating-preference-field p { margin: .45rem 0 0; }
.preference-enforcement-note { padding-left: .7rem; border-left: 3px solid var(--info);
  color: var(--muted); font-size: .8rem; line-height: 1.45; }
.preference-map-setup { margin-top: 1rem; padding-top: 1rem; border-top: 1px solid var(--line); }
.preference-map-setup h3, .preference-map-setup p { margin: .2rem 0; }
.preference-mode-options { display: grid; grid-template-columns: repeat(2,minmax(0,1fr)); gap: .65rem; margin-top: .75rem; }
.preference-mode-card { padding: .8rem; display: flex; flex-direction: row; align-items: flex-start; gap: .65rem;
  color: var(--text); border: 1px solid var(--line); border-radius: var(--control-radius); background: var(--panel2); cursor: pointer; }
.preference-mode-card:has(input:checked) { border-color: var(--accent); background: rgba(122,193,67,.08);
  box-shadow: inset 0 0 0 1px rgba(122,193,67,.25); }
.preference-mode-card input { width: 1.1rem; height: 1.1rem; margin-top: .1rem; }
.preference-mode-card span { display: flex; flex-direction: column; gap: .18rem; }
.preference-mode-card small { color: var(--muted); line-height: 1.35; }
.manual-preference-map { margin-top: .9rem; padding: .85rem; border: 1px solid var(--line);
  border-radius: var(--radius); background: rgba(255,255,255,.018); }
.preference-zone-tools { display: flex; flex-wrap: wrap; gap: .4rem; margin: .65rem 0 .8rem; }
.zone-tool { min-height: 34px; padding: .3rem .58rem; color: var(--muted); background: var(--panel2); border-color: var(--line-strong); font-size: .76rem; }
.zone-tool.active { color: var(--on-accent); background: var(--accent); border-color: var(--accent); }
.preference-room { max-height: 520px; }
.preference-grid { display: grid; grid-template-columns: repeat(var(--seat-columns), minmax(76px,1fr));
  gap: .55rem; min-width: calc(var(--seat-columns) * 84px); }
.preference-cell { min-height: 68px; padding: .4rem; display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: .3rem; color: var(--text); background: var(--panel-raised); border: 1px solid var(--line-strong); border-radius: 9px; }
.preference-cell.selected-zone { border-color: var(--accent); background: rgba(122,193,67,.13);
  box-shadow: inset 0 0 0 2px rgba(122,193,67,.2); }
.preference-cell.empty { opacity: .18; border-style: dashed; background: transparent; }
.preference-cell strong { font-size: .74rem; }.preference-cell span { display: flex; flex-wrap: wrap; justify-content: center; gap: .18rem; color: var(--muted); font-size: .58rem; }
.preference-cell i { padding: .08rem .22rem; color: var(--accent); background: rgba(122,193,67,.1);
  border-radius: 4px; font-style: normal; }
.zone-map-help { margin-top: .55rem !important; }
@media (max-width: 650px) {
  .preference-mode-options { grid-template-columns: 1fr; }
}


/* Archived classes: a collapsed section of the class list, not its own page. */
.archived-classes { margin: 1.5rem 0 0; padding: .8rem; border: 1px solid var(--line);
  border-radius: var(--radius); background: var(--panel2); }
.archived-classes summary { display: flex; align-items: baseline; gap: .6rem; cursor: pointer; }
.archived-classes .list li { align-items: center; gap: .75rem; }
.archived-classes .list span { display: flex; flex-direction: column; }

/* One class-setup page: a header, jump links, and the room section it absorbed. */
.manage-class-head { display: flex; align-items: end; justify-content: space-between;
  gap: 1rem; margin-bottom: .75rem; }
.manage-class-head h1 { margin: .15rem 0; }
.manage-class-actions { display: flex; align-items: center; flex-wrap: wrap; gap: .5rem; }
.section-jump { display: flex; flex-wrap: wrap; gap: .4rem; margin: 0 0 1.25rem; }
.section-jump a { padding: .3rem .7rem; color: var(--muted); font-size: .82rem; font-weight: 700;
  text-decoration: none; border: 1px solid var(--line); border-radius: 999px; background: var(--panel2); }
.section-jump a:hover { color: var(--text); border-color: var(--line-strong); }
.manage-room-section { margin-top: 1.5rem; padding-top: 1.25rem; border-top: 1px solid var(--line); }
.manage-room-section .seating-page-head { margin-bottom: 1rem; }
@media (max-width: 650px) {
  .manage-class-head { align-items: stretch; flex-direction: column; }
}

/* Wheel: One and done + Reset names sit above the spin button. */
.wheel-controls { display: flex; align-items: center; gap: .6rem; margin: .5rem 0 .25rem; }
.wheel-controls label.inline { flex-direction: row; align-items: center; gap: .4rem;
  color: var(--text); font-size: .95rem; }
.wheel-controls input[type="checkbox"] { width: 1.1rem; height: 1.1rem; min-height: 0; }

/* Roster: personal leadership is off / every day / A days / B days. */
.pl-select { gap: .2rem; }
.pl-select select { min-width: 8.5rem; padding: .3rem .4rem; font-size: .82rem; min-height: 0; }
/* Pills sit inline beside the name; the row's spans are block by default. */
.attendance-student strong .pill { display: inline-block; margin-left: .1rem; }
.leadership-pill { color: #c4b5fd; background: rgba(167,139,250,.14);
  border: 1px solid rgba(167,139,250,.42); font-size: .62rem; vertical-align: middle; }

/* Name list: the seating-chart cards in last-name order. The column count
   follows the screen — as many ~170px cards as fit, no fixed breakpoints. */
.name-card-grid { display: grid; gap: .65rem;
  grid-template-columns: repeat(auto-fill, minmax(min(170px, 100%), 1fr)); }
.name-card-grid .live-desk { min-height: 76px; }

/* Shop: safety certification and tool training.
   The card is the name-list desk with a star in the top-left corner and a row of
   tool icons. Color carries the training level — amber under supervision, green
   independently — and a tool the student isn't cleared on has no icon at all, so
   the row reads as "what they may touch" rather than a checklist. A student
   without the safety certification loses both the star and the icons and turns
   red, which is the one state that has to be visible across the room. */
/* Glyph key. A tooltip is useless on the classroom touchscreen, so which icon
   means which tool is spelled out above the grid and stays on screen. */
.shop-key { display: flex; flex-wrap: wrap; gap: .35rem .9rem; margin: 0 0 .9rem;
  padding: .6rem .75rem; color: var(--muted); font-size: .76rem;
  background: var(--panel2); border: 1px solid var(--line); border-radius: var(--control-radius); }
.shop-key-item { display: inline-flex; align-items: center; gap: .35rem; }
.shop-card-grid { display: grid; gap: .65rem;
  grid-template-columns: repeat(auto-fill, minmax(min(180px, 100%), 1fr)); }
.shop-card { position: relative; min-width: 0; min-height: 92px;
  padding: 1.5rem .6rem .55rem; display: flex; flex-direction: column;
  align-items: flex-start; justify-content: flex-start; gap: .18rem; overflow: hidden;
  background: var(--panel-raised); border: 1px solid var(--line-strong); border-radius: 11px;
  box-shadow: 0 7px 20px rgba(0,0,0,.17); }
.shop-card strong { width: 100%; overflow: hidden; text-overflow: ellipsis;
  font-size: clamp(.75rem, 1.2vw, .98rem); white-space: nowrap; }
.shop-card small { color: var(--muted); font-size: .63rem; }
.shop-card .shop-none { font-style: italic; }
.shop-card[role="button"] { cursor: pointer; }
.shop-card[role="button"]:hover { border-color: var(--info); transform: translateY(-2px); }
.shop-card[role="button"]:focus-visible { outline: 3px solid var(--info); outline-offset: 2px; }
/* Uncertified: the whole card goes brand red so it carries across the shop. */
.shop-card.uncertified { color: #fff; background: var(--bad); border-color: var(--bad); }
/* Full-strength white: the brand red only clears 4.5:1 against pure white, so
   dimming this line would drop it under the contrast floor. */
.shop-card.uncertified small { color: #fff; }
.shop-card.uncertified[role="button"]:hover { border-color: #fff; }
/* The star sits top-left; the seating desk's behavior button holds top-right. */
.shop-star { position: absolute; top: .3rem; left: .35rem; display: flex;
  color: var(--sdscpa-orange); }
/* Filled, so the certification badge reads as a solid mark rather than one more
   outline glyph. A rule on the svg beats its own fill="none" attribute. */
.shop-star svg { fill: currentColor; }
.shop-tool-icons { margin-top: auto; padding-top: .3rem; display: flex; flex-wrap: wrap;
  align-items: center; gap: .3rem; }
.shop-tool { display: flex; }
.shop-tool.level-supervised { color: var(--warn); }
.shop-tool.level-independent { color: var(--good); }
.legend-dot.shop-supervised { background: var(--warn); }
.legend-dot.shop-independent { background: var(--good); }
.legend-dot.shop-none { background: var(--bad); }
/* Edit panel: one row per tool, three levels, the active one filled like the
   attendance buttons it borrows its markup from. */
.shop-actions-tools { display: flex; flex-direction: column; gap: .6rem;
  max-height: 46vh; overflow-y: auto; }
.shop-tool-row { display: flex; flex-direction: column; gap: .3rem; }
.shop-tool-row .attendance-status-buttons { flex-wrap: wrap; }
.shop-tool-row .attendance-status-buttons button { flex: 1 1 auto; }
#shop-safety-toggle { width: 100%; }
/* The admin tool list and the student page pair each glyph with its name. */
.tool-name { display: inline-flex; align-items: center; gap: .4rem; }
/* Student page: one radio column per level, so the whole record reads as a grid
   rather than seven separate controls. */
.training-table th:not(:first-child), .training-table .training-choice { text-align: center; }
.training-table .training-choice label { align-items: center; margin: 0; }
.training-table input[type="radio"] { width: 1.15rem; height: 1.15rem; accent-color: var(--accent); }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* Shop board: pull an IMIN sign-in packet for a past week. */
.imin-week-card { margin-bottom: 1.2rem; }
.imin-week-card h2 { display: flex; align-items: center; gap: .45rem; }
.imin-week-card form { align-items: flex-end; }
.imin-week-card select { min-width: 14rem; }

/* ==========================================================================
   Show attendance (/productions)
   Calls, ensembles, and the live call board. The calendar borrows the shop
   board's cell shape (see .cal above) with a seven-column week, because a show
   rehearses on weekends once tech starts.
   ========================================================================== */

/* --- The show list --- */
.show-grid { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr)); }
.show-card { background: var(--panel); border: 1px solid var(--line);
  border-left: 4px solid var(--showc, var(--accent)); border-radius: var(--radius);
  padding: 1rem 1.1rem; }
.show-card-title { margin: 0 0 .35rem; font-size: 1.15rem; }
.show-card-title a { text-decoration: none; }
.show-card-meta { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap;
  font-size: .82rem; margin-bottom: .5rem; }
.show-next { margin: .3rem 0; font-size: .88rem; }
.show-staff { display: flex; gap: .3rem; flex-wrap: wrap; margin: .4rem 0 0; }
.archived-shows { margin-top: 1.5rem; }
.plain-list { list-style: none; margin: .4rem 0; padding: 0; display: flex;
  flex-direction: column; gap: .35rem; }
.plain-list li { display: flex; align-items: center; gap: .45rem; flex-wrap: wrap; }

/* --- The per-show header and tab strip --- */
.show-head { display: flex; align-items: flex-start; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap; padding-bottom: .7rem; margin-bottom: 1rem;
  border-bottom: 3px solid var(--showc, var(--accent)); }
.show-head h1 { margin: 0; display: flex; align-items: center; gap: .5rem; }
.show-head p { margin: .2rem 0 0; }
.show-tabs { display: flex; gap: .35rem; flex-wrap: wrap; align-items: center; }
.show-tabs a { display: inline-flex; align-items: center; gap: .3rem; padding: .35rem .7rem;
  border: 1px solid var(--line); border-radius: 99px; font-size: .82rem;
  font-weight: 600; text-decoration: none; color: var(--text); }
.show-tabs a:hover { border-color: var(--accent); }
.show-tabs a[aria-current="page"] { background: var(--showc, var(--accent));
  border-color: transparent; color: var(--on-accent); }

/* --- Calendar: seven columns, and one chip per call --- */
.cal-grid-7 { grid-template-columns: repeat(7, 1fr); }
.cal-cell[href] { text-decoration: none; color: inherit; display: block; }
.callchip { display: inline-flex; align-items: center; gap: .25rem; font-size: .64rem;
  font-weight: 700; padding: .12rem .4rem; border-radius: 99px; max-width: 100%;
  background: var(--panel2); color: var(--text); }
.callchip-time { font-family: var(--mono); opacity: .85; }
.callchip-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.callchip.call-canceled, .call-card.call-canceled { opacity: .5; text-decoration: line-through; }
.cal-called { font-size: .62rem; }

/* Call kinds share one colour language across the calendar, the day sheet, the
   board tabs, and the kiosk cards. */
.call-rehearsal { --callc: var(--accent); }
.call-tech { --callc: var(--sdscpa-orange); }
.call-dress { --callc: var(--sdscpa-magenta); }
.call-performance { --callc: var(--sdscpa-red); }
.call-meeting { --callc: var(--muted); }
.call-strike { --callc: var(--sdscpa-cyan); }
.callchip.call-rehearsal, .callchip.call-tech, .callchip.call-dress,
.callchip.call-performance, .callchip.call-meeting, .callchip.call-strike,
.shopchip.call-rehearsal, .shopchip.call-tech, .shopchip.call-dress,
.shopchip.call-performance, .shopchip.call-meeting, .shopchip.call-strike,
.today-chip.call-rehearsal, .today-chip.call-tech, .today-chip.call-dress,
.today-chip.call-performance, .today-chip.call-meeting, .today-chip.call-strike {
  background: color-mix(in srgb, var(--callc) 18%, transparent); color: var(--callc); }
.today-chip.armed { outline: 2px solid var(--callc, var(--accent)); }

/* --- Ensemble chips --- */
.ens-chip { display: inline-flex; align-items: center; gap: .25rem; font-size: .64rem;
  font-weight: 700; padding: .1rem .45rem; border-radius: 99px; margin-right: .2rem;
  background: color-mix(in srgb, var(--ensc, var(--accent)) 20%, transparent);
  border: 1px solid var(--ensc, var(--accent)); color: var(--text); }
.ens-chip.lg { font-size: .8rem; padding: .22rem .6rem; }
[data-ensemble].dimmed, [data-ensembles].dimmed { opacity: .18; }
.ensemble-dot { width: .6rem; height: .6rem; border-radius: 99px; flex: none;
  background: var(--ensc, var(--accent)); }

/* --- "Who is called, day by day" under the calendar --- */
.called-list { display: flex; flex-direction: column; gap: .8rem; }
.called-day { background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: .8rem 1rem; }
.called-day.called-today { border-color: var(--accent); }
.called-day h3 { margin: 0 0 .4rem; display: flex; align-items: center; gap: .45rem;
  flex-wrap: wrap; font-size: .95rem; }
.called-call { display: flex; align-items: center; gap: .35rem; flex-wrap: wrap;
  margin-bottom: .3rem; font-size: .82rem; }
.called-names { margin: .3rem 0 0; font-size: .82rem; color: var(--muted); line-height: 1.6; }

/* --- The day call sheet --- */
.call-card { border-left: 4px solid var(--callc, var(--accent)); margin-bottom: 1rem; }
.call-card-head { display: flex; align-items: flex-start; justify-content: space-between;
  gap: .8rem; flex-wrap: wrap; }
.call-card-head h3 { margin: 0; display: flex; align-items: center; gap: .45rem; }
.call-card-meta { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap;
  font-size: .84rem; }
.call-notes { margin: .5rem 0; padding: .5rem .7rem; background: var(--panel2);
  border-radius: var(--control-radius); font-size: .88rem; }
.call-ensembles { display: flex; gap: .3rem; flex-wrap: wrap; margin: .6rem 0; }
.call-add-person { margin-top: .6rem; }
.call-add-person summary { cursor: pointer; font-size: .85rem; color: var(--muted); }
.row-excused { opacity: .55; }
.ensemble-picker { border: 1px solid var(--line); border-radius: var(--control-radius);
  padding: .7rem .9rem; }
.ensemble-picker legend { font-weight: 700; padding: 0 .3rem; }
/* A grid, not a flex row: the two time boxes have to line up in columns down
   the picker, however long the group names are. */
.ensemble-row { display: grid; align-items: center; gap: .5rem;
  grid-template-columns: minmax(6rem, 1fr) 8.5rem 8.5rem;
  padding: .25rem 0; border-bottom: 1px solid var(--line); }
.ensemble-row:last-child { border-bottom: 0; }
.ensemble-row .inline { display: flex; align-items: center; gap: .4rem; min-width: 0; }
.ensemble-row input[type="time"] { width: 100%; }
.ensemble-row-head { border-bottom: 0; padding-bottom: 0; font-size: .7rem;
  text-transform: uppercase; letter-spacing: .06em; color: var(--muted); }
/* Calling everybody of one kind sits above the named groups and is marked as
   the standing instruction it is. */
.role-row { border-bottom: 1px dashed var(--line); }
/* The board's "what time did they arrive?" picker, which stands in for the
   plain Late button once a call is over. */
.board-late-ask { display: inline-flex; align-items: center; gap: .25rem; }
.board-late-ask select { padding: .15rem .3rem; font-size: .8rem; }

.role-row.role-actor { --ensc: #EC008C; }
.role-row.role-assistant_director { --ensc: #8B5CF6; }
.role-row.role-crew { --ensc: #00AEEF; }
.role-row.role-stage_management { --ensc: #7AC143; }
@media (max-width: 520px) {
  .ensemble-row { grid-template-columns: 1fr 1fr; }
  .ensemble-row .inline { grid-column: 1 / -1; }
  .ensemble-row-head { display: none; }
}
.ensemble-block { background: var(--panel2); border: 1px solid var(--line);
  border-left: 3px solid var(--ensc, var(--accent)); border-radius: var(--control-radius);
  padding: .5rem .8rem; margin: .6rem 0; }
.ensemble-block summary { cursor: pointer; display: flex; align-items: center;
  gap: .45rem; flex-wrap: wrap; }
.ensemble-admin { margin-top: .5rem; justify-content: space-between; }
.color-input { width: 2.6rem; padding: .1rem; }
.modal-card.wide { max-width: 44rem; }

/* --- The live call board --- */
.board-summary { display: grid; gap: .6rem; margin: .8rem 0;
  grid-template-columns: repeat(auto-fit, minmax(7rem, 1fr)); }
.stat-tile { background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--control-radius); padding: .6rem .8rem; text-align: center; }
.stat-tile.good { border-color: var(--good); }
.stat-tile.warn { border-color: var(--warn); }
.stat-tile.bad { border-color: var(--bad); }
.stat-num { display: block; font-size: 1.8rem; font-weight: 900; line-height: 1.1; }
.stat-label { display: block; font-size: .7rem; text-transform: uppercase;
  letter-spacing: .06em; color: var(--muted); }
.board-caption { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; }
.call-board-grid { display: grid; gap: .7rem;
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); }
.call-person { background: var(--panel); border: 1px solid var(--line);
  border-left: 4px solid var(--line-strong); border-radius: var(--control-radius);
  padding: .6rem .8rem; }
.call-person header { display: flex; align-items: baseline; justify-content: space-between;
  gap: .5rem; }
.call-person-name { font-weight: 800; }
.call-person-state { font-size: .68rem; font-weight: 800; text-transform: uppercase;
  letter-spacing: .05em; }
.call-person-detail { margin: .25rem 0; font-size: .8rem; color: var(--muted); }
.call-person-ens { margin: .3rem 0 0; }
.call-person-actions { display: flex; gap: .25rem; flex-wrap: wrap; margin-top: .5rem; }
.call-person-actions button { font-size: .7rem; padding: .18rem .5rem; }
.call-person.state-on_time { border-left-color: var(--good); }
.call-person.state-on_time .call-person-state { color: var(--good); }
.call-person.state-late { border-left-color: var(--warn); }
.call-person.state-late .call-person-state { color: var(--warn); }
.call-person.state-absent { border-left-color: var(--bad); }
.call-person.state-absent .call-person-state { color: var(--bad); }
.call-person.state-excused { opacity: .6; }
.call-person.state-not_yet { border-left-color: var(--line-strong); }

/* --- The week strip on the call board: how the week has gone so far --- */
.week-strip { margin: .8rem 0 1rem; }
.week-strip-head { display: flex; align-items: baseline; gap: .8rem; flex-wrap: wrap; }
.week-strip-head h3 { margin: 0; }
.week-days { display: grid; gap: .4rem; margin-top: .5rem;
  grid-template-columns: repeat(7, minmax(0, 1fr)); }
.week-day { display: flex; flex-direction: column; gap: .18rem; padding: .5rem .55rem;
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--control-radius); text-decoration: none; color: inherit;
  min-width: 0; }
.week-day:hover { border-color: var(--line-strong); }
.week-day.armed { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent) inset; }
.week-day.week-today .week-day-name { color: var(--accent); }
.week-day.week-dark { opacity: .55; }
.week-day-name { font-size: .7rem; font-weight: 800; text-transform: uppercase;
  letter-spacing: .06em; }
.week-day-date { font-size: .78rem; color: var(--muted); }
.week-call { display: inline-flex; align-items: center; gap: .2rem; font-size: .68rem;
  font-weight: 700; padding: .1rem .35rem; border-radius: var(--control-radius);
  background: var(--panel2); border-left: 3px solid var(--callc, var(--accent));
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.week-call.call-canceled { text-decoration: line-through; opacity: .6; }
.week-day-counts { font-size: .7rem; color: var(--muted); margin-top: .1rem; }
.week-day-counts .good { color: var(--good); font-weight: 800; }
.week-day-counts .bad { color: var(--bad); font-weight: 800; }
@media (max-width: 720px) {
  .week-days { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* --- The company grid: ensembles across the top, the company down the side --- */
.matrix-scroll { overflow-x: auto; margin: .6rem 0; }
.matrix { border-collapse: collapse; font-size: .85rem; }
.matrix th, .matrix td { border: 1px solid var(--line); padding: .3rem .5rem; }
.matrix-corner, .matrix-name { position: sticky; left: 0; z-index: 1;
  background: var(--panel); text-align: left; font-weight: 700; white-space: nowrap; }
.matrix-name .pill { margin-left: .35rem; font-weight: 700; }
.matrix-head { background: var(--panel2); border-top: 3px solid var(--ensc, var(--accent));
  vertical-align: bottom; text-align: center; white-space: nowrap; }
.matrix-head-name { display: block; font-size: .8rem; }
.matrix-head .ensemble-dot { display: inline-block; }
.matrix-all { margin-top: .2rem; font-size: .65rem; padding: .1rem .4rem; }
.matrix-cell { text-align: center; padding: 0; }
.matrix-box { display: block; padding: .4rem .6rem; cursor: pointer; }
.matrix-box input { width: 1.05rem; height: 1.05rem; }
.matrix tbody tr:hover .matrix-name,
.matrix tbody tr:hover .matrix-cell { background: var(--panel2); }
.matrix-actions { align-items: center; gap: .7rem; }

/* The board's month: the same day cards, laid out as a calendar. */
.month-grid { display: grid; gap: .35rem; margin-top: .5rem;
  grid-template-columns: repeat(7, minmax(0, 1fr)); }
.month-head { font-size: .68rem; font-weight: 800; text-transform: uppercase;
  letter-spacing: .06em; color: var(--muted); text-align: center; }
.month-day { display: flex; flex-direction: column; gap: .15rem; min-height: 4.2rem;
  padding: .35rem .4rem; background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--control-radius); text-decoration: none; color: inherit;
  min-width: 0; }
.month-day:hover { border-color: var(--line-strong); }
.month-day.armed { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent) inset; }
.month-day.week-today .month-day-num { color: var(--accent); }
.month-day.month-outside { opacity: .4; }
.month-day-num { font-size: .72rem; font-weight: 800; }
.view-switch { display: inline-flex; gap: .2rem; align-items: center; }
.board-filter { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
  margin: .6rem 0 .2rem; font-size: .85rem; }
.board-filter label { font-weight: 700; }

/* --- The day roll: the same reading a class roster gives, for calls --- */
.pill.state-pill { font-weight: 800; }
.pill.state-on_time { background: rgba(34,197,94,.18); color: var(--good); }
.pill.state-late { background: rgba(245,158,11,.18); color: var(--warn); }
.pill.state-absent { background: rgba(239,68,68,.18); color: var(--bad); }
.pill.state-not_yet { background: var(--panel2); color: var(--muted); }
.pill.state-excused { background: rgba(139,92,246,.18); color: #a78bfa; }
/* What somebody does on a show, so a name reads as cast or crew at a glance. */
.pill.role-actor { background: rgba(236,0,140,.16); color: #f472b6; }
.pill.role-assistant_director { background: rgba(139,92,246,.16); color: #a78bfa; }
.pill.role-crew { background: rgba(0,174,239,.16); color: #38bdf8; }
.pill.role-stage_management { background: rgba(122,193,67,.16); color: #86c34a; }
.day-roll td, .call-roll td { vertical-align: top; }
.day-roll-call { display: block; margin: .1rem 0; }
.day-roll-absent td:first-child, .day-roll-late td:first-child { font-weight: 700; }
.roll-actions { gap: .25rem; flex-wrap: wrap; }
.roll-actions button { font-size: .7rem; padding: .18rem .5rem; }
.company-group { margin: 1rem 0 .3rem; font-size: .95rem; }
.company-table .card-scan-input { font-family: var(--mono); }

/* --- A show's public call board (/calls/<key>) --- */
.public-calls { max-width: 60rem; margin: 0 auto; padding: 1rem; }
.public-calls-head { display: flex; align-items: flex-start; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap; border-left: 5px solid var(--showc, var(--accent));
  padding-left: .9rem; margin-bottom: 1rem; }
.public-calls-head h1 { margin: .1rem 0; }
.public-calls-brand { display: flex; align-items: center; gap: .8rem; }
.public-call { border-left: 4px solid var(--callc, var(--accent)); background: var(--panel2);
  border-radius: var(--control-radius); padding: .7rem .9rem; margin-bottom: .7rem; }
.public-call h3 { margin: 0 0 .3rem; display: flex; align-items: center; gap: .45rem; }
.public-call-meta { display: flex; align-items: center; gap: .7rem; flex-wrap: wrap;
  margin: .2rem 0; font-size: .9rem; }
.public-call-people { list-style: none; display: flex; flex-wrap: wrap; gap: .3rem;
  margin: .5rem 0 0; padding: 0; }
.public-call-people li { font-size: .8rem; padding: .12rem .55rem; border-radius: 999px;
  background: var(--panel); color: var(--muted); }
.public-call-people li.is-in { background: rgba(34,197,94,.18); color: var(--good); font-weight: 700; }
.public-schedule td { vertical-align: top; }
.public-calls-foot { margin-top: 1rem; text-align: center; }

/* --- The sign-in kiosk: reuses the shop check-in shell (.ci-*) --- */
.ci-call { border-left: 5px solid var(--sc, var(--accent)); cursor: default; }
.ci-call.pickable { cursor: pointer; }
.ci-count { margin-top: .4rem; font-size: .8rem; }

/* ==========================================================================
   3D printing queue (/3dprinting)
   One public page: two machine cards on top, the join box, then the line. The
   machine cards carry their state in the left border and the state chip —
   green when open, amber while a print runs — so the board reads from across
   the shop. Manager controls live inside the same cards and are rendered only
   for a Tech Club manager.
   ========================================================================== */
.print-head h1 { display: flex; align-items: center; gap: .5rem; margin-bottom: .2rem; }
.print-head p { margin: 0 0 1.2rem; max-width: 44rem; }

.printer-grid { display: grid; gap: 1rem; margin-bottom: 1.4rem;
  grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr)); }
.printer-card { background: var(--panel); border: 1px solid var(--line);
  border-left: 5px solid var(--pc, var(--line-strong)); border-radius: var(--radius);
  padding: 1rem 1.15rem; box-shadow: var(--shadow); }
.printer-card.is-open { --pc: var(--good); }
.printer-card.is-printing { --pc: var(--warn); }
.printer-card-head { display: flex; align-items: flex-start; justify-content: space-between;
  gap: .8rem; }
.printer-card-head h2 { margin: 0; font-size: 1.3rem; }
.printer-model { margin: .1rem 0 0; font-size: .78rem; }
.printer-state { display: inline-flex; align-items: center; gap: .3rem; flex: none;
  font-size: .72rem; font-weight: 800; text-transform: uppercase; letter-spacing: .06em;
  padding: .2rem .55rem; border-radius: 99px; color: var(--pc);
  background: color-mix(in srgb, var(--pc) 16%, transparent); }
.printer-line { margin: .5rem 0 0; font-size: .9rem; }
.printer-open-line { font-weight: 600; }
.printer-who { display: flex; align-items: center; gap: .45rem; flex-wrap: wrap; }
.printer-job { font-style: italic; }
.printer-time { margin: .7rem 0 0; display: flex; align-items: baseline; gap: .45rem;
  flex-wrap: wrap; }
.printer-time-num { font-size: 1.7rem; font-weight: 900; line-height: 1.1;
  font-family: var(--mono); color: var(--warn); }
.printer-time-label { font-size: .78rem; color: var(--muted); }
.printer-time.is-soon .printer-time-num { color: var(--bad); }
.printer-time.is-done .printer-time-num { font-size: 1.2rem; color: var(--good); }

.printer-controls { margin-top: .9rem; padding-top: .8rem; border-top: 1px solid var(--line);
  display: flex; flex-direction: column; gap: .6rem; }
.printer-start { display: flex; flex-direction: column; gap: .5rem; }
.printer-est { display: flex; align-items: flex-end; gap: .6rem; margin: 0;
  border: 1px solid var(--line); border-radius: var(--control-radius); padding: .5rem .7rem; }
.printer-est legend { font-size: .78rem; color: var(--muted); padding: 0 .3rem; }
.printer-est input, .printer-retime input { width: 5rem; }
.printer-retime { display: flex; align-items: flex-end; gap: .5rem; flex-wrap: wrap; }
.printer-retime .field-label { margin: 0 0 .45rem; }
.hint { margin: 0; font-size: .78rem; }

/* --- Joining the line --- */
.print-join { margin-bottom: 1.4rem; }
.print-join h2 { margin-top: 0; }
.print-join-form { display: flex; align-items: flex-end; gap: .8rem; flex-wrap: wrap; }
.print-join-form .field { flex: 1 1 14rem; }
.print-join-form input { font-size: 1.05rem; }
.print-join-form #join-code { font-family: var(--mono); letter-spacing: .04em; }
.print-start-own { margin-bottom: 1.4rem; }
.print-start-own h2 { margin-top: 0; }
.print-own-form .printer-est { flex: 0 0 auto; }
.print-leave { margin-top: .8rem; }
.print-leave summary { cursor: pointer; font-size: .85rem; color: var(--muted); }
.print-leave form { margin-top: .5rem; }

/* --- The line itself --- */
.print-queue-section h2, .print-recent h2 { display: flex; align-items: baseline; gap: .6rem; }
.count-note { font-size: .85rem; font-weight: 400; }
.print-queue { list-style: none; margin: .4rem 0 1.4rem; padding: 0;
  display: flex; flex-direction: column; gap: .4rem; counter-reset: none; }
.print-row { display: flex; align-items: center; gap: .8rem; flex-wrap: wrap;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--control-radius);
  padding: .55rem .8rem; }
.print-row.is-next { border-color: var(--good);
  background: linear-gradient(145deg, color-mix(in srgb, var(--good) 10%, transparent),
              transparent 55%), var(--panel); }
.print-place { flex: none; width: 2rem; height: 2rem; border-radius: 99px;
  display: grid; place-items: center; font-family: var(--mono); font-weight: 800;
  background: var(--panel2); color: var(--muted); }
.print-row.is-next .print-place { background: var(--good); color: #06210a; }
.print-who { display: flex; align-items: center; gap: .45rem; flex-wrap: wrap;
  flex: 1 1 16rem; }
.print-job { font-size: .82rem; font-style: italic; }
.print-since { font-size: .78rem; }
.print-row-actions { display: flex; gap: .35rem; flex-wrap: wrap; align-items: center; }
.print-row-actions form { margin: 0; }
/* The two demotions and their shared "+ strike" tick-box read as one control. */
.demote-form { display: flex; align-items: center; gap: .35rem; flex-wrap: wrap; }
.strike-toggle { display: inline-flex; flex-direction: row; align-items: center; gap: .22rem;
  font-size: .7rem; font-weight: 700; color: var(--muted); cursor: pointer;
  padding: .18rem .4rem; border: 1px dashed var(--line-strong); border-radius: 99px; }
.strike-toggle input { accent-color: var(--bad); margin: 0; }
.strike-toggle:hover { color: var(--bad); border-color: var(--bad); }
.strike-toggle:has(input:checked) { color: var(--bad); border-style: solid;
  border-color: var(--bad); background: color-mix(in srgb, var(--bad) 14%, transparent); }
.idcode { font-family: var(--mono); font-size: .78rem; color: var(--muted);
  background: var(--panel2); border-radius: 6px; padding: .05rem .35rem; }
.prod-chip { font-size: .68rem; font-weight: 800; text-transform: uppercase;
  letter-spacing: .05em; padding: .1rem .45rem; border-radius: 99px; color: var(--violet);
  background: color-mix(in srgb, var(--violet) 22%, transparent); }
.strike-chip { display: inline-flex; align-items: center; gap: .2rem; font-size: .68rem;
  font-weight: 800; padding: .1rem .45rem; border-radius: 99px; color: var(--bad);
  background: color-mix(in srgb, var(--bad) 16%, transparent); }
.next-chip { font-size: .68rem; font-weight: 800; text-transform: uppercase;
  letter-spacing: .05em; padding: .1rem .45rem; border-radius: 99px; color: var(--good);
  background: color-mix(in srgb, var(--good) 16%, transparent); }

.print-recent { margin-bottom: 1.4rem; }
.print-rules ul { margin: .4rem 0 0; padding-left: 1.1rem; font-size: .9rem;
  color: var(--muted); }
.print-rules li { margin-bottom: .3rem; }
.print-rules h2 { margin-top: 0; font-size: 1.05rem; }

@media (max-width: 760px) {
  .print-row { align-items: flex-start; }
  .print-since { width: 100%; }
}

/* -----------------------------------------------------------------------
   The phone layout
   -----------------------------------------------------------------------
   Everything here hangs off html[data-view="phone"], which base.html sets
   before paint from the screen width (or the Layout picker in the account
   menu). It is an attribute rather than a plain media query for two reasons:
   a teacher can force either layout from a tablet or a laptop, and the few
   behaviours that need JS — the nav drawer, the install hint — key off the
   same flag the CSS does.

   The rules below are additive: a phone still gets every max-width block
   above, and this section only fixes what is left over once the screen is
   genuinely hand-sized. */

/* The notch and the home indicator. In an installed app the page paints under
   both (viewport-fit=cover plus the black-translucent status bar), so the bar
   at the top and the last thing on the page have to hold themselves clear. */
html[data-view="phone"] .topbar {
  flex-wrap: nowrap; gap: .5rem; padding: .5rem .75rem;
  padding-top: calc(.5rem + env(safe-area-inset-top));
  padding-left: max(.75rem, env(safe-area-inset-left));
  padding-right: max(.75rem, env(safe-area-inset-right));
}
html[data-view="phone"] .app-footer { padding-bottom: calc(2rem + env(safe-area-inset-bottom)); }
html[data-view="phone"] .container {
  padding-left: max(.85rem, env(safe-area-inset-left));
  padding-right: max(.85rem, env(safe-area-inset-right));
}

/* Nav: eight links become one button and a drawer. */
html[data-view="phone"] .brand-sub { display: none; }
html[data-view="phone"] .sdscpa-wordmark { height: 26px; }
html[data-view="phone"] .nav-toggle { display: inline-flex; margin-left: auto; }
html[data-view="phone"] .topbar .links {
  position: absolute; left: 0; right: 0; top: 100%; z-index: 1050;
  /* nowrap matters: the bar's own rule is flex-wrap: wrap, and a wrapping
     column with a bounded height spills into a second column instead of
     scrolling — the account menu ends up beside the links rather than under. */
  display: none; flex-direction: column; flex-wrap: nowrap; align-items: stretch; gap: 0;
  /* dvh, so an iPhone's collapsing Safari toolbar doesn't crop the last item;
     vh first for anything that doesn't know the unit. */
  max-height: calc(100vh - 4.5rem); max-height: calc(100dvh - 4.5rem); overflow-y: auto;
  padding: .35rem max(.75rem, env(safe-area-inset-left)) calc(.6rem + env(safe-area-inset-bottom));
  /* Opaque --panel rather than the bar's translucent --surface: this sheet
     covers the page rather than tinting it, and the page must not read through. */
  background: var(--panel); border-bottom: 1px solid var(--line);
  box-shadow: 0 18px 40px rgba(0,0,0,.4);
}
html[data-view="phone"] .topbar .links.open { display: flex; }
/* Dim whatever the sheet doesn't cover, so the open menu reads as one layer. */
body.nav-open::before {
  /* Under the sticky topbar (z-index 1000) — the sheet is painted inside the
     bar's own stacking context, so anything above 1000 would cover it too. */
  content: ""; position: fixed; inset: 0; z-index: 900; background: rgba(0,0,0,.45);
}
html[data-view="phone"] .topbar .links > a {
  display: flex; align-items: center; min-height: 48px;
  padding: .1rem .35rem; font-size: 1.02rem; border-bottom: 1px solid var(--line);
}
html[data-view="phone"] .topbar .links > a:last-child { border-bottom: none; }
html[data-view="phone"] .nav-now-pill { justify-content: center; margin: .5rem 0; }
html[data-view="phone"] .account { margin-top: .5rem; }
html[data-view="phone"] .account-btn { width: 100%; justify-content: space-between; min-height: 48px; }
/* Inside the drawer the account menu drops downwards in flow rather than
   floating, so it can't spill off the bottom of a short phone screen. */
html[data-view="phone"] .account-dropdown { position: static; width: 100%; margin-top: .4rem; box-shadow: none; }
html[data-view="phone"] .account-dropdown a { min-height: 44px; display: flex; align-items: center; }
/* In the drawer the quick-search spans the sheet, and its results list opens
   in flow (pushing the links below down) instead of floating over them. */
html[data-view="phone"] .nav-search { width: 100%; margin: .35rem 0; }
html[data-view="phone"] .nav-search-input,
html[data-view="phone"] .nav-search-input:focus { width: 100%; min-height: 44px; font-size: 16px; }
html[data-view="phone"] .nav-search-results { position: static; width: 100%; min-width: 0;
  margin-top: .4rem; box-shadow: none; }
html[data-view="phone"] .nav-search-results [role="option"] { min-height: 44px; justify-content: center; }

.nav-toggle {
  display: none; align-items: center; justify-content: center;
  width: 44px; height: 44px; padding: 0; flex: 0 0 auto;
  background: rgba(255,255,255,.045); color: var(--text);
  border: 1px solid var(--line); border-radius: var(--control-radius);
}
.nav-toggle-bars, .nav-toggle-bars::before, .nav-toggle-bars::after {
  display: block; width: 18px; height: 2px; border-radius: 2px; background: currentColor;
}
.nav-toggle-bars { position: relative; }
.nav-toggle-bars::before, .nav-toggle-bars::after { content: ""; position: absolute; left: 0; }
.nav-toggle-bars::before { top: -6px; }
.nav-toggle-bars::after { top: 6px; }
.nav-toggle[aria-expanded="true"] { color: var(--on-accent); background: var(--accent); border-color: var(--accent); }

/* Touch targets. A 44px minimum is the size a finger actually hits; the
   desktop `.sm` buttons in the roster are half that.
   `.app-surface` here is every staff page — the kiosks, the sign-in screens and
   the two TV boards size themselves for a tablet across the room and must keep
   their own scale even when the window is narrow, so they opt out. */
html[data-view="phone"] .app-surface button, html[data-view="phone"] .app-surface .btn-link,
html[data-view="phone"] .app-surface input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
html[data-view="phone"] .app-surface select,
html[data-view="phone"] .app-surface textarea { min-height: 44px; }
html[data-view="phone"] .app-surface button.sm,
html[data-view="phone"] .app-surface .btn-link.sm { min-height: 40px; padding: .5rem .7rem; }
/* iOS zooms the whole page in when a focused field is under 16px. */
html[data-view="phone"] .app-surface input, html[data-view="phone"] .app-surface select,
html[data-view="phone"] .app-surface textarea { font-size: 16px; }

/* The class view. The two floating rails, the projector link, and the sound
   meter are all board-and-laptop tools: the rails sit fixed over both edges of
   a phone screen, and iOS won't hand a home-screen app the microphone anyway. */
html[data-view="phone"] .class-tools-panel,
html[data-view="phone"] .sound-meter-panel { display: none; }
html[data-view="phone"] .live-head-actions .ghost-link[target="_blank"] { display: none; }
html[data-view="phone"] .seating-live-head h1 { font-size: 1.35rem; }
/* Undo and Manage class share a row rather than becoming two full-width bars
   that push the roster off the first screen. */
html[data-view="phone"] .live-head-actions {
  flex-direction: row; flex-wrap: wrap; align-items: stretch; gap: .5rem;
}
html[data-view="phone"] .live-head-actions > .presence-summary { flex: 1 1 100%; }
html[data-view="phone"] #workspace-undo .undo-what { display: none; }
html[data-view="phone"] .live-head-actions > button,
html[data-view="phone"] .live-head-actions > .btn-link { flex: 1 1 8rem; justify-content: center; }

/* Tabs: one swipeable strip of pills rather than six stacked full-width
   buttons, which on an iPhone is the whole screen before any class is on it. */
html[data-view="phone"] .seating-mode-tabs {
  display: flex; flex-wrap: nowrap; gap: .4rem; overflow-x: auto;
  margin-inline: calc(-1 * max(.85rem, env(safe-area-inset-left)));
  padding: .1rem max(.85rem, env(safe-area-inset-left)) .5rem;
  scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
html[data-view="phone"] .seating-mode-tabs::-webkit-scrollbar { display: none; }
html[data-view="phone"] .seating-tab {
  flex: 0 0 auto; min-height: 42px; padding: .5rem .85rem;
  border-radius: 999px; white-space: nowrap;
  background: var(--panel2); border-color: var(--line);
}
html[data-view="phone"] .seating-tab.active { background: var(--accent); border-color: var(--accent); }

/* Attendance: the counts stay one glanceable block, and each student is a card
   whose four status buttons share the width instead of overflowing it. */
/* Headings shrink so the roster starts on the first screen rather than below
   two lines of title, a counts block, and a filter. */
html[data-view="phone"] .seating-tool-panel h2 { font-size: 1.15rem; margin: 0 0 .4rem; }
html[data-view="phone"] .presence-summary { padding: .5rem .7rem; }
html[data-view="phone"] .attendance-review-counts { grid-template-columns: repeat(3, 1fr); gap: .4rem; margin: .7rem 0; }
html[data-view="phone"] .attendance-review-counts article { padding: .5rem .25rem; }
html[data-view="phone"] .attendance-review-counts strong { font-size: 1.2rem; }
html[data-view="phone"] .attendance-review-counts span { font-size: .58rem; letter-spacing: .04em; }
html[data-view="phone"] .attendance-control-row { gap: .5rem; padding: .7rem; }
html[data-view="phone"] .attendance-student strong { font-size: 1.05rem; }
/* Four equal status buttons on one row — flex-wrap put the fourth on a line of
   its own and stretched it, which read as the selected one. */
html[data-view="phone"] .attendance-status-buttons {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: .35rem;
}
html[data-view="phone"] .attendance-status-buttons button { min-height: 42px; padding: .5rem .15rem; font-size: .78rem; }
html[data-view="phone"] .attendance-status-buttons .left-early-button { grid-column: 1 / -1; }
html[data-view="phone"] .pass-quick-control { flex-wrap: wrap; }
html[data-view="phone"] .pass-quick-control select { flex: 1 1 8rem; min-width: 0; font-size: 16px; }
html[data-view="phone"] .pass-quick-control button { flex: 1 1 7rem; }
html[data-view="phone"] .behavior-quick-control button { width: 100%; }
html[data-view="phone"] #roster-filter { font-size: 16px; }

/* Wide-by-nature panels pan sideways instead of squeezing every desk to a
   sliver: a seating chart is a picture of the room and has to keep its shape. */
html[data-view="phone"] .room-shell { overflow-x: auto; -webkit-overflow-scrolling: touch; }
html[data-view="phone"] .live-seat-grid { min-width: 32rem; }
html[data-view="phone"] .live-room { min-height: auto; }
html[data-view="phone"] .name-card-grid,
html[data-view="phone"] .shop-card-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
html[data-view="phone"] .wheel-stage { width: min(92vw, 420px); }

/* Dialogs are the full width of the screen, and scroll rather than run off it. */
html[data-view="phone"] .app-surface .modal-card {
  width: calc(100vw - 1.2rem); max-height: 88vh; overflow-y: auto;
}

/* Anything laid out as a side-by-side pair collapses, and a wide table pans.
   minmax(0,…) rather than a bare 1fr: a grid column's automatic minimum is its
   min-content width, so one long unbreakable cell (an admin card's ID list)
   otherwise pushes the whole page wider than the screen. */
html[data-view="phone"] .app-surface .grid.two { grid-template-columns: minmax(0, 1fr); }
html[data-view="phone"] .app-surface .mgmt-monthnav {
  flex-wrap: wrap; justify-content: center; row-gap: .4rem;
}
html[data-view="phone"] .app-surface table.roster { display: block; overflow-x: auto; -webkit-overflow-scrolling: touch; }

/* The iOS "add to home screen" nudge (phone_view.js). Safari has no install
   prompt to offer, so this is the only way to say how it is done. */
.ios-install-hint {
  position: fixed; z-index: 1200; left: .6rem; right: .6rem;
  bottom: calc(.6rem + env(safe-area-inset-bottom));
  display: flex; align-items: center; gap: .75rem;
  padding: .75rem .85rem; background: var(--panel); border: 1px solid var(--line-strong);
  border-radius: var(--radius); box-shadow: 0 18px 40px rgba(0,0,0,.45);
}
.ios-install-hint > div { display: flex; flex-direction: column; gap: .15rem; }
.ios-install-hint strong { font-size: .92rem; }
.ios-install-hint span { color: var(--muted); font-size: .8rem; line-height: 1.35; }
.ios-install-hint button { flex: 0 0 auto; }

/* Release notes screen (/changelog). */
.changelog-intro { margin-top: -.4rem; }
.changelog-release h2 { display: flex; align-items: center; gap: .5rem;
  font-family: var(--mono); font-size: 1.05rem; }
.changelog-release.current { border-color: var(--accent); }

/* -----------------------------------------------------------------------
   The now-bar (phone layout)
   -----------------------------------------------------------------------
   Pinned under the top bar: what period it is, which class, and how long is
   left in it — tap to drop today's whole schedule down. now_bar.js fills the
   text and decides which period is current; everything here is presentation.

   Hidden in the full layout, where there is room for the class view's own
   header to carry the period times. */
.now-bar { display: none; }

html[data-view="phone"] .now-bar {
  display: block;
  /* Directly below the sticky top bar. --topbar-h is measured by now_bar.js;
     the fallback covers the moment before it first runs. */
  position: sticky; top: var(--topbar-h, 58px); z-index: 950;
  background: var(--panel); border-bottom: 1px solid var(--line);
  box-shadow: 0 10px 22px rgba(0,0,0,.28);
}
html[data-view="phone"] .now-bar[hidden] { display: none; }

.now-bar-summary {
  width: 100%; display: flex; align-items: center; gap: .6rem;
  padding: .5rem max(.85rem, env(safe-area-inset-left));
  padding-right: max(.6rem, env(safe-area-inset-right));
  background: none; border: none; border-radius: 0; color: var(--text);
  font: inherit; text-align: left; min-height: 46px;
}
/* The app's generic button:hover fill would otherwise paint this strip solid
   accent — and a tap on iOS leaves :hover stuck there until you tap elsewhere. */
.now-bar-summary:hover, .now-bar-summary:active { background: none; }
.now-bar-where { display: flex; align-items: baseline; gap: .45rem; min-width: 0; }
.now-bar-where strong { font-size: .95rem; white-space: nowrap; }
/* The class name is the one part that can be long; it ellipsizes so the
   countdown never gets pushed off the right edge. */
.now-bar-class {
  color: var(--muted); font-size: .85rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.now-bar-countdown {
  margin-left: auto; flex: 0 0 auto;
  font-variant-numeric: tabular-nums; font-weight: 800; font-size: .95rem;
  color: var(--good);
}
/* Under five minutes left, and between periods, read differently at a glance. */
.now-bar.is-soon .now-bar-countdown { color: var(--warn); }
.now-bar.is-between .now-bar-countdown { color: var(--info); }
.now-bar-chevron {
  flex: 0 0 auto; color: var(--muted); font-size: 1.1rem; line-height: 1;
  transform: rotate(90deg); transition: transform .18s var(--ease-fluid);
}
.now-bar.open .now-bar-chevron { transform: rotate(270deg); }

.now-bar-schedule { display: none; margin: 0; padding: 0 0 .4rem; list-style: none; }
.now-bar.open .now-bar-schedule { display: block; }
.now-bar-override {
  padding: .3rem max(.85rem, env(safe-area-inset-left));
  color: var(--warn); font-size: .74rem; font-weight: 800;
  letter-spacing: .05em; text-transform: uppercase;
}
.now-bar-period {
  /* Wide enough for a named period ("Advisory") and a full time range without
     either wrapping; the class name takes whatever is left and ellipsizes. */
  display: grid; grid-template-columns: minmax(0, 4.4rem) minmax(0, 8.4rem) minmax(0, 1fr);
  align-items: center; gap: .7rem;
  padding: .45rem max(.85rem, env(safe-area-inset-left));
  border-top: 1px solid var(--line); font-size: .82rem;
}
.now-bar-period .nbp-name {
  font-weight: 800; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.now-bar-period .nbp-time {
  color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap;
}
.now-bar-period .nbp-class { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* A period already over stays listed — the day's shape is the point — but
   steps back so the eye lands on what is running. */
.now-bar-period.is-past { opacity: .45; }
.now-bar-period.is-now {
  background: rgba(122,193,67,.10);
  box-shadow: inset 3px 0 0 0 var(--good);
}
.now-bar-period.is-now .nbp-name { color: var(--good); }

/* The class view's header and the class list's own strip both say what the bar
   above has already said; on a phone there is no room to say it twice. */
html[data-view="phone"] .period-status,
html[data-view="phone"] .schedule-strip { display: none; }

/* ---------------------------------------------------------------------------
   Screen audit polish (v1.70): layout defects found walking every screen at
   desktop and phone widths. Each rule names the screen it was seen on.
   --------------------------------------------------------------------------- */
/* Analytics stat tiles: the label is inline text with a help mark, not a form
   field, so it must not stack like the column layout every <label> gets. */
.count label { display: flex; flex-direction: row; justify-content: center; align-items: center; gap: .35rem; }
/* Empty-state notes inside a card grid (Concerns, Who's in the shop) were
   squeezed into one grid column and wrapped every few words. */
.grid > p.muted, .grid > .resource-empty, .shop-cards-grid > p.muted { grid-column: 1 / -1; }
/* Class roster (Manage class): the name column collapsed to one word a line
   while the tag and role forms took the width. */
.roster.compact td:first-child { min-width: 10rem; }
.roster.compact td:first-child > a { white-space: nowrap; }
/* Staff accounts: the per-row edit form wrapped Save and Delete onto their own
   lines; keep the whole thing one wrapping row with even gaps. */
.admin-edit-cell .row { align-items: center; gap: .4rem; }
.admin-edit-cell .row > * { margin: 0; }
/* Attendance history header: the actions stacked when the trend strip was
   long. They are one row; the text column gives way instead. */
.manage-class-head > div:first-child { min-width: 0; flex: 1 1 auto; }
.manage-class-actions { flex: 0 0 auto; }
/* Titles that sit in a flex row (a show's header, the 3D printing head) put
   the rainbow rule beside the words instead of under them. */
.show-head h1, .print-head h1 { display: block; }
.show-head h1 .pill, .print-head h1 svg { vertical-align: middle; }
/* Classroom kiosks: the pairing banner sat on the station name under the
   wordmark. Give the header its height and hang the banners below it. */
.kiosk-header { min-height: 4.6rem; }
.teacher-banner { top: 4.6rem; }
.current-course { top: 4.8rem; }
.kiosk-universal .current-course { top: 7rem; }
/* Kiosks stand on the same ground as every other screen: the house dark with
   its two faint radial washes, not a slate blue of their own. */
.kiosk-body {
  background: var(--bg);
  background-image:
    radial-gradient(900px 480px at 50% -8%, rgba(59,130,246,.10), transparent 70%),
    radial-gradient(700px 420px at 90% 110%, rgba(139,92,246,.08), transparent 70%);
}
@keyframes kioskflash {
  0%, 100% { background: var(--bg); }
  50%      { background: #b91c1c; }
}
/* The sign-in kiosks (shop check-in, show sign-in, activity sign-in) carry the
   wordmark like every other screen. */
.ci-head { align-items: center; }
.ci-brand { display: inline-flex; align-items: center; line-height: 1; }
.ci-brand svg { height: 26px; width: auto; }
/* The offline page's wordmark sat off to the left of its centred copy. */
.kiosk-logo-block { display: flex; justify-content: center; margin-bottom: .6rem; }
/* Accommodation inputs were narrower than their own placeholder text. */
.input-w-12 { width: 12rem; }
/* Settings: the test-digest row is a slim footer under the digest card. */
.settings-test-digest { display: flex; align-items: center; justify-content: space-between; gap: .8rem; flex-wrap: wrap; padding: .8rem 1.1rem; }
/* Production board pager: a pill and two button styles shared one row. */
.mgmt-monthnav .pill { align-self: center; }
/* Phones: nothing scrolls the page sideways. Wide tables and form rows scroll
   inside their own card instead, and grids fall to one column. */
@media (max-width: 760px) {
  .card, .panel, section.card { overflow-x: auto; }
  table { max-width: 100%; }
  .row > input, .row > select, .row > textarea, label > input, label > select { max-width: 100%; min-width: 0; }
  .input-w-10, .input-w-12 { max-width: 100%; }
  .roster.compact td:first-child { min-width: 7rem; }
  .print-sheet table, .print-sheet { max-width: 100%; }
  /* A block-level scrolling table still reports its full row width to the
     document in Chromium, so the page could be dragged sideways into empty
     space; painting containment keeps the overflow inside the table. */
  table { contain: paint; }
}
@media (max-width: 520px) {
  .imin-ten-grid { grid-template-columns: minmax(0, 1fr); }
  .imin-day-card, .imin-tv-head, .imin-today, .imin-next { min-width: 0; max-width: 100%; }
  .imin-tv-head { flex-wrap: wrap; }
}
/* Card grids (Concerns, the class list): a 220px column wrapped a student's
   name onto two lines beside its badge; 260px lets a card read in one glance. */
.grid:not(.two) { grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); }

/* ---------------------------------------------------------------------------
   Admin page (v1.70 restructure): anchored sections, forms as field rows and
   grids, and an account table whose editor opens as a row beneath the account
   instead of living inside the table cell.
   --------------------------------------------------------------------------- */
.admin-classes-grid { grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); }
.admin-field-row > input, .admin-field-row > select { flex: 1 1 12rem; min-width: 0; }
.admin-field-row > button { flex: 0 0 auto; }
.admin-field-grid { display: grid; gap: .6rem .8rem; grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr)); }
.admin-field-grid label { min-width: 0; }
.admin-field-grid input, .admin-field-grid select { width: 100%; }
.admin-subgrid { margin-top: 1.1rem; padding-top: 1rem; border-top: 1px solid var(--line); }
.admin-subgrid h3 { margin: 0 0 .3rem; }
.admin-inline-edit { display: flex; align-items: center; gap: .5rem; flex-wrap: nowrap; }
.admin-inline-edit > form.row { flex: 1 1 auto; min-width: 0; align-items: center; gap: .4rem; flex-wrap: nowrap; }
.admin-inline-edit > form.row > input[name="name"] { flex: 1 1 5rem; min-width: 4rem; width: auto; }
.admin-inline-edit > form.row > select { flex: 0 1 7rem; min-width: 0; }
.admin-inline-edit > form:last-child { flex: 0 0 auto; }
.shop-dot { flex: 0 0 auto; width: 14px; height: 14px; border-radius: 50%; border: 1px solid rgba(255,255,255,.25); }
.admin-add-account { margin: .2rem 0 1rem; }
.admin-add-account > summary { cursor: pointer; }
.admin-add-account form { margin-top: .8rem; }
.admin-accounts td { vertical-align: middle; }
.admin-accounts .pill + .pill { margin-left: .25rem; }
.admin-account-actions { text-align: right; white-space: nowrap; }
.admin-account-disabled td { color: var(--muted); }
.admin-account-editor > td { background: var(--panel2); border-radius: var(--control-radius); padding: 1rem; }
.admin-account-editor form.stack { gap: .8rem; }
.admin-editor-actions { align-items: center; }
.admin-editor-delete { margin-top: .8rem; padding-top: .8rem; border-top: 1px solid var(--line); }
#data > .export-groups { margin-top: .9rem; }
.admin-accounts th:nth-child(3), .admin-accounts td:nth-child(3),
.admin-accounts th:nth-child(4), .admin-accounts td:nth-child(4) { white-space: nowrap; }
@media (max-width: 760px) {
  .admin-classes-grid { grid-template-columns: minmax(0, 1fr); }
  .admin-account-actions { text-align: left; }
  /* Phone: each shop/tool row wraps to two lines (name, then colour/icon + controls)
     instead of squashing the name box to a few letters. */
  .admin-inline-edit { align-items: flex-start; }
  .admin-inline-edit > form.row { flex-wrap: wrap; flex: 1 1 0; min-width: 0; row-gap: .45rem; }
  .admin-inline-edit > form.row > input[name="name"] { flex: 1 1 11rem; }
  .admin-inline-edit > form.row > select { flex: 0 1 7rem; max-width: 7rem; }
  .admin-inline-edit > form.row > input[type="color"] { flex: 0 0 3.2rem; width: 3.2rem; }
  .admin-inline-edit > form.row > label.inline, .admin-inline-edit > form.row > button { flex: 0 0 auto; }
  .admin-inline-edit > form:last-child { margin-top: .1rem; }
  /* The tag and show columns are for looking things up, not for phones. */
  .admin-accounts th:nth-child(3), .admin-accounts td:nth-child(3),
  .admin-accounts th:nth-child(4), .admin-accounts td:nth-child(4) { display: none; }
}
