:root {
  /* One token set for both themes: follows the system unless the toggle sets data-theme. */
  color-scheme: light dark;
  /* The tear-off calendar (ปฏิทินฉีก): warm grey ground, white paper, ink type; seedling green = action and today,
     calendar red = holidays, weekends, deadlines and errors. Dark: the same paper at night. */
  --bg: light-dark(#efeeea, #121211); --card: light-dark(#fff, #1c1c1a); --text: light-dark(#141414, #f3f2ee);
  --muted: light-dark(#6a6a66, #a3a29c); --line: light-dark(#e4e2dc, #2f2e2a); --accent: light-dark(#2c7a3f, #5cbf72);
  --accent-text: #fff; --danger: light-dark(#d3212d, #ff5a52); --bad-bg: light-dark(#fdeceb, #3a1b19);
  --ex-bg: light-dark(#f2f1ec, #2a2926); --warn-bg: light-dark(#fff6df, #332a14); --head: light-dark(#faf9f6, #222120);
  --fill: light-dark(#f2f1ec, #2a2926); --ring: light-dark(rgb(44 122 63 / .28), rgb(92 191 114 / .4));
  --sprout: light-dark(#e4f0dd, #1f3324); --pad-under: light-dark(#dcd9d0, #0a0a09);
  --shadow: 0 1px 0 var(--pad-under), 0 0 0 1px light-dark(rgb(40 36 20 / .07), rgb(255 255 255 / .07)); /* paper on the desk: a hairline and the sheet's edge */
  /* one paper pad: bound at the top (small top corners), the next sheet showing underneath */
  --pad-shadow: 0 2px 0 var(--pad-under), 0 8px 22px light-dark(rgb(40 36 20 / .07), rgb(0 0 0 / .45));
  --display: 'Kanit', 'IBM Plex Sans Thai', system-ui, sans-serif; /* titles and calendar numerals, Thai and English */
  --body: 'IBM Plex Sans Thai', system-ui, sans-serif; /* everything else: one family for Thai and English, the same on every device */
  /* KSAii: c = column tint, b = bar / accent. K red · S yellow · A pink · i (Integrity) sky blue · i (Imagination) blue */
  --c0: light-dark(#ffecea, #3a1714); --c1: light-dark(#fff8d6, #332b0a); --c2: light-dark(#fdeef6, #3a1428);
  --c3: light-dark(#e8f7fa, #0f2a30); --c4: light-dark(#eaf3ff, #0f2338); --b0: light-dark(#ff3b30, #ff453a);
  --b1: light-dark(#ffcc00, #ffd60a); --b2: light-dark(#ec4899, #f472b6); --b3: light-dark(#30b0c7, #40c8e0);
  --b4: light-dark(#007aff, #0a84ff); --track: light-dark(#e4e2dc, #34332f); --stripe: light-dark(#faf9f6, #20201e);
  /* not KSAii: done / submitted green and the program badges keep their own colours */
  --mid: #d4a017; --mid-text: light-dark(#9a7300, #e0b23a); /* yellow: 'fine' scores, same as a late plan */
  --ok: light-dark(#28a745, #30d158); --ok-bg: light-dark(#eafaf0, #10291a); --ip-bg: light-dark(#eaf3ff, #0f2338); --iep-bg: light-dark(#fff4e5, #33240c);
  --hover: light-dark(#f3f6f0, #262624);
  --xhair: light-dark(rgb(44 122 63 / .06), rgb(92 191 114 / .12)); --xhair-on: light-dark(rgb(44 122 63 / .11), rgb(92 191 114 / .22));
  --ease: cubic-bezier(.25, .1, .25, 1);
  --glide: cubic-bezier(.16, 1, .3, 1); /* expo ease-out: arrivals that slow to a stop (page switches, the loading line) */
  /* Motion (transitions.dev scale). ui.js reads the timings too, so they live only here. */
  --text-swap-dur: 150ms; --text-swap-translate-y: 4px; --text-swap-blur: 2px; --text-swap-ease: ease-in-out;
  --shimmer-dur: 1400ms; --shimmer-base: var(--muted); --shimmer-highlight: var(--text); --shimmer-band: 400%; --shimmer-ease: linear;
  --toast-open: 350ms; --toast-close: 250ms; --toast-distance: 16px; --toast-blur: 2px; --toast-scale: 0.97; --toast-ease: cubic-bezier(0.22, 1, 0.36, 1);
  --list-dur: 250ms; --list-stagger: 40ms; --list-distance: 6px; --list-ease: cubic-bezier(0.22, 1, 0.36, 1);
  --scroll-distance: 12px;
  --btn: #2c7a3f; --btn-danger: #c81e2a; /* filled buttons: white text stays >= 4.5:1 in both themes */
  font: 15px/1.5 var(--body);
  letter-spacing: -.011em; -webkit-font-smoothing: antialiased;
  /* browser surfaces in the palette too: checkboxes, caret, scrollbars */
  accent-color: var(--accent); caret-color: var(--accent); scrollbar-color: color-mix(in srgb, var(--muted) 45%, transparent) transparent;
}
:root[data-theme='light'] { color-scheme: light; }
:root[data-theme='dark'] { color-scheme: dark; }
* { box-sizing: border-box; }
html { scrollbar-gutter: stable; } /* short and long pages keep the same centre line */
body { margin: 0; background: var(--bg); color: var(--text); }
h1 { font: 700 2rem/1.1 var(--display); letter-spacing: -.01em; margin: 0 0 .25rem; text-wrap: balance; }
h2 { font: 600 1.15rem/1.3 var(--display); letter-spacing: 0; margin: 0 0 .75rem; }
/* One page column for every view; the bar's contents line up with it */
:root { --page: 1440px; --gutter: 24px; --page-pad: max(var(--gutter), (100% - var(--page)) / 2); }
@media (max-width: 640px) { :root { --gutter: 16px; } }
main { padding: 24px var(--gutter) 72px; max-width: calc(var(--page) + 2 * var(--gutter)); margin: 0 auto; } /* bottom room for the floating account button */
/* Page header, the same on every view: title (+ muted line) left, a figure or control right */
.page-head { display: flex; flex-wrap: wrap; gap: .6rem 2rem; align-items: flex-end; justify-content: space-between; margin: 0 0 1.5rem; }
.page-head h1 { margin: 0; }
.page-head p { margin: .2rem 0 0; font-size: .85rem; color: var(--muted); }
::selection { background: var(--ring); }
input, select, button { font: inherit; color: inherit; }
/* Filled fields (iOS style): soft fill, no hard border, blue focus ring */
input, select { background: var(--fill); border: 1px solid transparent; border-radius: 8px; padding: .45rem .65rem; min-width: 0;
  transition: box-shadow .15s var(--ease), background .15s var(--ease); }
input:focus, select:focus, textarea:focus { outline: none; background: var(--card); border-color: var(--accent); box-shadow: 0 0 0 4px var(--ring); }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Buttons: pill shapes, quiet secondary, press feedback */
button { background: var(--fill); border: 1px solid transparent; border-radius: 980px; padding: .45rem 1rem; cursor: pointer; font-weight: 500;
  transition: background .15s var(--ease), color .15s var(--ease), transform .1s var(--ease), opacity .15s; }
button:hover:not(:disabled) { background: color-mix(in srgb, var(--fill) 88%, var(--text)); }
button:active:not(:disabled) { transform: scale(.97); }
button:disabled { opacity: .4; cursor: not-allowed; }
button.primary { background: var(--btn); color: #fff; font-weight: 600; }
button.primary:hover:not(:disabled) { background: color-mix(in srgb, var(--btn) 88%, #000); }
button.ghost { background: none; color: var(--accent); }
button.ghost:hover:not(:disabled) { background: color-mix(in srgb, var(--accent) 10%, transparent); }
button.danger { color: var(--danger); }
button.link { background: none; border: none; color: var(--accent); padding: .2rem 0; text-align: left; }
/* Frosted, sticky top bar with a hairline */
.top { position: sticky; top: 0; z-index: 20; display: flex; align-items: center; gap: .5rem; padding: .55rem var(--page-pad); flex-wrap: wrap;
  background: var(--card);
  border-bottom: 1px solid var(--line); }
.top strong, .top b { font-weight: 600; letter-spacing: -.01em; }
.top .brand { font: 600 1.2rem var(--display); letter-spacing: 0; white-space: nowrap; }
.top .logo { height: 2.1rem; }
.navrow { display: flex; align-items: center; }
.top:not(.staff) .navrow { margin-left: .9rem; padding-left: 1rem; border-left: 1px solid var(--line); } /* teachers: one bar */
.top.staff .navrow { order: 10; flex-basis: 100%; padding-top: .3rem; }                                  /* staff: the long menu gets its own row */
@media (max-width: 760px) { .top .navrow, .top:not(.staff) .navrow { order: 10; flex-basis: 100%; margin: 0; padding: .3rem 0 0; border: 0; } }
.top .themebtn, .top .lang { height: 2.25rem; border: 1px solid var(--line); background: var(--card); }
.top .themebtn { width: 2.25rem; }
.top .lang { padding: 0 .85rem; color: var(--text); font-size: .85rem; font-weight: 600; }
.top .themebtn:hover, .top .lang:hover:not(:disabled) { background: var(--fill); }
@media (max-width: 640px) { .top { position: static; } } /* a tall wrapped bar shouldn't eat a phone screen */
.grow { flex: 1; }
.muted { color: var(--muted); }
.hint { color: var(--muted); font-size: .9rem; margin: .5rem 0; }
.msg { color: var(--danger); }
.banner { margin: 0; padding: .6rem 16px; background: var(--warn-bg); font-size: .9rem; }
.banner.warn { border-radius: 12px; margin-bottom: 1rem; }
/* Cards: no borders, soft layered shadow, generous radius */
.card { background: var(--card); border: 0; border-radius: 14px; padding: 1.5rem; max-width: 760px; margin: 0 auto; box-shadow: var(--shadow); }
.card.narrow { max-width: 380px; display: grid; gap: .9rem; margin-top: 10vh; padding: 2rem; }
.card label { display: grid; gap: .25rem; }
.row { display: flex; gap: .5rem; flex-wrap: wrap; align-items: center; margin-bottom: .5rem; }
.row input { flex: 1 1 140px; }

/* Admin overview dashboard: SVG cards (charts.js), each with a copy-as-image button */
.dash { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr)); gap: 1rem; margin: .5rem 0 1rem; }
.dash.charts { grid-template-columns: repeat(auto-fit, minmax(min(100%, 440px), 1fr)); margin-bottom: 1.5rem; }
.viz[data-viz="students-by-room"] { grid-column: 1 / -1; } /* rooms flow into columns across the full width */
.viz { position: relative; margin: 0; padding: .5rem .5rem .75rem; background: var(--card); border-radius: 14px; box-shadow: var(--shadow); min-width: 0; }
.viz svg { display: block; max-width: 100%; height: auto; }
.viz text { font-family: inherit; fill: var(--text); }
.viz .v-title { font-family: var(--display); font-size: 16px; font-weight: 600; }
.viz .v-sub { font-size: 13px; fill: var(--muted); }
.viz .v-lbl { font-size: 13px; }
.viz .v-val { font-size: 13px; font-weight: 600; }
.viz .v-big { font-family: var(--display); font-size: 46px; font-weight: 700; letter-spacing: -.02em; }
.viz .track { fill: var(--fill); }
.viz .bar { fill: var(--kb, var(--accent)); }
.viz-ctl { display: flex; gap: .5rem; flex-wrap: wrap; align-items: center; padding: 0 .5rem; }
.viz-ctl .tabs { margin: 0; }
.viz-ctl select { flex: 1 1 10rem; max-width: 18rem; }
.viz-copy { position: absolute; top: .5rem; right: .5rem; padding: .4rem; border-radius: 50%; line-height: 0; }
.bar { display: flex; gap: .5rem; align-items: center; flex-wrap: wrap; margin-bottom: .75rem; font-size: .88rem; }
/* Class page header: subject name leads, code · room · program under it, icon buttons for back / change log */
.class-head { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem .75rem; margin-bottom: 1.1rem; font-size: .88rem; }
.ch-title h1 { margin: 0; font-size: 1.35rem; line-height: 1.25; }
.ch-title p { display: flex; align-items: center; gap: .35rem; margin: .15rem 0 0; font-size: .82rem; color: var(--muted); }
/* Part classes (STEM, Science Lab): the group line under the header; the at-risk dot in the pinned Term / % cell */
.parts-line { display: flex; flex-wrap: wrap; align-items: center; gap: .35rem .9rem; margin: -.4rem 0 1rem; font-size: .82rem; color: var(--muted); }
.parts-line > span { display: inline-flex; align-items: center; gap: .35rem; color: var(--text); }
.risk { display: inline-block; width: 7px; height: 7px; margin-left: .3rem; vertical-align: middle; border-radius: 50%; background: var(--danger); }
button.icon { display: inline-grid; place-items: center; width: 2.25rem; height: 2.25rem; padding: 0; border-radius: 50%; flex: none; }
button.icon svg { width: 18px; height: 18px; }
:is(button:not(.icon), .badge, .miss):has(> svg.i) { display: inline-flex; align-items: center; gap: .35em; }
button.icon[aria-pressed="true"] { background: color-mix(in srgb, var(--accent) 14%, transparent); }
.tabrow { display: flex; flex-wrap: wrap; align-items: center; gap: .35rem; margin-bottom: 1rem; }
.tabs { scrollbar-width: none; } /* a phone swipes the segmented control; no scrollbar strip under it */
.tabrow .tabs { margin-bottom: 0; }
/* Sign in with Google: a quiet secondary pill with Google's own mark, then a hairline "or" before the email form */
.google-btn { display: inline-flex; align-items: center; justify-content: center; gap: .6rem; width: 100%; background: var(--fill); color: var(--text); font-weight: 600; }
.google-btn:hover { background: color-mix(in srgb, var(--fill) 88%, var(--text)); }
.login .or { display: flex; align-items: center; gap: .75rem; margin: .25rem 0; color: var(--muted); font-size: .8rem; }
.login .or::before, .login .or::after { content: ''; flex: 1; border-top: 1px solid var(--line); }
/* change log: a quiet link at the foot of every staff page; the dialog scrolls its table */
.page-foot { display: flex; justify-content: flex-end; margin-top: 2rem; padding-top: .75rem; border-top: 1px solid var(--line); }
.page-foot .link { display: inline-flex; align-items: center; gap: .35rem; font-size: .8rem; color: var(--muted); }
.page-foot .link:hover { color: var(--accent); }
.log-scroll { max-height: 60vh; overflow: auto; margin-bottom: .75rem; }
.log-scroll td { font-size: .8rem; vertical-align: top; }
dialog:has(.log-scroll) { width: min(960px, calc(100vw - 32px)); }
/* welcome screen: language choice above the form */
.tn-lang { display: flex; align-items: center; justify-content: space-between; gap: .75rem; flex-wrap: wrap; }
.tn-lang > span { font-weight: 600; }
.tn-lang .tabs { margin: 0; }
.tn-lang small { flex-basis: 100%; }
.menu.tip { font-size: .85rem; line-height: 1.5; padding: .75rem .9rem; }
.bar input { width: 12rem; }
.bar input.short { width: 7rem; }
label.inline { display: inline-flex; align-items: center; gap: .35rem; white-space: nowrap; }
input.num { width: 4.5rem; }
.status { font-size: .85rem; color: var(--muted); }
.status.saveError, .status.conflict { color: var(--danger); }
/* Segmented control (class tabs) */
.tabs { display: inline-flex; gap: 2px; padding: 2px; border-radius: 9px; background: var(--fill); margin-bottom: 1rem; overflow-x: auto; max-width: 100%; }
.tabs button { border: 0; border-radius: 7px; background: none; white-space: nowrap; font-size: .85rem; color: var(--text); padding: .3rem .95rem; }
.tabs button:hover:not(.on):not(:disabled) { background: none; opacity: .7; }
.tabs button.on { background: var(--text); color: var(--card); font-weight: 600; box-shadow: 0 1px 3px rgb(0 0 0 / .18); }
/* Touch screens (phones, iPads): controls a thumb can hit, about 40px; mouse users keep the compact sizes. */
@media (pointer: coarse) {
  .tabs button { min-height: 2.5rem; padding-inline: 1.05rem; }
  .viz-copy { display: grid; place-items: center; width: 2.5rem; height: 2.5rem; padding: 0; top: .25rem; right: .25rem; }
  .pl-open, .panel-link, .day-more { min-height: 2.5rem; }
  .pl-page .pl-filters select { min-height: 2.75rem; }
}
.grid-wrap { width: fit-content; max-width: 100%; overflow: auto; max-height: 70vh; border-radius: 14px; background: var(--card); margin-bottom: 1rem; box-shadow: var(--shadow); }
.grid { border-collapse: separate; border-spacing: 0; font-size: .9rem; }
.grid th, .grid td { padding: .35rem .55rem; white-space: nowrap; border-bottom: 1px solid color-mix(in srgb, var(--line) 60%, transparent); }
.grid tbody tr:nth-child(even) td { background: var(--stripe); }
.grid tbody tr:hover td { background: var(--hover); }
.grid thead { position: sticky; top: 0; z-index: 2; }
.grid thead th { background: var(--head); font-size: .74rem; font-weight: 600; color: var(--muted); vertical-align: bottom; text-align: left; }
.grid thead tr:last-child th, .grid thead th[rowspan] { box-shadow: inset 0 -1px 0 var(--line); } /* one hairline under the header */
.grid thead th small { color: var(--muted); }
.grid thead th small { font-weight: 400; }
.grid th.grp { font-size: .7rem; font-style: italic; font-weight: 500; text-align: center; }
.grid th.maxlbl { text-align: right; }
.grid tr.maxrow input { width: 3.2rem; text-align: center; padding: .1rem .3rem; font-size: .78rem; color: var(--text); }
.grid tr.maxrow input:not(.bad) { border-color: var(--line); background: var(--card); }
.grid td.addcol { background: var(--head); }
.grid td.no { color: var(--muted); text-align: center; }
.grid td.nm { max-width: 14rem; overflow: hidden; text-overflow: ellipsis; }
.grid td.calc, .grid th.calc { text-align: center; font-variant-numeric: tabular-nums; }
.grid td.strong { font-weight: 600; }
/* Term /100 is the number teachers look for: tinted, bold, and pinned with the nickname when the grid scrolls sideways. */
.grid .pin { position: sticky; z-index: 1; background: var(--card); }
.grid thead .pin { z-index: 3; background: var(--head); }
.grid .nm.pin { left: 0; width: 8.5rem; min-width: 8.5rem; max-width: 8.5rem; }
.grid .term.pin { left: 8.5rem; border-right: 1px solid var(--line); }
.grid thead th.term { color: var(--accent); background: color-mix(in srgb, var(--accent) 8%, var(--head)); }
.grid tbody tr td.term { font-size: 1.1rem; font-weight: 700; color: color-mix(in srgb, var(--accent) 80%, var(--text));
  background: color-mix(in srgb, var(--accent) 8%, var(--card)); }
.grid input { border-color: transparent; background: transparent; width: 100%; }
.grid input.wide { width: 18rem; }
.grid input.sc { width: 3.2rem; text-align: center; padding: .2rem .35rem; }
.grid input { border-radius: 6px; }
/* Staff list: names show in full; the choices are compact tags (the area cut short, its full name on hover) */
.grid input.fit { width: auto; field-sizing: content; min-width: 4.5rem; max-width: 20rem; }
.grid select.tag { font-size: .8rem; padding: .2rem .35rem .2rem .6rem; border-radius: 999px; }
.grid select.tag.area { max-width: 10rem; text-overflow: ellipsis; }
.grid .pin:first-child { left: 0; }   /* the name stays in view while the row scrolls sideways */
.grid td.pin:first-child { box-shadow: inset -1px 0 var(--line); }
.grid input.sc:focus { box-shadow: 0 0 0 3px var(--ring); }
.grid input.bad { background: var(--bad-bg); border-color: var(--danger); }
.grid input.ex { background: var(--ex-bg); color: var(--muted); }
.grid input.empty { background: var(--warn-bg); border-color: #d4a017; }
.ih { display: grid; gap: .2rem; min-width: 6.5rem; font-weight: 400; }
.ih select, .ih input, .ih button { font-size: .76rem; padding: .1rem .3rem; color: var(--text); }
.ih select { max-width: 8rem; }
.ih input { border-color: var(--line); }
.ih-name { display: flex; align-items: center; gap: .15rem; }
.ih-name button { display: inline-grid; place-items: center; padding: .2rem; }
/* The remove × stays out of sight until the column is pointed at (touch screens always show it). */
@media (hover: hover) {
  .ih-name button { opacity: 0; transition: opacity .15s var(--ease); }
  th.item:hover .ih-name button, .ih-name button:focus-visible { opacity: 1; }
}
.ih-name button svg { width: 12px; height: 12px; }
.grid input.sc:disabled { cursor: not-allowed; }
.c0 { background: var(--c0) !important; } .c1 { background: var(--c1) !important; } .c2 { background: var(--c2) !important; }
.c3 { background: var(--c3) !important; } .c4 { background: var(--c4) !important; }
/* Admin nav: same segmented control */
.anav { display: flex; gap: 4px; flex-wrap: wrap; }
.anav button { border: 0; background: none; padding: .3rem .9rem; border-radius: 999px; font: 500 .93rem var(--display); color: var(--text); }
.anav button:hover:not(.on):not(:disabled) { background: var(--fill); }
.anav button.on { background: var(--text); color: var(--card); font-weight: 600; }
.anav button.hub { font-weight: 700; color: var(--accent); } /* the Hub reads as home */
.anav button.hub.on { color: var(--card); font-weight: 700; }
/* a menu group: name ▾, plus the page you are on in small type; its pages open as a small menu (same look as the account menu) */
.anav button.grp { display: inline-flex; align-items: center; gap: .35rem; }
.anav button.grp small { font: 400 .8rem var(--display); opacity: .75; }
.anav button.grp small::before { content: '·'; margin-right: .35rem; }
.anav button.grp svg { opacity: .6; }
.menu.navmenu { padding: .4rem; }
.menu.navmenu button { display: block; width: 100%; padding: .5rem .7rem; border-radius: 8px; background: none; text-align: left; color: var(--text); font: 500 .93rem var(--display); }
.menu.navmenu button:hover, .menu.navmenu button:focus-visible { background: var(--fill); }
.menu.navmenu button[aria-current='page'] { background: var(--text); color: var(--card); font-weight: 600; }

/* Tab switches (swap() in ui.js): the selected pill slides over, the page content fades up. The bar is named too so it stays on top. */
.top { view-transition-name: top; }
main { view-transition-name: page; }
/* Loading a view (busy() in ui.js): clicks wait, and only a slow load (over .4s) softens the page a little; the loading line says the rest. */
#app[aria-busy="true"] { cursor: progress; }
#app[aria-busy="true"] main { opacity: .8; pointer-events: none; transition: opacity .3s .4s; }
/* Loading line: any request over 150ms (db.js, loading or saving) slides a thin seedling-green line along the top edge. */
body::before { content: ''; position: fixed; inset: 0 0 auto; z-index: 1000; height: 3px; pointer-events: none; opacity: 0; transition: opacity .4s var(--glide);
  background: linear-gradient(90deg, transparent, var(--accent) 30%, color-mix(in srgb, var(--accent) 55%, #fff) 50%, var(--accent) 70%, transparent) 0 0 / 45% 100% no-repeat; }
html[data-net] body::before { opacity: 1; animation: net-slide 1.3s cubic-bezier(.45, 0, .25, 1) infinite; }
@keyframes net-slide { from { background-position: -85% 0; } to { background-position: 185% 0; } }
/* First load (before the app has anything to show): a calm ring in the middle. */
.boot { display: grid; place-items: center; min-height: 55vh; }
.ring { width: 30px; aspect-ratio: 1; border-radius: 50%; border: 3px solid color-mix(in srgb, var(--accent) 18%, transparent); border-top-color: var(--accent); animation: ring-turn .9s linear infinite; }
@keyframes ring-turn { to { rotate: 1turn; } }
@media (prefers-reduced-motion: reduce) {
  html[data-net] body::before { animation: net-breathe 1.6s ease-in-out infinite; background-size: 100% 100%; }
  .ring { animation: net-breathe 1.6s ease-in-out infinite; border-color: var(--accent); }
}
@keyframes net-breathe { 50% { opacity: .35; } }
.tabs button.on { view-transition-name: tab-pill; }
.pl-filters .tabs button.on, .viz-ctl .tabs button.on { view-transition-name: none; } /* one sliding pill per page: the Lesson plans tabs slide, the On time / Handed in switch below them does not */
.anav > button.on { view-transition-name: nav-pill; } /* not the open group's menu items: one name per page */
/* Switching pages and tabs: the old view lets go quickly, the new one settles in slowly (expo ease-out), so nothing snaps. */
::view-transition-group(*) { animation-duration: .45s; animation-timing-function: var(--glide); }
::view-transition-old(page) { animation: .16s var(--ease) both vt-out; }
::view-transition-new(page) { animation: .5s var(--glide) both vt-in; }
@keyframes vt-out { to { opacity: 0; } }
@keyframes vt-in { from { opacity: 0; transform: translateY(8px); filter: blur(2px); } }
@media (prefers-reduced-motion: reduce) { ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation: none !important; } }
.badge { display: inline-block; padding: .1rem .55rem; border-radius: 999px; background: var(--fill); font-size: .75rem; font-weight: 500; white-space: nowrap; }
.badge.submitted { background: var(--ok-bg); }
.badge.draft { background: var(--warn-bg); }
.card.wide { max-width: none; margin: 0 0 1.25rem; display: grid; gap: .75rem; }
.card.wide > button, .card.wide > .row > button.primary { justify-self: start; min-width: 9rem; } /* compact pills, not full-width bars */
input[type='file'] { background: none; padding: 0; border: 0; color: var(--muted); }
input[type='file']::file-selector-button { font: inherit; font-weight: 500; margin-right: .75rem; padding: .45rem 1rem; border: 0; border-radius: 980px;
  background: var(--fill); color: var(--accent); cursor: pointer; transition: background .15s var(--ease); }
input[type='file']::file-selector-button:hover { background: color-mix(in srgb, var(--accent) 12%, var(--fill)); }
.card h2 { margin: 0; }
textarea { font: inherit; color: inherit; background: var(--fill); border: 1px solid transparent; border-radius: 10px; padding: .6rem .75rem; width: 100%; }
.mapgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr)); gap: .5rem; }
.mapgrid label { display: grid; gap: .2rem; font-size: .85rem; }
.diff { margin: 0; padding-left: 1.2rem; display: grid; gap: .25rem; }
.diff li.warn { color: var(--danger); }
/* First load on the Hub: the Hub's own layout with shimmering blocks (app.js hubSkeleton), replaced in place by the real Hub */
.skel .tear { height: 130px; } .skel .day { min-height: 167px; display: grid; align-content: start; gap: .5rem; padding: .8rem; }
.skel .hub-panel { display: grid; gap: .6rem; padding: 1rem 1.1rem; min-height: 380px; align-content: start; }
.skel .launch { display: flex; gap: .5rem; flex-wrap: wrap; }
.sk { display: block; height: .8rem; border-radius: 6px; background: linear-gradient(90deg, var(--fill) 25%, color-mix(in srgb, var(--fill) 50%, var(--card)) 50%, var(--fill) 75%) 0 0 / 300% 100%;
  animation: sk-shimmer 1.6s ease-in-out infinite; }
.sk.w40 { width: 40%; } .sk.w60 { width: 60%; } .sk.w80 { width: 80%; }
.sk-h1 { height: 2.2rem; width: min(22rem, 70%); } .sk-num { width: 5rem; height: 4.4rem; margin: 1rem auto 0; }
.sk-ql { width: 7.5rem; height: 2.4rem; border-radius: 999px; } .sk-cal { width: 2.6rem; height: 2.6rem; border-radius: 8px; }
@keyframes sk-shimmer { from { background-position: 100% 0; } to { background-position: 0 0; } }
/* Photos and the background: fade in over their colour box once loaded (app.js marks .loaded), instead of popping in */
.mt-pic img, .mt-thumb img, #bg > img, #bg > video { opacity: 0; transition: opacity .5s var(--glide); }
.mt-pic img.loaded, .mt-thumb img.loaded, #bg > img.loaded, #bg > video.loaded { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .sk { animation: none; } .mt-pic img, .mt-thumb img, #bg > img, #bg > video { transition: none; } }
/* Overview → Gradebook progress: a grid of teacher cards; each teacher's own muted colour on the band and the initial */
.tb-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 20rem), 1fr)); gap: 1rem; align-items: start; }
.tb-card { background: var(--card); border-radius: 14px; box-shadow: var(--shadow); overflow: hidden; }
.tb-card header { display: flex; align-items: center; gap: .7rem; padding: .75rem .9rem .6rem; background: light-dark(hsl(var(--tc) 45% 94%), hsl(var(--tc) 22% 20%)); }
.tb-card header b { display: block; font: 600 1rem/1.25 var(--display); } .tb-card header small { color: var(--muted); font-size: .8rem; }
.tb-av { display: grid; place-items: center; flex: none; width: 2.2rem; height: 2.2rem; border-radius: 50%; background: hsl(var(--tc) 42% 42%); color: #fff; font: 700 1rem var(--display); }
.tb-card > progress { display: block; width: 100%; height: 4px; border-radius: 0; }
.tb-list { list-style: none; margin: 0; padding: .35rem .5rem .55rem; display: grid; gap: .1rem; }
.tb-list li { display: flex; align-items: center; gap: .3rem; }
.tb-cls { flex: 1; min-width: 0; display: grid; grid-template-columns: minmax(0, 1fr) auto auto; align-items: center; gap: .6rem; padding: .45rem .5rem; border: 0; border-radius: 8px; background: none; text-align: left; font-size: .88rem; }
.tb-cls:hover:not(:disabled) { background: var(--fill); }
.tb-name { overflow-wrap: anywhere; line-height: 1.3; } /* long subject names wrap rather than cut */
.tb-st { padding: .05rem .45rem; border-radius: 999px; font-size: .72rem; font-weight: 600; background: var(--fill); color: var(--muted); white-space: nowrap; }
.tb-st.doing { background: var(--warn-bg); color: var(--text); } .tb-st.submitted { background: var(--ok-bg); color: var(--ok); }
.tb-steps { display: inline-flex; gap: 2px; } .tb-steps i { width: 7px; height: 7px; border-radius: 2px; background: var(--fill); } .tb-steps i.on { background: var(--ok); }
.tb-unlock { font-size: .75rem; padding: .2rem .5rem; }
/* Rooms page: the whole width, the page scrolls (no inner box); grade header rows; on phones each room is a card */
.rm-summary { margin: .2rem 0 .8rem; font-size: .9rem; } .rm-summary .link { font-size: inherit; padding: 0; color: var(--danger); text-decoration: underline; text-underline-offset: 2px; }
.rm-wrap { background: var(--card); border-radius: 14px; box-shadow: var(--shadow); margin-bottom: 1rem; overflow-x: auto; }
.rm-table { width: 100%; } .rm-table td { vertical-align: middle; }
.rm-table .rm-grade th { text-align: left; padding-top: 1rem; font: 600 .8rem var(--display); color: var(--muted); background: none; }
.rm-table .rm-prog { margin-left: .4rem; padding: .2rem 1.6rem .2rem .5rem; font-size: .8rem; }
.rm-table .num { font-variant-numeric: tabular-nums; }
.rm-sub { display: inline-grid; gap: .2rem; min-width: 8rem; font-size: .85rem; } .rm-sub progress { width: 100%; height: 6px; }
@media (max-width: 700px) {
  .rm-table thead { display: none; }
  .rm-table, .rm-table tbody, .rm-table tr, .rm-table td { display: block; width: auto; }
  .rm-table tr:not(.rm-grade) { margin: 0 .6rem .6rem; padding: .5rem .75rem; border-radius: 12px; background: var(--fill); }
  .rm-table .rm-grade, .rm-table .rm-grade th { display: block; }
  .rm-table td { display: flex; justify-content: space-between; gap: 1rem; padding: .25rem 0; border: 0; white-space: normal; }
  .rm-table td::before { content: attr(data-label); color: var(--muted); font-size: .8rem; }
}
/* Access page: modules grouped under headings; each row spells out what View and Edit allow */
.acc-group th { text-align: left; padding-top: 1rem; font: 600 .78rem var(--display); color: var(--muted); text-transform: none; background: none; }
.acc-lv { list-style: none; margin: .2rem 0 0; padding: 0; display: grid; gap: .1rem; font-size: .8rem; color: var(--muted); white-space: normal; max-width: 34rem; }
.acc-lv b { color: var(--text); font-weight: 600; margin-right: .3rem; }
.acc-always { margin: 0 0 .9rem; padding: .6rem .85rem; border-radius: 10px; background: var(--fill); font-size: .88rem; max-width: 60rem; }
.acc-always summary { cursor: pointer; font-weight: 600; } .acc-always p { margin: .45rem 0 0; color: var(--muted); }
button.link.small { font-size: .75rem; font-weight: 500; padding: 0; }
.edit-tag { display: inline-block; margin-left: .3rem; padding: .1rem .3rem; border-radius: 3px; background: var(--fill); color: var(--muted); font: 500 .6rem/1 var(--body); vertical-align: middle; white-space: nowrap; } /* tiny tag beside the value changed in the app; line-height 1 so rows keep their height */
.tag-under { position: relative; } .tag-under > .edit-tag { position: absolute; left: 0; top: 100%; margin: 0; padding: 0; background: none; font-size: .5rem; letter-spacing: .02em; } /* plain, flush left with the value above */ /* in tables: tucked under the value, taking no space */
details.sync summary { cursor: pointer; }
details.sync ul { margin: .4rem 0 0; padding-left: 1.2rem; font-size: .9rem; }
.mapgrid small { display: block; }
.schemegrid { grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr)); }
.schemegrid fieldset { display: grid; gap: .4rem; margin: 0; padding: .75rem; border: 0; border-top: 3px solid var(--kb); border-radius: 12px; background: var(--fill); }
.warnlist { margin: 0; padding: .6rem .75rem .6rem 1.8rem; background: var(--warn-bg); border-radius: 12px; }
/* import: per-student changes, checked before applying */
.diff details:has(.changes) { display: block; margin: .3rem 0 0; }
.changes { margin: 0; padding-left: 1rem; display: grid; gap: .15rem; max-height: 22rem; overflow: auto; color: var(--text); }
.stack { display: grid; gap: .75rem; }
/* import progress: native <progress>, pulses while waiting on the server */
.progress { display: grid; gap: .35rem; padding: .7rem .9rem; border-radius: 12px; background: color-mix(in srgb, var(--accent) 8%, var(--card)); font-size: .9rem; }
.progress .row { margin: 0; }
.progress progress { width: 100%; height: 8px; appearance: none; border: 0; border-radius: 999px; background: var(--track); overflow: hidden; }
.progress progress::-webkit-progress-bar { background: var(--track); border-radius: 999px; }
.progress progress::-webkit-progress-value { background: var(--btn); border-radius: 999px; transition: width .4s var(--ease); }
.progress progress::-moz-progress-bar { background: var(--btn); border-radius: 999px; }
.progress.busy progress { animation: prog-pulse 1.2s ease-in-out infinite; }
@keyframes prog-pulse { 50% { opacity: .55; } }
@media (prefers-reduced-motion: reduce) { .progress.busy progress { animation: none; } }
/* assignment coverage (overall + per room card): same bar, blue while filling, green once every subject has a teacher */
.asg-overall { margin-bottom: 1rem; }
.asg-import { margin: 0 auto 1rem; } .asg-import > summary { cursor: pointer; } .asg-import[open] > summary { margin-bottom: .5rem; }
.room-card progress.fill { display: block; width: 100%; height: 6px; margin: .1rem 0 .5rem; appearance: none; border: 0; border-radius: 999px; background: var(--track); overflow: hidden; }
.room-card progress.fill::-webkit-progress-bar { background: var(--track); border-radius: 999px; }
.room-card progress.fill::-webkit-progress-value { background: var(--btn); border-radius: 999px; transition: width .4s var(--ease); }
.room-card progress.fill::-moz-progress-bar { background: var(--btn); border-radius: 999px; }
progress.fill.done::-webkit-progress-value, .asg-overall.done progress::-webkit-progress-value { background: var(--ok); }
progress.fill.done::-moz-progress-bar, .asg-overall.done progress::-moz-progress-bar { background: var(--ok); }
.stack > button { justify-self: start; min-width: 9rem; }
/* activity-type library */
.schemegrid fieldset { align-content: start; }
.schemegrid legend { float: left; width: 100%; font-weight: 600; font-size: .9rem; padding: 0; }
.ty { display: grid; grid-template-columns: 1fr auto; gap: .15rem .5rem; align-items: center; padding: .4rem .5rem; border-radius: 10px; background: var(--card); }
.ty .ty-name { font-weight: 500; }
.ty .ty-name small { color: var(--muted); font-weight: 400; margin-left: .3rem; }
.ty .chips { grid-column: 1; display: flex; flex-wrap: wrap; gap: .25rem; }
.ty > button { grid-column: 2; grid-row: 1 / span 2; padding: .2rem .6rem; }
.ty.retired { opacity: .55; }
.chip { font-size: .72rem; padding: .05rem .5rem; border-radius: 999px; background: color-mix(in srgb, var(--kb, var(--accent)) 14%, var(--card)); }
.chip.all { background: var(--fill); color: var(--muted); }
.tyform { display: grid; gap: .75rem; padding: 1rem; border-radius: 14px; background: var(--fill); }
.tyform h3 { margin: 0; }
.checks { display: flex; flex-wrap: wrap; gap: .3rem 1rem; margin: 0; padding: 0; border: 0; }
.checks legend { font-size: .85rem; margin-bottom: .3rem; padding: 0; }
/* teacher home: "activity types updated" notice */
.notice { display: flex; gap: .75rem; align-items: center; flex-wrap: wrap; max-width: 760px; margin: 0 auto 1rem; padding: .75rem 1rem;
  border-radius: 14px; background: color-mix(in srgb, var(--accent) 10%, var(--card)); box-shadow: var(--shadow); font-size: .9rem; }
.notice > span { flex: 1 1 16rem; }
/* assignments board: teacher panel (drag source) + room cards with subject slots (drop targets) */
.board { display: grid; grid-template-columns: minmax(220px, 280px) 1fr; gap: 1rem; align-items: start; }
@media (max-width: 760px) { .board { grid-template-columns: 1fr; } }
.tpanel { position: sticky; top: 4.5rem; display: grid; gap: .5rem; padding: .9rem; border-radius: 14px; background: var(--card); box-shadow: var(--shadow); max-height: calc(100vh - 6rem); overflow: auto; }
@media (max-width: 760px) { .tpanel { position: static; max-height: 18rem; } }
.tpanel .row { margin: 0; } .tpanel .row select { flex: 1 1 6rem; min-width: 0; }
.tpanel .hint { margin: 0; font-size: .8rem; }
.tlist { list-style: none; margin: 0; padding: 0; display: grid; gap: .35rem; }
.tchip { display: grid; gap: .1rem; width: 100%; text-align: left; padding: .45rem .7rem; border-radius: 12px; background: var(--fill); color: var(--text); cursor: grab; }
.tchip:hover:not(:disabled) { background: color-mix(in srgb, var(--accent) 10%, var(--fill)); }
.tchip:disabled { cursor: default; opacity: 1; }
.tchip.picked { background: var(--btn); color: #fff; box-shadow: 0 2px 8px rgb(0 0 0 / .18); }
.tchip .tname { font-weight: 600; font-size: .9rem; }
.tchip .tmeta { display: flex; gap: .35rem; align-items: center; font-size: .75rem; opacity: .8; }
.tchip.small { display: inline-block; width: auto; padding: .15rem .6rem; font-size: .85rem; font-weight: 600; cursor: default; }
.rooms { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr)); gap: 1rem; }
/* room cards are <details>: the summary (header + bar) stays visible when closed; chevron shows the state */
.room-card { padding: .9rem; border-radius: 14px; background: var(--card); box-shadow: var(--shadow); align-self: start; transition: box-shadow .15s var(--ease); }
.room-card > summary { display: grid; gap: .45rem; list-style: none; cursor: pointer; }
.room-card > summary::-webkit-details-marker { display: none; }
.room-card header { display: flex; gap: .5rem; align-items: center; }
.room-card header::after { content: ''; flex: none; width: .45rem; height: .45rem; margin: 0 .2rem 0 .1rem; border: solid var(--muted); border-width: 0 2px 2px 0;
  transform: rotate(-45deg); transition: transform .2s var(--ease); }
.room-card[open] header::after { transform: rotate(45deg); }
.room-card progress.fill { margin-bottom: 0; }
.room-card .slots { margin-top: .6rem; }
.room-card.drop-before { box-shadow: var(--shadow), -4px 0 0 var(--accent); }
.room-card.drop-after { box-shadow: var(--shadow), 4px 0 0 var(--accent); }
.grip { padding: .1rem .3rem; border-radius: 6px; background: none; color: var(--muted); cursor: grab; font-weight: 700; letter-spacing: -.2em; line-height: 1; }
.grip:hover:not(:disabled) { background: var(--fill); color: var(--text); }
.slot .tchip.small[draggable="true"] { cursor: grab; }
.slot .who .copy { margin-left: auto; font-size: .8rem; color: var(--accent); }
/* room chips (Assignments): pick any set of rooms; none picked = all */
.chips { display: flex; flex-wrap: wrap; gap: .35rem; align-items: center; margin: 0 0 1rem; }
.chips button { padding: .25rem .8rem; font-size: .85rem; }
.chips button[aria-pressed="true"] { background: var(--btn); color: #fff; }
.picklist { list-style: none; padding: 0; margin: .5rem 0; display: grid; gap: .35rem; }
.slots { display: grid; } /* rows in the room's sheet, not boxes in a box */
.slot { display: grid; gap: .25rem; padding: .55rem .5rem; border-radius: 8px; border: 1.5px solid transparent; box-shadow: 0 -1px 0 var(--line); transition: background .15s var(--ease), border-color .15s var(--ease); }
.slot .subj { font-size: .85rem; }
.slot .who { display: flex; gap: .35rem; align-items: center; flex-wrap: wrap; }
.slot .who button { padding: .1rem .5rem; }
.slot > button { justify-self: start; padding: .2rem .7rem; font-size: .85rem; }
.slot input { font-size: .85rem; }
.slot[data-act="drop"] { cursor: pointer; }
.slot.over, .slot[data-act="drop"]:hover { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, var(--card)); }
/* while a teacher is dragged / picked: empty slots in rooms of their program glow */
#app[data-drag-prog="IP"] .room-card[data-prog="IP"] .slot:not(.filled), #app[data-drag-prog="IEP"] .room-card[data-prog="IEP"] .slot:not(.filled),
.board[data-pick-prog="IP"] .room-card[data-prog="IP"] .slot:not(.filled), .board[data-pick-prog="IEP"] .room-card[data-prog="IEP"] .slot:not(.filled) {
  border-color: var(--accent); background: color-mix(in srgb, var(--accent) 6%, var(--card)); }
@media (prefers-reduced-motion: reduce) { .slot { transition: none; } }
.diff details { display: inline; margin-left: .5rem; color: var(--muted); font-size: .85rem; }
.grid tr.inactive td { color: var(--muted); text-decoration: line-through; }
.grid tbody tr.flag td { background: var(--warn-bg); }
/* Subjects: the row being edited stays lit, everything else darkens behind it */
.spot-dim { position: fixed; inset: 0; z-index: 30; background: color-mix(in srgb, #141414 55%, transparent); animation: spot-in .2s ease-out; }
.grid tbody tr.spot-row td { position: relative; z-index: 31; background: var(--card); }
.spot-row input, .spot-row select { min-width: 4rem; }
@keyframes spot-in { from { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .spot-dim { animation: none; } }
.grid td.actions { display: flex; gap: .3rem; }
.badge.prog-IP { background: var(--ip-bg); } .badge.prog-IEP { background: var(--iep-bg); } .badge.prog-both { background: var(--ok-bg); }
.banner ul { margin: .3rem 0 0; }
/* Sheets: borderless, large radius, deep soft shadow, blurred backdrop */
dialog { border: 0; border-radius: 16px; background: var(--card); color: var(--text); max-width: min(560px, 92vw); padding: 1.4rem 1.5rem;
  box-shadow: 0 24px 60px rgb(0 0 0 / .22), 0 0 0 .5px rgb(0 0 0 / .06); }
dialog[open] { animation: sheet-in .22s var(--ease); }
@keyframes sheet-in { from { opacity: 0; transform: translateY(8px) scale(.98); } }
dialog ul { max-height: 50vh; overflow: auto; padding-left: 1.2rem; }
/* Dialog forms: the label above its field, like forms in cards; a checkbox or radio keeps its text beside it */
dialog form label:not(.inline):not(:has(> input[type="checkbox"], > input[type="radio"])) { display: grid; gap: .3rem; font-size: .88rem; font-weight: 500; }
dialog form label:not(.inline) > :is(input:not([type="checkbox"], [type="radio"]), select, textarea) { font-weight: 400; font-size: 1rem; width: 100%; }
dialog form.stack { min-width: min(22rem, 78vw); } /* room for a full date beside a time */
dialog::backdrop { background: color-mix(in srgb, #141414 40%, transparent); }
@media (prefers-reduced-motion: reduce) { dialog[open] { animation: none; } button:active:not(:disabled) { transform: none; } }

/* KSAii progress (class work + summary): score over a thin bar in the category colour */
.k0 { --kb: var(--b0); } .k1 { --kb: var(--b1); --kt: light-dark(#9a7400, var(--b1)); /* yellow text needs a darker gold on white */ } .k2 { --kb: var(--b2); } .k3 { --kb: var(--b3); } .k4 { --kb: var(--b4); }
.grid th.ksa-title { text-align: center; letter-spacing: .08em; color: var(--text); }
.grid th.ksa-h { min-width: 3.25rem; text-align: center; vertical-align: bottom; padding: .35rem .4rem .25rem; }
.ksa-lbl { display: flex; align-items: flex-end; justify-content: center; gap: .1rem; }
.ksa-word { writing-mode: vertical-rl; transform: rotate(180deg); font-size: .6rem; font-weight: 400; color: var(--muted); line-height: 1; }
.ksa-lbl b { font-size: 1.6rem; font-weight: 900; line-height: .85; color: var(--kt, var(--kb)); }
.grid th.ksa-h small { display: block; font-size: .68rem; margin-top: .2rem; }
.grid td.ksa-td { background: color-mix(in srgb, var(--kb) 8%, var(--card)); }
.grid tbody tr:nth-child(even) td.ksa-td { background: color-mix(in srgb, var(--kb) 13%, var(--card)); }
.grid tbody tr:hover td.ksa-td { background: color-mix(in srgb, var(--kb) 20%, var(--card)); }
.ksa { display: grid; gap: 3px; min-width: 4.25rem; }
.ksa span { text-align: center; font-weight: 600; font-size: .85rem; }
.ksa i { display: block; height: 4px; border-radius: 2px; background: var(--track); overflow: hidden; }
.ksa i::after { content: ''; display: block; height: 100%; width: var(--p); background: var(--kb); border-radius: 2px; transition: width .2s ease; }
@media (prefers-reduced-motion: reduce) { .ksa i::after { transition: none; } }

/* Add-activity button + type dropdown (native popover, positioned under the button by app.js) */
.grid th.addcol { vertical-align: middle; min-width: 0; }
.addbtn { display: grid; place-items: center; width: 2.25rem; height: 2.25rem; padding: 0; border: none; border-radius: 50%;
  background: var(--btn); color: #fff; transition: background .15s var(--ease), transform .1s var(--ease); } /* round green plus */
.addbtn:hover, .addbtn:focus-visible { background: color-mix(in srgb, var(--btn) 85%, #000); color: #fff; }
.menu { inset: auto; margin: 0; overflow: auto; border: 0; border-radius: 14px;
  background: color-mix(in srgb, var(--card) 88%, transparent); backdrop-filter: saturate(180%) blur(24px); -webkit-backdrop-filter: saturate(180%) blur(24px);
  color: var(--text); padding: .85rem 1rem; box-shadow: 0 16px 40px rgb(0 0 0 / .18), 0 0 0 .5px rgb(0 0 0 / .08); }
.menu h3 { margin: 0 0 .6rem; font-size: .8rem; font-weight: 600; color: var(--muted); }
.menu-body { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: .75rem; }
.menu-grp { display: grid; gap: .2rem; align-content: start; border-top: 3px solid var(--kb); padding-top: .4rem; }
.menu-grp b { font-size: .72rem; font-style: italic; font-weight: 500; color: var(--muted); }
.menu-grp button { text-align: left; border: none; background: none; padding: .3rem .4rem; font-size: .85rem; border-radius: 6px; }
.menu-grp button:hover, .menu-grp button:focus-visible { background: var(--head); }

/* Theme toggle (top bar) */
.themebtn { display: grid; place-items: center; width: 2.1rem; height: 2.1rem; padding: 0; border-radius: 50%; color: var(--text); }
.themebtn:hover { background: var(--head); }

/* "View as" (coordinator and up): one pill holding eye + label + a bare select; solid blue while previewing */
.viewas { display: inline-flex; align-items: center; gap: .35rem; height: 2.1rem; padding: 0 .3rem 0 .75rem; border-radius: 980px;
  background: var(--fill); color: var(--muted); font-size: .85rem; cursor: pointer; transition: background .2s var(--ease), color .2s var(--ease), box-shadow .15s var(--ease); }
.viewas:hover { background: color-mix(in srgb, var(--fill) 88%, var(--text)); }
.viewas:focus-within { box-shadow: 0 0 0 4px var(--ring); }
.viewas select, .viewas select:focus { background: transparent; border: 0; box-shadow: none; padding: .3rem .25rem; max-width: 11rem;
  color: var(--text); font-weight: 600; cursor: pointer; text-overflow: ellipsis; }
.viewas.on, .viewas.on:hover { background: var(--btn); color: rgb(255 255 255 / .85); }
.viewas.on select { color: #fff; }
.viewas option { color: var(--text); background: var(--card); } /* the open list stays readable on the blue pill */
.notice.preview { background: color-mix(in srgb, var(--btn) 12%, var(--card)); box-shadow: var(--shadow), inset 0 0 0 1px color-mix(in srgb, var(--btn) 35%, transparent); }
.notice.preview > svg { color: var(--accent); flex: none; }
@media (max-width: 640px) { .viewas > span { display: none; } } /* phones: eye + name only */

/* Crosshair highlight: an overlay (inset shadow) so it sits on top of zebra rows and category tints */
.grid .col-hover { box-shadow: inset 0 0 0 999px var(--xhair); }
.grid .col-active, .grid tr.row-active td { box-shadow: inset 0 0 0 999px var(--xhair-on); }
.grid thead th.col-active { box-shadow: inset 0 -3px 0 var(--accent), inset 0 0 0 999px var(--xhair-on); }
.grid td, .grid th { transition: box-shadow .15s ease; }
@media (prefers-reduced-motion: reduce) { .grid td, .grid th { transition: none; } }

/* Submit problems: one card per learner; each problem is a link to its cell */
dialog:has(.probs) { padding: 1.3rem 1.4rem; }
.probs h3 { font-size: .8rem; font-weight: 600; color: var(--muted); margin: .3rem 0 .3rem; }
.probs ul { list-style: none; padding: 0; margin: 0; max-height: none; overflow: visible; }
.probs > ul { max-height: 50vh; overflow: auto; }
.prob-list { display: grid; gap: .15rem; }
.prob-who { display: flex; gap: .5rem; align-items: baseline; padding: .35rem .6rem .1rem; }
.prob-who .muted { font-size: .8rem; }
.probs button.link { display: block; width: 100%; padding: .3rem .6rem; border: 0; border-radius: 8px; text-align: left; font-size: .9rem;
  color: var(--text); background: transparent; transition: background .15s, color .15s; }
.probs button.link::before { content: '→'; margin-right: .45rem; color: var(--danger); transition: margin .15s; }
.probs button.link:hover, .probs button.link:focus-visible { background: color-mix(in srgb, var(--accent) 14%, transparent); color: var(--accent); outline: none; }
.probs button.link:hover::before, .probs button.link:focus-visible::before { margin-right: .65rem; }
.probs .hint { margin: .6rem .6rem 0; }
@media (prefers-reduced-motion: reduce) { .probs button.link, .probs button.link::before { transition: none; } }

/* Cautious confirm (term switch, past-term import): same sleek dialog, danger OK + quiet Cancel */
.probs.confirm p { margin: .3rem 0; }
.probs.confirm ul { list-style: disc; padding-left: 1.2rem; max-height: 40vh; overflow: auto; }
.probs.confirm li { padding: .1rem 0; }
dialog:has(.confirm) form.row { margin-top: .8rem; }
button.danger-btn { background: var(--btn-danger); color: #fff; font-weight: 600; }

/* Teacher home: past terms, view only */
.card.past h3 { font-size: .85rem; margin: .8rem 0 .2rem; }

/* "Needs more scores" list (submit dialog + admin form view) */
.short-wrap { max-height: 50vh; overflow: auto; border-radius: 8px; margin: .5rem 0; }
.grid.short { width: 100%; }
.grid.short thead { position: static; }

/* Change log: compact; each change is a link that jumps to it */
.log h2 { font-size: .85rem; }
.log .grid { font-size: .76rem; }
.log td.when { white-space: nowrap; }
.log button.link { font-size: inherit; color: var(--text); padding: 0; }
.log button.link:hover, .log button.link:focus-visible { color: var(--accent); text-decoration: underline; }
@keyframes flash { from { box-shadow: inset 0 0 0 999px color-mix(in srgb, var(--accent) 40%, transparent); } }
.grid .flash { animation: flash 1.4s ease-out; }
@media (prefers-reduced-motion: reduce) { .grid .flash { animation-duration: .01s; } }

/* ---------- Tonkla logo: black line art on white, tinted per theme (multiply drops the white; dark = white lines) ---------- */
.brand { display: inline-flex; align-items: center; gap: .55rem; }
.logo { display: block; height: 1.9rem; width: auto; border-radius: 50%; mix-blend-mode: multiply; }
.card.login .logo { height: 5.5rem; justify-self: center; margin-bottom: -.25rem; }
:root[data-theme="dark"] .logo { filter: invert(1); mix-blend-mode: screen; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .logo { filter: invert(1); mix-blend-mode: screen; } }

/* ---------- Personalization background (#bg sits behind #app; see syncBg in app.js) ---------- */
#bg, .pv { container-type: size; }
#bg { position: fixed; inset: 0; z-index: -1; overflow: hidden; pointer-events: none; }
#bg:empty { display: none; }
#bg > img, #bg > video, .pv > img, .pv > video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
#bg > iframe, .pv > iframe { position: absolute; top: 50%; left: 50%; width: max(100cqw, 177.78cqh); height: max(100cqh, 56.25cqw); transform: translate(-50%, -50%); border: 0; }
/* sign-in: vivid, with a soft vignette so the frosted card and the header stay readable */
body.bg-login { background: #000; }
body.bg-login #bg::after, .pv-login::after { content: ''; position: absolute; inset: 0; background: radial-gradient(ellipse at 50% 40%, rgb(0 0 0 / .1), rgb(0 0 0 / .55)); }
body.bg-login .top { background: rgb(0 0 0 / .28); border-bottom-color: rgb(255 255 255 / .12); color: #fff; }
body.bg-login .top .logo { filter: invert(1); mix-blend-mode: screen; }
body.bg-login .card.login { background: color-mix(in srgb, var(--card) 74%, transparent); backdrop-filter: saturate(180%) blur(24px); -webkit-backdrop-filter: saturate(180%) blur(24px);
  box-shadow: 0 24px 64px rgb(0 0 0 / .35), 0 0 0 1px rgb(255 255 255 / .12); }
/* inside the app: faint, blurred and slightly enlarged (hides the blurred edges); strength = the admin's slider */
.pv-app > img, .pv-app > video { opacity: var(--bg-strength, .12); filter: grayscale(1) contrast(.8) blur(10px); transform: scale(1.04); }
/* the live background: a quarter-size copy blurred 2.5px and scaled ×4.16 looks like the full-size blur(10px) at ~1/16 of the
   per-frame cost, in its own layer, so scrolling and page swaps stay smooth on school laptops */
body.bg-app #bg > * { inset: 0 auto auto 0; width: 25%; height: 25%; transform: scale(4.16); transform-origin: 0 0; will-change: transform;
  opacity: var(--bg-strength, .12); filter: grayscale(1) contrast(.8) blur(2.5px); }
/* admin previews */
.brand-pv { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr)); gap: 1rem; }
.brand-pv figure { margin: 0; display: grid; gap: .4rem; }
.brand-pv figcaption { font-size: .85rem; color: var(--muted); }
.pv { position: relative; aspect-ratio: 16 / 10; border-radius: 14px; overflow: hidden; background: var(--bg); box-shadow: var(--shadow); }
.pv-login { background: #000; }
.pv-app > img, .pv-app > video { filter: grayscale(1) contrast(.9) blur(1px); }
.pv-card { position: absolute; z-index: 1; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 40%; display: grid; gap: .35rem; justify-items: center; padding: .8rem;
  border-radius: 12px; font-size: .8rem; background: color-mix(in srgb, var(--card) 74%, transparent); backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px); }
.pv-card .logo { height: 1.8rem; }
.pv-card i, .pv-ui i { display: block; width: 100%; height: .55rem; border-radius: 4px; background: var(--fill); }
.pv-card i.btn { background: var(--btn); }
.pv-ui { position: absolute; inset: 12% 7% 7%; display: grid; grid-template-rows: .5fr 1fr 1fr; gap: 7%; }
.pv-ui i { height: auto; border-radius: 8px; background: var(--card); box-shadow: var(--shadow); }

/* staff second step: QR code on a white tile (scanners need contrast in dark mode too) */
/* welcome screen: the fixed "T." sits inside the input's box */
.tn-field { display: flex; align-items: center; gap: .3rem; padding-left: .65rem; border: 1px solid transparent; border-radius: 8px; background: var(--fill); }
.tn-field:focus-within { background: var(--card); border-color: var(--accent); box-shadow: 0 0 0 4px var(--ring); }
.tn-field > span { font-weight: 600; }
.tn-field input, .tn-field input:focus { flex: 1; background: transparent; border: 0; box-shadow: none; padding-left: 0; }
.tn-pw { display: grid; gap: .6rem; border: 0; padding: .75rem 0 0; margin: 0; border-top: 1px solid var(--line); }
.tn-pw legend { font-weight: 600; padding: 0; }
.card.login .qr { justify-self: center; width: 200px; height: 200px; padding: 10px; border-radius: 14px; background: #fff; }
.card.login .secret { display: block; margin-top: .4rem; word-break: break-all; font-size: .85rem; user-select: all; }

/* ---------- account menu (header): initial + email; popover with name, role, set password, sign out ---------- */
/* Floating account button, bottom right: just the initial (dimmed) until hovered/focused, then the email slides out */
.acct-btn { position: fixed; z-index: 25; left: 16px; bottom: 16px; display: inline-flex; align-items: center; padding: .25rem; border: 0; border-radius: 999px;
  background: var(--card); color: var(--text); font-size: .85rem; font-weight: 500; opacity: .7;
  box-shadow: 0 4px 16px rgb(0 0 0 / .14), 0 0 0 .5px rgb(0 0 0 / .06); transition: opacity .2s var(--ease); }
.acct-btn:hover, .acct-btn:focus-visible, .acct-btn:has(+ :popover-open) { opacity: 1; }
.avatar { display: grid; place-items: center; width: 1.75rem; height: 1.75rem; border-radius: 50%; background: var(--btn); color: #fff; font-size: .8rem; font-weight: 700; }
.acct-email { max-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; transition: max-width .25s var(--ease), padding .25s var(--ease); }
.acct-btn:hover .acct-email, .acct-btn:focus-visible .acct-email { max-width: 16rem; padding: 0 .55rem 0 .45rem; }
@media (prefers-reduced-motion: reduce) { .acct-btn, .acct-email { transition: none; } }
.menu.acct { padding: .4rem; }
.menu.acct:popover-open { display: grid; gap: .1rem; }
.acct-head { display: grid; gap: .15rem; justify-items: start; padding: .5rem .6rem .65rem; margin-bottom: .25rem; border-bottom: 1px solid var(--line); }
.acct-head small { overflow-wrap: anywhere; }
.menu.acct button { display: flex; align-items: center; gap: .6rem; width: 100%; padding: .5rem .6rem; border-radius: 8px; background: none; text-align: left; font-weight: 500; }
.menu.acct button:hover, .menu.acct button:focus-visible { background: var(--fill); }
.menu.acct button.danger { color: var(--danger); }

/* ---------- teacher home: classes grouped by room or subject, one compact card each ---------- */
.home-prog { display: grid; gap: .4rem; min-width: min(100%, 240px); font-size: .85rem; color: var(--muted); }
.home-prog i { display: block; height: 6px; border-radius: 3px; background: var(--track); overflow: hidden; }
.home-prog i::after { content: ''; display: block; height: 100%; width: var(--p); background: var(--ok); border-radius: 3px; }
.cc-group + .cc-group { margin-top: 1.75rem; }
.home-sec { display: flex; gap: .5rem; align-items: center; margin: 0 0 .75rem; font-size: 1.05rem; }
.home-sec .muted { font-weight: 500; }
.class-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 210px), 1fr)); gap: .75rem; }
/* view options: Cards / List and the grouping, right under the title */
.home-view { display: flex; flex-wrap: wrap; gap: .5rem .75rem; margin: -.75rem 0 1.25rem; }
.home-view .tabs { margin: 0; }
.home-view .tabs button { display: inline-flex; align-items: center; gap: .35rem; }
/* List: one slim row per class (name | KSAii | counts | next step | arrow), hairlines between rows, one paper panel per group */
.class-list { display: grid; background: var(--card); border-radius: 14px; box-shadow: var(--shadow); overflow: hidden; }
.class-row { display: grid; grid-template-columns: minmax(0, 1.6fr) minmax(150px, 1fr) auto minmax(0, 1.4fr) auto; gap: 1.25rem; align-items: center;
  width: 100%; padding: .6rem 1rem; border: 0; border-radius: 0; background: none; text-align: left; font-weight: 400; transition: background-color .15s var(--ease); }
.class-row + .class-row { box-shadow: 0 -1px 0 var(--line); }
.cl-group { display: flex; align-items: center; gap: .5rem; margin: 0; padding: .45rem 1rem; background: var(--head); box-shadow: 0 -1px 0 var(--line), 0 1px 0 var(--line); font: 600 .85rem/1.3 var(--display); }
.cl-group:first-child { box-shadow: 0 1px 0 var(--line); }
.class-row:hover:not(:disabled) { background: var(--hover); }
.class-row:active:not(:disabled) { transform: none; }
.class-row:hover .cc-go { transform: translateX(3px); }
.cl-name { display: flex; align-items: baseline; gap: .5rem; min-width: 0; }
.cl-name b { font: 600 1rem/1.3 var(--display); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cl-counts { display: inline-flex; gap: .8rem; font-size: .82rem; color: var(--muted); font-variant-numeric: tabular-nums; }
.cl-counts > span { display: inline-flex; gap: .3rem; align-items: center; }
.cl-counts svg { width: 14px; height: 14px; }
.cl-next { display: flex; align-items: center; gap: .5rem; min-width: 0; font-size: .85rem; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cl-next .dot { margin: 0; }
@media (max-width: 760px) { /* phones: name, then the KSAii bar under it; counts and next step move to the dot's tooltip */
  .class-row { grid-template-columns: minmax(0, 1fr) auto; gap: .4rem .75rem; }
  .class-row .ksa-bar { grid-column: 1; grid-row: 2; }
  .class-row .cc-go { grid-column: 2; grid-row: 1 / 3; }
  .cl-counts, .cl-next { display: none; }
}
.class-card { position: relative; display: flex; flex-direction: column; gap: .55rem; width: 100%; padding: 1.1rem 1.1rem 1rem; border-radius: 4px 4px 14px 14px; border: 1px solid transparent;
  background: var(--card); color: var(--text); box-shadow: var(--pad-shadow); text-align: left; font-weight: 400;
  transition: transform .15s var(--ease), border-color .15s var(--ease), box-shadow .15s var(--ease); }
.class-card:hover:not(:disabled) { background: var(--card); border-color: color-mix(in srgb, var(--accent) 40%, transparent); }
.class-card:active:not(:disabled) { transform: none; }
.cc-row { display: flex; gap: .5rem; align-items: flex-start; justify-content: space-between; }
.cc-title { font: 600 1.1rem/1.3 var(--display); letter-spacing: 0; }
.dot { flex: none; width: 9px; height: 9px; margin-top: .45rem; border-radius: 50%; background: var(--track); }
.dot.on { background: var(--accent); }
.dot.ok { background: var(--ok); }
/* KSAii coverage: one segment per category, letter + bar coloured once it has an activity */
.ksa-bar { display: grid; grid-template-columns: repeat(5, 1fr); gap: 3px; }
.ksa-bar > span { display: grid; gap: 3px; justify-items: center; }
.ksa-bar b { font-size: .68rem; font-weight: 800; line-height: 1; color: var(--muted); opacity: .6; }
.ksa-bar i { width: 100%; height: 5px; border-radius: 3px; background: var(--track); }
.ksa-bar .on b { color: var(--kt, var(--kb)); opacity: 1; }
.ksa-bar .on i { background: var(--kb); }
.cc-foot { display: flex; gap: .9rem; align-items: center; margin-top: auto; font-size: .82rem; color: var(--muted); font-variant-numeric: tabular-nums; }
.cc-foot > span { display: inline-flex; gap: .3rem; align-items: center; }
.cc-foot svg { width: 14px; height: 14px; }
.cc-go { display: inline-flex; color: var(--accent); transition: transform .15s var(--ease); }
.class-card:hover .cc-go { transform: translateX(3px); }
.class-card.done { background: color-mix(in srgb, var(--card) 70%, transparent); }
.home-past > summary { margin: 1.75rem 0 .5rem; cursor: pointer; font-weight: 600; }
.home-past h3 { margin: 1rem 0 .5rem; font-size: .85rem; }
@media (prefers-reduced-motion: reduce) { .class-card, .cc-go { transition: none; } .class-card:hover:not(:disabled), .class-card:hover .cc-go { transform: none; } }

/* ---------- activity-type presets: each named set is a dropdown ---------- */
details.preset { border-radius: 14px; padding: .2rem .9rem; box-shadow: inset 0 0 0 1px var(--line); }
details.preset + details.preset { margin-top: .6rem; }
details.preset > summary { display: flex; gap: .6rem; align-items: center; padding: .6rem 0; cursor: pointer; }
details.preset[open] > summary { border-bottom: 1px solid var(--line); margin-bottom: .75rem; }
details.preset > .schemegrid { margin-bottom: .9rem; }
.preset-rename { margin: 0 0 .75rem; } .preset-rename input { flex: 1 1 16rem; }

/* Subjects: preset at the end of each row (+ type count, missing KSAii categories); filters + bulk apply */
.preset-cell { display: grid; gap: .2rem; min-width: 13rem; }
.preset-cell select { max-width: 16rem; }
.preset-cell .miss { color: var(--danger); }
.sub-filters { margin: 0 0 .75rem; }

/* "Make a preset": one box per KSAii category, tinted with its colour */
.presetform .pm-cat { display: grid; gap: .35rem; padding: .6rem .7rem .5rem; border-radius: 12px; border-top: 3px solid var(--kb);
  background: color-mix(in srgb, var(--kb) 6%, var(--card)); font-weight: 600; font-size: .9rem; }
.presetform textarea { width: 100%; min-height: 6rem; resize: vertical; font-weight: 400; }

/* ---------- motion: save status, toast (transitions.dev snippets) ---------- */
/* Text states swap: driven by swapText() in ui.js */
.t-text-swap {
  display: inline-block;
  transform: translateY(0);
  filter: blur(0);
  opacity: 1;
  transition:
    transform var(--text-swap-dur) var(--text-swap-ease),
    filter    var(--text-swap-dur) var(--text-swap-ease),
    opacity   var(--text-swap-dur) var(--text-swap-ease);
  will-change: transform, filter, opacity;
}
.t-text-swap.is-exit {
  transform: translateY(calc(var(--text-swap-translate-y) * -1));
  filter: blur(var(--text-swap-blur));
  opacity: 0;
}
.t-text-swap.is-enter-start {
  transform: translateY(var(--text-swap-translate-y));
  filter: blur(var(--text-swap-blur));
  opacity: 0;
  transition: none;
}
@media (prefers-reduced-motion: reduce) {
  .t-text-swap { transition: none !important; }
}

/* Shimmer text: "Saving…" while the write is in flight (data-text mirrors the label) */
.t-shimmer {
  position: relative;
  display: inline-block;
  color: var(--shimmer-base);
}
.t-shimmer::before {
  content: attr(data-text);
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image: linear-gradient(
    90deg,
    transparent          0%,
    transparent         40%,
    var(--shimmer-highlight) 50%,
    transparent         60%,
    transparent        100%
  );
  background-size: var(--shimmer-band) 100%;
  background-repeat: no-repeat;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  animation: t-shimmer var(--shimmer-dur) var(--shimmer-ease) infinite;
}
@keyframes t-shimmer {
  0%   { background-position: 100% 0; }
  100% { background-position: 0% 0; }
}
@media (prefers-reduced-motion: reduce) {
  .t-shimmer::before { animation: none !important; }
}

/* Toast: admin save confirmations (toast() in ui.js) */
.t-toast {
  opacity: 0;
  transform: translateY(var(--toast-distance)) scale(var(--toast-scale));
  filter: blur(var(--toast-blur));
  will-change: transform, opacity, filter;
  transition:
    opacity var(--toast-close) var(--toast-ease),
    transform var(--toast-close) var(--toast-ease),
    filter var(--toast-close) var(--toast-ease);
}
.t-toast.is-open {
  opacity: 1;
  transform: translateY(0) scale(1);
  filter: blur(0);
  transition:
    opacity var(--toast-open) var(--toast-ease),
    transform var(--toast-open) var(--toast-ease),
    filter var(--toast-open) var(--toast-ease);
}
@media (prefers-reduced-motion: reduce) {
  .t-toast { transition: none !important; }
}
.toast { position: fixed; z-index: 30; bottom: 24px; left: 16px; right: 16px; width: max-content; max-width: min(100% - 32px, 520px); margin: 0 auto;
  padding: .7rem 1.1rem; border-radius: 14px; background: var(--card); color: var(--text); box-shadow: var(--shadow), 0 10px 30px light-dark(rgb(0 0 0 / .12), rgb(0 0 0 / .5));
  font-size: .9rem; font-weight: 500; pointer-events: none; }
.toast.is-open { pointer-events: auto; }
.toast { display: flex; gap: .5rem; align-items: center; }
.toast svg { flex: none; color: var(--ok); }

/* ---------- scroll: the top bar lifts once the page moves; cards ease in as they scroll into view ---------- */
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
  @supports (animation-timeline: scroll()) {
    body:not(.bg-login) .top { animation: top-lift linear both; animation-timeline: scroll(root); animation-range: 0 48px; }
    .class-card, .room-card { animation: scroll-in linear both; animation-timeline: view(); animation-range: entry 0% entry 70%; }
  }
}
@keyframes top-lift { from { border-bottom-color: transparent; box-shadow: none; } to { box-shadow: 0 6px 20px light-dark(rgb(0 0 0 / .06), rgb(0 0 0 / .45)); } }
@keyframes scroll-in { from { opacity: 0; translate: 0 var(--scroll-distance); } }

/* ---------- Hub (home tab): a weekly briefing. Today + launch strip, week board, agenda document, calendar ahead ---------- */
:root {
  /* transitions.dev: avatar group hover (launch strip) and accordion expand (agenda sections) */
  --avatar-lift: -4px; --avatar-dur: 320ms; --avatar-scale: 1.05; --avatar-falloff: 0.45;
  --avatar-ease-in: cubic-bezier(0.22, 1, 0.36, 1); --avatar-ease-out: cubic-bezier(0.34, 3.85, 0.64, 1);
  --acc-expand: 250ms; --acc-collapse: 250ms; --acc-chevron: 250ms; --acc-ease: cubic-bezier(0.22, 1, 0.36, 1);
}
.hub { display: grid; grid-template-columns: minmax(0, 1fr); gap: 1.25rem; } /* minmax(0): wide content may not widen the page */
.hub a { color: var(--accent); text-decoration: none; }
.hub a:hover { text-decoration: underline; text-underline-offset: .2em; }
.hub > .page-head { margin-bottom: .25rem; } /* + the grid gap = the same 1.5rem as other pages */
.hub-top { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: 1.25rem 2rem; }
.greet { align-self: end; display: grid; justify-items: end; gap: .2rem; min-width: 0; width: min(24rem, 34vw); text-align: right; } /* never wider: the page margin holds */
.hub-top .hello { margin: 0; font: 600 1.3rem/1.3 var(--display); color: var(--text); }
/* the private status: a paper pill like the launch strip (pencil, text, Save on focus) with an "only you" note under it */
.status { display: grid; justify-items: end; gap: .3rem; width: 100%; min-width: 0; } /* the box hugs its text inside the greeting's width */
.status-field { display: inline-flex; align-items: center; gap: .45rem; max-width: 100%; min-height: 2.4rem; padding: .15rem .25rem .15rem .8rem; border-radius: 1.2rem;
  background: transparent; border: 1px solid var(--line); cursor: text; transition: border-color .15s var(--ease), background-color .15s var(--ease); }
.status-field:hover { border-color: color-mix(in srgb, var(--muted) 55%, var(--line)); }
.status-field:focus-within { background: var(--card); border-color: var(--accent); }
.status-ico { display: grid; place-items: center; flex: none; color: var(--muted); opacity: 0; transition: opacity .15s var(--ease), color .15s var(--ease); }
.status-field:hover .status-ico, .status-field:focus-within .status-ico { opacity: 1; color: var(--accent); } /* the pencil shows only on hover / while typing */
@media (hover: none) { .status-ico { opacity: 1; } } /* touch screens have no hover: keep it visible there */
.status-field textarea, .status-field textarea:focus { flex: 0 1 auto; field-sizing: content; min-width: 9rem; max-width: 100%; min-height: 0; padding: .3rem 0;
  border: 0; border-radius: 0; background: none; box-shadow: none; outline: none; resize: none; overflow: hidden;
  font: inherit; font-size: .93rem; line-height: 1.4; color: var(--text); text-align: right; overflow-wrap: anywhere; }
.status-field textarea::placeholder { color: var(--muted); }
@supports not (field-sizing: content) { .status-field textarea, .status-field textarea:focus { width: 14rem; overflow: auto; } } /* Safari: fixed width, scrolls */
.status-save { display: none; flex: none; padding: .3rem .85rem; border-radius: 999px; font-size: .8rem; font-weight: 600; background: var(--btn, var(--accent)); color: var(--accent-text); }
.status-field:focus-within .status-save { display: inline-block; }
.status-note { display: none; align-items: center; gap: .3rem; font-size: .75rem; color: var(--muted); }
.status:focus-within .status-note { display: inline-flex; }
.hub-top h1 span { color: var(--muted); font-weight: 500; }
.hub-top h1 .hub-wk { color: inherit; font-weight: inherit; } /* the week number counting up on a new week (hub.js) is part of the title */
.hub-top .launch { grid-column: 1 / -1; }
/* tear-off calendar pads: paper bound at the top, a perforated edge, the next sheet showing underneath */
.pad { position: relative; background: var(--card); border-radius: 4px 4px 14px 14px; box-shadow: var(--pad-shadow); }
.pad::before, .class-card::before { content: ''; position: absolute; left: 10px; right: 10px; top: -4px; height: 8px; pointer-events: none;
  background: radial-gradient(circle at 4px 4px, var(--bg) 2.5px, transparent 3px) 0 0 / 10px 8px repeat-x; }
/* today: the top page of the pad */
.tear { display: grid; justify-items: center; width: 10.5rem; padding: 1.1rem .5rem .85rem; font-variant-numeric: tabular-nums;
  box-shadow: 0 2px 0 var(--card), 0 3px 0 var(--pad-under), 0 5px 0 var(--card), 0 6px 0 var(--pad-under), 0 12px 26px light-dark(rgb(40 36 20 / .1), rgb(0 0 0 / .5)); } /* the pages still underneath */
.tear span { font: 500 .85rem/1.3 var(--display); color: var(--muted); }
.tear span:first-child { font-weight: 600; color: var(--accent); }
.tear b { font: 800 4.75rem/.95 var(--display); letter-spacing: -.03em; }
.tear.wkend span:first-child, .tear.wkend b { color: var(--danger); }

/* ---------- What's new since this person's last visit (hub.js noteChanges); each entrance plays once per visit ---------- */
/* A new day: the last page they saw sits on top of today's and tears off: a small tug at the binding, then it falls away. */
.tear > .torn { position: absolute; inset: 0; width: auto; margin: 0; grid-area: auto; z-index: 2; transform-origin: 50% 0; pointer-events: none;
  animation: tear-off 1.2s .5s both; }
@keyframes tear-off {
  0% { transform: none; animation-timing-function: cubic-bezier(.3, 0, .2, 1); }
  20% { transform: rotate(-2.5deg) translateY(3px); animation-timing-function: cubic-bezier(.55, 0, .85, .3); }
  100% { transform: translate(-22%, 150%) rotate(-22deg); opacity: 0; }
}
/* A new week: the five weekday pads drop in from their binding, Monday first. */
.hub.new-week .week > .day { animation: day-in .7s var(--glide) calc(.55s + var(--i, 0) * 80ms) backwards; } /* --i = 0 (Mon) … 4 (Fri), hub.js */
@keyframes day-in { from { opacity: 0; transform: perspective(900px) rotateX(-16deg) translateY(10px); } }
/* The note above the week, and a New tag + one green sweep on each new agenda item, due item and event. */
.hub-new { display: flex; align-items: center; flex-wrap: wrap; gap: .5rem .85rem; margin: 0 0 .9rem; padding: .7rem .9rem; border-radius: 12px;
  background: color-mix(in srgb, var(--accent) 9%, var(--card)); }
.hub-new p { margin: 0; display: grid; gap: .1rem; flex: 1 1 14rem; }
.hub-new p b { font: 600 .95rem/1.3 var(--display); }
.hub-new p span { font-size: .85rem; }
.hub-new button { display: inline-flex; align-items: center; gap: .3rem; color: var(--accent); font-weight: 600; }
.new-tag { display: inline-block; margin-right: .4rem; padding: 0 .45rem; border-radius: 999px; background: var(--accent); color: var(--accent-text);
  font: 600 .68rem/1.55 var(--display); letter-spacing: .02em; vertical-align: .12em; }
.hub-new > .new-tag { margin: 0; }
.entry.is-new { border-radius: 6px; }
.hub.intro .hub-new { animation: new-note .7s var(--glide) .3s backwards; }
@keyframes new-note { from { opacity: 0; transform: translateY(-8px); } }
.hub.intro .is-new { animation: new-sweep 1.8s var(--glide) .9s backwards; }
.hub .is-new.flash { animation: new-sweep 1.8s var(--glide) .4s backwards; } /* "Show me" replays it on the first one */
@keyframes new-sweep { from { background: linear-gradient(100deg, transparent 30%, color-mix(in srgb, var(--accent) 30%, transparent) 50%, transparent 70%) 130% 0 / 250% 100% no-repeat color-mix(in srgb, var(--accent) 16%, transparent); }
  to { background: linear-gradient(100deg, transparent 30%, color-mix(in srgb, var(--accent) 30%, transparent) 50%, transparent 70%) -130% 0 / 250% 100% no-repeat transparent; } }
@media (prefers-reduced-motion: reduce) { /* no tearing, dropping or sweeping: the New tags and the note say it */
  .tear > .torn { display: none; }
  .hub.new-week .week > .day, .hub.intro .hub-new, .hub.intro .is-new, .hub .is-new.flash { animation: none; }
}
@media (max-width: 640px) { /* phones: the page lies sideways, numeral left */
  .hub-top { grid-template-columns: minmax(0, 1fr); }
  .greet { justify-items: start; text-align: left; }
  .status { justify-items: start; max-width: 100%; }
  .greet { width: 100%; }
  .status-field textarea, .status-field textarea:focus { text-align: left; } /* phones: the greeting sits on the left */
  .tear { width: 100%; grid-template-columns: auto minmax(0, 1fr); justify-items: start; align-items: center; column-gap: 1rem; padding: .8rem 1.1rem; }
  .tear b { grid-column: 1; grid-row: 1 / 3; font-size: 3.25rem; }
  .tear span { grid-column: 2; }
}
.hub-panel { min-width: 0; border-radius: 14px; background: var(--card); box-shadow: var(--shadow); }
.hub-panel > header { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem .75rem; padding: .85rem 1.25rem; border-bottom: 1px solid var(--line); }
.hub-panel h2 { margin: 0; }
.hub-panel > header .tabs { margin: 0; }
.panel-link { display: inline-flex; align-items: center; gap: .4rem; font-size: .85rem; }
.panel-sub { margin: 0; padding: .75rem 1.25rem 0; font-size: .85rem; color: var(--muted); }
.panel-empty { margin: 0; padding: 1.25rem; color: var(--muted); }
.hub-foot { margin: 0; text-align: center; font-size: .8rem; color: var(--muted); }
.hub-foot .stale { margin-left: .4rem; padding: .05rem .5rem; border-radius: 6px; background: var(--warn-bg); color: var(--text); }
.mark { flex: none; display: block; }

/* a date as a tear-off calendar page: weekday over a big numeral (green today, red holidays and weekends) */
.cal-page { flex: none; display: grid; justify-items: center; align-content: start; width: 2.75rem; text-align: center; line-height: 1.1; font-variant-numeric: tabular-nums; }
.cal-page span { font: 500 .75rem var(--display); color: var(--muted); }
.cal-page b { font: 700 1.75rem/1 var(--display); letter-spacing: -.02em; color: var(--text); }
.cal-page.today span, .cal-page.today b { color: var(--accent); }
.cal-page.off b, .cal-page.wkend b, .cal-page.off span, .cal-page.wkend span { color: var(--danger); }
.cal-page.past { opacity: .5; }

/* the launch strip: app-style icon tiles; the tile says where a link opens (Google Sheets green / this site's ink) */
.launch { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; }
.hub :is(a, button).ql { display: inline-flex; align-items: center; gap: .55rem; padding: .3rem .85rem .3rem .3rem; border-radius: 999px; background: var(--card); color: var(--text);
  box-shadow: 0 0 0 1px var(--line); font-size: .85rem; font-weight: 500; white-space: nowrap; }
.hub :is(a, button).ql:hover { text-decoration: none; }
.hub :is(a, button).ql:active { scale: .96; }
.app-ico { display: grid; place-items: center; width: 1.85rem; height: 1.85rem; border-radius: 999px; }
.app-ico.sheets { background: #1e8e4e; color: #fff; }
.app-ico.site { background: var(--sprout); color: var(--accent); }
.launch-sep { width: 1px; height: 1.4rem; margin: 0 .25rem; background: var(--line); }
@media (max-width: 760px) {
  .launch { flex-wrap: nowrap; overflow-x: auto; margin: 0 calc(-1 * var(--gutter)); padding: .4rem var(--gutter) .7rem; scroll-padding-inline: var(--gutter); scrollbar-width: none; scroll-snap-type: x proximity; }
  .launch::-webkit-scrollbar { display: none; }
  .hub :is(a, button).ql { scroll-snap-align: start; }
}
/* transitions.dev: avatar group hover (verbatim) */
.t-avatar {
  transform-origin: center;
  transform:
    translateY(var(--shift, 0px))
    scale(var(--scale-active, 1));
  transition: transform var(--avatar-dur) var(--avatar-ease-in);
  will-change: transform;
}
@media (prefers-reduced-motion: reduce) {
  .t-avatar { transition: none !important; transform: none !important; }
}

/* who it's for: a K | P | H strip (filled = for that level; all three = All), and IP / IEP only when the sheet says so */
.tags { display: inline-flex; flex-wrap: wrap; align-items: center; gap: .3rem; vertical-align: 1px; }
.lvl { display: inline-flex; overflow: hidden; border-radius: 6px; box-shadow: 0 0 0 1px var(--line); font-size: .66rem; font-weight: 700; line-height: 1.55; }
.lvl i { width: 1.15rem; font-style: normal; text-align: center; color: color-mix(in srgb, var(--muted) 55%, transparent); }
.lvl i + i { box-shadow: -1px 0 0 var(--line); }
.lvl i.on { background: var(--text); color: var(--card); }
.lvl i.on + i.on { box-shadow: -1px 0 0 color-mix(in srgb, var(--card) 35%, transparent); }
.tag { display: inline-block; padding: 0 .4rem; border-radius: 6px; font-size: .66rem; font-weight: 700; line-height: 1.55; color: var(--text); }
.tag.prog-IP { background: var(--ip-bg); }
.tag.prog-IEP { background: var(--iep-bg); }
.until { font-size: .75rem; color: var(--muted); white-space: nowrap; }
.entry-meta { display: inline-flex; flex-wrap: wrap; align-items: center; gap: .3rem; }

/* the week: five pads side by side; today outlined in green; a school holiday tinted red */
.week { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: .75rem; }
.day { display: grid; align-content: start; gap: .75rem; min-height: 11rem; padding: 1rem 1rem 1.1rem; }
.day > .cal-page { width: auto; display: flex; flex-direction: row-reverse; justify-content: flex-end; align-items: baseline; gap: .45rem;
  padding-bottom: .65rem; border-bottom: 1px solid var(--line); }
.day > .cal-page b { font-size: 2.1rem; }
.day > .cal-page span { font-size: .85rem; font-weight: 600; }
.day.today { outline: 2px solid var(--accent); outline-offset: -2px; }
.day.off { background: color-mix(in srgb, var(--danger) 6%, var(--card)); }
.day ul { list-style: none; margin: 0; padding: 0; display: grid; gap: .6rem; }
.entry { display: grid; gap: .25rem; font-size: .85rem; line-height: 1.35; overflow-wrap: anywhere; }
.hub a.entry-title, .hub span.entry-title { color: var(--text); font-weight: 600; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.entry.due .entry-title { font-weight: 500; }
.entry.off .entry-title { color: var(--danger); }
.day.past .entry-title { color: var(--muted); }
.due-word { font-size: .75rem; font-weight: 600; color: var(--danger); }
.day.past .due-word { color: var(--muted); }
.day-empty { margin: 0; font-size: .8rem; color: var(--muted); }
.day li.due-word { margin-bottom: -.4rem; }   /* one heading over the day's due items */
.day:not(.open) .more { display: none; }
.day-more { justify-self: start; margin-top: -.35rem; padding: .15rem 0; border: 0; background: none; font-size: .8rem; font-weight: 600; color: var(--accent); cursor: pointer; }
.day-more:hover:not(:disabled) { background: none; text-decoration: underline; }
.day-empty, .panel-empty { display: flex; align-items: center; gap: .4rem; }
.day-empty .i, .panel-empty .i { flex: none; color: var(--accent); opacity: .8; }
@media (max-width: 900px) { /* a phone reads the week top to bottom: the date page on the left, the day's entries beside it */
  .week { grid-template-columns: minmax(0, 1fr); gap: .65rem; }
  .day { grid-template-columns: 3.25rem minmax(0, 1fr); align-items: start; gap: .9rem; min-height: 0; padding: .85rem 1rem; }
  .day > .cal-page { display: grid; justify-items: center; padding: 0; border: 0; }
  .day > .cal-page span { order: -1; }
  .day > .day-more { grid-column: 2; }
}

/* agenda + calendar side by side */
.hub-main { display: grid; gap: 1.25rem; grid-template-columns: minmax(0, 1.65fr) minmax(300px, 1fr); align-items: start; }
@media (max-width: 960px) { .hub-main { grid-template-columns: minmax(0, 1fr); }
  .hub-main > .hub-side { display: contents; } .rc-panel { order: -1; } } /* stacked: Recently used first, Coming up after the agenda */

/* the agenda as one document: sections fold (accordion); due, person, tags and the row link sit on the right */
.agenda { padding: .25rem 1.25rem .75rem; }
.ag-sec + .ag-sec { border-top: 1px solid var(--line); }
.hub .ag-head { display: flex; align-items: center; gap: .45rem; width: 100%; padding: .85rem 0 .55rem; border: 0; border-radius: 0; background: none; color: var(--text); font-weight: 600; text-align: left; }
.hub .ag-head:hover:not(:disabled) { background: none; }
.hub .ag-head:active:not(:disabled) { transform: none; }
.ag-head .t-acc-chevron { color: var(--muted); }
.ag-head .count { font-size: .8rem; font-weight: 500; color: var(--muted); font-variant-numeric: tabular-nums; }
.ag-list { list-style: none; margin: 0 0 .7rem; padding: 0 0 0 1.4rem; }
/* transitions.dev: accordion expand (verbatim) */
.t-acc-panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--acc-collapse) var(--acc-ease);
}
.t-acc[data-open="true"] .t-acc-panel {
  grid-template-rows: 1fr;
  transition: grid-template-rows var(--acc-expand) var(--acc-ease);
}
.t-acc-panel-inner {
  overflow: hidden;
  opacity: 0;
  filter: blur(2px);
  transition:
    opacity var(--acc-collapse) var(--acc-ease),
    filter var(--acc-collapse) var(--acc-ease);
}
.t-acc[data-open="true"] .t-acc-panel-inner {
  opacity: 1;
  filter: blur(0);
  transition:
    opacity var(--acc-expand) var(--acc-ease),
    filter var(--acc-expand) var(--acc-ease);
}
.t-acc-chevron {
  display: inline-flex;
  transform: scaleY(1);
  transform-origin: center;
  transition: transform var(--acc-chevron) var(--acc-ease);
}
.t-acc-chevron path { vector-effect: non-scaling-stroke; }
.t-acc[data-open="true"] .t-acc-chevron {
  transform: scaleY(-1);
}
@media (prefers-reduced-motion: reduce) {
  .t-acc-panel, .t-acc-panel-inner, .t-acc-chevron {
    transition: none !important;
  }
}
.ag-grp { margin: .8rem 0 .2rem; font-size: .8rem; font-weight: 600; color: var(--muted); }
.ag-grp:first-child { margin-top: .1rem; }
.ag-grp span { font-weight: 500; }
.ag-item { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: .2rem 1.25rem; padding: .5rem .6rem; margin-inline: -.6rem; border-radius: 8px; border-top: 1px solid color-mix(in srgb, var(--line) 55%, transparent); }
.ag-grp + .ag-item { border-top: 0; }
.ag-text { font-size: .93rem; line-height: 1.45; max-width: 68ch; overflow-wrap: anywhere; text-wrap: pretty; }
.ag-item.lead .ag-text { font-weight: 500; }
.ag-ref { margin-top: .15rem; font-size: .8rem; }
.ag-ref a, .ag-ref span { display: inline-flex; align-items: center; gap: .25rem; }
.ag-ref span { color: var(--muted); }
.ag-subs { margin: .2rem 0 0; padding-left: 1.1rem; font-size: .85rem; color: var(--muted); }
.ag-meta { display: flex; flex-wrap: wrap; justify-content: flex-end; align-items: center; align-content: start; gap: .35rem .6rem; max-width: 14rem;
  font-size: .8rem; color: var(--muted); white-space: nowrap; font-variant-numeric: tabular-nums; }
.ag-meta .soon { color: var(--danger); font-weight: 600; }
.hub a.row-link { position: relative; display: grid; place-items: center; width: 1.75rem; height: 1.75rem; border-radius: 8px; opacity: .45; filter: grayscale(1); transition: opacity .15s, filter .15s, background .15s; }
.hub a.row-link::after { content: ''; position: absolute; inset: -.4rem; } /* a 44px touch target around the small mark */
.hub a.row-link:hover, .hub a.row-link:focus-visible, .ag-item:hover a.row-link { opacity: 1; filter: none; }
.hub a.row-link:hover, .hub a.row-link:focus-visible { background: var(--fill); }
@media (hover: none) { .hub a.row-link { opacity: 1; filter: none; } }

/* the calendar ahead, by month: one line per event */
.cal { list-style: none; margin: 0; padding: .25rem 1.25rem 1rem; }
.cal-month { padding: .85rem 0 .3rem; font-size: .8rem; font-weight: 600; color: var(--muted); }
.cal-row { display: grid; grid-template-columns: 2.6rem minmax(0, 1fr) auto; gap: .8rem; align-items: center; padding: .55rem .6rem; margin-inline: -.6rem; border-radius: 8px; border-top: 1px solid color-mix(in srgb, var(--line) 55%, transparent); }
.cal-month + .cal-row { border-top: 0; }
.cal-body { display: grid; gap: .25rem; min-width: 0; }
.hub a.cal-title, .hub span.cal-title { color: var(--text); font-size: .93rem; line-height: 1.35; font-weight: 500; }
.hub .cal-row.off .cal-title { color: var(--danger); }
.cal-when { font-size: .8rem; color: var(--muted); white-space: nowrap; }
@media (prefers-reduced-motion: reduce) { .hub a.row-link { transition: none; } .hub :is(a, button).ql:active { scale: 1; } }

/* ---------- hover motion: paper lifts from its binding ----------
   A pad is bound along its top edge, so on hover it tips toward you from there and its shadow deepens; today's page
   (the top of the tear-off pad) tips further, as if about to be torn. Rows tint and their date numeral rises a little.
   Mouse only (hover: hover); reduced motion keeps the tints and drops the movement. */
.pad, .class-card { transform-origin: 50% 0;
  transition: transform 320ms cubic-bezier(.16, 1, .3, 1), box-shadow 320ms cubic-bezier(.16, 1, .3, 1), border-color .15s var(--ease); }
.cal-row, .ag-item { transition: background-color .15s var(--ease); }
.cal-page b { transition: transform 240ms cubic-bezier(.16, 1, .3, 1), color .15s var(--ease); }
@media (hover: hover) {
  .cal-row:hover, .ag-item:hover { background-color: var(--hover); }
}
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .day.pad:hover, .class-card:hover:not(:disabled) { transform: perspective(900px) rotateX(5deg);
    box-shadow: 0 2px 0 var(--pad-under), 0 16px 30px light-dark(rgb(40 36 20 / .13), rgb(0 0 0 / .6)); }
  .tear:hover { transform: perspective(700px) rotateX(10deg); }
  .cal-row:hover .cal-page b { transform: translateY(-2px) scale(1.08); }
}

/* ---------- comment cards: writing boxes, the A4 cards, printing ---------- */
/* Writing comments: one learner at a time. Bar (Previous · picker · Next · progress · save status), the learner's paper card,
   a box per field with its count and an "Earlier comments" bubble (hover, focus or tap), Previous / Next again at the foot. */
.cw { display: grid; gap: .75rem; max-width: 980px; }
.cw-bar { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem .75rem; font-size: .85rem; }
.cw-bar select { max-width: 16rem; }
.cw-bar button, .cw-foot button { display: inline-flex; align-items: center; gap: .35rem; }
.cw-learner { background: var(--card); border-radius: 16px; box-shadow: var(--shadow); padding: 1rem 1.25rem; display: grid; gap: 1rem; }
.cw-learner header { display: flex; align-items: center; gap: .9rem; }
.cw-learner h2 { margin: 0; font: 700 1.3rem/1.1 var(--display); }
.cw-learner header p { margin: .15rem 0 0; font-size: .82rem; }
.cw-learner header .badge { margin-left: auto; }
.cw-no { display: grid; place-items: center; width: 2.4rem; height: 2.4rem; border-radius: 12px; background: var(--sprout); color: var(--accent); font: 700 1rem var(--display); }
.cw-fields { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 380px), 1fr)); gap: .9rem 1.25rem; }
.cw-field { display: grid; gap: .3rem; }
.cw-label { display: flex; align-items: center; justify-content: space-between; gap: .5rem; font-size: .85rem; font-weight: 600; }
.cw-field textarea { width: 100%; resize: vertical; font: inherit; font-size: .93rem; line-height: 1.45; color: var(--text); }
.cw-field textarea[aria-invalid="true"] { border-color: var(--danger); }
.cw-nopast { font-size: .75rem; font-weight: 400; color: var(--muted); }
.cw-past { position: relative; display: inline-flex; align-items: center; gap: .3rem; font-size: .75rem; font-weight: 600; color: var(--accent);
  padding: .15rem .55rem; border-radius: 999px; background: color-mix(in srgb, var(--accent) 10%, transparent); cursor: help; }
.cw-past-pop { display: none; position: absolute; z-index: 20; top: calc(100% + 6px); right: 0; width: min(420px, 80vw); max-height: 320px; overflow: auto;
  padding: .75rem .9rem; border-radius: 12px; background: var(--card); color: var(--text); box-shadow: 0 10px 30px rgb(0 0 0 / .18), 0 0 0 1px var(--line);
  font-weight: 400; font-size: .82rem; line-height: 1.45; cursor: auto; }
.cw-past:hover .cw-past-pop, .cw-past:focus .cw-past-pop, .cw-past:focus-within .cw-past-pop { display: grid; gap: .3rem; }
.cw-past-pop b { font-size: .72rem; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }
.cw-past-pop b:not(:first-child) { margin-top: .5rem; padding-top: .5rem; border-top: 1px solid var(--line); }
.cw-foot { display: flex; align-items: center; gap: .75rem; padding-top: .25rem; border-top: 1px solid var(--line); }
.cw-keys { font-size: .75rem; }
@media (max-width: 640px) { .cw-keys { display: none; } .cw-bar select { flex: 1 1 100%; max-width: none; order: 3; } }
.cm-count { justify-self: end; font-variant-numeric: tabular-nums; }
.cm-count.over { color: var(--danger); font-weight: 600; }
.banner.ok { border-radius: 12px; margin-bottom: 1rem; background: var(--sprout); }
.cm-missing summary { cursor: pointer; font-weight: 600; }
.cm-missing li { margin: .2rem 0; }
.hr-cell { display: flex; gap: .4rem; }
.home-hr { margin-bottom: 1.25rem; }
/* Homeroom card: a checklist of what this teacher writes for the room (rows open the page to type in) */
.home-hr .class-grid { grid-template-columns: repeat(auto-fill, minmax(min(100%, 360px), 1fr)); }
.hr-list { display: grid; gap: .3rem; margin: .1rem 0 0; padding: 0; list-style: none; }
.hr-list button { position: relative; display: grid; grid-template-columns: minmax(0, 1fr) auto auto; align-items: center; gap: .6rem; width: 100%;
  padding: .55rem .65rem .7rem; border-radius: 10px; background: var(--fill); text-align: left; font-weight: 400; overflow: hidden; }
.hr-list button:hover .cc-go { transform: translateX(3px); }
.hr-what { display: grid; min-width: 0; }
.hr-what b { font-weight: 600; font-size: .93rem; }
.hr-what small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: .78rem; color: var(--muted); }
.hr-count { font-size: .85rem; font-weight: 600; font-variant-numeric: tabular-nums; color: var(--muted); }
.hr-count.ok { color: var(--ok); }
.hr-bar { position: absolute; left: .65rem; right: .65rem; bottom: .3rem; height: 3px; border-radius: 2px; background: linear-gradient(var(--accent), var(--accent)) 0 0 / var(--p) 100% no-repeat, var(--track); }
.hr-cards { display: inline-flex; align-items: center; gap: .35rem; align-self: flex-start; font-size: .85rem; }
.home-hr + .home-view { margin-top: 0; }

/* The card: the school's Narrative Report Card, a white A4 sheet on screen and on paper (always light; ink-friendly).
   Always 210 mm wide so the on-screen "too long" check measures exactly what prints; small screens scroll it sideways.
   Letterhead, one typeface (IBM Plex Sans Thai), black text, school green only for the wordmark, rules and section labels; an open table
   (hairline rows, top-aligned labels, ragged-right text); signatures pinned to the foot of the page. */
.ccards { display: grid; justify-content: center; gap: 1.5rem; margin-top: 1rem; overflow-x: auto; padding-bottom: .5rem; }
.ccard { display: grid; gap: 1.5rem; scroll-margin-top: 5rem; }
.cc-page { --ink: #1a1a1a; --soft: #6b6b6b; --rule: #d9d9d4; --green: #2c7a3f;
  width: 210mm; min-height: 297mm; box-sizing: border-box; padding: 8mm 11mm 7mm; display: flex; flex-direction: column;
  background: #fff; color: var(--ink); color-scheme: light; box-shadow: var(--shadow); font: 7.8pt/1.22 var(--body);
  print-color-adjust: exact; -webkit-print-color-adjust: exact; }
.cc-page.too-long { outline: 3px solid var(--danger); outline-offset: 2px; }
.cc-head { display: flex; align-items: center; justify-content: space-between; height: 10mm; }
.cc-mark { width: 33mm; height: 10mm; background: var(--green); -webkit-mask: url(brand/tonkla-wordmark.webp) left center / contain no-repeat;
  mask: url(brand/tonkla-wordmark.webp) left center / contain no-repeat; }
.cc-ipc { height: 10mm; width: auto; }
.cc-title { margin: 2mm 0 0; padding-top: 1.8mm; border-top: 1.5px solid var(--green); }
.cc-title h2 { margin: 0; font: 600 12pt/1.15 var(--body); letter-spacing: -.01em; }
.cc-title p { margin: 0; color: var(--soft); font-size: 8pt; }
.cc-h { margin: 2.6mm 0 .8mm; font-size: 6.8pt; font-weight: 700; letter-spacing: .09em; text-transform: uppercase; color: var(--green); }
.cc-id { display: grid; grid-template-columns: 2fr 1fr 1fr 1.6fr; gap: 0 6mm; margin: 0; padding: 1.1mm 0; border-block: 1px solid var(--rule); }
.cc-id div { display: grid; gap: 1px; }
.cc-id dt { color: var(--soft); font-size: 6.6pt; letter-spacing: .04em; text-transform: uppercase; }
.cc-id dd { margin: 0; font-weight: 600; font-size: 8.4pt; }
.cc-acad { width: 100%; border-collapse: collapse; table-layout: fixed; }
.cc-acad th, .cc-acad td { padding: .9mm 2mm .9mm 0; vertical-align: top; text-align: left; border-top: 1px solid var(--rule); }
.cc-acad tr.cc-band > * { border-top: 1px solid #a9a9a3; }
.cc-acad tr:last-child > * { border-bottom: 1px solid #a9a9a3; }
.cc-acad th { width: 20mm; font-weight: 600; }
.cc-acad th.cc-grp { width: 12mm; font-size: 6.8pt; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--green); }
.cc-acad tr:not(.cc-band) th.cc-grp { border-top-color: transparent; }
.cc-acad td { padding-right: 0; }
.cc-acad tr { break-inside: avoid; }
.cc-sec { break-inside: avoid; }
.cc-sec p { margin: 0; white-space: pre-line; }
@page { size: A4; margin: 0; }
@media print {
  header.top, .banner, .acct-btn, #bg, .notice, .room-view > :not(.ccards) { display: none !important; }
  body, main, #app { background: #fff !important; margin: 0 !important; padding: 0 !important; }
  .ccards { display: block; margin: 0; }
  .ccard { display: block; }
  .cc-page { box-shadow: none; width: 210mm; min-height: 294mm; break-after: page; } /* too long = spills onto a page of its own, never cut */
  .ccard:last-child .cc-page:last-child { break-after: auto; } /* 294 mm, not 297: the pinned signatures never push the last sheet onto an extra page */
}

/* ---------- IPC map (Subjects tab): Thai subject | IPC ticks | grades found ---------- */
.ipcmap { display: grid; gap: .5rem; }
.ipcmap h2, .ipcmap .hint { margin: 0; }
.ipc-head, .ipc-row { display: grid; grid-template-columns: minmax(180px, 240px) 1fr auto 2rem; gap: .5rem 1rem; align-items: center; }
.ipc-head { font-size: .74rem; font-weight: 600; color: var(--muted); padding: .5rem .25rem 0; }
.ipc-row { padding: .55rem .25rem; border-top: 1px solid var(--line); }
.ipc-row.bad select { border-color: var(--danger); }
.ipc-ticks { display: flex; flex-wrap: wrap; gap: .35rem; }
.ipc-tick { display: inline-flex; align-items: center; gap: .3rem; padding: .3rem .75rem; font-size: .8rem; border-radius: 999px;
  border: 1px solid var(--line); background: var(--card); color: var(--text); transition: background-color .15s var(--ease), border-color .15s var(--ease); }
.ipc-tick[aria-pressed="true"] { background: var(--sprout); border-color: var(--accent); }
.ipc-tick .box { display: inline-grid; place-items: center; width: 14px; height: 14px; border-radius: 4px; border: 1.5px solid var(--muted); flex: none; }
.ipc-tick[aria-pressed="true"] .box { background: var(--accent); border-color: var(--accent); color: var(--accent-text); }
.ipc-tick:disabled { opacity: .4; cursor: not-allowed; }
.ipc-grades { display: flex; gap: .2rem; }
.ipc-grades span { font-size: .66rem; font-weight: 600; padding: .15rem .3rem; border-radius: 6px; background: var(--fill); color: var(--muted); opacity: .55; }
.ipc-grades span.on { background: var(--sprout); color: var(--accent); opacity: 1; }
.ipc-foot { align-items: center; gap: .75rem; padding-top: .5rem; border-top: 1px solid var(--line); }
@media (max-width: 760px) {
  .ipc-head { display: none; }
  .ipc-row { grid-template-columns: 1fr 2rem; }
  .ipc-row .ipc-ticks, .ipc-row .ipc-grades { grid-column: 1 / -1; }
  .ipc-row > .danger { grid-column: 2; grid-row: 1; }
}

/* Assignments: one IPC slot per IP room (all its IPC subjects, one teacher) */
.slot.ipc-slot { background: color-mix(in srgb, var(--ip-bg) 70%, transparent); }
.slot.ipc-slot .subj small { display: block; margin-top: .1rem; }
.warn-text { color: var(--danger); font-size: .8rem; }

/* ---------- Learner Profile: field cards, signatories, card signature block ---------- */
.lpf-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 440px), 1fr)); gap: .75rem; margin: .5rem 0 1rem; }
.lpf { background: var(--card); border-radius: 14px; box-shadow: var(--shadow); padding: .8rem 1rem; display: grid; gap: .5rem; }
.lpf.off { opacity: .65; }
.lpf-name { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.lpf-name input { flex: 1 1 140px; }
.lpf-name .danger { margin-left: auto; }
.lpf-grid { display: grid; grid-template-columns: 7.5rem 1fr; gap: .45rem .75rem; margin: 0; align-items: center; font-size: .85rem; }
.lpf-grid dt { color: var(--muted); font-size: .78rem; }
.lpf-grid dd { margin: 0; }
.lpf-for, .lpf-when { display: flex; flex-wrap: wrap; gap: .35rem .6rem; align-items: center; }
.lpf-grid input[type=number] { width: 6rem; }
.lpf-add { gap: .5rem; align-items: center; }
.lp-head { gap: .5rem; align-items: center; margin-bottom: .5rem; }
.lp-names { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr)); gap: .5rem 1rem; }
.lp-names label { display: grid; gap: .2rem; font-size: .78rem; color: var(--muted); }
.cc-sign { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0 10mm; margin-top: auto; padding-top: 4mm; break-inside: avoid; }
.cc-sign div { display: grid; text-align: center; font-size: 8pt; }
.cc-sign i { display: block; height: 7mm; border-bottom: 1px solid #1a1a1a; margin-bottom: 1.2mm; }
.cc-sign span { color: #6b6b6b; font-size: 7pt; letter-spacing: .03em; }
@media (max-width: 560px) { .lpf-grid { grid-template-columns: 1fr; } }

/* Hub: the agenda panel's header is a pair of title tabs (Weekly agenda | Links) resting on the header hairline, the active
   one underlined in ink; the program pills and "Open sheet" sit together on the right. Links rows follow the agenda rows:
   ink label, muted "what it opens" on the right, hairlines between rows, a row-hover tint, two columns when there is room. */
.hub-panel > header.switch-head { align-items: flex-end; padding: .35rem 1.25rem 0; gap: 0 1rem; }
.panel-switch { display: flex; gap: 1.1rem; margin: 0; align-self: stretch; }
.panel-switch button { position: relative; background: none; border: 0; border-radius: 0; padding: .55rem 0 .7rem;
  font: 600 1.15rem/1.2 var(--display); color: var(--muted); transition: color .15s var(--ease); }
.panel-switch button::after { content: ''; position: absolute; inset: auto 0 -1px; height: 2px; border-radius: 2px; background: var(--text);
  transform: scaleX(0); transition: transform .2s var(--ease); }
.panel-switch button.on { color: var(--text); }
.panel-switch button { display: inline-flex; align-items: center; gap: .4rem; }
.panel-switch button.on::after { transform: scaleX(1); }
.panel-switch button:hover:not(.on):not(:disabled) { background: none; color: var(--text); }
.panel-switch button:active:not(:disabled) { transform: none; }
/* Teaching resources: always green; hops with a pinging dot until this device has opened it once (owner's request) */
.panel-switch button[data-v="links"]:not(.on) { color: var(--accent); }
.panel-switch button.nudge { transform-origin: 50% 100%; animation: res-hop 4s var(--ease) infinite; }
.panel-switch button.nudge::before { content: ''; position: absolute; top: .4rem; right: -.65rem; width: 7px; height: 7px; border-radius: 50%; background: var(--accent);
  animation: res-ping 2s ease-out infinite; }
@keyframes res-hop { 0%, 22%, 100% { transform: none; } 5% { transform: translateY(-4px) rotate(-3deg); } 10% { transform: translateY(-2px) rotate(3deg); } 15% { transform: rotate(-1.5deg); } }
@keyframes res-ping { from { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 55%, transparent); } to { box-shadow: 0 0 0 9px transparent; } }
@media (prefers-reduced-motion: reduce) { .panel-switch button.nudge, .panel-switch button.nudge::before { animation: none; } }
.head-tools { display: flex; align-items: center; gap: .75rem; margin-left: auto; padding-bottom: .5rem; }
.hl-list { list-style: none; margin: -.15rem 0 .75rem; padding: 0 0 0 1.4rem; display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 16rem), 1fr)); column-gap: 1.25rem; }
.hub-side { display: grid; gap: 1.25rem; min-width: 0; }
.rc-list { margin: 0; padding: .5rem 1.25rem .75rem; }
.hub button.hl-link { width: 100%; border: 0; background: none; color: inherit; font: inherit; text-align: left; }
.hub .hl-link { display: flex; align-items: center; gap: .65rem; min-height: 2.5rem; padding: .35rem .5rem; margin-inline: -.5rem; border-radius: 8px;
  color: var(--text); text-decoration: none; transition: background-color .15s var(--ease); }
.hl-ico { display: grid; place-items: center; flex: none; width: 1.25rem; height: 1.25rem; color: var(--muted); transition: color .15s var(--ease); }
.hl-ico .mark { width: 18px; height: 18px; }
.hl-label { flex: 1; min-width: 0; font-size: .93rem; line-height: 1.35; overflow-wrap: anywhere; }
.hub a.hl-link:hover { text-decoration: none; }
@media (hover: hover) { .hub .hl-link:hover { background-color: var(--hover); } .hub .hl-link:hover .hl-ico { color: var(--accent); } }
.hub .hl-link:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
@media (pointer: coarse) { .hub .hl-link { min-height: 2.95rem; } } /* 44px touch targets on phones and tablets */
@media (max-width: 640px) { .head-tools { width: 100%; margin-left: 0; padding: .1rem 0 .6rem; } .panel-switch { flex: 1 1 100%; } }

/* ---------- Themes (account menu → Theme; per browser, set before paint by index.html). Only colours and menus change:
   the admin's background photo, the KSAii hues and calendar red keep their meaning in every theme. Calendar = the :root set above. ---------- */
/* Pumpkin: candle-lit parchment, pumpkin orange for action, a night-purple bar */
:root[data-skin='pumpkin'] {
  --bg: light-dark(#f4ece0, #120d16); --card: light-dark(#fffaf3, #1d1622); --text: light-dark(#21152b, #f5ead9); --muted: light-dark(#6f6177, #b3a5bd);
  --line: light-dark(#eadccb, #33283b); --accent: light-dark(#c2410c, #ff8a3d); --ring: light-dark(rgb(194 65 12 / .25), rgb(255 138 61 / .4));
  --fill: light-dark(#f3e8da, #2a2030); --ex-bg: var(--fill); --head: light-dark(#fdf5ea, #241b2a); --sprout: light-dark(#fde5d2, #3a2216);
  --pad-under: light-dark(#e2d2bd, #07050a); --hover: light-dark(#fbefe2, #2a2030); --stripe: light-dark(#fdf6ec, #1a141f); --track: light-dark(#eadccb, #3a2e42);
  --xhair: light-dark(rgb(194 65 12 / .06), rgb(255 138 61 / .12)); --xhair-on: light-dark(rgb(194 65 12 / .11), rgb(255 138 61 / .22)); --btn: #c2410c;
}
:root[data-skin='pumpkin'] .top { --card: #23133a; --text: #f8ecdc; --muted: #c4b0dc; --line: #3b2559; --fill: #33204f; --accent: #ff8a3d; color: var(--text); }
:root[data-skin='pumpkin'] .anav button.on { background: var(--accent); color: #23133a; }
:root[data-skin='pumpkin'] .tabs button.on { background: var(--btn); color: #fff; }
/* Lagoon: Andaman water, teal for action, a frosted bar with underlined menu items */
:root[data-skin='lagoon'] {
  --bg: light-dark(#e6f0f2, #0b1618); --card: light-dark(#fff, #122125); --text: light-dark(#0c2229, #e6f3f5); --muted: light-dark(#557079, #93b0b7);
  --line: light-dark(#d3e3e7, #20363b); --accent: light-dark(#0e7490, #3cc8dc); --ring: light-dark(rgb(14 116 144 / .25), rgb(60 200 220 / .4));
  --fill: light-dark(#eaf3f5, #1a2d32); --ex-bg: var(--fill); --head: light-dark(#f4f9fa, #162a2e); --sprout: light-dark(#d6eef3, #123238);
  --pad-under: light-dark(#c9dade, #050b0c); --hover: light-dark(#eef7f9, #183034); --stripe: light-dark(#f5fafb, #10201f); --track: light-dark(#d3e3e7, #24393e);
  --xhair: light-dark(rgb(14 116 144 / .06), rgb(60 200 220 / .12)); --xhair-on: light-dark(rgb(14 116 144 / .11), rgb(60 200 220 / .22)); --btn: #0e7490;
}
:root[data-skin='lagoon'] .top { background: color-mix(in srgb, var(--card) 78%, transparent); backdrop-filter: saturate(160%) blur(18px); -webkit-backdrop-filter: saturate(160%) blur(18px); }
:root[data-skin='lagoon'] .anav button { border-radius: 0; }
:root[data-skin='lagoon'] .anav button.on, :root[data-skin='lagoon'] .anav button.hub.on { background: none; color: var(--accent); box-shadow: inset 0 -3px 0 var(--accent); }
:root[data-skin='lagoon'] .tabs button.on { background: var(--card); color: var(--accent); }
/* Lotus: petal pink paper, rose for action, soft tinted pills */
:root[data-skin='lotus'] {
  --bg: light-dark(#f6edef, #170f13); --card: light-dark(#fffbfc, #21161b); --text: light-dark(#2a1520, #f7e9ee); --muted: light-dark(#7a5f6b, #bfa2ad);
  --line: light-dark(#eedbe1, #3a2630); --accent: light-dark(#be185d, #f472b6); --ring: light-dark(rgb(190 24 93 / .22), rgb(244 114 182 / .4));
  --fill: light-dark(#f8ecf0, #2d1f26); --ex-bg: var(--fill); --head: light-dark(#fdf6f8, #271b21); --sprout: light-dark(#fbe1ec, #3d1a2b);
  --pad-under: light-dark(#e6d3d9, #080506); --hover: light-dark(#fcf0f4, #2d1f26); --stripe: light-dark(#fdf7f9, #1d1318); --track: light-dark(#eedbe1, #3d2a33);
  --xhair: light-dark(rgb(190 24 93 / .05), rgb(244 114 182 / .12)); --xhair-on: light-dark(rgb(190 24 93 / .1), rgb(244 114 182 / .22)); --btn: #be185d;
}
:root[data-skin='lotus'] .anav button.on, :root[data-skin='lotus'] .anav button.hub.on,
:root[data-skin='lotus'] .tabs button.on { background: var(--sprout); color: var(--accent); box-shadow: none; }
/* the picker in the account menu: one swatch per theme (its ground and its action colour) */
.skins { display: grid; grid-template-columns: repeat(4, 1fr); gap: .15rem; padding: .45rem .3rem .55rem; margin: .2rem 0; border-block: 1px solid var(--line); }
.skins small { grid-column: 1 / -1; padding: 0 .3rem .2rem; font-size: .75rem; font-weight: 600; color: var(--muted); }
.menu.acct .skins button { display: grid; justify-items: center; gap: .3rem; padding: .4rem .2rem; font-size: .75rem; font-weight: 500; text-align: center; }
.menu.acct .skins button[aria-pressed='true'] { color: var(--accent); font-weight: 600; }
.skins.roles { grid-template-columns: repeat(3, 1fr); } .skins.roles button svg { color: var(--accent); } /* Preview as: Teacher · Coordinator · Manager */
.sw { width: 1.75rem; height: 1.75rem; border-radius: 50%; box-shadow: 0 0 0 1px rgb(0 0 0 / .12); background: linear-gradient(135deg, var(--a) 50%, var(--b) 50%); }
.skins [aria-pressed='true'] .sw { box-shadow: 0 0 0 2px var(--card), 0 0 0 4px var(--accent); }
.sw-classic { --a: #efeeea; --b: #2c7a3f; } .sw-pumpkin { --a: #23133a; --b: #ff8a3d; } .sw-lagoon { --a: #e6f0f2; --b: #0e7490; } .sw-lotus { --a: #f6edef; --b: #be185d; }

/* ---------- Halloween corner (boo.js, October only): a night sky filling the space between the title and the greeting; wide screens only ---------- */
.boo { position: relative; align-self: stretch; min-height: 7.5rem; min-width: 0; border-radius: 14px; overflow: hidden; color: #f6eedf;
  background: radial-gradient(circle at calc(100% - 2.4rem) .8rem, #fdf3c9 0 1.1rem, rgb(253 243 201 / .14) 1.15rem 1.9rem, transparent 1.95rem),
    radial-gradient(1.5px 1.5px at 12% 22%, #fff8 99%, transparent), radial-gradient(1px 1px at 30% 70%, #fff7 99%, transparent),
    radial-gradient(1.5px 1.5px at 48% 18%, #fff9 99%, transparent), radial-gradient(1px 1px at 62% 58%, #fff6 99%, transparent),
    radial-gradient(1.5px 1.5px at 72% 80%, #fff7 99%, transparent), radial-gradient(1px 1px at 93% 64%, #fff8 99%, transparent),
    linear-gradient(160deg, #2b1745, #160c24); box-shadow: inset 0 0 0 1px rgb(255 255 255 / .06);
  cursor: var(--bat), crosshair; }
/* October: the pointer is a bat while the Hub is open (other pages, e.g. class grades, keep the normal one); text fields keep their text cursor */
:root { --bat: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='16' viewBox='0 0 64 32'%3E%3Cpath d='M32 12L29.5 7 28 12.5Q20 6 4 8Q10 12 9 17Q14 15 17 19Q21 16 25 20Q28 18 32 24Q36 18 39 20Q43 16 47 19Q50 15 55 17Q54 12 60 8Q44 6 36 12.5L34.5 7Z' fill='%23f98a2c' stroke='%23140a1f' stroke-width='2.5' stroke-linejoin='round'/%3E%3C/svg%3E") 16 8; }
body:has(.boo), body:has(.boo) :is(a, button, label, select, summary, [role='button']) { cursor: var(--bat), auto; }
body:has(.boo) :is(textarea, input:not([type='checkbox'], [type='radio'])) { cursor: text; }
@media (min-width: 1181px) { .hub-top:has(> .boo) { grid-template-columns: auto auto minmax(18rem, 1fr) auto; }
  .hub-top:has(> .boo) .greet { width: auto; max-width: 22rem; } } /* the greeting hugs its text, the sky takes the rest */
@media (max-width: 1180px) { .boo { display: none; } }
.boo-field { position: absolute; inset: .5rem; }
.boo-panel { position: relative; display: flex; align-items: center; gap: 1rem; height: 100%; padding: .75rem 1.25rem; }
.boo-panel > svg { flex: none; width: 4rem; height: 4rem; filter: drop-shadow(0 0 14px rgb(249 138 44 / .45)); }
.boo-text { flex: 1; display: grid; gap: .2rem; min-width: 0; }
.boo-text b { font: 800 1.75rem/1.1 var(--display); letter-spacing: -.01em; color: #ffb066; text-shadow: 0 0 18px rgb(249 138 44 / .35); }
.boo-text small { font-size: .85rem; color: #cbbbe0; }
.boo .boo-go { flex: none; padding: .5rem 1.25rem; font-size: .93rem; font-weight: 600; background: #ea6a12; color: #fff; }
.boo .boo-go:hover { background: #c95a0c; }
.boo { container-type: inline-size; }
.boo-board { display: none; margin: 0; padding: 0 .9rem 0 0; list-style: none; min-width: 8.5rem; font-size: .8rem; color: #cbbbe0; font-variant-numeric: tabular-nums; }
.boo-board li { display: flex; justify-content: space-between; gap: .75rem; line-height: 1.5; }
.boo-board li.boo-board-h { font-size: .66rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: #9d8bb6; }
.boo-board li b { color: #f6eedf; }
.boo-board li.mine, .boo-board li.mine b { color: #ffb066; font-weight: 600; }
@container (min-width: 36rem) { .boo-board { display: block; } .boo-rec { display: none; } }
.boo-hud { position: absolute; right: .9rem; bottom: .6rem; font: 500 .85rem var(--display); color: #cbbbe0; font-variant-numeric: tabular-nums; pointer-events: none; }
.boo-hud b { color: #fff; font-size: 1.05rem; }
.boo-ghost { position: absolute; width: 2.6rem; height: 2.6rem; padding: 0; border: 0; border-radius: 50%; background: none; animation: boo-in .18s ease-out both, boo-bob 1s ease-in-out .18s infinite alternate; }
.boo-ghost:hover:not(:disabled) { background: none; }
.boo-ghost svg { width: 100%; height: 100%; display: block; }
.boo-ghost.gold svg { filter: drop-shadow(0 0 6px rgb(252 196 25 / .8)); }
.boo-ghost.got { animation: boo-got .25s ease-out forwards; pointer-events: none; }
.boo-ghost.gone { animation: boo-out .2s ease-in forwards; pointer-events: none; }
@keyframes boo-in { from { opacity: 0; transform: scale(.4) translateY(6px); } }
@keyframes boo-bob { to { transform: translateY(-3px) rotate(4deg); } }
@keyframes boo-got { to { opacity: 0; transform: scale(1.6); } }
@keyframes boo-out { to { opacity: 0; transform: translateY(-8px); } }
@media (prefers-reduced-motion: reduce) { .boo-ghost, .boo-ghost.got, .boo-ghost.gone { animation: none; } .boo-ghost.got, .boo-ghost.gone { opacity: 0; } }
/* bats crossing the window: the outer box flies, the inner one swoops, the wings flap */
.bat { position: fixed; left: 0; z-index: 30; width: var(--w); pointer-events: none; animation: bat-fly 6s linear both; }
.bat i { display: block; animation: bat-swoop .9s ease-in-out infinite alternate; }
.bat svg { display: block; width: 100%; fill: #1b1024; transform: scaleX(var(--flip)); transform-origin: 50% 40%;
  filter: drop-shadow(0 0 3px rgb(249 138 44 / .55)); animation: bat-flap .16s ease-in-out infinite alternate; }
@keyframes bat-fly { from { transform: translateX(var(--from)); } to { transform: translateX(var(--to)); } }
@keyframes bat-swoop { from { transform: translateY(-1.5rem); } to { transform: translateY(1.5rem); } }
@keyframes bat-flap { to { transform: scaleX(var(--flip)) scaleY(.35); } }

/* ---------- Materials: a small shop (category bar, product cards, the Wish List), then the lead's lists ---------- */
.mt-shop { display: grid; grid-template-columns: minmax(0, 1fr) 360px; gap: 1.5rem; align-items: start; }
.mt-search { width: 100%; max-width: 420px; margin-bottom: .75rem; }
/* category bar: big pills with an icon and a count, scrolls sideways on a phone */
.mt-cats { display: flex; gap: .4rem; overflow-x: auto; scrollbar-width: none; padding: 2px 2px .6rem; margin: 0 0 .25rem; }
.mt-cats button { flex: none; display: inline-flex; align-items: center; gap: .4rem; padding: .45rem .85rem; border-radius: 999px; background: var(--card);
  box-shadow: 0 0 0 1px var(--line); font-size: .88rem; white-space: nowrap; }
.mt-cats button small { font-size: .72rem; color: var(--muted); font-variant-numeric: tabular-nums; }
.mt-cats button.on { background: var(--text); color: var(--card); box-shadow: none; font-weight: 600; }
.mt-cats button.on small { color: inherit; opacity: .7; }
/* product cards: picture on top (photo, or the category's art), name, unit, approval tag, Add / stepper */
.mt-grid { list-style: none; margin: .25rem 0 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(168px, 1fr)); gap: .75rem; }
.mt-card { display: flex; flex-direction: column; gap: .45rem; padding: .6rem; border-radius: 16px; background: var(--card); box-shadow: var(--shadow); transition: box-shadow .15s var(--ease); }
.mt-card.in { box-shadow: 0 0 0 2px var(--accent); }
.mt-card[hidden] { display: none; }
.mt-pic { display: grid; place-items: center; aspect-ratio: 1; border-radius: 12px; font-size: 3rem; background: var(--fill); overflow: hidden; }
.mt-pic img, .mt-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.cat-paper { background: var(--c4); } .cat-tape { background: var(--c1); } .cat-office { background: var(--c3); } .cat-writing { background: var(--c0); }
.cat-craft { background: var(--c2); } .cat-classroom { background: var(--sprout); } .cat-science { background: var(--ok-bg); } .cat-other { background: var(--fill); }
.mt-name { flex: 1; min-width: 0; display: grid; line-height: 1.3; align-content: start; }
.mt-name b { font-weight: 600; overflow-wrap: anywhere; }
.mt-name small { font-size: .78rem; }
.mt-tag { align-self: start; font-size: .72rem; padding: .08rem .5rem; border-radius: 999px; white-space: nowrap; }
.mt-tag.ask { background: var(--warn-bg); color: light-dark(#8a5a00, #f4c35a); }
.mt-tag.new { background: var(--ip-bg); color: light-dark(#1d4f91, #8cb8ff); }
.mt-other { background: none; box-shadow: inset 0 0 0 1.5px var(--line); }
.mt-step { flex: none; display: inline-flex; align-items: center; justify-content: space-between; gap: 2px; padding: 2px; border-radius: 999px; background: var(--fill); }
.mt-step button.icon { width: 1.9rem; height: 1.9rem; font-size: 1.1rem; line-height: 1; background: var(--card); }
.mt-step input.num { width: 2.6rem; padding: .2rem 0; text-align: center; background: none; font-weight: 600; font-variant-numeric: tabular-nums; -moz-appearance: textfield; }
.mt-step input.num::-webkit-inner-spin-button, .mt-step input.num::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
/* the Wish List */
.card.mt-cart { position: sticky; top: 5rem; margin: 0; max-width: none; max-height: calc(100vh - 6rem); overflow: auto; }
.mt-cart h2 { display: flex; align-items: center; gap: .5rem; }
.mt-sub { font-size: .78rem; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); margin: .75rem 0 .1rem; }
.mt-lines { list-style: none; margin: 0 0 .5rem; padding: 0; display: grid; }
.mt-lines > li { padding: .55rem 0; border-bottom: 1px solid var(--line); }
.mt-wl { display: flex; gap: .6rem; align-items: flex-start; }
.mt-wl-body { flex: 1; min-width: 0; display: grid; gap: .35rem; }
.mt-thumb { flex: none; display: inline-grid; place-items: center; width: 2.4rem; height: 2.4rem; border-radius: 9px; font-size: 1.2rem; overflow: hidden; }
.mt-line { display: flex; align-items: center; gap: .4rem; }
.mt-qty { font-variant-numeric: tabular-nums; white-space: nowrap; }
.mt-note { width: 100%; font-size: .85rem; padding: .3rem .55rem; }
.mt-reason { display: flex; gap: .3rem; align-items: center; margin: 0; font-size: .82rem; color: var(--danger); }
.mt-submit { width: 100%; margin-top: .25rem; }
.badge.mt-ls { font-size: .7rem; } .badge.mt-ls.approved, .badge.mt-ls.locked { background: var(--ok-bg); }
.badge.mt-ls.pending { background: var(--warn-bg); } .badge.mt-ls.rejected { background: var(--bad-bg); color: var(--danger); }
.mt-wl.rejected .mt-name b { color: var(--danger); }
.mt-fab { display: none; }
.mt-count { display: inline-grid; place-items: center; min-width: 1.2rem; height: 1.2rem; padding: 0 .3rem; margin-left: .2rem; border-radius: 999px; background: var(--danger); color: #fff; font-size: .7rem; font-weight: 700; }
.mt-empty { text-align: center; display: grid; gap: .5rem; justify-items: center; margin-top: 2rem; }
.mt-empty > p:first-child { font-size: 2.5rem; margin: 0; }
.badge.mt-st.open { background: var(--ok-bg); } .badge.mt-st.closed { background: var(--warn-bg); } .badge.mt-st.ordered { background: var(--ip-bg); }
/* the lead's tables */
.mt-lead .row { margin: 0; }
.mt-sug { display: grid; gap: .25rem; }
.mt-sug:empty { display: none; }
.mt-sug .mt-row { width: 100%; }
.mt-paste { display: flex; gap: .7rem; align-items: center; padding: .7rem; border: 1px dashed var(--line); border-radius: 12px; }
.mt-paste img { width: 56px; height: 56px; object-fit: cover; border-radius: 8px; }
.mt-paste [hidden] { display: none; }
.mt-paste small { display: block; }
.mt-file { flex: none; margin: 0; cursor: pointer; padding: .4rem .8rem; border-radius: 999px; }
.mt-file input { position: absolute; width: 1px; height: 1px; opacity: 0; }
.mt-file:focus-within { outline: 2px solid currentColor; outline-offset: 2px; }
/* Approvals: a stack of teachers' folders. Each tab flares into its sheet with a concave curve on both sides. */
.mt-stack { --tab-h: 2.3rem; --tab-r: 14px; --step: 1.5rem; margin-top: .9rem; }
.mt-behind { display: grid; max-height: max(40vh, 14rem); overflow: hidden auto; padding-top: 4px; margin-bottom: calc(var(--tab-h) * -1); scrollbar-width: thin; }
.mt-tab { position: relative; display: inline-flex; vertical-align: top; align-items: center; gap: .5rem; height: var(--tab-h); max-width: min(70%, 22rem); margin: 0; margin-left: calc(var(--tab-r) + var(--i) * var(--step) * 3); padding: 0 1.05rem; border-radius: var(--tab-r) var(--tab-r) 0 0; background: var(--f); color: var(--text); font: 600 .95rem var(--display); white-space: nowrap; overflow: visible; }
.mt-tab small { font: 600 .75rem/1.5 inherit; min-width: 1.4em; padding: 0 .4em; border-radius: 999px; background: var(--bg); color: var(--muted); text-align: center; font-variant-numeric: tabular-nums; }
.mt-tab::before, .mt-tab::after { content: ''; position: absolute; bottom: 0; width: var(--tab-r); height: var(--tab-r); }
.mt-tab::before { right: 100%; background: radial-gradient(circle at 0 0, transparent calc(var(--tab-r) - .5px), var(--f) var(--tab-r)); }
.mt-tab::after { left: 100%; background: radial-gradient(circle at 100% 0, transparent calc(var(--tab-r) - .5px), var(--f) var(--tab-r)); }
.mt-tab:focus { outline: none; }
.mt-peek { --f: var(--fill); position: relative; display: flex; align-items: flex-start; justify-content: flex-start; width: 100%; height: calc(var(--tab-h) * 2 + .3rem); margin: 0 0 calc(var(--tab-h) * -1); padding: 0; border: 0; border-radius: 0; background: none; box-shadow: none; text-align: left; cursor: pointer; filter: drop-shadow(0 -1px 2px light-dark(rgb(40 36 20 / .14), rgb(0 0 0 / .4))); transition: transform .18s var(--ease); }
.mt-peek:last-child { margin-bottom: 0; }
.mt-peek::after { content: ''; position: absolute; inset: var(--tab-h) 0 0; border-radius: 16px 16px 0 0; background: var(--f); }
.mt-peek .mt-tab { z-index: 1; vertical-align: top; }
.mt-peek:hover { --f: var(--hover); background: none; transform: translateY(-2px); }
.mt-peek:focus-visible .mt-tab { outline: 2px solid var(--accent); outline-offset: -2px; }
.mt-folder { --f: var(--card); position: relative; z-index: 1; filter: drop-shadow(0 -2px 5px light-dark(rgb(40 36 20 / .09), rgb(0 0 0 / .35))); }
.mt-sheet { padding: .35rem 1.1rem 1.1rem; border-radius: 16px; background: var(--f); }
.mt-sheet-head { justify-content: flex-end; margin: .35rem 0 0; }
.mt-sheet .mt-sub { display: flex; align-items: center; gap: .5rem; margin: 1.3rem 0 .15rem; padding-top: 1rem; border-top: 1px solid var(--line); }
.mt-sheet .mt-sub:first-child { margin-top: .5rem; padding-top: 0; border-top: 0; }
.mt-reqs { list-style: none; margin: 0; padding: 0; max-height: none; }
.mt-req { display: grid; grid-template-columns: auto minmax(10rem, 1fr) auto auto; gap: .8rem; align-items: center; padding: .7rem 0; border-top: 1px solid var(--line); }
.mt-reqs > .mt-req:first-child { border-top: 0; }
.mt-req .mt-name small { display: block; margin-top: .15rem; }
.mt-req .mt-qty { font-variant-numeric: tabular-nums; white-space: nowrap; }
.mt-req .mt-acts { justify-content: flex-end; }
@media (max-width: 640px) {
  .mt-stack { --step: .5rem; }
  .mt-req { grid-template-columns: auto 1fr auto; }
  .mt-req .mt-acts { grid-column: 1 / -1; justify-content: flex-start; }
}
.mt-h2 { margin-top: 1.5rem; display: flex; gap: .5rem; align-items: center; }
.mt-cell { display: inline-flex; align-items: center; gap: .5rem; }
.mt-acts { display: flex; flex-wrap: wrap; gap: .35rem; align-items: center; }
.mt-acts button { padding: .3rem .8rem; }
.mt-table td.mt-notes { white-space: normal; min-width: 12rem; max-width: 26rem; font-size: .85rem; }
.mt-table td.mt-notes small { display: block; }
.mt-table input:not([type='checkbox']):not(.num), .mt-table select { width: 100%; min-width: 9rem; }
.mt-table input.mt-unit { min-width: 6rem; }
.mt-table tr.off td { opacity: .5; }
.mt-photo { position: relative; display: inline-block; cursor: pointer; }
.mt-photo input { position: absolute; inset: 0; opacity: 0; cursor: pointer; width: 100%; }
.mt-photo:hover .mt-thumb, .mt-photo:focus-within .mt-thumb { box-shadow: 0 0 0 2px var(--accent); }
.mt-form { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: .75rem; }
.mt-people { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 1rem; align-items: start; }
.card.mt-person { margin: 0; max-width: none; padding: 1rem 1.25rem; }
.mt-person.done { opacity: .65; }
.mt-person header h2 { margin: 0; }
.mt-person .mt-lines > li { display: flex; align-items: center; gap: .5rem; }
.card label.mt-give { flex: 1; display: flex; align-items: center; gap: .6rem; cursor: pointer; }
.mt-give input { width: 1.15rem; height: 1.15rem; flex: none; }
.mt-give:has(input:checked) b { text-decoration: line-through; color: var(--muted); }
@media (max-width: 960px) {
  .mt-shop { grid-template-columns: minmax(0, 1fr); } .card.mt-cart { position: static; max-height: none; scroll-margin-top: 1rem; }
  .mt-fab { display: inline-flex; align-items: center; gap: .4rem; position: fixed; right: 16px; bottom: 16px; z-index: 5; padding: .65rem 1.1rem; border-radius: 999px;
    background: var(--btn); color: #fff; font-weight: 600; box-shadow: 0 6px 20px rgb(0 0 0 / .25); text-decoration: none; }
}
@media (max-width: 640px) { .mt-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .5rem; } .mt-pic { font-size: 2.4rem; } }
@media print { .mt-lead, .tabrow, .page-head label, button.ghost, .mt-fab { display: none; } .mt-people { display: block; } .card.mt-person { break-inside: avoid; box-shadow: none; border: 1px solid #ccc; margin-bottom: .5rem; } }
.mt-table td.mt-pair { min-width: 10rem; } .mt-table td.mt-pair input { display: block; } .mt-table td.mt-pair input + input { margin-top: .25rem; }
/* quiet cards: photo, name, a count. Options open the panel; a single item adds from its + */
.mt-card { gap: .5rem; transform-origin: top center; transition: transform 320ms cubic-bezier(.16, 1, .3, 1), box-shadow 320ms cubic-bezier(.16, 1, .3, 1); }
@media (hover: hover) and (prefers-reduced-motion: no-preference) { .mt-card:hover { transform: perspective(900px) rotateX(5deg); box-shadow: var(--pad-shadow); } .mt-card.in:hover { box-shadow: 0 0 0 2px var(--accent), var(--pad-shadow); } }
.mt-pic-wrap { position: relative; display: block; }
.mt-pic-wrap > .mt-pic { display: grid; }
button.mt-open { display: flex; flex-direction: column; gap: .5rem; width: 100%; padding: 0; border: 0; border-radius: 12px; background: none; color: inherit; font-weight: inherit; text-align: left; }
button.mt-open:hover:not(:disabled) { background: none; }
button.mt-open:active:not(:disabled) { transform: none; }
.mt-open:focus-visible, .mt-row:focus-visible, button.mt-add:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.mt-badge { position: absolute; top: .4rem; right: .4rem; display: grid; place-items: center; min-width: 1.5rem; height: 1.5rem; padding: 0 .35rem; border-radius: 999px; background: var(--btn); color: #fff; font-size: .75rem; font-weight: 700; font-variant-numeric: tabular-nums; }
button.mt-add { position: absolute; right: .4rem; bottom: .4rem; display: grid; place-items: center; width: 2.25rem; height: 2.25rem; padding: 0; border-radius: 50%; background: var(--card); color: var(--accent); box-shadow: var(--shadow); }
button.mt-add:hover:not(:disabled) { background: var(--btn); color: #fff; }
.mt-card .mt-tag { font-size: .7rem; }
/* the options panel: paper from the same pad, with the app's menu shadow; a bottom sheet on touch */
.mt-panel { position: fixed; z-index: 60; width: 320px; max-width: calc(100vw - 16px); max-height: min(72vh, 540px); overflow: auto; overscroll-behavior: contain; padding: .9rem 1rem 1rem; border-radius: 14px; background: var(--card); box-shadow: var(--shadow), 0 16px 40px rgb(0 0 0 / .18); transform-origin: top center; }
.mt-panel-head { display: flex; align-items: center; gap: .6rem; }
.mt-panel-head h2 { margin: 0; font-size: 1.1rem; }
.mt-panel-head .mt-name small:empty { display: none; }
.mt-thumb.big { width: 3.25rem; height: 3.25rem; }
.mt-panel .hint { margin: .35rem 0 .5rem; font-size: .82rem; }
.mt-rows { list-style: none; margin: 0; padding: 0; }
.mt-rows > li { border-top: 1px solid var(--line); }
.mt-row { display: flex; align-items: center; gap: .6rem; width: 100%; min-height: 3.1rem; padding: .35rem .3rem; border-radius: 8px; background: none; color: inherit; font-weight: inherit; text-align: left; }
button.mt-row:hover:not(:disabled) { background: var(--hover); }
button.mt-row:active:not(:disabled) { transform: none; }
.mt-row .mt-name small { display: flex; flex-wrap: wrap; align-items: center; gap: .1rem .3rem; }
.mt-plus { flex: none; display: grid; place-items: center; width: 1.9rem; height: 1.9rem; border-radius: 50%; background: var(--sprout); color: var(--accent); }
button.mt-row:hover:not(:disabled) .mt-plus { background: var(--btn); color: #fff; }
.mt-scrim { position: fixed; inset: 0; z-index: 59; background: rgb(0 0 0 / .4); }
.mt-panel.sheet { left: 0; right: 0; bottom: 0; width: 100%; max-width: none; max-height: 80vh; border-radius: 16px 16px 0 0; padding-bottom: calc(1rem + env(safe-area-inset-bottom)); box-shadow: 0 -8px 30px rgb(0 0 0 / .22); }
.mt-grab { display: block; width: 2.5rem; height: 4px; margin: 0 auto .6rem; border-radius: 999px; background: var(--track); }
.mt-panel.sheet .mt-row { min-height: 3.5rem; }
.mt-panel.sheet .mt-step button.icon, .mt-panel.sheet .mt-plus { width: 2.5rem; height: 2.5rem; }
@media (pointer: coarse) { button.mt-add { width: 2.75rem; height: 2.75rem; } }

/* ---------- Observations: big targets for a thumb, the running total stays in reach at the bottom ---------- */
.ob-back { display: inline-flex; align-items: center; gap: .3rem; margin: 0 0 .6rem; padding-left: 0; }
.ob-panel { margin-bottom: 1rem; }
.ob-list { list-style: none; margin: 0; padding: 0; }
.ob-row { display: flex; align-items: center; gap: .8rem; width: 100%; min-height: 3.4rem; padding: .6rem 1.25rem; background: none; border: 0; border-top: 1px solid var(--line); border-radius: 0; text-align: left; color: inherit; }
.ob-list li:first-child .ob-row { border-top: 0; }
.ob-row:hover:not(:disabled) { background: var(--fill); }
.ob-who { display: grid; gap: .1rem; flex: 1; min-width: 0; }
.ob-result { font: 600 .93rem var(--display); white-space: nowrap; font-variant-numeric: tabular-nums; }
.ob-st.shared { background: var(--ok-bg); } .ob-st.draft { background: var(--warn-bg); }
.ob-tabs { display: flex; width: fit-content; }
.ob-tabs button { min-height: 2.75rem; padding: .3rem .8rem; display: inline-flex; align-items: center; gap: .35rem; }
.ob-tabs small { color: var(--muted); font-variant-numeric: tabular-nums; }
.ob-items { list-style: none; margin: 0; padding: 0; }
.ob-item { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: .5rem 1rem; align-items: center; padding: .8rem 1.25rem; border-top: 1px solid var(--line); }
.ob-items li:first-child { border-top: 0; }
.ob-text { line-height: 1.4; }
.ob-score { display: flex; gap: .3rem; }
.ob-score button { width: 3rem; height: 3rem; padding: 0; border-radius: 10px; font-weight: 600; font-variant-numeric: tabular-nums; background: var(--fill); border: 0; color: var(--text); }
.ob-score button[data-v="na"] { width: 3.2rem; font-size: .8rem; font-weight: 500; }
.ob-score button.on, .ob-score button.on:hover:not(:disabled) { background: var(--accent); color: var(--accent-text); }
.ob-note { grid-column: 1 / -1; font-size: .85rem; color: var(--muted); }
.ob-note summary { cursor: pointer; width: fit-content; padding: .2rem 0; }
.ob-note textarea { width: 100%; margin-top: .3rem; font-size: 1rem; }
.ob-next { padding: .8rem 1.25rem 1rem; margin: 0; }
.ob-next button { display: inline-flex; align-items: center; gap: .3rem; min-height: 2.75rem; }
.ob-feedback { padding: 1.25rem; display: grid; gap: 1rem; }
.ob-feedback label, .ob-ack label { display: grid; gap: .3rem; font-weight: 600; font-size: .85rem; }
.ob-feedback textarea, .ob-ack textarea { width: 100%; font-size: 1rem; font-weight: 400; }
.ob-actions { margin: 0; } .ob-actions button { min-height: 2.75rem; }
.ob-bar { position: sticky; bottom: 0; z-index: 5; display: flex; align-items: center; gap: .7rem; flex-wrap: wrap; padding: .6rem 1rem calc(.6rem + env(safe-area-inset-bottom)); border-radius: 12px 12px 0 0; background: var(--card); box-shadow: 0 -1px 0 var(--line), 0 -6px 18px rgb(0 0 0 / .06); }
.ob-bar #ob-tally { display: inline-flex; align-items: baseline; gap: .7rem; }
.ob-total { font-family: var(--display); font-variant-numeric: tabular-nums; } .ob-total b { font-size: 1.15rem; }
.ob-save { color: var(--muted); } .ob-save[data-state="offline"] { color: var(--danger); }
.ob-when { margin: 0; } .ob-when label { flex: 1 1 8rem; }
.ob-summary { padding: 1.25rem; display: flex; flex-wrap: wrap; gap: 1rem 2.5rem; align-items: center; }
.ob-big { font-family: var(--display); display: flex; align-items: baseline; gap: .4rem; font-variant-numeric: tabular-nums; }
.ob-big b { font-size: 3rem; line-height: 1; } .ob-big span { font-size: 1.15rem; color: var(--muted); } .ob-big small { font-size: 1.15rem; margin-left: .5rem; color: var(--accent); }
.ob-secs { list-style: none; margin: 0; padding: 0; flex: 1 1 16rem; display: grid; gap: .35rem; }
.ob-secs li { display: flex; justify-content: space-between; gap: 1rem; } .ob-secs b { font-variant-numeric: tabular-nums; white-space: nowrap; }
.ob-para { padding: .2rem 1.25rem .8rem; } .ob-para h3 { margin: 0 0 .25rem; font-size: .85rem; color: var(--muted); font-weight: 600; } .ob-para p { margin: 0; white-space: pre-wrap; overflow-wrap: anywhere; }
.ob-chip { display: grid; place-items: center; width: 2.25rem; height: 2.25rem; border-radius: 9px; background: var(--fill); font-weight: 600; font-variant-numeric: tabular-nums; } .ob-chip.na { font-size: .75rem; font-weight: 500; color: var(--muted); }
.ob-itemnote { margin: .3rem 0 0; color: var(--muted); font-size: .85rem; white-space: pre-wrap; overflow-wrap: anywhere; }
.ob-ack { padding: 1.25rem; display: grid; gap: .8rem; } .ob-ack > p { margin: 0; display: flex; gap: .4rem; align-items: center; } .ob-ack .ob-para { padding: 0; } .ob-ack .row { margin: 0; } .ob-ack button { min-height: 2.75rem; }
.ob-wait { text-align: center; }
.nav-dot { display: inline-block; width: 7px; height: 7px; margin-left: .35rem; border-radius: 50%; background: var(--danger); vertical-align: middle; }
@media (max-width: 720px) {
  .ob-item:not(.read *) { grid-template-columns: minmax(0, 1fr); }
  .ob-score { width: 100%; } .ob-score button, .ob-score button[data-v="na"] { flex: 1; width: auto; }
  .read .ob-item { grid-template-columns: minmax(0, 1fr) auto; }
  .ob-row { flex-wrap: wrap; } .ob-who { flex-basis: 100%; }
}

/* Lesson plans: a week is a small square, read like a calendar row (green = in on time, amber edge = late, red = missing) */
.pl-page { display: grid; gap: 1.5rem; }
.pl-panel { overflow: hidden; }
.pl-panel > header { justify-content: space-between; }
.pl-body:has(> .pl-filters) { padding-top: 1rem; }
.pl-filters { padding: 0 1.25rem; align-items: stretch; } /* the switch and the dropdown share one height and text size */
.pl-filters .tabs { margin-bottom: 0; }
.pl-filters select { flex: 0 1 12rem; font-size: .85rem; padding-block: 0; border-radius: 9px; min-height: 2.15rem; }
.pl-why { display: inline-flex; align-items: center; gap: .45rem; font-size: .8rem; color: var(--muted); white-space: nowrap; }
.pl-why::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: #d4a017; } /* gold: rename or move the file */
.pl-why.notplan::before { background: var(--danger); } /* red: a week with no plan */
.pl-why.subject::before { background: var(--track); } /* grey: nobody teaches it yet, nothing to fix */
.pl-hint { margin: 0; padding: .75rem 1.25rem; font-size: .8rem; }
.pl-list { list-style: none; margin: 0; padding: 0; font-size: .85rem; }
.pl-list small { display: block; }
.pl-list li { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .25rem 1rem; padding: .6rem 1.25rem; border-top: 1px solid var(--line); overflow-wrap: anywhere; }
.pl-setup { display: grid; gap: 1.5rem; padding: 1.25rem 0; }
.pl-setup h3, .pl-setup p, .pl-setup > section > button { margin: 0 1.25rem .6rem; }
.pl-setup .pl-list { margin-bottom: .75rem; }

.pl-score { display: grid; justify-items: end; gap: .1rem; }
.pl-score b { font: 700 2.6rem/1 var(--display); letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.pl-score span { font-size: .82rem; color: var(--muted); font-variant-numeric: tabular-nums; }
.pl-score.ok b, .pl-pct.ok { color: var(--ok); } .pl-score.low b, .pl-pct.low { color: var(--danger); }

.pl-mine { display: grid; grid-template-columns: minmax(0, 1fr) 19rem; grid-template-areas: "weeks next"; gap: 1.5rem; align-items: start; }
.pl-mine > .pl-weeks { grid-area: weeks; } .pl-mine > .pl-next { grid-area: next; }
.pl-person { display: flex; flex-wrap: wrap; align-items: end; justify-content: space-between; gap: .75rem 2rem; padding: 1.1rem 1.25rem .4rem; }
.pl-person h3 { margin: 0; font: 700 1.35rem/1.25 var(--display); }
.pl-person-scores { display: flex; gap: 2.25rem; }
.pl-person-scores > div { display: grid; justify-items: end; }
.pl-person-scores > div > small { font: 500 .78rem var(--display); color: var(--muted); }
.pl-person-scores .pl-score b { font-size: 2rem; } .pl-person-scores .pl-score.ok b { color: var(--text); }
.pl-one { padding: .75rem 1.25rem 1.25rem; }
.pl-one .pl-weeks .pl-legend { padding: 0 0 .25rem; }
.pl-next h2 { margin: .1rem 0 .85rem; font: 600 1.15rem var(--display); }
/* the next deadlines: torn calendar pages stacked down the side */
.pl-pads { list-style: none; margin: 0; padding: .3rem 0 0; display: grid; gap: .85rem; }
.pl-pad { display: grid; grid-template-columns: 3rem minmax(0, 1fr); gap: .1rem .9rem; align-items: start; padding: .95rem 1rem .8rem; }
.pl-cal { display: grid; justify-items: center; align-content: start; font-variant-numeric: tabular-nums; }
.pl-cal span { font: 500 .75rem/1.3 var(--display); color: var(--muted); }
.pl-cal span:first-child { font-weight: 600; }
.pl-cal b { font: 800 2.3rem/.95 var(--display); letter-spacing: -.03em; }
.pl-pad .pl-what { display: grid; align-content: start; min-width: 0; }
.pl-what b { font: 700 1.15rem/1.2 var(--display); letter-spacing: -.01em; }
.pl-what span:not(.pl-when) { font-weight: 600; font-size: .88rem; overflow-wrap: anywhere; }
.pl-what small { font-size: .78rem; }
.pl-when { font: 600 .78rem var(--display); color: var(--muted); font-variant-numeric: tabular-nums; }
.pl-pad.late { background: color-mix(in srgb, var(--danger) 6%, var(--card)); }
.pl-pad.late .pl-cal span:first-child, .pl-pad.late .pl-cal b, .pl-pad.late .pl-when, .pl-pad.soon .pl-when, .pl-pad.soon .pl-cal span:first-child { color: var(--danger); }
.pl-open { display: inline-flex; align-items: center; gap: .2rem; justify-self: start; margin-top: .35rem; font-size: .82rem; text-decoration: none; }
.pl-clear { display: flex; align-items: center; gap: .5rem; margin: 0; padding: 1rem 1.25rem; border-radius: 14px; background: var(--card); box-shadow: var(--shadow); color: var(--muted); }
.pl-clear .i { color: var(--accent); }

/* the term sheet: weeks across, a row per class, the red line = deadlines up to here have passed */
.pl-term { overflow-x: auto; padding: 0 0 .4rem; }
.pl-tr { display: grid; grid-template-columns: minmax(8.5rem, 12rem) repeat(var(--weeks), minmax(1.3rem, 1fr)) 3.2rem; align-items: center; gap: 3px;
  min-width: calc(8.5rem + var(--weeks) * 1.5rem + 4rem); padding: .55rem 1.1rem; border-top: 1px solid color-mix(in srgb, var(--line) 55%, transparent); }
.pl-tr:not(.pl-thead):hover, .pl-tr:not(.pl-thead):hover > .pl-who { background: var(--hover); }
.pl-thead { border-top: 0; padding-block: .6rem .2rem; align-items: end; }
.pl-who { display: grid; min-width: 0; padding-right: .75rem; font-size: .9rem; }
.pl-who b { font-weight: 600; overflow-wrap: anywhere; } .pl-who small { font-size: .78rem; font-variant-numeric: tabular-nums; }
.pl-thead .pl-who small { font-size: .72rem; color: var(--muted); }
.pl-tr > .pl-who { position: sticky; left: 0; z-index: 1; align-self: stretch; align-content: center; background: var(--card); }
.pl-h { position: relative; display: grid; justify-items: center; line-height: 1.1; font-variant-numeric: tabular-nums; color: var(--muted); }
.pl-h b { font: 500 .8rem var(--display); }
.pl-h small { font-size: .64rem; }
.pl-h.now { color: var(--accent); } .pl-h.now b { font-weight: 700; }
.pl-pct { justify-self: end; font: 600 1.05rem var(--display); font-variant-numeric: tabular-nums; }
.pl-pct small { margin-left: 1px; font-size: .68em; font-weight: 500; color: var(--muted); }
.pl-tr .pl-pct.ok { color: var(--text); } .pl-tr .pl-pct.mid { color: var(--muted); }
/* one ribbon per class: a thin track; weeks in the same state join into one run, missing is a hollow red outline, this week stands a little taller */
.wk { --done: color-mix(in oklab, var(--ok), var(--accent)); position: relative; display: block; height: 1.5rem; border-radius: 4px; text-decoration: none; }
.wk::after { content: ''; position: absolute; inset: calc(50% - 4px) 0; border-radius: 2px; background: var(--track); transition: inset .2s var(--ease); }
.wk:not(.re)::after { right: -3px; }
.wk.rs::after { border-top-left-radius: 4px; border-bottom-left-radius: 4px; } .wk.re::after { border-top-right-radius: 4px; border-bottom-right-radius: 4px; }
.wk.ontime::after { background: var(--done); }
.wk.late::after { background: #d4a017; }
.wk.missing::after { background: var(--bad-bg); box-shadow: inset 0 0 0 1.5px var(--danger); }
.wk.missing::after { right: 0; border-radius: 3px; } /* each missing week its own outline, so they can be counted */
.wk.off::after { opacity: .4; }
.wk.now::after { inset-block: calc(50% - 7px); }
a.wk:hover::after { inset-block: calc(50% - 8px); }
a.wk:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.pl-tr .edge::before { content: ''; position: absolute; left: -2.5px; top: -.6rem; bottom: -.6rem; border-left: 1.5px solid color-mix(in srgb, var(--danger) 55%, transparent); pointer-events: none; }
.pl-thead .edge::before { top: 0; bottom: -.3rem; }
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.pl-edge-key { display: inline-block; width: 0; height: .9rem; border-left: 1.5px solid color-mix(in srgb, var(--danger) 55%, transparent); }
.pl-prog { margin-top: 1.25rem; }
.pl-prog h3 { display: flex; align-items: baseline; gap: .6rem; margin: 0 1.25rem; font: 600 1.05rem var(--display); }
.pl-prog-name { font: 700 1.15rem var(--display); }
.pl-prog h3 .pl-pct { font-size: 1.35rem; }
.pl-prog h3 small { font: 400 .82rem var(--body); }
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .pl-pad:hover { transform: perspective(900px) rotateX(5deg); box-shadow: 0 2px 0 var(--pad-under), 0 16px 30px light-dark(rgb(40 36 20 / .13), rgb(0 0 0 / .6)); }
}
.pl-legend { display: flex; flex-wrap: wrap; gap: .3rem 1rem; margin: 0; padding: 0 1.25rem .5rem; font-size: .78rem; }
.pl-panel > header .pl-legend { padding: 0; }
.pl-legend span { display: inline-flex; align-items: center; gap: .4rem; } .pl-legend .wk { width: 1.4rem; height: 1rem; }
.pl-charts { padding: 0 1.25rem 1.25rem; margin: 1rem 0 0; }
.dash.charts.pl-charts { grid-template-columns: repeat(auto-fit, minmax(min(100%, max(440px, calc(50% - .5rem))), 1fr)); } /* never more than 2 across: no empty third track on wide screens */
.pl-charts .viz { box-shadow: none; background: var(--card); outline: 1px solid color-mix(in srgb, var(--line) 70%, transparent); }
.viz.wide { grid-column: 1 / -1; }
.viz .bar.ok, .viz .cell.ok { fill: color-mix(in srgb, var(--ok) 78%, var(--card)); } .viz .bar.mid, .viz .cell.mid { fill: var(--mid); } .viz .bar.low, .viz .cell.low { fill: color-mix(in srgb, var(--danger) 72%, var(--card)); }
.pl-score.mid b, .pl-pct.mid, .pl-tr .pl-pct.mid { color: var(--mid-text); }
.viz .grid { stroke: var(--line); stroke-width: 1; }
.viz .v-val.on { fill: #fff; } .viz .cell.mid + .v-val.on { fill: #2b2205; }
@media (max-width: 1100px) {
  .pl-mine { grid-template-columns: minmax(0, 1fr); grid-template-areas: "next" "weeks"; }
  .pl-pads { grid-template-columns: repeat(auto-fill, minmax(min(100%, 16rem), 1fr)); }
}
@media (max-width: 640px) {
  .pl-pads { grid-template-columns: minmax(0, 1fr); gap: .75rem; }
  .pl-score, .pl-person-scores > div { justify-items: start; }
  .pl-tr { grid-template-columns: 8.5rem repeat(var(--weeks), 1.5rem) 3.2rem; min-width: 0; width: max-content; padding-inline: .9rem; }
}
}
@media (prefers-reduced-motion: reduce) { .wk::after { transition: none; } }
