/* Core16 advisor portal. Palette and table styling carried over from the
   advisor-board mockup (web/board-x7k2/). The typefaces are served from this
   origin (static/fonts/, each under the SIL Open Font License beside it),
   never from Google Fonts: a page showing minors' records shouldn't make
   third-party requests, and the CSP wouldn't allow one. Latin subset,
   variable weight; the system face shows until a file arrives. */
@font-face {
  font-family: "Bricolage Grotesque"; font-style: normal; font-weight: 500 700; font-display: swap;
  src: url("/portal/static/fonts/bricolage-grotesque.woff2") format("woff2");
}
@font-face {
  font-family: "Hanken Grotesk"; font-style: normal; font-weight: 400 700; font-display: swap;
  src: url("/portal/static/fonts/hanken-grotesk.woff2") format("woff2");
}
@font-face {
  font-family: "Geist Mono"; font-style: normal; font-weight: 400 500; font-display: swap;
  src: url("/portal/static/fonts/geist-mono.woff2") format("woff2");
}
:root {
  --ink: #0E2340;
  --ink2: #3C5573;
  --ink3: #6E829B;
  --ice: #E6ECF3;
  --ice2: #F2F6FA;
  --surface: #FFFFFF;
  --rule: #CCDAE8;
  --rule2: #A6BED6;
  --blue: #0B4C86;
  --alarm: #A8261C;
  --alarmbg: #FAEAE8;
  --warn: #8A5A00;
  --warnbg: #FBF1DC;
  --ok: #1B6140;
  --okbg: #E4EFE9;
  --okrule: #A9CBB9;
  --alarmrule: #E0B3AE;
  --warnrule: #E3CB95;
  --warnstripe: #C99A2E;
  /* The team page's week-of-work bar, green to red (6 Nov 2026). */
  --loadlow: #2E9E5B;
  --loadmid: #E0A526;
  --loadhigh: #D2392B;
  --infobg: #E8F0F5;
  --inforule: #A9C4D4;
  --replybg: #DAEAF7;
  /* Hockey on a parent's calendar. A warm orange, opposite --blue for
     school: dark green and then violet both sat too close to the navy to
     tell apart on a thin stripe (28 Sep 2026). */
  --hockey: #A94A0C;
  --hockeybg: #FDEBDD;
  --onink: #FFFFFF;
  --onalarm: #FFFFFF;
  --backdrop: rgba(16, 32, 52, .45);
  --hero: #0E2340;
  --onhero: #FFFFFF;
  --onhero2: #C4D4E6;
  --herorule: #5F7C9C;
  --tourdim: rgba(6, 16, 30, .55);
  --sans: "Hanken Grotesk", system-ui, -apple-system, "Segoe UI", sans-serif;
  --mono: "Geist Mono", ui-monospace, "SF Mono", Menlo, monospace;
  /* Headings and big figures. */
  --display: "Bricolage Grotesque", system-ui, -apple-system, "Segoe UI", sans-serif;
  --radius: 16px;
  --radius-s: 10px;
  color-scheme: light;
}
/* Dark mode. Follows the device unless someone picks Light or Dark in the top
   bar, which theme.js applies as data-theme before the page paints. The token
   list is repeated because CSS can't share one block between a media query
   and an attribute selector. */
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) {
  --ink: #E3EBF4;
  --ink2: #AFC0D3;
  --ink3: #8497AE;
  --ice: #0A1420;
  --ice2: #16263A;
  --surface: #0F1C2C;
  --rule: #22344A;
  --rule2: #36506B;
  --blue: #7DB2E3;
  --alarm: #F0897E;
  --alarmbg: #351B1A;
  --warn: #E2B25E;
  --warnbg: #2F2513;
  --ok: #6FC79B;
  --okbg: #122C20;
  --okrule: #2D5E45;
  --alarmrule: #6B312B;
  --warnrule: #65501F;
  --warnstripe: #C99A2E;
  --loadlow: #4CC283;
  --loadmid: #E8B04A;
  --loadhigh: #EE5A4C;
  --infobg: #132A3D;
  --inforule: #2E5573;
  --replybg: #1B3A57;
  --hockey: #F29A5C;
  --hockeybg: #36210F;
  --onink: #0A1420;
  --onalarm: #1E0A08;
  --backdrop: rgba(0, 0, 0, .6);
  --hero: #16263A;
  --onhero: #E3EBF4;
  --onhero2: #AFC0D3;
  --herorule: #4A6585;
  --tourdim: rgba(0, 0, 0, .68);
  color-scheme: dark;
}
}
:root[data-theme="dark"] {
  --ink: #E3EBF4;
  --ink2: #AFC0D3;
  --ink3: #8497AE;
  --ice: #0A1420;
  --ice2: #16263A;
  --surface: #0F1C2C;
  --rule: #22344A;
  --rule2: #36506B;
  --blue: #7DB2E3;
  --alarm: #F0897E;
  --alarmbg: #351B1A;
  --warn: #E2B25E;
  --warnbg: #2F2513;
  --ok: #6FC79B;
  --okbg: #122C20;
  --okrule: #2D5E45;
  --alarmrule: #6B312B;
  --warnrule: #65501F;
  --warnstripe: #C99A2E;
  --loadlow: #4CC283;
  --loadmid: #E8B04A;
  --loadhigh: #EE5A4C;
  --infobg: #132A3D;
  --inforule: #2E5573;
  --replybg: #1B3A57;
  --hockey: #F29A5C;
  --hockeybg: #36210F;
  --onink: #0A1420;
  --onalarm: #1E0A08;
  --backdrop: rgba(0, 0, 0, .6);
  --hero: #16263A;
  --onhero: #E3EBF4;
  --onhero2: #AFC0D3;
  --herorule: #4A6585;
  --tourdim: rgba(0, 0, 0, .68);
  color-scheme: dark;
}
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  background: var(--ice);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 14px;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
}
.wrap { max-width: 1280px; margin: 0 auto; padding: 0 16px 72px; }
a:focus-visible, button:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }

/* top bar */
.topbar { border-bottom: 1px solid var(--rule2); background: var(--surface); }
.topbar-in {
  max-width: 1280px; margin: 0 auto; padding: 8px 16px;
  display: flex; align-items: center; gap: 8px 24px; min-height: 54px; flex-wrap: wrap;
}
.brand { display: flex; align-items: center; gap: 9px; font-weight: 700; font-size: 15px; }
.brand svg { width: 24px; height: 24px; color: var(--ink); flex: none; }
.brand span { color: var(--ink3); font-weight: 400; }
nav { display: flex; gap: 2px; }
nav a {
  color: var(--ink2); font-weight: 500; text-decoration: none;
  padding: 8px 12px; border-bottom: 2px solid transparent;
}
nav a:hover { color: var(--ink); }
nav a[aria-current="page"] { color: var(--ink); border-bottom-color: var(--blue); }
nav .badge {
  display: inline-block; min-width: 20px; height: 20px; padding: 0 6px; margin-left: 4px;
  border-radius: 10px; background: var(--alarm); color: var(--onalarm);
  font-size: 12px; font-weight: 600; line-height: 20px; text-align: center;
  font-variant-numeric: tabular-nums; vertical-align: 1px;
}
.me { margin-left: auto; display: flex; align-items: center; gap: 12px; color: var(--ink2); font-size: 13px; }
.me form { margin: 0; }
.linkbtn { font: inherit; color: var(--blue); background: none; border: none; padding: 0; cursor: pointer; }

/* sign-in and enrollment */
.card {
  max-width: 440px; margin: 48px auto 0; padding: 24px;
  background: var(--surface); border: 1px solid var(--rule);
}
.card h1 { margin: 0 0 10px; font-size: 20px; font-weight: 600; }
.card p { margin: 0 0 14px; color: var(--ink2); }
.primary {
  font: inherit; font-weight: 600; color: var(--onink); background: var(--ink);
  border: none; border-radius: var(--radius-s); padding: 10px 16px; cursor: pointer;
}
.primary:disabled { opacity: .6; cursor: default; }
.status { min-height: 1.45em; margin: 12px 0 0; }
.status.error { color: var(--alarm); }
.notice { padding: 9px 12px; background: var(--ice2); border: 1px solid var(--rule); color: var(--ink); }
.fineprint { max-width: 440px; margin: 12px auto 0; color: var(--ink3); font-size: 12px; }

/* How a student gets a sign-in code: the phone's own screens in order. Four
   across on a laptop, where the page is read beside the phone in their hand. */
.code-steps { max-width: 1040px; margin: 40px auto 0; scroll-margin-top: 16px; }
.card p a, .code-steps a { color: var(--blue); }
.code-steps h2 { font-size: 18px; margin-bottom: 14px; }
.code-steps ol {
  list-style: none; counter-reset: step; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 24px;
}
.code-steps li { counter-increment: step; }
.code-steps h3 { display: flex; align-items: center; gap: 8px; margin: 0 0 10px; font-size: 15px; font-weight: 600; }
.code-steps h3::before {
  content: counter(step); flex: none; width: 24px; height: 24px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--ink); color: var(--onink); font-size: 13px;
}
.code-steps img {
  display: block; width: 100%; max-width: 280px; height: auto;
  border: 1px solid var(--rule2); border-radius: var(--radius);
}
.code-steps li p { margin: 10px 0 0; max-width: 280px; color: var(--ink2); }
.code-steps ol + h2 { margin-top: 32px; }
.code-steps dl { margin: 0; max-width: 64ch; }
.code-steps dt { font-weight: 600; }
.code-steps dd { margin: 2px 0 14px; color: var(--ink2); }
@media (max-width: 1000px) { .code-steps ol { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 520px) { .code-steps ol { grid-template-columns: minmax(0, 1fr); } }

/* A call the advisor reading the roster is the second adult on. The only
   thing on that page addressed to the reader rather than to a student, so it
   sits above the counts in the warning palette: not an alarm, but somewhere
   they are expected to be. */
.duty {
  margin-top: 20px; padding: 12px 14px;
  background: var(--warnbg); border: 1px solid var(--warnrule);
}
.duty h2 { color: var(--warn); }
.duty ul { list-style: none; margin: 9px 0 0; padding: 0; display: grid; gap: 8px; }
.duty li { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; font-size: 13px; }
.duty li b { min-width: 86px; font-weight: 600; font-variant-numeric: tabular-nums; }
.duty li.now b { color: var(--warn); }
.duty li a { color: var(--ink); font-weight: 600; }
.duty form { margin: 0; }
.duty .primary { padding: 5px 12px; font-size: 13px; }
.duty > p { margin: 11px 0 0; color: var(--ink2); font-size: 12.5px; max-width: 80ch; }

/* counts strip */
.counts { display: flex; flex-wrap: wrap; margin-top: 20px; border: 1px solid var(--rule); background: var(--surface); }
.count { flex: 1 1 0; min-width: 132px; padding: 13px 16px; border-right: 1px solid var(--rule); }
.count:last-child { border-right: none; }
.count b { display: block; font-size: 22px; font-weight: 600; font-variant-numeric: tabular-nums; }
.count small { color: var(--ink3); font-size: 12px; }
.count.flagged b { color: var(--alarm); }

/* sections */
.sec { margin-top: 26px; }
.sechead { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 12px; margin-bottom: 9px; }
h2 { font-size: 15px; font-weight: 600; margin: 0; }
.sechead p { margin: 0; color: var(--ink3); font-size: 12.5px; }
/* A collapsible section: the h2 (or a form's h3) sits in the summary, with a chevron that turns when open. */
.fold > summary { cursor: pointer; list-style: none; }
.fold > summary::-webkit-details-marker { display: none; }
.fold > summary h2::before, .fold > summary h3::before {
  content: ""; display: inline-block; width: 6px; height: 6px; margin: 0 9px 2px 1px;
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
  transform: rotate(-45deg); transition: transform 0.15s;
}
.fold[open] > summary h2::before, .fold[open] > summary h3::before { transform: rotate(45deg); }
.fold:not([open]) > summary.sechead { margin-bottom: 0; }
.panel.fold > summary h2 { display: inline-block; margin: 0; }
.panel.fold[open] > summary { margin-bottom: 3px; }
.empty { padding: 16px; background: var(--surface); border: 1px solid var(--rule); color: var(--ink3); }
/* the roster's search box, above its table */
.find { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; margin-bottom: 9px; }
.find[hidden], .empty[hidden] { display: none; }
[data-find-item][hidden], [data-find-group][hidden], [data-email-other][hidden] { display: none; }
main > .find { margin-top: 16px; }
/* the row the arrow keys are on, while the cursor stays in the search box */
tbody tr.picked, tbody tr.picked:hover, .gate-row.picked { background: var(--ice); box-shadow: inset 0 0 0 2px var(--blue); }
.find input {
  flex: 0 1 340px; min-width: 0; height: 34px; box-sizing: border-box; font: inherit; color: var(--ink);
  padding: 7px 9px; border: 1px solid var(--rule2); border-radius: var(--radius-s); background: var(--surface);
}
.find .found { color: var(--ink3); font-size: 12.5px; font-variant-numeric: tabular-nums; }

/* roster table */
.tablewrap { background: var(--surface); border: 1px solid var(--rule); overflow-x: auto; }
table { border-collapse: collapse; width: 100%; min-width: 1020px; }
th {
  text-align: left; font-size: 12px; font-weight: 600; color: var(--ink2);
  padding: 9px 12px; border-bottom: 1px solid var(--rule2); white-space: nowrap; background: var(--ice2);
}
th.num, td.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
td { padding: 11px 12px; border-bottom: 1px solid var(--rule); vertical-align: top; }
tbody tr:last-child td { border-bottom: none; }
/* The row's worst chip, as a stripe down its left edge rather than a tint across
   it, the same marking the review queue uses. */
tbody tr.alarm td:first-child { box-shadow: inset 4px 0 var(--alarm); }
tbody tr.warn td:first-child { box-shadow: inset 4px 0 var(--warnstripe); }
tbody tr:hover { background: var(--ice2); }
.who { font-weight: 600; }
.who em { display: block; font-style: normal; font-weight: 400; color: var(--ink3); font-size: 12px; }
.prov { font-family: var(--mono); font-size: 12.5px; color: var(--ink2); }
.tag {
  font-size: 11px; font-weight: 500; color: var(--ink3); border: 1px solid var(--rule2);
  border-radius: var(--radius-s); padding: 0 5px; vertical-align: 1px;
}
.chips { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 5px; }
.chip { font-size: 11.5px; font-weight: 400; padding: 2px 7px; border-radius: var(--radius-s); border: 1px solid; }
.chip.alarm { color: var(--alarm); border-color: var(--alarmrule); background: var(--alarmbg); }
.chip.warn { color: var(--warn); border-color: var(--warnrule); background: var(--warnbg); }
.chip.info { color: var(--blue); border-color: var(--inforule); background: var(--infobg); }
.sechead h2 .chip { margin-left: 6px; vertical-align: 2px; }
/* Roster chips come in three weights, so an alarm is found without reading:
   solid for an alarm, an outline for a warning, and plain text for a note. The
   full sentence is in the title. */
.who .chip { font-size: 12px; padding: 2px 8px; }
.who .chip b { font-weight: 700; }
.who .chip.alarm { color: var(--onalarm); background: var(--alarm); border-color: var(--alarm); }
.who .chip.alarm::before { content: "\25CF"; font-size: 9px; margin-right: 5px; vertical-align: 1px; }
.who .chip.warn { background: none; }
/* Followed up: the same colour, no fill, and the date of the conversation. */
.who .chip.alarm.done { color: var(--alarm); background: var(--alarmbg); border-color: var(--alarmrule); }
.who .tick { font-weight: 600; color: var(--ok); margin-left: 2px; }
/* Flagged, not yet followed up: still a solid alarm, with the step taken. */
.who .flag { opacity: 0.85; margin-left: 2px; }
.who .notes { margin-top: 5px; font-size: 12px; font-weight: 400; color: var(--ink3); }
.who .notes .chip { all: unset; }
.who .notes .chip b { font-weight: 600; }
.who .notes .chip + .chip::before { content: " \00B7 "; }
/* A course near the next grade band: a chance to lift the GPA, not a problem. */
.lift { color: var(--blue); font-size: 11px; margin-left: 3px; border-bottom: 1px dotted var(--inforule); }
.bad { color: var(--alarm); font-weight: 600; }
.sub { font-size: 12.5px; }
/* The app build a check-in reported, beside the date on the student file. */
.build { font-family: var(--mono); font-size: 11.5px; color: var(--ink3); }
.dash { color: var(--rule2); }
abbr { text-decoration: none; }
/* Anything that explains itself: portal.js moves its title into data-tip and
   shows it in the bubble below on a click, so it gets the pointing hand. The
   second selector outweighs the notes' `all: unset`. */
[data-tip], .who .notes [data-tip] { cursor: pointer; }
[data-tip]:focus-visible, .who .notes [data-tip]:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }
.tip {
  position: absolute; z-index: 20; max-width: min(340px, calc(100vw - 16px));
  padding: 7px 10px; border-radius: var(--radius-s); background: var(--ink); color: var(--onink);
  font-size: 12.5px; font-weight: 400; line-height: 1.4; white-space: pre-line;
  box-shadow: 0 2px 8px rgba(0, 0, 0, .2); pointer-events: none;
}
footer { margin-top: 30px; color: var(--ink3); font-size: 12px; max-width: 70ch; }

.who a { color: inherit; text-decoration: none; border-bottom: 1px solid var(--rule2); }
.who a:hover { border-bottom-color: var(--ink); }
code { font-family: var(--mono); font-size: 12.5px; }
.quiet { margin: 0; color: var(--ink3); }

/* student file */
.back {
  display: inline-flex; align-items: center; gap: 8px; margin: 20px 0 4px;
  padding: 8px 14px 8px 11px; font-size: 14px; font-weight: 600; color: var(--ink);
  text-decoration: none; background: var(--surface); border: 1px solid var(--rule2); border-radius: var(--radius-s);
}
.back:hover { border-color: var(--blue); color: var(--blue); }
.back span { font-size: 16px; line-height: 1; }
.file { background: var(--surface); border: 1px solid var(--rule); margin-top: 10px; }
.filehead { padding: 18px 20px; border-bottom: 1px solid var(--rule2); }
.filehead h1 { margin: 0; font-size: 24px; font-weight: 600; }
.meta { display: flex; flex-wrap: wrap; gap: 10px 24px; margin: 12px 0 0; font-size: 13px; }
.meta dt { color: var(--ink3); font-size: 11.5px; }
.meta dd { margin: 0; font-weight: 500; }
.panel { padding: 18px 20px; border-bottom: 1px solid var(--rule); }
.panel:last-child { border-bottom: none; }
.panel h2 { margin: 0 0 3px; font-size: 14px; }
.note { margin: 0 0 12px; color: var(--ink3); font-size: 12.5px; max-width: 80ch; }
.verdict { padding: 13px 15px; border: 1px solid var(--okrule); border-radius: var(--radius-s); background: var(--okbg); }
.verdict b { font-size: 15px; color: var(--ok); }
.verdict.alarm { border-color: var(--alarmrule); background: var(--alarmbg); }
.verdict.alarm b { color: var(--alarm); }
.verdict.warn { border-color: var(--warnrule); background: var(--warnbg); }
.verdict.warn b { color: var(--warn); }
.verdict p { margin: 10px 0 0; color: var(--ink2); font-size: 12.5px; }
/* One entry per issue: the sentence, its why, the courses behind it (each
   with where it stands and what to do), then "Next". The same shape whether
   it's the headline or a reason under it, so the eye learns it once. */
.verdict .why, .file-notes .why { display: block; margin-top: 3px; color: var(--ink2); font-size: 12.5px; }
.verdict > .why { color: var(--ink); font-size: 13.5px; }
.verdict ul.issues { margin: 10px 0 0; padding: 0; list-style: none; display: grid; gap: 8px; }
.verdict .issues > li { padding: 8px 0 0; border-top: 1px solid rgba(0, 0, 0, .08); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .verdict .issues > li { border-top-color: rgba(255, 255, 255, .1); }
}
:root[data-theme="dark"] .verdict .issues > li { border-top-color: rgba(255, 255, 255, .1); }
.verdict .issue-text { font-weight: 600; }
.verdict .alarm > .issue-text { color: var(--alarm); }
.verdict .warn > .issue-text { color: var(--warn); }
/* The ⓘ: why, and what to do, in portal.js's bubble on a click. */
.ask-why {
  display: inline-block; width: 16px; height: 16px; border-radius: 50%; margin-left: 2px;
  border: 1px solid currentColor; color: var(--blue); font: 600 11px/14px var(--sans);
  text-align: center; vertical-align: 1px; cursor: pointer; user-select: none;
}
.ask-why:hover { background: var(--blue); color: var(--surface); }
.verdict a.where, .file-notes a.where { color: var(--blue); font-size: 12.5px; margin-left: 6px; }
/* The courses behind an issue, one box each, in the box's own tint. */
.verdict ul.raised, .file-notes ul.raised { list-style: none; padding: 0; margin: 8px 0 0; display: grid; gap: 6px; }
.verdict .raised li {
  display: grid; gap: 4px; padding: 8px 12px; border: 1px solid rgba(0, 0, 0, .1);
  border-radius: var(--radius-s); background: rgba(255, 255, 255, .45);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .verdict .raised li { border-color: rgba(255, 255, 255, .12); background: rgba(0, 0, 0, .18); }
}
:root[data-theme="dark"] .verdict .raised li { border-color: rgba(255, 255, 255, .12); background: rgba(0, 0, 0, .18); }
.verdict .raised-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 10px; }
.verdict .raised-head strong { font-weight: 600; color: var(--ink); }
.verdict .raised-head .meta { color: var(--ink3); font-size: 12px; }
.verdict .raised .why { margin-top: 0; }
.verdict .raised .route { display: block; color: var(--ink); font-size: 13px; max-width: 80ch; }
.verdict .raised .do { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; margin: 4px 0 0; }
.verdict .raised .do a, .verdict .raised .do button {
  display: inline-block; padding: 6px 12px; font-size: 13px; text-decoration: none;
}
.verdict .raised .do a:hover, .verdict .raised .do button:hover { border-color: var(--blue); color: var(--blue); }
.verdict .raised .by { color: var(--ink2); font-size: 12.5px; }
.verdict .raised .by q { quotes: "“" "”"; }
.verdict .raised .by.done { color: var(--ok); font-weight: 600; }
.file-notes { margin: 10px 0 0; padding-left: 18px; color: var(--ink2); font-size: 13px; }
.file-notes li { margin: 2px 0; }
.contact-form label.check .by { color: var(--ink3); font-size: 12px; font-weight: 400; }
.figures { display: flex; flex-wrap: wrap; gap: 12px 36px; margin: 14px 0 0; }
.figures dt { color: var(--ink3); font-size: 12px; }
.figures dd { margin: 0; font-size: 20px; font-weight: 600; font-variant-numeric: tabular-nums; }
/* Shared by the Core courses and 10/7 panels: the big figure, the key,
   and the bars the 10/7 gate still uses. */
.req-total { display: flex; align-items: flex-end; gap: 12px; margin: 4px 0 12px; }
.req-total b { font-size: 44px; line-height: .9; font-weight: 700; font-variant-numeric: tabular-nums; }
.req-total p { margin: 0; color: var(--ink2); font-size: 13.5px; }
.pace-row, .clock-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; max-width: 640px; margin: 0 0 14px; font-size: 14px; }
.pace-row abbr { border-bottom: 1px dotted var(--ink3); }
.pace-row .by, .clock-row .by { color: var(--ink3); }
.pace-row .chip { flex: none; font-size: 12.5px; font-weight: 600; padding: 3px 9px; }
.req-key { list-style: none; display: flex; flex-wrap: wrap; gap: 4px 16px; margin: 0 0 10px; padding: 0; color: var(--ink2); font-size: 12.5px; }
.req-key li::before { content: ""; display: inline-block; width: 10px; height: 10px; margin-right: 6px; border-radius: var(--radius-s); vertical-align: -1px; }
.req-key .completed::before { background: var(--ink); }
.req-key .in-progress::before { background: var(--warnstripe); }
.req-key .planned::before { background: var(--rule2); }
.req-bars { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; max-width: 640px; }
.req-bars li { display: grid; grid-template-columns: minmax(96px, 13em) 1fr 3.5em; align-items: center; gap: 12px; font-size: 14px; }
.req-bars svg { display: block; width: 100%; height: 12px; border-radius: 6px; overflow: hidden; }
.req-bars .req-count { font-family: var(--mono); font-size: 13px; text-align: right; font-variant-numeric: tabular-nums; }
.req-bars .met .req-count { color: var(--ok); }
.req-bars .track { fill: var(--ice); }
.req-bars .completed { fill: var(--ink); }
.req-bars .in-progress { fill: var(--warnstripe); }
.req-bars .planned { fill: var(--rule2); }
.req-bars + .note { margin-top: 14px; }
/* Core courses: the app's slot grid, one box per required course. The boxes
   are what the 16 actually is, a count; the 10/7 panel above keeps a bar,
   because a gate is a pace. --warnbg/--ice fills with a --warnstripe/--rule2 edge stand
   in for the app's tinted fills, which are one colour at low opacity. */
.core-slots {
  list-style: none; margin: 0; padding: 0; max-width: 560px;
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px 28px;
}
.core-slots li { display: grid; gap: 6px; justify-items: start; }
.core-slots .slot-head { display: flex; align-items: baseline; gap: 6px; color: var(--ink2); font-size: 13.5px; }
.core-slots .req-count { font-family: var(--mono); font-size: 12.5px; font-variant-numeric: tabular-nums; }
.core-slots .met .req-count { color: var(--ok); }
.core-slots svg { display: block; height: 30px; width: auto; max-width: 100%; }
.core-slots .completed { fill: var(--ink); }
.core-slots .in-progress { fill: var(--warnbg); }
.core-slots .planned { fill: var(--ice); }
.core-slots .edge { fill: none; stroke-width: 1.5; }
.core-slots .edge.done { stroke: var(--ink); }
.core-slots .edge.now { stroke: var(--warnstripe); }
.core-slots .edge.later, .core-slots .edge.empty { stroke: var(--rule2); }
.core-slots .edge.empty { stroke-dasharray: 4 3; }
.core-slots .hit { fill: transparent; pointer-events: all; cursor: help; }
.core-slots .tick { fill: none; stroke: var(--onink); stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; }
.core-slots + .note { margin-top: 14px; }
/* The 10/7 panel: what's missing, in the colour of the flag it explains. */
.req-key .missing.alarm::before { background: var(--alarm); }
.req-key .missing.warn::before { background: var(--warn); }
.gate-bars .missing { fill: var(--alarm); }
.gate-bars .warn .missing { fill: var(--warn); }
.gate-bars .pace { fill: var(--ink2); }
.gate-bars .alarm .req-count { color: var(--alarm); }
.gate-bars .warn .req-count { color: var(--warn); }
.gate-short { margin: 12px 0 0; font-weight: 600; }
.gate-short.alarm { color: var(--alarm); }
.gate-short.warn { color: var(--warn); }
#ten-seven h2 abbr { border-bottom: 1px dotted var(--ink3); }
/* The one shortened label: dotted, so it reads as something to click. */
.req-label abbr { border-bottom: 1px dotted var(--ink3); }
@media (max-width: 520px) {
  .req-bars li { grid-template-columns: 1fr 3.5em; gap: 4px 12px; }
  .req-bars .req-label { grid-column: 1 / -1; }
  .core-slots { grid-template-columns: minmax(0, 1fr); }
}
/* The Core GPA panel, after the app's GPA tab. */
.gpa-head { display: flex; align-items: flex-end; gap: 12px; margin: 4px 0 12px; max-width: 480px; }
.gpa-head b { font-size: 44px; line-height: .9; font-weight: 700; font-variant-numeric: tabular-nums; }
.gpa-head p { margin: 0; color: var(--ink2); font-size: 13.5px; }
.gpa-head .chip { margin-left: auto; align-self: center; font-size: 12.5px; font-weight: 600; padding: 3px 9px; }
.chip.ok { color: var(--ok); border-color: var(--okrule); background: var(--okbg); }
.gpa-scale { display: block; width: 100%; max-width: 480px; height: auto; margin-bottom: 12px; }
.gpa-scale .track { fill: var(--ice); }
.gpa-scale .fill { fill: var(--ink); }
.gpa-scale .minimum { fill: var(--warnstripe); }
.gpa-scale text { fill: var(--ink3); font-family: var(--mono); font-size: 9px; text-anchor: middle; }
.cliffs { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.cliff {
  border: 1px solid var(--inforule); background: var(--infobg); border-radius: var(--radius-s);
  padding: 11px 14px; display: flex; flex-wrap: wrap; gap: 6px 16px; align-items: center;
}
.cliff .jump { font-size: 18px; font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
.cliff .jump s { text-decoration: none; color: var(--ink3); font-weight: 400; }
.cliff p { margin: 0; font-size: 13px; }
.tablewrap.inner { border: none; }
table.courses { min-width: 680px; }
tr.nocount td { color: var(--ink3); }
/* A stronger rule where the grade changes, so each grade reads as a group. */
table.courses tr.newgrade td { border-top: 2px solid var(--rule2); }
td.match { font-size: 12px; font-weight: 600; }
td.match.approved { color: var(--ok); }
td.match.excluded, td.match.unrecognized { color: var(--alarm); }
td.match .why { display: block; font-weight: 400; color: var(--ink3); }
/* A course the file raises reads at full strength, not greyed like a gym course. */
tr.flagged td.match .why { color: var(--warn); font-weight: 600; }
/* A course behind one of the file's chips, tinted in that chip's colour with
   the stripe the roster uses, so the chip and its course read as one. Its text
   is at full strength even when it won't count: it's the course being raised. */
table.courses tr.alert-alarm, table.courses tr.alert-alarm:hover { background: var(--alarmbg); }
table.courses tr.alert-warn, table.courses tr.alert-warn:hover { background: var(--warnbg); }
table.courses tr.alert-info, table.courses tr.alert-info:hover { background: var(--infobg); }
table.courses tr.alert-alarm td:first-child { box-shadow: inset 4px 0 var(--alarm); }
table.courses tr.alert-warn td:first-child { box-shadow: inset 4px 0 var(--warnstripe); }
table.courses tr.alert-info td:first-child { box-shadow: inset 4px 0 var(--inforule); }
table.courses tr[class*="alert-"] td { color: var(--ink); }
table.courses tr.alert-alarm td.match { color: var(--alarm); }
table.courses tr.alert-warn td.match { color: var(--warn); }
table.courses tr.alert-info td.match { color: var(--blue); }
/* Its title explains the chip on a click, as the roster's chips do. */
table.courses abbr.course-why { border-bottom: 1px dotted currentColor; }
/* A flag with a rule behind it (the 10/7 gate) explains the rule on a click. */
.verdict abbr.rule { border-bottom: 1px dotted currentColor; }
.time { list-style: none; margin: 0; padding: 0; }
.time li { display: grid; grid-template-columns: 110px 1fr; gap: 14px; padding: 9px 0; border-bottom: 1px solid var(--ice); }
.time li:last-child { border-bottom: none; }
.time time { color: var(--ink3); font-size: 12px; font-variant-numeric: tabular-nums; }
.time p { margin: 0 0 2px; }
.time p.alarm { color: var(--alarm); font-weight: 600; }
.time p.warn { color: var(--warn); }
.log .said-with { font-weight: 600; }
.log .said { margin: 3px 0; white-space: pre-line; max-width: 70ch; }
.log .by { color: var(--ink3); font-size: 12px; }
.log .corrected { color: var(--warn); font-size: 12px; font-weight: 600; margin-left: 6px; }
.log-asked { margin: 3px 0; max-width: 70ch; }
.log-asked > summary { color: var(--blue); cursor: pointer; }
.log-asked[open] { margin-bottom: 8px; }
.log-asked[open] > summary { margin-bottom: 4px; }
/* What Ask Core16 said, in the box the family saw it in (.bubble.ask),
   which also keeps it from reading as the start of the reply under it. */
.said-box { margin: 3px 0; padding: 8px 10px; max-width: 70ch; background: var(--ice2); border-radius: var(--radius-s); }
.said-box p { margin: 0; }
.said-box .by { margin-bottom: 2px; color: var(--ink2); font-size: 12px; font-weight: 600; }
.said-box .said { white-space: pre-line; }
/* Above the latest entries now that the log reads oldest first. */
.log-older { margin-bottom: 10px; padding-bottom: 9px; border-bottom: 1px solid var(--ice); }
.log-older[open] > summary { margin-bottom: 10px; }
.log-older > summary { color: var(--blue); cursor: pointer; font-size: 13px; }
.log-older:not([open]) .when-open, .log-older[open] .when-closed { display: none; }
/* minmax(0, 1fr) and min-width: 0 keep the form to its panel's width. Left to
   size themselves, the form and its labels grow to their widest content: a
   select's longest option ("Corrects an earlier entry" names a date, channel
   and person) or a fieldset's, which ran the whole form past the file's
   narrow side column between 1240px and a wide window. */
.contact-form { margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--rule); display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; max-width: 720px; }
.contact-form h3 { margin: 0; font-size: 13.5px; }
.fields { display: flex; flex-wrap: wrap; gap: 12px; }
.fields .grow { flex: 1 1 200px; }
.contact-form label { display: grid; grid-template-columns: minmax(0, 1fr); gap: 4px; align-content: start; min-width: 0; font-size: 12.5px; color: var(--ink2); font-weight: 500; }
.contact-form fieldset { min-width: 0; }
.contact-form input, .contact-form select, .contact-form textarea {
  font: inherit; color: var(--ink); padding: 7px 9px; border: 1px solid var(--rule2);
  border-radius: var(--radius-s); background: var(--surface); max-width: 100%;
}
.contact-form textarea { width: 100%; resize: vertical; }
/* A parent's name and address make a long option, which would otherwise widen
   the whole form past a narrow panel. */
.contact-form [data-email-to] { width: 100%; }
.contact-form .primary { justify-self: start; }
.field-error, .form-error { color: var(--alarm); font-size: 12px; font-weight: 500; margin: 0; }
@media (max-width: 600px) {
  .time li { grid-template-columns: 1fr; gap: 2px; }
  .panel, .filehead { padding-inline: 14px; }
}

/* the Grade 11 gate: ten slots, the Core16 mark's own picture of the rule */
.gate { background: var(--surface); border: 1px solid var(--rule); }
.gate-row {
  display: grid; grid-template-columns: 220px 1fr 150px; align-items: center; gap: 18px;
  padding: 13px 16px; border-bottom: 1px solid var(--rule);
}
.gate-name { font-weight: 600; }
.gate-name a { color: inherit; text-decoration: none; border-bottom: 1px solid var(--rule2); }
.gate-name em { display: block; font-style: normal; font-weight: 400; color: var(--ink3); font-size: 12px; }
.gate-name em.stale { color: var(--warn); }
.slots { display: flex; gap: 3px; }
.slot { height: 26px; flex: 1; border: 3px solid var(--rule2); border-radius: 6px; }
.slot.done { background: var(--ink); border-color: var(--ink); }
.slot.proj { background: repeating-linear-gradient(45deg, var(--rule2) 0 3px, transparent 3px 6px); }
.slot.short { border-color: var(--alarm); background: var(--alarmbg); }
.gate-verdict { text-align: right; font-weight: 600; font-variant-numeric: tabular-nums; }
.gate-verdict em { display: block; font-style: normal; font-weight: 400; font-size: 12px; color: var(--ink3); }
.gate-verdict.bad { color: var(--alarm); }
.gate-verdict.good { color: var(--ok); }
/* What to do, under the verdict: in the ink, since the figure above is already the colour. */
.gate-verdict em.next { color: var(--ink2); max-width: 24ch; margin-left: auto; }
@media (max-width: 720px) { .gate-verdict em.next { margin-left: 0; } }
.legend { display: flex; flex-wrap: wrap; gap: 16px; padding: 9px 16px; background: var(--ice2); font-size: 12px; color: var(--ink3); }
.legend i { display: inline-block; width: 12px; height: 12px; border: 2px solid var(--rule2); border-radius: var(--radius-s); vertical-align: -2px; margin-right: 5px; }
.legend i.done { background: var(--ink); border-color: var(--ink); }
.legend i.proj { background: repeating-linear-gradient(45deg, var(--rule2) 0 3px, transparent 3px 6px); }
.legend i.short { border-color: var(--alarm); background: var(--alarmbg); }
@media (max-width: 720px) {
  .gate-row { grid-template-columns: 1fr; gap: 9px; }
  .gate-verdict { text-align: left; }
}

/* review queue */
.people { display: flex; flex-wrap: wrap; gap: 4px 12px; }
.people a { color: var(--blue); }
/* How far along each student is: a completed blocking course can only be
   submitted to NCAA, not swapped, so it reads in the alarm colour. */
.person { display: inline-flex; flex-direction: column; }
.person .status { font-size: 12px; color: var(--ink3); }
.person .status.done { color: var(--alarm); font-weight: 600; }
/* What resolves the course, under its name: read before anything is opened. */
table.queue .who .route { display: block; margin-top: 4px; font-weight: 400; font-size: 12.5px; color: var(--ink2); max-width: 52ch; }
table.queue { min-width: 860px; }
/* Urgency: red blocks certification, yellow blocks nothing but needs a look. */
.sec.alarm .sechead h2 { color: var(--alarm); }
.sec.warn .sechead h2 { color: var(--warn); }
.sec.alarm .sechead h2::before, .sec.warn .sechead h2::before {
  content: ""; display: inline-block; width: 9px; height: 9px; border-radius: 50%;
  margin-right: 8px; vertical-align: 1px; background: currentColor;
}
table.queue.alarm tbody tr, table.queue.alarm tbody tr:hover { background: var(--alarmbg); }
table.queue.warn tbody tr, table.queue.warn tbody tr:hover { background: var(--warnbg); }
table.queue.alarm td { border-bottom-color: var(--alarmrule); }
table.queue.warn td { border-bottom-color: var(--warnrule); }
table.queue.alarm td:first-child { box-shadow: inset 4px 0 var(--alarm); }
table.queue.warn td:first-child { box-shadow: inset 4px 0 var(--warnstripe); }
td.act { min-width: 220px; }
.filed { display: block; font-weight: 400; color: var(--ink3); font-size: 12px; }
.act summary { color: var(--blue); cursor: pointer; }
/* The toggle names what it will do: "Show options" closed, "Hide options" open. */
.act details:not([open]) .when-open, .act details[open] .when-closed { display: none; }
.queue-action { display: grid; gap: 8px; margin-top: 8px; }
.queue-action label { display: grid; gap: 4px; font-size: 12.5px; color: var(--ink2); font-weight: 500; }
.queue-action .opt { font-weight: 400; color: var(--ink3); }
.queue-action textarea {
  font: inherit; color: var(--ink); padding: 6px 8px; border: 1px solid var(--rule2);
  border-radius: var(--radius-s); background: var(--surface); width: 100%; resize: vertical;
}
.queue-action .buttons { display: flex; flex-wrap: wrap; gap: 8px; }
.queue-action .buttons button:not(.primary) {
  font: inherit; font-size: 13px; padding: 6px 10px; cursor: pointer; color: var(--ink);
  background: var(--surface); border: 1px solid var(--rule2); border-radius: var(--radius-s);
}
.queue-action .note { margin: 0; font-size: 12px; }
.flags { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.flags .by { display: block; color: var(--ink3); font-size: 12px; }
.flags .said { display: block; white-space: pre-line; max-width: 40ch; }
.flags + details { margin-top: 8px; }
.contact-form fieldset.resolves { border: 1px solid var(--rule); border-radius: var(--radius-s); padding: 8px 12px; margin: 0; }
.contact-form fieldset.resolves legend { font-size: 12.5px; color: var(--ink2); font-weight: 500; padding: 0 4px; }
.contact-form label.check { display: flex; gap: 8px; align-items: center; font-weight: 400; color: var(--ink); }
/* Each course on a line of its own with what ticking it does underneath, so
   a narrow column never splits a course name to make room for the note. */
.contact-form fieldset.resolves { display: grid; gap: 8px; }
.contact-form fieldset.resolves label.check { align-items: flex-start; }
.contact-form fieldset.resolves label.check input { margin-top: 3px; }
.contact-form fieldset.resolves .what .by { display: block; margin-top: 1px; }

/* staff */
table.staff { min-width: 760px; }
td.actions { white-space: nowrap; text-align: right; }
td.actions form { display: inline; margin-left: 14px; }
.linkbtn.danger { color: var(--alarm); }
.form-error.banner { padding: 9px 12px; margin: 0 0 10px; background: var(--alarmbg); border: 1px solid var(--alarmrule); }
.notice { margin: 0 0 10px; padding: 9px 12px; background: var(--ice2); border: 1px solid var(--rule); }
.staff-form { display: grid; gap: 12px; max-width: 760px; }
.staff-form label { display: grid; gap: 4px; align-content: start; font-size: 12.5px; color: var(--ink2); font-weight: 500; }
.staff-form input, .staff-form select {
  font: inherit; color: var(--ink); padding: 7px 9px; border: 1px solid var(--rule2);
  border-radius: var(--radius-s); background: var(--surface); max-width: 100%;
}
.staff-form .primary, .staff-form .note { justify-self: start; margin: 0; }
/* families */
table.families { min-width: 640px; }
table.families td div + div { margin-top: 3px; }
tr.muted td, tr.muted td a { color: var(--ink3); }
.staff-form .opt { font-weight: 400; color: var(--ink3); }
/* Add a family is one grid of three sections, so each heading sits on its own
   fields and the space goes between sections instead. */
.staff-form.add-family h3 { margin: 8px 0 -8px; }
.staff-form.add-family h3:first-of-type { margin-top: 0; }
/* The folded second student: its fields are outside the form's grid, so they
   need the grid's 12px themselves. */
.staff-form.add-family .second-student > summary h3 { margin: 0; }
.staff-form.add-family .second-student > .fields { margin-top: 12px; }
.staff-form.add-family .second-student > summary + .fields { margin-top: 8px; }
.staff-form h3 { margin: 4px 0 0; }
.card.wide { max-width: 640px; }
.code-dialog {
  width: min(520px, calc(100vw - 32px)); padding: 22px 24px; color: var(--ink);
  background: var(--surface); border: 1px solid var(--rule2); border-radius: var(--radius-s);
}
.code-dialog::backdrop { background: var(--backdrop); }
.code-dialog h2 { margin: 0 0 10px; font-size: 17px; }
.code-dialog p { margin: 0 0 12px; color: var(--ink2); }
.code-dialog .code { font: 600 30px var(--mono); letter-spacing: .08em; color: var(--ink); margin-bottom: 10px; }
.code-dialog textarea {
  width: 100%; font: 12.5px var(--mono); color: var(--ink); padding: 8px 9px; resize: none;
  border: 1px solid var(--rule2); border-radius: var(--radius-s); background: var(--ice2);
}
.code-dialog .buttons { display: flex; gap: 8px; align-items: center; margin-top: 10px; }
.code-dialog .buttons form { margin: 0; }
.code-dialog .status { margin: 6px 0 4px; }
.code-dialog .note { margin: 0; font-size: 12.5px; color: var(--ink3); }

/* asking before something that can't be undone -- see portal.js */
.ask {
  width: min(460px, calc(100vw - 32px)); padding: 22px 24px; color: var(--ink);
  background: var(--surface); border: 1px solid var(--rule2); border-radius: var(--radius-s);
}
.ask::backdrop { background: var(--backdrop); }
.ask h2 { margin: 0; font-size: 17px; }
.ask p { margin: 10px 0 0; color: var(--ink2); }
.ask p[hidden] { display: none; }
.ask .buttons { display: flex; flex-wrap: wrap; gap: 8px; justify-content: flex-end; margin-top: 20px; }
@media (prefers-reduced-motion: no-preference) {
  .ask[open] { animation: ask-in .13s ease-out; }
  @keyframes ask-in { from { opacity: 0; transform: translateY(-6px); } }
}
.linkbox { display: flex; gap: 8px; flex-wrap: wrap; }
.setup-email { margin-bottom: 20px; }
.linkbox input {
  flex: 1 1 280px; min-width: 0; font: 12.5px var(--mono); color: var(--ink);
  padding: 8px 9px; border: 1px solid var(--rule2); border-radius: var(--radius-s); background: var(--ice2);
}
.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* renaming, archiving and deleting a student */
.notice.top, .form-error.banner.top { margin: 12px 0 0; }
.archived-note { margin: 8px 0 0; color: var(--warn); font-size: 13px; }
.archived { list-style: none; margin: 0; padding: 0; background: var(--surface); border: 1px solid var(--rule); }
.archived li { padding: 9px 12px; border-bottom: 1px solid var(--rule); }
.archived li:last-child { border-bottom: none; }
.archived a { color: var(--ink); font-weight: 600; }
.archived .by { color: var(--ink3); font-size: 12px; }
.contact-form.first { margin-top: 10px; padding-top: 0; border-top: none; }
.contact-form .note { margin: 0; color: var(--ink3); font-size: 12.5px; max-width: 70ch; }
/* A footnote under a form ("To add a parent…" below the Call button) needs room, or it reads as part of the button. */
.contact-form + .quiet { margin-top: 12px; font-size: 12.5px; }
.secondary, .danger {
  font: inherit; font-weight: 600; justify-self: start; cursor: pointer;
  border-radius: var(--radius-s); padding: 9px 15px; background: var(--surface);
}
.secondary { color: var(--ink); border: 1px solid var(--rule2); }
.danger { color: var(--onalarm); background: var(--alarm); border: 1px solid var(--alarm); }
/* A link-style button that's also dangerous (Revoke, Withdraw, Cancel) stays a
   link: without this, .danger above fills it in and its red text vanishes. */
.linkbtn.danger { background: none; border: none; padding: 0; font-weight: inherit; }
.danger-zone h2, .danger-zone h3 { color: var(--alarm); }

/* appearance switch in the top bar */
.brand svg rect[stroke] { stroke: var(--rule2); }
.theme { display: inline-flex; border: 1px solid var(--rule2); border-radius: var(--radius-s); overflow: hidden; }
.theme[hidden] { display: none; }
.theme button {
  font: inherit; font-size: 12px; color: var(--ink2); background: var(--surface);
  border: none; padding: 3px 9px; cursor: pointer;
}
.theme button + button { border-left: 1px solid var(--rule2); }
.theme button:hover { color: var(--ink); }
.theme button[aria-pressed="true"] { color: var(--onink); background: var(--ink); }

/* read aloud, not shown */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* Mentor sessions: the Sessions page and the panel on a student's file. */
.sessions-figures { margin: 12px 0 16px; }
.sessions-figures dd .sub { display: block; font-size: 12.5px; font-weight: 400; }
.sessions-figures dd .bad { font-size: 15px; }
td.actions label { font-size: 12.5px; color: var(--ink3); }
td.actions label.check { display: inline-flex; gap: 6px; align-items: center; margin-right: 10px; }
td.actions input[type="text"] {
  width: 240px; margin-left: 6px; font: inherit; padding: 5px 8px; color: var(--ink);
  background: var(--surface); border: 1px solid var(--rule2); border-radius: var(--radius-s);
}
.staff-form label > textarea {
  display: block; width: 100%; max-width: 70ch; margin-top: 4px; font: inherit; padding: 7px 9px;
  color: var(--ink); background: var(--surface); border: 1px solid var(--rule2);
  border-radius: var(--radius-s); resize: vertical;
}
.staff-form h3 { margin: 0 0 10px; font-size: 14px; }
#sessions .time.log form { margin-top: 6px; display: flex; gap: 12px; align-items: center; flex-wrap: wrap; }
#sessions .contact-form { margin-top: 18px; }
/* A contact form folded away by default: the rule above it moves to the details, its h3 to the summary. */
.form-fold { margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--rule); max-width: 720px; }
.form-fold > summary h3 { display: inline-block; margin: 0; font-size: 13.5px; }
#sessions .form-fold > .contact-form { margin-top: 12px; padding-top: 0; border-top: none; }
.ledger[open] > summary { margin-bottom: 12px; }

/* The availability calendar on a professional's own page. A week of half-hour
   bands; the free ones are real checkboxes, so ticking a week works with no
   JavaScript at all and portal.js only adds sweeping a run with one drag. */
.weeknav { display: flex; flex-wrap: wrap; gap: 12px 18px; align-items: end; margin: 0 0 10px; }
.weekjump { display: flex; gap: 10px; align-items: center; }
.weekjump strong { font-size: 13px; color: var(--ink); min-width: 15ch; text-align: center; }
.weekjump a { text-decoration: none; }
.weekjump .is-off { opacity: .35; }
.weeknav label { display: grid; gap: 4px; font-size: 12.5px; color: var(--ink2); font-weight: 500; }
.weeknav select[name] { height: 40px; }
.weeknav select { font: inherit; padding: 6px 8px; color: var(--ink); background: var(--surface); border: 1px solid var(--rule2); border-radius: var(--radius-s); }
.calwrap { overflow-x: auto; border: 1px solid var(--rule); background: var(--surface); }
.calwrap .cal { border-collapse: collapse; width: 100%; min-width: 620px; table-layout: fixed; }
.calwrap .cal thead th { padding: 7px 4px; font-size: 12px; font-weight: 600; color: var(--ink); background: var(--ice2); border-bottom: 1px solid var(--rule); }
.calwrap .cal thead th span { display: block; font-size: 11px; font-weight: 400; color: var(--ink3); }
.calwrap .cal thead th:first-child, .calwrap .cal tbody th { width: 62px; }
.calwrap .cal tbody th { padding: 0 8px 0 0; font-size: 11px; font-weight: 400; color: var(--ink3); text-align: right; vertical-align: top; white-space: nowrap; }
.calwrap .cal td { padding: 0; border-left: 1px solid var(--rule); height: 17px; }
.calwrap .cal td.onhour { border-top: 1px solid var(--rule); }
.calwrap .cal tbody tr:first-child td { border-top: none; }
/* The checkbox is the cell: no tick, just the whole band filling in, which is
   what someone sweeping a Tuesday evening is actually looking at. */
.cal .band input {
  appearance: none; -webkit-appearance: none; display: block; margin: 0;
  width: 100%; height: 17px; cursor: pointer; background: transparent; border: none;
}
.cal .band input:hover { background: var(--ice); }
.cal .band input:checked { background: var(--blue); }
.cal .band input:focus-visible { outline: 2px solid var(--ink); outline-offset: -2px; }
.cal .band.open { background: var(--okbg); }
.cal .band.booked { background: var(--infobg); }
.cal .band.past { background: var(--ice2); }
.cal .band .held { display: block; height: 17px; padding: 0 4px; overflow: hidden; font-size: 11px; line-height: 17px; color: var(--ink2); white-space: nowrap; }
.cal .band.booked .held { font-weight: 600; color: var(--ink); }
.callegend { display: flex; flex-wrap: wrap; gap: 6px 14px; align-items: center; margin: 8px 0 0; font-size: 12.5px; color: var(--ink3); }
.callegend .key { display: inline-block; width: 13px; height: 13px; margin-right: 2px; vertical-align: -2px; border: 1px solid var(--rule2); }
.callegend .key.free { background: var(--surface); }
.callegend .key.open { background: var(--okbg); border-color: var(--okrule); }
.callegend .key.booked { background: var(--infobg); border-color: var(--inforule); }
.callegend .key.past { background: var(--ice2); }
.calgo { display: flex; flex-wrap: wrap; gap: 12px 16px; align-items: end; margin: 14px 0 0; }
.calgo label { display: grid; gap: 4px; font-size: 12.5px; color: var(--ink2); font-weight: 500; }
.calgo select[name] { height: 40px; }
.calgo select { font: inherit; padding: 7px 8px; color: var(--ink); background: var(--surface); border: 1px solid var(--rule2); border-radius: var(--radius-s); }
.calgo .primary { margin: 0; }
.calgo p { margin: 0 0 8px; }
.onetime { margin: 22px 0 0; }
.onetime > summary { cursor: pointer; font-size: 13px; font-weight: 600; color: var(--ink2); }
.onetime .staff-form { margin-top: 12px; }
/* Sweeping a run shouldn't select the day names along the way. */
.cal.sweeping { user-select: none; -webkit-user-select: none; }
/* A fortnight of evenings is forty rows. Folded away once it is longer than a
   glance, since the calendar above already shows the same week in a shape
   somebody can read; this is the list you withdraw from. */
.alltimes > summary { cursor: pointer; margin: 0 0 10px; font-size: 13px; font-weight: 600; color: var(--ink2); }
.alltimes[open] > summary { margin-bottom: 10px; }

/* A family's parents and guardians, on the family's page. */
.guardians { list-style: none; margin: 8px 0 12px; padding: 0; }
.guardians li { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 8px 0; border-bottom: 1px solid var(--rule); }
.guardians form { margin: 0; }
.calls details { margin: 8px 0 16px; }
.guardians .login { display: block; font-style: normal; color: var(--ink3); font-size: 12.5px; }
.guardians .acts { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 4px 14px; }

/* A parent's page (parent.html): each student's figures, then one calendar. */
.fineprint.wide { max-width: 80ch; margin: 26px 0 0; }
.child .status { display: grid; gap: 14px; }
.child .status > * { margin: 0; }
/* The GPA row is capped narrower than the pace rows under it, which left its
   chip about 160px left of theirs. On the parent page they share one width. */
.child .status .gpa-head { max-width: 640px; }
.agenda { list-style: none; margin: 8px 0 12px; padding: 0; max-width: 760px; }
.agenda li { display: grid; grid-template-columns: 6.5em 1fr auto; align-items: baseline; gap: 12px; padding: 7px 0 7px 10px; border-bottom: 1px solid var(--rule); border-left: 3px solid var(--rule2); margin-bottom: 2px; font-size: 14px; }
.agenda time { color: var(--ink2); font-variant-numeric: tabular-nums; }
.agenda b { font-weight: 600; }
.agenda em { display: block; font-style: normal; color: var(--ink3); font-size: 12.5px; }
.agenda .due, .agenda .school { border-left-color: var(--blue); }
.agenda .hockey { border-left-color: var(--hockey); }
.agenda .session { border-left-color: var(--warnstripe); }
.agenda .done b, .agenda .done time { color: var(--ink3); font-weight: 400; }
/* The month's list mixes school and hockey: a wider stripe, the calendar's
   tint behind the row, and the kind named under the date. */
.agenda.mixed li { border-left-width: 5px; padding-right: 8px; }
.agenda.mixed .due, .agenda.mixed .school { background: var(--infobg); }
.agenda.mixed .hockey { background: var(--hockeybg); }
.agenda.mixed .session { background: var(--warnbg); }
.agenda .when { display: flex; flex-direction: column; }
.agenda .when .at { color: var(--ink); font-weight: 600; font-variant-numeric: tabular-nums; }
.agenda .done .when .at { color: var(--ink3); font-weight: 400; }
.agenda .kind { font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .04em; }
.agenda .due .kind, .agenda .school .kind { color: var(--blue); }
.agenda .hockey .kind { color: var(--hockey); }
.agenda .session .kind { color: var(--warn); }
/* A parent's add and edit forms: a card, two columns, every box full width
   in its column so the rows line up. One column on a phone. */
.parent-edit .edit-fields { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px 16px; }
.parent-edit .edit-fields .wide { grid-column: 1 / -1; }
.parent-edit .edit-field input, .parent-edit .edit-field select { width: 100%; height: 38px; box-sizing: border-box; }
.parent-edit .staff-form { gap: 16px; }
/* Beside the repeat field on a wide screen, under it on a phone. */
.parent-edit .field-note { margin: 0; align-self: end; font-size: 12px; color: var(--ink3); line-height: 1.4; }
@media (max-width: 520px) {
  .parent-edit .edit-fields { grid-template-columns: 1fr; }
}
.edit-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px; }
.edit-actions .secondary { text-decoration: none; }
.remove-edit { margin-top: 14px; display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 20px; }
.remove-edit .quiet { flex-basis: 100%; margin: 0; }
.agenda .item-extras { align-self: center; }
.item-extras { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 4px 10px; }
.agenda .waiting-chip, .agenda .edit-link { font-size: 12px; }
.agenda .edit-link { color: var(--blue); white-space: nowrap; }
/* Buttons, not links: they're how a parent changes the calendar, and as
   underlined text at the foot of a panel they read as fine print. */
.add-links { display: flex; flex-wrap: wrap; gap: 8px; margin: 10px 0 8px; }
.add-links .secondary {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 13px; font-weight: 500; line-height: 1.2; padding: 7px 12px;
  text-decoration: none;
}
.add-links .secondary svg { flex: none; color: var(--blue); }
.add-links a.secondary:hover { border-color: var(--blue); }
/* No course to put a due date under: the button stays, greyed, so the
   choice is still visible, with a "?" saying why. */
.add-links .add-off { display: inline-flex; align-items: center; gap: 6px; }
.add-links .is-disabled { color: var(--ink3); border-style: dashed; cursor: not-allowed; }
.add-links .is-disabled svg { color: var(--ink3); }
.add-panel .note { margin: 0; }
.agenda.calls li { align-items: center; }
.call-actions { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 6px 10px; }
.call-actions form { margin: 0; }
.call-actions .sub { color: var(--ink3); font-size: 12.5px; }
.monthnav { display: flex; gap: 14px; margin-left: auto; font-size: 13px; }
.monthnav a { color: var(--blue); }
.cal-key { list-style: none; display: flex; flex-wrap: wrap; gap: 4px 16px; margin: 0 0 8px; padding: 0; color: var(--ink2); font-size: 12.5px; }
.cal-key li::before { content: ""; display: inline-block; width: 10px; height: 10px; margin-right: 6px; border-radius: var(--radius-s); vertical-align: -1px; }
.cal-key .due::before { background: var(--blue); }
.cal-key .hockey::before { background: var(--hockey); }
.cal-key .session::before { background: var(--warnstripe); }
.cal-wrap .cal { width: 100%; border-collapse: collapse; table-layout: fixed; background: var(--surface); }
.cal-wrap .cal th { padding: 6px 8px; border: 1px solid var(--rule); color: var(--ink3); font-size: 12px; font-weight: 600; text-align: left; }
.cal-wrap .cal td { height: 96px; padding: 5px 6px; border: 1px solid var(--rule); vertical-align: top; overflow: hidden; }
.cal-wrap .cal td.out { background: var(--ice2); }
.cal-wrap .cal td.out .date { color: var(--ink3); }
.cal-wrap .cal .date { display: block; margin-bottom: 3px; font-size: 12px; font-variant-numeric: tabular-nums; color: var(--ink2); }
.cal-wrap .cal td.today { box-shadow: inset 0 0 0 2px var(--blue); }
.cal-wrap .cal td.today .date { color: var(--blue); font-weight: 700; }
.cal-wrap .cal .ev { display: block; margin-top: 2px; padding: 1px 5px; border-left: 3px solid; font-size: 11.5px; line-height: 1.35; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cal-wrap .cal .ev i { font-style: normal; font-weight: 600; }
.cal-wrap .cal .ev.due, .cal-wrap .cal .ev.school { border-color: var(--blue); background: var(--infobg); }
.cal-wrap .cal .ev.hockey { border-color: var(--hockey); background: var(--hockeybg); }
.cal .ev.session { border-color: var(--warnstripe); background: var(--warnbg); }
.cal .ev.done { color: var(--ink3); background: none; }
@media (max-width: 720px) {
  .cal-wrap, .cal-key { display: none; }
  .monthnav { margin-left: 0; width: 100%; }
  .agenda li { grid-template-columns: 5.5em 1fr auto; }
  /* A phone has no room for buttons beside a session: they go under it. */
  .agenda.calls li { grid-template-columns: 5.5em 1fr; }
  .agenda.calls .call-actions { grid-column: 1 / -1; justify-content: flex-start; }
}

/* Safari draws a <select> in its own system style and ignores the padding and
   height set above, so it sits shorter than the text boxes beside it. Turning
   the native look off and drawing the arrow ourselves makes it match Firefox. */
select[name] {
  -webkit-appearance: none; appearance: none; height: 34px; line-height: normal; padding: 7px 28px 7px 9px;
  font: inherit; color: var(--ink); background-color: var(--surface); border: 1px solid var(--rule2); border-radius: var(--radius-s);
  background-repeat: no-repeat; background-position: right 9px center; background-size: 10px 6px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%236E829B' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

/* Safari pads the inside of a date field, which leaves it taller than the text
   boxes and dropdowns beside it. Pin it to the same height and drop the padding. */
input[type="date"], input[type="time"], input[type="datetime-local"] { height: 34px; line-height: normal; }
input[type="date"]::-webkit-datetime-edit, input[type="time"]::-webkit-datetime-edit,
input[type="datetime-local"]::-webkit-datetime-edit { padding: 0; }
input[type="date"]::-webkit-datetime-edit-fields-wrapper, input[type="time"]::-webkit-datetime-edit-fields-wrapper,
input[type="datetime-local"]::-webkit-datetime-edit-fields-wrapper { padding: 0; }

/* Which builds are running, quietly at the foot of every page. */
.build-foot { display: flex; gap: 16px; flex-wrap: wrap; padding-top: 0; padding-bottom: 20px; }

/* ------------------------------------------------------------------------
   The October 2026 look, from the canvas mockup: a side menu for staff,
   cards with soft corners, the 16 drawn as boxes wherever it's counted, and
   large figures. It sits after the rules above and reshapes them rather than
   replacing them, so every class the templates and tests use still means
   what it did. Colours are still the tokens at the top.
   ------------------------------------------------------------------------ */
h1, h2, .count b, .req-total b, .gpa-head b, .figures dd, .cliff .jump { font-family: var(--display); letter-spacing: -.01em; }
.wrap { padding-inline: 20px; }
.primary, .secondary, .danger { padding: 10px 16px; }
.duty .primary { padding: 6px 14px; }
.card, .empty, .notice, .form-error.banner, .duty, .gate, .archived, .calwrap, .code-dialog, .ask { border-radius: var(--radius); }
.card { padding: 28px; }
.card h1 { font-size: 24px; }

/* Every page opens the same way: an optional line above (the roster's
   date), the title, and one or two sentences under it. Sections below use
   h2 at the smaller size, never as a page title. */
.pagehead { margin-top: 26px; }
.pagehead p { margin: 0; color: var(--ink3); font-size: 13px; }
.pagehead h1 { margin: 0; font-size: 28px; font-weight: 700; line-height: 1.05; letter-spacing: -.02em; }
/* The line over the heading gets a little air, so it doesn't sit on the
   heading's caps while the line under it has 8px. */
.pagehead > p:has(+ h1) { margin-bottom: 6px; }
.pagehead h1 + p { margin-top: 8px; max-width: 80ch; font-size: 14.5px; color: var(--ink2); }
.pagehead h1 .chip { margin-left: 8px; vertical-align: 4px; letter-spacing: 0; }
.pagehead h1 .tag { margin-left: 4px; vertical-align: 4px; font-size: 12px; letter-spacing: 0; }
.pagehead + .sec { margin-top: 22px; }
.pagehead + .notice, .pagehead + .form-error.banner { margin-top: 18px; }
main > .notice:first-child:not(.top), main > .form-error.banner:first-child:not(.top) { margin-top: 18px; }

/* Staff pages on a wide screen: the top bar turns into a side menu. Below
   that width, and for a parent or a professional, it stays a bar; on a phone
   a staff member's nav folds into a drawer from the left (below). */
/* A link's icon is a mask over its own text colour, keyed on where it goes,
   so the links themselves stay plain text in the template. */
nav[aria-label="Portal"] a::before {
  content: ""; flex: none; width: 18px; height: 18px; background: currentColor;
  -webkit-mask: var(--ico) center / contain no-repeat; mask: var(--ico) center / contain no-repeat;
}
nav[aria-label="Portal"] a[href="/portal"] { --ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6l1.5 1.5L8 5M4 12l1.5 1.5L8 11M4 18l1.5 1.5L8 17M12 6h8M12 12h8M12 18h8'/%3E%3C/svg%3E"); }
nav[aria-label="Portal"] a[href$="/roster"] { --ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6h16M4 12h16M4 18h10'/%3E%3C/svg%3E"); }
nav[aria-label="Portal"] a[href$="/families"] { --ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 11l9-7 9 7v9H3z'/%3E%3C/svg%3E"); }
nav[aria-label="Portal"] a[href$="/gate"] { --ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 21V4h13l-3 4 3 4H5'/%3E%3C/svg%3E"); }
nav[aria-label="Portal"] a[href$="/review"] { --ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='6.5'/%3E%3Cpath d='M16 16l4.5 4.5'/%3E%3C/svg%3E"); }
nav[aria-label="Portal"] a[href$="/sessions"] { --ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='6' width='12' height='12' rx='2.5'/%3E%3Cpath d='M15 10.5l6-3v9l-6-3'/%3E%3C/svg%3E"); }
nav[aria-label="Portal"] a[href$="/schedule"] { --ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3.5' y='5' width='17' height='15.5' rx='2.5'/%3E%3Cpath d='M3.5 10h17M8 3v4M16 3v4'/%3E%3C/svg%3E"); }
nav[aria-label="Portal"] a[href$="/chat"] { --ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 5.5h16v10.5H10l-4.5 3.5V16H4z'/%3E%3C/svg%3E"); }
nav[aria-label="Portal"] a[href$="/teams"] { --ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='9' cy='8' r='3'/%3E%3Cpath d='M3 19c0-3.3 2.7-5 6-5s6 1.7 6 5'/%3E%3Ccircle cx='17' cy='9' r='2.5'/%3E%3Cpath d='M16.5 14.2c2.6.3 4.5 1.9 4.5 4.8'/%3E%3C/svg%3E"); }
nav[aria-label="Portal"] a[href$="/staff"] { --ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='8' r='3.5'/%3E%3Cpath d='M5 20c1-3.6 3.5-5.5 7-5.5s6 1.900 7 5.500'/%3E%3C/svg%3E"); }
nav[aria-label="Portal"] a { display: inline-flex; align-items: center; gap: 8px; }
nav[aria-label="Portal"] { flex-wrap: wrap; counter-reset: section-key; }
/* The Core16 Portal app's Command-1 to Command-9, shown beside each section
   while Command is held there (portal.js sets the class). Counted in the
   order of the links, which is how the app numbers them, and drawn by the
   stylesheet so the links' own text stays what the app reads for its menu. */
nav[aria-label="Portal"] a { counter-increment: section-key; }
.section-keys nav[aria-label="Portal"] a:nth-of-type(-n+9)::after {
  content: "\2318" counter(section-key);
  flex: none; padding: 0 5px; border: 1px solid var(--rule2); border-radius: 6px;
  background: var(--surface); color: var(--ink2);
  font-size: 11px; font-weight: 500; line-height: 16px; font-variant-numeric: tabular-nums;
}
@media (min-width: 1000px) {
  body.shell { display: grid; grid-template-columns: 236px minmax(0, 1fr); grid-template-rows: 1fr auto; min-height: 100vh; }
  body.shell .topbar { grid-row: 1 / 3; position: sticky; top: 0; height: 100vh; overflow-y: auto; border-bottom: none; border-right: 1px solid var(--rule); }
  body.shell .topbar-in { flex-direction: column; flex-wrap: nowrap; align-items: stretch; gap: 26px; min-height: 100%; box-sizing: border-box; padding: 22px 14px; }
  body.shell .brand { padding: 0 8px; font-size: 17px; }
  body.shell .brand svg { width: 28px; height: 28px; }
  body.shell .brand div { display: flex; flex-direction: column; line-height: 1.2; font-family: var(--display); }
  body.shell .brand span { font-family: var(--sans); font-size: 12px; }
  body.shell nav[aria-label="Portal"] { flex-direction: column; flex-wrap: nowrap; }
  body.shell nav[aria-label="Portal"] a { display: flex; gap: 10px; min-height: 42px; padding: 0 12px; border-bottom: none; border-radius: var(--radius-s); }
  body.shell nav[aria-label="Portal"] a:hover { background: var(--ice2); }
  body.shell nav[aria-label="Portal"] a[aria-current="page"] { background: var(--ice); font-weight: 600; }
  body.shell nav .badge { margin-left: auto; }
  /* Closer together while the numbers show, so Review queue, with its count,
     still fits on one line. */
  body.shell.section-keys nav[aria-label="Portal"] a { gap: 6px; }
  body.shell.section-keys nav[aria-label="Portal"] a::after { margin-left: auto; }
  body.shell.section-keys nav[aria-label="Portal"] a:has(.badge)::after { margin-left: 0; }
  body.shell .me { flex-direction: column; align-items: flex-start; gap: 8px; margin: auto 0 0; padding: 12px; border: 1px solid var(--rule); border-radius: 12px; background: var(--ice2); }
  body.shell .me > span { color: var(--ink); font-weight: 600; }
  body.shell main.wrap, body.shell footer.wrap { grid-column: 2; width: 100%; max-width: 1280px; margin: 0; box-sizing: border-box; padding-inline: 32px; }
}
/* On a widescreen monitor the staff pages take the room, up to a width a row
   can still be read across: the roster's flags sit on one line, so more
   students show at once, Today's cards go four across and the student file's
   two columns both widen. Past that the page stays to the left, beside the
   menu, and sentences keep to a readable length. */
@media (min-width: 1560px) {
  body.shell main.wrap, body.shell footer.wrap { max-width: 1800px; }
  body.shell .sechead p { max-width: 110ch; }
}

/* The roster's totals: four cards, the one that needs something in red. */
.counts { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(150px, 100%), 1fr)); gap: 14px; margin-top: 18px; border: none; background: none; }
.count, .count:last-child { min-width: 0; padding: 18px 20px; border: 1px solid var(--rule); border-radius: var(--radius); background: var(--surface); }
.count b { font-size: 34px; line-height: 1.1; }
.count small { font-size: 14px; color: var(--ink2); }
.count.flagged { background: var(--alarmbg); border-color: var(--alarmrule); }
.count.flagged small { color: var(--alarm); }

/* Sections and tables. */
.sechead h2 { font-size: 20px; }
.tablewrap { border-radius: var(--radius); }
.tablewrap.inner { border-radius: 0; }
th { padding: 10px 12px; font-size: 11.5px; letter-spacing: .04em; text-transform: uppercase; color: var(--ink3); border-bottom-color: var(--rule); }
td { padding: 14px 12px; }
th:first-child, td:first-child { padding-left: 18px; }
.find { margin-bottom: 12px; }
.find input { height: 42px; padding: 0 14px; flex-basis: 380px; border-radius: 12px; }
.find select[name] { height: 42px; border-radius: 12px; }
.chip { border-radius: 8px; padding: 3px 9px; font-size: 12px; }
.who .chip { padding: 3px 10px; font-size: 12.5px; }
.tag { border-radius: 6px; padding: 1px 6px; }

/* A roster row: initials in a ring the colour of the row's worst flag, in
   place of the stripe down the edge, then the 16 as boxes and the GPA large. */
.who-in { display: flex; align-items: flex-start; gap: 12px; }
.who-in > div { min-width: 0; }
.who a { border-bottom: none; font-size: 15px; }
.who a:hover { text-decoration: underline; }
.avatar {
  flex: none; display: grid; place-items: center; width: 38px; height: 38px; box-sizing: border-box;
  border: 2px solid var(--rule); border-radius: 50%; background: var(--ice2);
  color: var(--ink2); font-size: 12px; font-weight: 700;
}
.avatar::before { content: attr(data-initials); }
tr.alarm .avatar, .avatar.alarm { border-color: var(--alarm); background: var(--alarmbg); color: var(--alarm); }
tr.warn .avatar, .avatar.warn { border-color: var(--warnstripe); background: var(--warnbg); color: var(--warn); }
#roster-rows tr.alarm td:first-child, #roster-rows tr.warn td:first-child { box-shadow: none; }
#roster-rows td { vertical-align: middle; }
#roster-rows td.who { vertical-align: top; width: 30%; min-width: 300px; }
td.cores { text-align: left; }
td.cores > span { margin-left: 10px; vertical-align: 8px; }
.core16 { display: inline-block; }
.core16 .on { fill: var(--ink); }
.core16 .off { fill: none; stroke: var(--rule2); stroke-width: 1.5; }
td.gpa { font-family: var(--display); font-size: 22px; font-weight: 600; }
td.gpa .lift { font-family: var(--sans); font-size: 12px; vertical-align: 3px; }
/* The arrow hangs in room every row keeps to the right of its figure, so a
   GPA with one lines up with a GPA without. */
#roster-rows td.gpa { padding-right: 27px; }
#roster-rows td.gpa .lift { display: inline-block; width: 12px; margin: 0 -15px 0 3px; text-align: center; }
/* The roster on an iPad, or in any window too narrow for it: rather than run
   off the side, the table gives up its spare room. Cells sit closer, the
   16 is its count alone without the boxes (the student file still draws
   them), two headings shorten and the rest may wrap.
   Keyed on the table's own space, not the screen's, since the side menu takes
   236px of some screens and none of others. 1100px is the width the table
   needs untouched. Below about 700px it scrolls sideways, as before. */
.tablewrap.fit { container-type: inline-size; }
th .short { display: none; }
@container (max-width: 1100px) {
  .fit table { min-width: 0; }
  .fit th, .fit td { padding-inline: 7px; }
  .fit th:first-child, .fit td:first-child { padding-left: 14px; }
  .fit th:last-child, .fit td:last-child { padding-right: 12px; }
  .fit th:not(.num) { white-space: normal; }
  .fit th { letter-spacing: .02em; vertical-align: bottom; }
  .fit th .full { display: none; }
  .fit th .short { display: inline; }
  .fit td:not(.who) { white-space: nowrap; }
  #roster-rows td.who { width: auto; min-width: 230px; }
  .fit .who-in { gap: 10px; }
  .fit .core16 { display: none; }
  .fit td.cores > span { margin-left: 0; vertical-align: baseline; }
  #roster-rows td.gpa { padding-right: 22px; }
}
/* Narrower still, the largest and smallest iPads held upright. */
@container (max-width: 750px) {
  .fit th, .fit td { padding-inline: 6px; }
  #roster-rows td.who { min-width: 195px; }
  #roster-rows td.gpa { padding-right: 21px; }
}

/* Wider than it needs, on a widescreen monitor: the spare room goes to the
   student, so a row's flags sit side by side rather than stacked. */
@container (min-width: 1400px) {
  #roster-rows td.who { width: 46%; }
}

/* A file: each panel a card of its own rather than a slice of one sheet. */
.file { display: grid; gap: 16px; background: none; border: none; }
.file > * { min-width: 0; }
.filehead, .panel, .panel:last-child { padding: 22px 24px; border: 1px solid var(--rule); border-radius: var(--radius); background: var(--surface); }
.panel h2 { margin-bottom: 8px; font-size: 18px; }
.filehead { display: grid; grid-template-columns: auto minmax(0, 1fr); column-gap: 18px; align-items: center; }
.filehead > * { grid-column: 2; }
.filehead > .avatar { grid-column: 1; grid-row: 1; }
.avatar.big { width: 60px; height: 60px; font-family: var(--display); font-size: 21px; }
.filehead h1 { font-size: 34px; font-weight: 700; line-height: 1.1; letter-spacing: -.02em; }
.filehead .meta { grid-column: 1 / -1; gap: 8px; margin-top: 16px; }
.filehead .meta > div { padding: 6px 12px; border-radius: var(--radius-s); background: var(--ice2); }
.filehead .meta .meta-action { margin-left: 6px; font-weight: 400; font-size: 11.5px; color: var(--ink3); text-decoration: underline; }
.filehead .meta .meta-action:hover { color: var(--ink); }
.verdict { padding: 18px 20px; border-radius: 14px; }
.verdict > b { font-family: var(--display); font-size: 19px; }
.verdict .raised li { border-radius: var(--radius-s); }
.req-total b, .gpa-head b { font-size: 56px; }
.core-slots { max-width: 720px; gap: 18px 32px; }
.core-slots svg { height: 38px; }
.cliff { border-radius: 12px; padding: 14px 16px; }
/* The student file on a wide screen: the record on the left, and beside it
   what a call needs (the GPA, the log, the family's documents). Below that
   width it is one column, and the two columns' panels are interleaved into
   the order of the file's "On this page" links: read in template order, the
   whole left column (ending in Manage) came before the GPA and the log.
   A panel missing here goes after the listed ones, never above them. */
.file-cols, .file-main, .file-side { display: grid; gap: 16px; align-content: start; min-width: 0; }
.file-main > *, .file-side > * { min-width: 0; }
@media (max-width: 1239.98px) {
  .file-main, .file-side { display: contents; }
  .file-main > *, .file-side > * { order: 50; }
  #ten-seven { order: 1; }
  #requirements { order: 2; }
  #gpa { order: 3; }
  #cliffs { order: 4; }
  #courses { order: 5; }
  #questions { order: 6; }
  #calls { order: 7; }
  #contacts { order: 8; }
  #documents { order: 9; }
  #agreements { order: 10; }
  #sessions { order: 11; }
  #ask-core16 { order: 12; }
  #timeline { order: 13; }
  #manage { order: 99; }
}
@media (min-width: 1240px) {
  .file-cols { grid-template-columns: minmax(0, 1.85fr) minmax(340px, 1fr); align-items: start; }
  .file-side .time li { grid-template-columns: 1fr; gap: 2px; }
  .file-side .gpa-head b { font-size: 64px; }
}
.back, .back:hover { margin: 16px 0 0; padding: 8px 0; border: none; background: none; color: var(--ink2); }
.back:hover { color: var(--ink); }
a.primary, a.secondary { display: inline-flex; align-items: center; text-decoration: none; }
.filehead { grid-template-columns: auto minmax(0, 1fr) auto; }
.filehead > .file-actions { grid-column: 3; grid-row: 1; display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 10px; margin: 0; }
/* Keyed on the file's own width, not the screen's: the side menu takes 236px
   of some screens, and the name wrapped beside the buttons on an iPad. */
.file { container-type: inline-size; }
@container (max-width: 900px) {
  .filehead > .file-actions { grid-column: 1 / -1; grid-row: auto; justify-content: flex-start; margin-top: 14px; }
}
/* What needs doing, as a banner: a square in the flag's colour with its
   sign, then the sentence. The sign is a mask, like the menu's icons. */
.verdict { position: relative; padding: 20px 22px 20px 84px; min-height: 44px; }
.verdict > b { font-size: 22px; line-height: 1.25; }
.verdict::before { content: ""; position: absolute; left: 22px; top: 20px; width: 44px; height: 44px; border-radius: 12px; background: var(--ok); }
.verdict.alarm::before { background: var(--alarm); }
.verdict.warn::before { background: var(--warnstripe); }
.verdict::after {
  content: ""; position: absolute; left: 33px; top: 31px; width: 22px; height: 22px; background: var(--surface);
  --sign: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7.5'/%3E%3C/svg%3E");
  -webkit-mask: var(--sign) center / contain no-repeat; mask: var(--sign) center / contain no-repeat;
}
.verdict.alarm::after, .verdict.warn::after { --sign: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 4l9 16H3z'/%3E%3Cpath d='M12 10v4.5M12 17.5v.1'/%3E%3C/svg%3E"); }
@media (max-width: 600px) {
  .verdict { padding: 16px; }
  .verdict::before, .verdict::after { display: none; }
}
/* The file's boxes are larger than a parent's, with each course's code
   under the box it fills. */
#requirements .core-slots { max-width: none; }
#requirements .core-slots svg { width: auto; height: auto; }
.core-slots text { fill: var(--ink2); font-family: var(--mono); font-size: 6.5px; text-anchor: middle; }
@media (max-width: 600px) {
  .filehead, .panel, .panel:last-child { padding: 16px; }
  .pagehead h1 { font-size: 24px; }
}

/* A parent's page. The summary is the one dark card: the 16 as the Core16
   mark draws it, four by four, with the count beside it. The GPA, pace and
   review rows are cards of their own, beside it when there's room. */
.child > .sechead h2 { font-size: 40px; font-weight: 700; line-height: 1.05; letter-spacing: -.02em; }
.child > .sechead p { flex-basis: 100%; font-size: 14.5px; color: var(--ink2); }
.status-row, .status-side, .child-cols, .child-main, .child-side { display: grid; gap: 16px; align-content: start; min-width: 0; }
.status-row > *, .status-side > *, .child-main > *, .child-side > * { min-width: 0; }
.child .status {
  display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 10px 36px; align-content: center; align-items: center;
  margin: 0; padding: 28px; border-radius: 24px; background: var(--hero); border-color: var(--hero); color: var(--onhero);
}
.child .status:not(:has(*)) { display: none; }
.child .status > * { grid-column: 2; margin: 0; }
.child .status > .hero-grid { grid-column: 1; grid-row: 1 / span 3; width: min(246px, 100%); height: auto; }
.child .status .req-total { align-items: flex-end; gap: 14px; }
.child .status .req-total b { font-size: 84px; letter-spacing: -.03em; }
.child .status .req-total p { color: var(--onhero2); font-size: 15px; }
.hero-grid .completed { fill: var(--onhero); }
.hero-grid .in-progress { fill: var(--warnstripe); }
.hero-grid .planned { fill: var(--herorule); }
.hero-grid .edge { fill: none; stroke: var(--herorule); stroke-width: 2; }
.hero-grid .edge.empty { stroke-dasharray: 6 5; }
.hero-grid .tick { fill: none; stroke: var(--hero); stroke-width: 5; stroke-linecap: round; stroke-linejoin: round; }
.hero-key { list-style: none; display: flex; flex-wrap: wrap; gap: 4px 16px; padding: 0; color: var(--onhero2); font-size: 13.5px; }
.hero-key li::before { content: ""; display: inline-block; width: 12px; height: 12px; box-sizing: border-box; margin-right: 7px; border-radius: 4px; vertical-align: -1px; }
.hero-key .completed::before { background: var(--onhero); }
.hero-key .in-progress::before { background: var(--warnstripe); }
.hero-key .planned::before { background: var(--herorule); }
.hero-key .unfilled::before { border: 1.5px dashed var(--onhero2); }
.hero-more { justify-self: start; padding: 8px 0; color: var(--onhero); font-weight: 600; text-underline-offset: 3px; }
.status-side > * { display: flex; align-items: center; justify-content: space-between; gap: 14px; max-width: none; margin: 0; padding: 20px 22px; border: 1px solid var(--rule); border-radius: 20px; background: var(--surface); }
.status-side .gpa-head { align-items: center; }
.status-side .gpa-head b { font-size: 44px; line-height: 1; letter-spacing: -.02em; }
.status-side .gpa-head p { margin-right: auto; }
.status-side .pace-row, .status-side .clock-row { font-size: 14.5px; }
.status-side .pace-row .by { font-size: 13px; }
.status-side .pace-row:has(.chip.warn) { background: var(--warnbg); border-color: var(--warnrule); }
.status-side .pace-row:has(.chip.warn) .by { color: var(--warn); }
.status-side .chip { padding: 3px 12px; border-radius: 10px; font-size: 13px; font-weight: 600; white-space: nowrap; }
@media (min-width: 940px) {
  .status-row { grid-template-columns: minmax(0, 3fr) minmax(300px, 2fr); align-items: stretch; }
  .status-side { align-content: stretch; grid-auto-rows: 1fr; }
  .child-cols { grid-template-columns: minmax(0, 3fr) minmax(300px, 2fr); align-items: stretch; }
  /* The two columns end level: the bottom panel of the shorter one grows.
     On the right that is the one before the calendar panel, which is last
     in the page and drawn first (below). */
  .child-main, .child-side { display: flex; flex-direction: column; }
  .child-main > :last-child, .child-side > :nth-last-child(2), .child-side > :only-child { flex: 1 0 auto; }
}
@media (max-width: 620px) {
  .child .status { grid-template-columns: minmax(0, 1fr); }
  .child .status > *, .child .status > .hero-grid { grid-column: 1; grid-row: auto; }
  .child .status > .hero-grid { width: 180px; }
  .child .status .req-total b { font-size: 64px; }
  .child > .sechead h2 { font-size: 32px; }
}
/* Which student, for a family with several: one is shown at a time. */
.child-tabs { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 24px; }
.child-tabs[hidden] { display: none; }
.child-tabs button {
  min-height: 44px; padding: 0 18px; border: 1px solid var(--rule2); border-radius: 22px;
  background: none; color: var(--ink2); font: inherit; font-size: 15px; font-weight: 500; cursor: pointer;
}
.child-tabs button:hover { color: var(--ink); border-color: var(--ink2); }
.child-tabs button[aria-pressed="true"] { color: var(--onink); background: var(--ink); border-color: var(--ink); font-weight: 600; }
/* The same count as the Ask Core16 button's, for a child who isn't showing. */
.child-count {
  display: inline-grid; place-items: center; box-sizing: border-box; min-width: 20px; height: 20px;
  margin-left: 8px; padding: 0 5px; vertical-align: 1px;
  font-size: 12px; font-weight: 700; line-height: 1; color: var(--onalarm); background: var(--alarm); border-radius: 10px;
}
.child-count[hidden] { display: none; }
/* What's due: plain rows, since everything in this list is school work. */
.child .panel { border-radius: 24px; }
.child .panel h2 { font-size: 22px; }
.child-main .agenda { max-width: none; }
.child-main .agenda li { grid-template-columns: 6.5em minmax(0, 1fr) auto; align-items: center; margin: 0; padding: 12px 0; border-left: none; border-bottom: none; border-top: 1px solid var(--ice); border-radius: 0; font-size: 15px; }
.child-main .agenda em { font-size: 13.5px; }
.agenda .edit-link { padding: 6px 4px; font-size: 14px; font-weight: 600; text-decoration: none; }
.agenda .edit-link:hover { text-decoration: underline; }
/* A parent's report-card list: the mark where a date goes elsewhere, so what's
   missing shows down one column. Words as well as colour say which is which. */
.marks-count { margin: 10px 0 0; font-size: 14px; font-weight: 600; }
.agenda.marks .entered { border-left-color: var(--ok); }
.mark-figure { font: 500 15px var(--mono); overflow-wrap: anywhere; }
.agenda.marks .missing .mark-figure { font: 400 13px var(--sans); color: var(--ink2); }
.chip.today { color: var(--onhero); background: var(--hero); border-color: var(--hero); font-weight: 600; }
/* What a parent can add: the calendar buttons first, stacked, the usual one
   filled. */
.child-side .add-panel:last-child { order: -1; }
.child-side .add-links { flex-direction: column; align-items: stretch; }
.child-side .add-links .secondary, .child-side .add-links .add-off { min-height: 48px; box-sizing: border-box; padding: 0 16px; border-radius: 14px; font-size: 15px; font-weight: 600; }
.child-side .add-links .add-off { padding: 0; }
.child-side .add-links .add-off .secondary { flex: 1; }
.child-side .add-links a[href$="/hockey/new"] { order: -1; color: var(--onink); background: var(--ink); border-color: var(--ink); }
.child-side .add-links a[href$="/hockey/new"] svg { color: inherit; }
.child-side .add-links a.secondary[href$="/documents"] { justify-content: center; }
.week-head { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 18px; }
.week-head h2 { margin: 0 auto 0 0; }
.week-head a { font-weight: 600; }
.week-key { list-style: none; display: flex; flex-wrap: wrap; gap: 4px 14px; margin: 0; padding: 0; color: var(--ink2); font-size: 13px; }
.week-key li::before { content: ""; display: inline-block; width: 10px; height: 10px; margin-right: 6px; border-radius: 3px; vertical-align: -1px; }
.week-key .due::before { background: var(--blue); }
.week-key .hockey::before { background: var(--hockey); border-radius: 50%; }
.week-key .session::before { background: var(--warnstripe); }
/* This week, a day to a tile; today is the dark one. */
.week-days { list-style: none; margin: 12px 0 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(min(128px, 100%), 1fr)); gap: 10px; }
.week-days li { display: flex; flex-direction: column; gap: 7px; min-height: 132px; padding: 12px; border-radius: 14px; background: var(--ice2); }
.week-days .dow { color: var(--ink3); font-size: 12.5px; }
.week-days .date { font-family: var(--display); font-size: 24px; font-weight: 600; line-height: 1; }
/* The ring is what marks it in dark mode, where the card and the tiles are one colour. */
.week-days li.today { background: var(--hero); color: var(--onhero); box-shadow: inset 0 0 0 2px var(--blue); }
.week-days li.today .dow { color: var(--onhero2); }
.week-days .ev { padding: 6px 9px; border-radius: 9px; font-size: 12.5px; line-height: 1.3; }
.week-days .ev i { font-style: normal; font-weight: 600; }
.week-days .ev em { display: block; font-style: normal; }
.week-days .ev.due, .week-days .ev.school { background: var(--infobg); color: var(--blue); }
.week-days .ev.hockey { background: var(--hockeybg); color: var(--hockey); }
.week-days .ev.session { background: var(--warnbg); color: var(--warn); }
.week-days .ev.done { opacity: .65; }
/* An event a parent can change is a link to its form, in the week and in the month grid. */
a.ev { color: inherit; text-decoration: none; }
a.ev:hover { text-decoration: underline; }
.week-days a.ev:hover { box-shadow: inset 0 0 0 1.5px currentColor; text-decoration: none; }
.week-days .none { color: var(--ink3); font-size: 12.5px; }
@media (max-width: 720px) { .week-days li { min-height: 0; } }
.agenda li { border-radius: 0 8px 8px 0; }
.add-links .secondary { padding: 10px 14px; font-size: 14px; }
.cal-wrap { border-radius: var(--radius); }

/* A professional's page: the next session as the one dark card. */
.next-call {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 18px 32px;
  margin-bottom: 14px; padding: 28px; border-radius: 24px; background: var(--hero); color: var(--onhero);
}
.next-call p { margin: 0; }
.next-call .eyebrow { color: var(--onhero2); font-size: 13px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; }
.next-call .when { margin: 6px 0 8px; font-family: var(--display); font-size: 34px; font-weight: 700; line-height: 1.1; letter-spacing: -.02em; }
.next-call .with { font-size: 16px; }
.next-call .topic { margin-top: 6px; color: var(--onhero2); font-size: 15px; max-width: 60ch; }
.next-call .next-action form { margin: 0; }
.next-call .next-action .bad, .next-call .next-action .quiet { display: inline-block; padding: 8px 14px; border-radius: 12px; background: var(--surface); }
.next-call .next-action .primary { min-height: 48px; padding: 0 22px; border-radius: 14px; background: var(--onhero); color: var(--hero); font-size: 16px; }
.weeknav, .calgo { align-items: center; }
.calwrap { border-radius: var(--radius); }
@media (max-width: 600px) {
  .next-call { padding: 20px; }
  .next-call .when { font-size: 26px; }
}

/* The documents list sits in the file's narrow column, so it gives up the
   width every other table asks for, puts who sent a file under its name, and
   keeps Open and Delete on one line. Last, so the rules above don't win. */
table.tbl { min-width: 0; margin-bottom: 16px; }
table.tbl td { vertical-align: middle; }
table.tbl td:first-child { white-space: nowrap; }
table.tbl td .by { display: block; color: var(--ink3); font-size: 12.5px; }
table.tbl td:last-child { text-align: right; white-space: nowrap; }
table.tbl td:last-child form { display: inline; margin-left: 10px; }

/* An advisor's marks sheet (marks.html): one narrow table per grade, a short
   box per mark. After table.tbl's rules, which it builds on. */
.marks-sheet { max-width: 760px; }
.marks-sheet h1 { margin: 0 0 10px; font-size: 20px; font-weight: 600; }
.marks-sheet .staff-form { max-width: none; }
.marks-sheet .marks-files { margin: 14px 0 22px; padding-bottom: 6px; border-bottom: 1px solid var(--rule); }
.marks-sheet .marks-files h2 { margin: 0 0 8px; }
table.tbl.marks { width: 100%; margin-bottom: 4px; }
table.tbl.marks td:first-child { white-space: normal; }
table.tbl.marks td:first-child label { display: inline; font-size: inherit; color: var(--ink); font-weight: 500; }
table.tbl.marks td:last-child { text-align: left; }
table.tbl.marks input[type="text"] { width: 6.5em; }
table.tbl.marks .field-error { display: block; margin-top: 4px; white-space: normal; }
.marks-sheet .marks-date { max-width: 320px; }
.marks-entry { margin: 0 0 14px; display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; }
.marks-entry .secondary { text-decoration: none; padding: 6px 12px; border-radius: var(--radius); }
/* The same three columns in every grade's table, so the boxes line up. */
table.tbl.marks { table-layout: fixed; }
table.tbl.marks th:nth-child(2) { width: 160px; }
table.tbl.marks th:nth-child(3) { width: 150px; }
table.tbl.marks td { padding-top: 8px; padding-bottom: 8px; }
table.tbl.marks.new td:first-child input { width: 100%; box-sizing: border-box; }
table.tbl.marks td:first-child .linkbtn { margin-left: 10px; font-size: 12px; }
/* The unlisted-course rows have seven columns, so they size to their boxes
   and scroll sideways on a narrow screen. */
table.tbl.marks.other { table-layout: auto; }
table.tbl.marks.other th:nth-child(n) { width: auto; }
table.tbl.marks.other td { padding-left: 6px; padding-right: 6px; white-space: normal; }
table.tbl.marks.other td:first-child { white-space: normal; }
table.tbl.marks.other input[type="text"] { width: 100%; min-width: 5em; box-sizing: border-box; }
table.tbl.marks.other select { max-width: 9.5em; }
.marks-sheet { max-width: 900px; }
/* Room for a code beside the list arrow a suggesting box grows. */
table.tbl.marks.other input[list] { min-width: 8em; }
/* A document a parent reads and signs (agreement.html). The text is set for
   reading, a little larger than the portal's forms. */
.agreement { max-width: 720px; }
.agreement h1 { margin: 2px 0 10px; }
.agreement-for { margin: 0; color: var(--ink3); font-size: 12.5px; }
.agreement-text { margin: 14px 0 18px; padding: 16px 18px; border: 1px solid var(--rule); border-radius: var(--radius); }
.agreement-text h2 { margin: 16px 0 4px; font-size: 14.5px; }
.agreement-text h2:first-child { margin-top: 0; }
.agreement-text p { margin: 0 0 8px; font-size: 14.5px; line-height: 1.55; max-width: 68ch; }
.agreement-sign { margin: 0 0 16px; padding-top: 14px; border-top: 1px solid var(--rule); }
.agreement-sign h2 { margin: 0 0 6px; font-size: 15px; }
.agreement-signed { margin: 18px 0; padding: 18px 20px; background: var(--okbg); border: 1px solid var(--okrule); border-radius: var(--radius); }
.agreement-signed h2 { margin: 0 0 6px; font-size: 22px; color: var(--ok); }
.setup-sent { margin: 0 0 18px; padding: 16px 18px; background: var(--okbg); border: 1px solid var(--okrule); border-radius: var(--radius); }
.setup-sent h2 { margin: 0 0 4px; font-size: 18px; color: var(--ok); overflow-wrap: anywhere; }
.setup-sent p { margin: 0; color: var(--ink); }
.setup-documents { margin: 0 0 18px; padding: 16px 18px; border: 1px solid var(--rule); border-radius: var(--radius); }
.setup-documents h2 { margin: 0 0 4px; font-size: 18px; }
.setup-documents p { margin: 0 0 6px; color: var(--ink); }
.setup-documents p:last-child { margin-bottom: 0; }
.card .agreement-signed-note { margin: 0 0 14px; font-size: 16px; line-height: 1.45; color: var(--ink); }
.card .agreement-signed-copy { margin: 10px 0 0; font-size: 13px; color: var(--ink2); }
.agreement-continue { margin: 18px 0 0; display: flex; justify-content: flex-end; }
.agreement-optional { margin: 18px 0 0; padding: 16px 18px; border: 1px solid var(--rule); border-radius: var(--radius); }
.agreement-optional h2 { margin: 0 0 6px; font-size: 18px; }
.agreement-optional-head { display: flex; align-items: center; gap: 10px; }
.agreement-optional-head img { flex: none; width: 32px; height: 32px; border-radius: 22.5%; }
.agreement-optional p { margin: 0 0 8px; font-size: 14.5px; line-height: 1.5; max-width: 68ch; color: var(--ink); }
.agreement-optional .agreement-optional-later { font-size: 13px; color: var(--ink2); }
.agreement-optional-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 10px; margin-top: 12px; }
.agreement-optional-actions form { margin: 0; }
.agreement-copies { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--okrule); }
.agreement-copies li { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px; padding: 12px 0; border-bottom: 1px solid var(--okrule); }
.agreement-copy-meta { font-size: 13px; color: var(--ink2); }
.agreement-sign label.check { display: flex; gap: 8px; align-items: center; font-size: 14px; font-weight: 400; color: var(--ink); }
.agreement-sign label.check input { width: auto; }
.agreement-sign input[type="text"] { max-width: 360px; }
.agreement-signed dl { margin: 0 0 12px; display: grid; gap: 4px; font-size: 13.5px; }
.agreement-signed dl div { display: grid; grid-template-columns: 110px 1fr; gap: 10px; }
.agreement-signed dt { color: var(--ink3); }
.agreement-signed dd { margin: 0; overflow-wrap: anywhere; }
.to-sign { margin: 24px 0 8px; }
.to-sign h2 { margin: 0 0 12px; }
/* Something still to sign is the one thing on the family page asking the
   parent to act, so it takes the warning palette, as the review row does. */
.to-sign.pending { background: var(--warnbg); border-color: var(--warnrule); }
.to-sign.pending h2 { color: var(--warn); }
.to-sign.pending li > span > a { color: var(--ink); font-weight: 600; }
/* It sits in the file's narrow column, about 370px, which can't hold a third
   column of buttons beside the title: the dropdown and Remind ran out past
   the panel's edge. So each row is a small grid instead, with the actions
   under the title: the dropdown on a line of its own, wide enough to show
   the whole address, then Remind and Withdraw side by side at its height.
   The two forms are display: contents so all three line up as one group.
   In the middle cell the title, the status and who sent it each get a line,
   and the status never breaks in two. The last row has no rule under it,
   since the Send a document form below draws its own. */
#agreements table.tbl, #agreements table.tbl thead, #agreements table.tbl tbody { display: block; }
#agreements table.tbl { margin-bottom: 0; }
#agreements table.tbl tr { display: grid; grid-template-columns: 6.5em minmax(0, 1fr); }
#agreements table.tbl th:last-child { display: none; }
#agreements table.tbl td { vertical-align: top; border-bottom: none; }
#agreements table.tbl tbody tr:not(:last-child) { border-bottom: 1px solid var(--rule); }
#agreements table.tbl td > a:first-child { display: block; }
#agreements table.tbl .chip { display: inline-block; margin: 4px 0 2px; white-space: nowrap; }
#agreements table.tbl td:last-child { grid-column: 2; display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding-top: 0; text-align: left; white-space: normal; }
#agreements table.tbl td:last-child form { display: contents; }
#agreements table.tbl select { flex: 1 1 100%; min-width: 0; max-width: 100%; }
#agreements table.tbl td:last-child .secondary { height: 34px; padding: 0 14px; font-size: 13.5px; }
.sign-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.sign-list li { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 14px; }
.sign-done { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px; }
.sign-done form { margin: 0; }

/* Today (today.html): one card per kind of work waiting, two across where
   there's room. A card's count is the figure; its colour says how loud the
   work is, on the count and a rule down the side rather than across the card,
   so a page of them doesn't read as all alarm. Last in the file so the
   October layer above doesn't reshape it. */
.scope { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 18px; }
.scope a {
  display: inline-flex; align-items: center; min-height: 36px; padding: 0 16px;
  border: 1px solid var(--rule2); border-radius: 18px; color: var(--ink2);
  font-size: 14px; font-weight: 500; text-decoration: none;
}
.scope a:hover { color: var(--ink); border-color: var(--ink2); }
.scope a[aria-current] { color: var(--onink); background: var(--ink); border-color: var(--ink); font-weight: 600; }
.queues { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(380px, 100%), 1fr)); gap: 14px; margin-top: 20px; align-items: start; }
.queue { padding: 18px 20px; border: 1px solid var(--rule); border-left-width: 4px; border-radius: var(--radius); background: var(--surface); }
.queue.alarm { border-left-color: var(--alarm); }
.queue.warn { border-left-color: var(--warn); }
.queue.lead { grid-column: 1 / -1; background: var(--alarmbg); border-color: var(--alarmrule); border-left-color: var(--alarm); }
.queue.lead li, .queue.lead .more { border-top-color: var(--alarmrule); }
.queue.lead .about, .queue.lead li time { color: var(--ink2); }
.queue > header { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.queue h2 { margin: 0; font-size: 18px; }
.queue .n { font-family: var(--display); font-size: 28px; font-weight: 600; line-height: 1; font-variant-numeric: tabular-nums; }
.queue.alarm .n { color: var(--alarm); }
.queue.warn .n { color: var(--warn); }
.queue .about { margin: 4px 0 0; color: var(--ink3); font-size: 12.5px; max-width: 60ch; }
.queue ul { list-style: none; margin: 12px 0 0; padding: 0; }
.queue li { padding: 9px 0; border-top: 1px solid var(--rule); font-size: 14px; }
.queue li > a { color: var(--ink); font-weight: 600; }
.queue li .what { color: var(--ink2); }
.queue li time { color: var(--ink3); font-size: 12.5px; white-space: nowrap; font-variant-numeric: tabular-nums; }
.queue li .chip { white-space: nowrap; }
.queue .more { margin: 0; padding-top: 10px; border-top: 1px solid var(--rule); font-size: 13px; }
.empty.quiet { margin-top: 20px; }

/* A student's pages (student_*.html). */
.code-form { display: grid; gap: 8px; }
.code-form input { font-size: 20px; letter-spacing: .08em; text-transform: uppercase; }
/* Signing in with an emailed code (login.html, login_code.html). An address
   isn't a code: no capitals forced on it, and 16px so an iPhone doesn't zoom. */
.code-form input[type="email"] { font-size: 16px; letter-spacing: normal; text-transform: none; }
.st-tabs { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 4px; margin: 20px 0; padding: 5px; background: var(--surface); border: 1px solid var(--rule2); border-radius: var(--radius); }
.st-tabs a { padding: 11px 8px; border-bottom: 0; border-radius: var(--radius-s); color: var(--ink); font-size: 16px; font-weight: 600; text-align: center; text-decoration: none; white-space: nowrap; }
.st-tabs a:hover { background: var(--ice); }
.st-tabs a[aria-current="page"] { background: var(--ink); color: var(--onink); }
.st-hero {
  display: flex; flex-wrap: wrap; align-items: center; gap: 20px;
  padding: 24px 28px; margin-bottom: 14px; border-radius: var(--radius);
  color: var(--onhero); background: linear-gradient(120deg, var(--hero), #1C4C80 70%, #2B6EA8);
}
.st-hello { flex: 1 1 280px; }
.st-hello h1 { margin: 2px 0 6px; font: 600 32px/1.15 var(--display); }
.st-hello p { margin: 0; color: var(--onhero2); }
.st-hello .st-date { font-size: 13px; letter-spacing: .06em; text-transform: uppercase; }
.st-hello .st-clock { margin-top: 10px; font-size: 13px; }
.st-dial { flex: 0 0 auto; text-decoration: none; }
.st-ring { display: block; width: 136px; height: 136px; }
.st-ring circle { fill: none; stroke-width: 11; stroke-linecap: round; }
.st-ring .track { stroke: rgba(255, 255, 255, .16); }
.st-ring .now { stroke: var(--warnstripe); }
.st-ring .done { stroke: #FFFFFF; }
.st-ring text, .st-gauge text { text-anchor: middle; }
.st-ring .big { fill: var(--onhero); font: 600 30px var(--display); }
.st-ring .small { fill: var(--onhero2); font-size: 10px; }
.st-gauge { display: block; width: 210px; }
.st-gauge path { fill: none; stroke-width: 13; stroke-linecap: round; }
.st-gauge .track { stroke: var(--rule); }
.st-gauge .tick { stroke: var(--ink); stroke-width: 3; }
.st-gauge .big { fill: var(--ink); font: 600 34px var(--display); }
.st-gauge .small { fill: var(--ink3); font-size: 10.5px; }
.st-gauge.above .fill { stroke: var(--ok); }
.st-gauge.below .fill { stroke: var(--alarm); }
.st-gauge.review .fill { stroke: var(--warnstripe); }
.st-hero .st-gauge .track { stroke: rgba(255, 255, 255, .16); }
.st-hero .st-gauge .tick { stroke: #FFFFFF; }
.st-hero .st-gauge .big { fill: var(--onhero); }
.st-hero .st-gauge .small { fill: var(--onhero2); }
.st-hero .st-gauge.above .fill { stroke: #7FD8AC; }
.st-hero .st-gauge.below .fill { stroke: #FF9D92; }
.st-week { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 8px; margin: 0; padding: 0; list-style: none; }
.st-week li { display: grid; justify-items: center; gap: 2px; padding: 10px 4px; border: 1px solid var(--rule); border-radius: var(--radius-s); background: var(--surface); }
.st-week li.today { border-color: var(--blue); box-shadow: inset 0 0 0 1px var(--blue); }
.st-week .dow { color: var(--ink3); font-size: 12px; }
.st-week b { font: 600 20px var(--display); }
.st-week .dots { display: flex; flex-wrap: wrap; justify-content: center; gap: 3px; min-height: 8px; }
.st-week i { width: 8px; height: 8px; border-radius: 50%; }
.st-week i.due, .st-week i.school { background: var(--blue); }
.st-week i.hockey { background: var(--hockey); }
.st-week i.session { background: var(--warnstripe); }
.st-key { margin: 8px 0 12px; }
.st-columns { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 12px; align-items: start; }
.st-columns > div { display: grid; gap: 12px; }
.st-head { margin: 4px 0 12px; font: 600 26px var(--display); }
.st-headrow { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 4px; }
.st-tabs ~ .panel { margin-top: 12px; }
.st-tabs ~ .panel:first-of-type { margin-top: 0; }
.st-list, .st-courses, .st-cliffs, .st-bars, .st-balances { margin: 0; padding: 0; list-style: none; }
.st-item { display: grid; grid-template-columns: 84px 1fr auto; gap: 12px; padding: 10px 0 10px 12px; border-top: 1px solid var(--rule); border-left: 3px solid var(--rule2); }
.st-item:first-child { border-top: 0; }
.st-item.due, .st-item.school { border-left-color: var(--blue); }
.st-item.hockey { border-left-color: var(--hockey); }
.st-item.session { border-left-color: var(--warnstripe); }
.st-when { color: var(--ink3); font-size: 13px; }
.st-when b { color: var(--ink2); }
.st-what em, .st-course em { display: block; color: var(--ink2); font-size: 13px; font-style: normal; }
.st-what .chip { margin-top: 4px; }
.st-actions { display: flex; align-items: center; gap: 10px; font-size: 13px; white-space: nowrap; }
.st-late { border-color: var(--warnrule); background: var(--warnbg); }
.st-waiting { padding: 9px 12px; margin: 0 0 12px; border: 1px solid var(--warnrule); border-radius: var(--radius-s); background: var(--warnbg); }
.st-foot { max-width: none; margin: 14px 0 0; }
.st-courses li { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 8px 16px; padding: 10px 0; border-top: 1px solid var(--rule); }
.st-courses li:first-child { border-top: 0; }
.st-course { flex: 1 1 260px; }
.st-course .st-note { margin-top: 4px; color: var(--warn); }
.st-course-side { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; font-size: 13px; }
.st-status { color: var(--ink3); }
.st-status.completed { color: var(--ok); }
.st-mark { font: 500 15px var(--mono); }
.st-pace { margin: 12px 0 0; }
.st-gpa { display: flex; flex-wrap: wrap; align-items: center; gap: 24px; }
.st-gpa p { margin: 8px 0 0; }
.st-cliffs { display: grid; gap: 8px; justify-items: start; }
.st-cliffs li { padding: 10px 16px; border: 1px solid var(--inforule); border-radius: 20px; background: var(--infobg); color: var(--blue); font-weight: 500; }
.st-bars li { display: grid; grid-template-columns: minmax(120px, 240px) 1fr; align-items: center; gap: 14px; padding: 6px 0; }
.st-bar-label em { margin-left: 8px; color: var(--ink2); font: 500 13px var(--mono); }
.st-bars svg { display: block; width: 100%; height: 12px; }
.st-bars .track { fill: var(--ice); }
.st-bars .fill { fill: var(--blue); }
.st-bars .cut { stroke: var(--surface); stroke-width: .6; }
.st-rink svg { display: block; width: 100%; max-height: 240px; }
.st-rink .bar { fill: var(--hockeybg); stroke: var(--hockey); }
.st-rink .bar.current { fill: var(--hockey); }
.st-rink text { fill: var(--ink3); font-size: 8px; text-anchor: middle; }
.st-rink line { stroke: var(--rule2); }
.st-stats { display: flex; gap: 28px; margin-bottom: 8px; }
.st-stats p { margin: 0; color: var(--ink2); }
.st-stats b { display: block; color: var(--ink); font: 600 28px var(--display); }
.st-balances { display: flex; flex-wrap: wrap; gap: 28px; }
.st-balances li { color: var(--ink2); }
.st-balances b { display: block; color: var(--ink); font: 600 28px var(--display); }
/* Ask Core16: a button in the corner of the window, opening a small chat over the page,
   on a student's pages, a parent's page and every staff page. */
.assistant {
  position: fixed; z-index: 30; right: 20px; bottom: calc(20px + env(safe-area-inset-bottom));
  display: flex; flex-direction: column; align-items: flex-end; gap: 12px;
}
.assistant[hidden], .assistant [hidden] { display: none; }
/* Room to scroll the page's last line out from under the button. */
body:has(.assistant) { padding-bottom: 76px; }
/* The tile from the brand sheet (design/ask-core16), in its own colours in light mode too. */
.assistant-launcher {
  position: relative; display: grid; place-items: center; width: 56px; height: 56px; padding: 0; cursor: pointer;
  color: var(--onhero); background: var(--hero); border: 1px solid var(--herorule); border-radius: 22.5%;
  box-shadow: 0 6px 18px var(--backdrop);
}
.assistant-launcher img { display: block; width: 100%; height: 100%; border-radius: inherit; }
/* Only with a real pointer: a touchscreen leaves :hover on after a tap, as a stuck ring. */
@media (hover: hover) {
  .assistant-launcher:hover { outline: 2px solid var(--blue); outline-offset: 1px; }
}
.assistant-launcher .opened, .assistant-launcher[aria-expanded="true"] .closed { display: none; }
.assistant-launcher[aria-expanded="true"] .opened { display: block; }
.assistant-window {
  display: flex; flex-direction: column; overflow: hidden;
  width: min(380px, calc(100vw - 40px)); height: min(560px, calc(100vh - 116px)); height: min(560px, calc(100dvh - 116px));
  color: var(--ink); background: var(--surface); border: 1px solid var(--rule2); border-radius: var(--radius);
  box-shadow: 0 12px 36px var(--backdrop);
}
.assistant-head {
  display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 12px 12px 12px 16px;
  color: var(--onhero); background: var(--hero); border-bottom: 1px solid var(--rule);
}
.assistant-mark { flex: none; width: 36px; height: 36px; border-radius: 22.5%; }
.assistant-name { flex: 1 1 auto; min-width: 0; }
.assistant-head h2 { margin: 0; font: 600 16px var(--display); color: inherit; }
.assistant-head p { margin: 1px 0 0; color: var(--onhero2); font-size: 12.5px; }
.assistant-collapse {
  display: grid; place-items: center; flex: none; width: 32px; height: 32px; padding: 0; cursor: pointer;
  color: inherit; background: none; border: 0; border-radius: var(--radius-s);
}
.assistant-collapse:hover { outline: 1px solid var(--herorule); }
.assistant-talk { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
.assistant-scroll { position: relative; flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 14px 16px; }
.assistant-scroll h3 { margin: 0 0 10px; font: 600 15px var(--display); }
.assistant-lines { display: grid; gap: 8px; margin: 0 0 14px; padding: 0; list-style: none; }
.assistant-lines b { display: block; font-size: 13.5px; }
.assistant-lines span { color: var(--ink2); font-size: 13px; }
.assistant-intro { margin: 0 0 12px; color: var(--ink2); font-size: 13px; }
.assistant-starters-label { margin: 0 0 6px; color: var(--ink2); font-size: 12px; font-weight: 600; }
.assistant-starters { display: grid; gap: 8px; margin: 0; padding: 0; list-style: none; }
.assistant-starters button {
  width: 100%; padding: 8px 12px; font: inherit; font-size: 13.5px; text-align: left; cursor: pointer;
  color: var(--ink); background: var(--surface); border: 1px solid var(--rule2); border-radius: var(--radius-s);
}
.assistant-starters button:hover { background: var(--ice2); }
.assistant-turns { display: grid; gap: 10px; margin: 0; padding: 0; list-style: none; }
.assistant-turns:empty { display: none; }
.assistant-turns li {
  max-width: 88%; padding: 8px 12px; font-size: 13.5px; white-space: pre-wrap; overflow-wrap: anywhere;
  border-radius: var(--radius-s);
}
.assistant-turns .turn-user { justify-self: end; color: var(--onink); background: var(--ink); }
.assistant-turns .turn-assistant {
  position: relative; justify-self: start; margin-left: 30px; color: var(--ink); background: var(--ice2); border: 1px solid var(--rule);
}
.assistant-turns .turn-assistant::before, .assistant-status::before {
  content: ""; flex: none; width: 22px; height: 22px; background: url("ask-core16.svg") center / contain; border-radius: 22.5%;
}
.assistant-turns .turn-assistant::before { position: absolute; top: 2px; left: -31px; }
.assistant-turns .turn-sent, .assistant-turns .turn-send {
  justify-self: start; margin: -4px 0 0 30px; padding: 0; font-size: 12.5px; background: none; border: 0;
}
/* The latest answer's link stays in view while a long answer is read from its start,
   as a strip across the bottom of the chat, instead of waiting below the answer's end. */
.assistant-turns .turn-send:last-child {
  position: sticky; bottom: -14px; justify-self: stretch; max-width: none;
  margin: -10px -16px -14px; padding: 6px 16px 14px 46px; background: var(--surface);
}
.assistant-turns .turn-sent { color: var(--ink2); }
.assistant-turns .turn-send button { padding: 0; color: var(--blue); font: inherit; text-decoration: underline; background: none; border: 0; cursor: pointer; }
.assistant-confirm { margin: 0 0 8px; font-size: 13px; color: var(--ink); }
.assistant-confirm p { margin: 0 0 6px; }
.assistant-confirm div { display: flex; gap: 8px; }
.assistant-replies { margin: 0 0 12px; }
.assistant-replies h3 { margin: 0 0 8px; }
.assistant-replies ul { display: grid; grid-template-columns: minmax(0, 1fr); gap: 14px; margin: 0; padding: 0; list-style: none; }
.assistant-replies li + li { padding-top: 14px; border-top: 1px solid var(--rule); }
/* The student file's thread (.thread, .bubble) the other way round, at the chat's size. */
.assistant-replies .bubble { max-width: 88%; font-size: 13.5px; }
.assistant-replies .bubble .said { white-space: pre-wrap; }
.assistant-replies .bubble.earlier { font-size: 12.5px; }
.assistant-replies .thread-note { font-size: 12.5px; }
.assistant-replies .acts { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 6px; }
.assistant-replies .acts button { padding: 0; color: var(--blue); font: inherit; font-size: 12.5px; text-decoration: underline; background: none; border: 0; cursor: pointer; }
.assistant-follow-up label { display: block; margin-bottom: 4px; font-weight: 600; }
.assistant-follow-up textarea {
  display: block; width: 100%; box-sizing: border-box; margin-bottom: 6px; padding: 8px 10px;
  font: inherit; font-size: 16px; line-height: 22px; resize: none;
  color: var(--ink); background: var(--surface); border: 1px solid var(--rule2); border-radius: var(--radius-s);
}
/* A count on the corner, as on an app's icon. Over the mark's own "?", because this is news. */
.assistant-count {
  position: absolute; top: -8px; right: -8px; min-width: 24px; height: 24px; padding: 0 6px; box-sizing: border-box;
  display: grid; place-items: center;
  font-size: 13px; font-weight: 700; line-height: 1; color: var(--onalarm); background: var(--alarm);
  border: 2px solid var(--surface); border-radius: 12px;
}
.assistant-count[hidden], .assistant-launcher[aria-expanded="true"] .assistant-count { display: none; }
.assistant-foot { flex: none; padding: 10px 12px 12px; border-top: 1px solid var(--rule); }
.assistant-status, .assistant-problem { margin: 0 0 8px; font-size: 13px; color: var(--ink2); }
.assistant-status { display: flex; align-items: center; gap: 8px; }
.assistant-problem { color: var(--alarm); }
.assistant-form { display: flex; align-items: flex-end; gap: 8px; }
/* 16px because an iPhone zooms the whole page in on a smaller box, and leaves it zoomed.
   One line, which portal.js grows as the question does, up to five as on the phone. */
.assistant-form textarea {
  flex: 1 1 auto; min-width: 0; max-height: 128px; box-sizing: border-box; padding: 8px 10px;
  font: inherit; font-size: 16px; line-height: 22px; resize: none;
  color: var(--ink); background: var(--surface); border: 1px solid var(--rule2); border-radius: var(--radius-s);
}
.assistant-form .primary { padding: 10px 14px; }
.assistant-off { margin-top: 8px; text-align: center; }
.assistant-off button {
  padding: 2px 6px; font: inherit; font-size: 12.5px; color: var(--ink2); text-decoration: underline;
  cursor: pointer; background: none; border: 0;
}
/* Clear of a phone's home bar and rounded corner, which the Portal app runs the page down
   behind. A fixed figure, because env(safe-area-inset-bottom) reads 0 on a page without
   viewport-fit=cover, and asking for that would put every page under the notch sideways. */
@media (max-width: 560px) {
  body:has(.assistant) { padding-bottom: 110px; }
  .assistant { right: 16px; bottom: 50px; }
  .assistant-window { width: calc(100vw - 32px); height: calc(100vh - 134px); height: calc(100dvh - 134px); }
}
/* The notice is read once, top to bottom, and ends in the button: as tall as its words, so
   it scrolls only on a screen too short to hold them. */
.assistant-window:has(> [data-assistant-notice]:not([hidden])) {
  width: min(450px, calc(100vw - 40px));
  height: auto; max-height: calc(100vh - 116px); max-height: calc(100dvh - 116px);
}
@media (max-width: 560px) {
  .assistant-window:has(> [data-assistant-notice]:not([hidden])) {
    max-height: calc(100vh - 134px); max-height: calc(100dvh - 134px);
  }
}
/* The part of the screen a phone's keyboard leaves, worked out in portal.js. */
.assistant.keyboard { top: var(--keyboard-top); bottom: auto; }
.assistant.keyboard .assistant-launcher { display: none; }
.assistant.keyboard .assistant-window { height: var(--keyboard-height); }
@media (prefers-reduced-motion: no-preference) {
  .assistant-window:not(.still) { animation: assistant-in .14s ease-out; }
  @keyframes assistant-in { from { opacity: 0; transform: translateY(8px); } }
}
@media print { .assistant { display: none; } }
@media (max-width: 560px) {
  .st-tabs { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .st-item { grid-template-columns: 1fr; gap: 3px; }
  .st-week { gap: 4px; }
  .st-bars li { grid-template-columns: 1fr; gap: 3px; }
}
@media (prefers-reduced-motion: no-preference) {
  .st-ring .done, .st-ring .now, .st-gauge .fill { transition: stroke-dasharray .6s ease; }
}

/* Show me around makes one more thing in the top bar, which a phone can't fit on a line. */
@media (max-width: 520px) {
  .me { flex-wrap: wrap; justify-content: flex-end; }
  .me > .linkbtn, .me > span, .me form .linkbtn { white-space: nowrap; }
}

/* The walkthrough (tour.js): the whole window, with the card docked at its foot or top. */
.tour {
  position: fixed; inset: 0; width: 100%; height: 100%; max-width: none; max-height: none;
  margin: 0; padding: 0; border: 0; overflow: hidden; background: transparent; color: var(--ink);
}
.tour::backdrop { background: transparent; }
.tour-dim { position: absolute; inset: 0; width: 100%; height: 100%; }
.tour-dim .shade { fill: var(--tourdim); }
.tour-dim .ring { fill: none; stroke: var(--blue); stroke-width: 2; }
.tour-card {
  position: absolute; left: 0; right: 0; bottom: 16px; box-sizing: border-box;
  width: min(520px, calc(100% - 32px)); max-height: calc(100% - 32px); margin-inline: auto; padding: 16px;
  overflow-y: auto; background: var(--surface); border: 1px solid var(--rule); border-radius: 18px;
  box-shadow: 0 8px 28px var(--backdrop);
}
.tour-card.top { top: 16px; bottom: auto; }
.tour-card.corner { left: auto; right: 16px; margin-inline: 0; }
.tour-step[hidden], .tour-skip[hidden], .tour-back[hidden] { display: none; }
.tour-title { display: flex; align-items: center; gap: 10px; min-height: 34px; padding-right: 48px; }
.tour-title img { flex: none; border-radius: 22.5%; }
.tour-title h2 { margin: 0; font: 600 20px var(--display); }
.tour-step p { margin: 10px 0 0; color: var(--ink2); font-size: 14px; line-height: 1.5; }
.tour-skip { position: absolute; top: 22px; right: 16px; color: var(--ink3); }
.tour-foot { display: flex; align-items: center; gap: 12px; margin-top: 14px; }
.tour-dots { display: flex; align-items: center; gap: 4px; flex: 1 1 auto; min-width: 0; margin: 0; padding: 0; list-style: none; }
.tour-dots li { width: 6px; height: 6px; border-radius: 3px; background: var(--rule2); }
.tour-dots li.on { width: 16px; background: var(--ink); }
.tour-next { flex: none; min-width: 74px; height: 38px; padding: 0 16px; cursor: pointer; }
@media (prefers-reduced-motion: no-preference) {
  .tour-card.nudge { animation: tour-nudge .22s ease-out; }
}
@keyframes tour-nudge { 50% { transform: scale(1.03); } }

/* A question sent from Ask Core16, on a student's file. minmax(0, …) because a thread's
   min-content is as wide as its longest bubble unwrapped, which pushed it past the card. */
.asked { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; margin: 0; padding: 0; list-style: none; }
.asked li + li { padding-top: 16px; border-top: 1px solid var(--rule); }
.asked-from { margin: 0 0 8px; color: var(--ink3); font-size: 12.5px; }
/* A chat thread, here and on the family's screen (.assistant-replies). Who is speaking
   decides the colour, the same on both screens; whose screen it is decides the side:
   the reader's own side on the right. */
.thread { display: flex; flex-direction: column; gap: 6px; }
.thread-note { margin: 0; color: var(--ink3); font-size: 12px; }
.bubble { max-width: 85%; padding: 8px 12px; border-radius: 14px; overflow-wrap: anywhere; }
.bubble p { margin: 0; }
.bubble .said { white-space: pre-line; }
.bubble .by { margin-bottom: 2px; color: var(--ink2); font-size: 12px; font-weight: 600; }
.bubble .when { margin-top: 4px; color: var(--ink2); font-size: 12px; }
.bubble.family { color: var(--onink); background: var(--ink); }
.bubble.family .by { color: inherit; opacity: .75; }
/* A shade lighter on the file, where the family's navy matched the Send reply button
   under it and a short message read as one more button (Graham, 2 Nov 2026). The
   contact log's too, so the two threads on the file match. */
.asked .bubble.family, .thread.log .bubble.family { background: var(--ink2); }
.bubble.ask { background: var(--ice2); border: 1px solid var(--rule); }
.bubble.reply { background: var(--replybg); }
.bubble.reply .by { color: var(--blue); }
.bubble.left { align-self: flex-start; border-bottom-left-radius: 4px; }
.bubble.right { align-self: flex-end; border-bottom-right-radius: 4px; }
/* What came before the question: there for context, so quieter than it. */
.bubble.earlier { font-size: 13px; opacity: .85; }
.bubble.earlier + .bubble:not(.earlier) { margin-top: 8px; }
.asked .do { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; }
/* The contact log as the same thread (student.html, log_entry), a day's heading
   between days. Ours are the advisor's reply colour, whatever the channel. */
.thread.log { margin: 0; padding: 0; list-style: none; gap: 8px; }
.thread.log .bubble { max-width: min(85%, 70ch); }
.thread.log .said { max-width: none; margin: 0; }
.thread-day { display: flex; align-items: center; gap: 10px; margin: 10px 0 2px; color: var(--ink3); font-size: 12px; font-variant-numeric: tabular-nums; }
.thread-day:first-child { margin-top: 0; }
.thread-day::before, .thread-day::after { content: ""; flex: 1; border-top: 1px solid var(--rule); }
/* Between two conversations on one day: short and darker than the day's rule, so it doesn't read as a day without its date. */
.thread-break { align-self: center; width: 48px; margin: 6px 0; border-top: 1.5px solid var(--ink); }
/* A family's reply nobody has answered yet (Today's "Replies from families"), ringed
   in the card's colour, and the one Today linked to lit while it's the address's target.
   Scrolled to a third of the way down, so what it answers is still in view above it. */
.thread.log .bubble { scroll-margin-top: 33vh; }
.thread.log .bubble.waiting { box-shadow: 0 0 0 2px var(--warn); }
.thread.log .bubble:target { box-shadow: 0 0 0 3px var(--warn), 0 0 0 7px var(--warnbg); }
.bubble .waiting-mark { margin-bottom: 4px; }
.bubble .waiting-mark .chip { font-weight: 600; }
.file-nav .chip { margin-left: 2px; vertical-align: 1px; }
/* A family's message under the Email form's box when replying, drawn as the email
   draws it (mail.py), and a logged email that quotes one, drawn the same way. */
.email-quote { margin: -2px 0 0; color: var(--ink2); font-size: 14px; }
.email-quote .quote-by { margin: 0 0 6px; }
.email-quote blockquote, .bubble blockquote.quoted { margin: 0; padding: 0 0 0 12px; border-left: 3px solid var(--rule2); white-space: pre-line; overflow-wrap: anywhere; }
.email-quote blockquote { color: var(--ink2); max-height: 14em; overflow: auto; }
.bubble blockquote.quoted { margin-top: 4px; border-left-color: currentColor; opacity: .8; }
.bubble .said.part + .said.part { margin-top: .8em; }
.bubble blockquote.quoted + .said.part { margin-top: .8em; }
/* Reply and No reply needed, under a family's reply. */
.bubble-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.bubble-actions form { margin: 0; }
.bubble-actions .secondary { padding: 5px 12px; font-size: 13px; }
.thread-warn { align-self: flex-start; max-width: 85%; margin: 2px 0 -4px; font-size: 12px; }
.bubble .subject { margin-bottom: 4px; font-weight: 600; }
.bubble .note-line { margin: 2px 0 4px; font-size: 12px; opacity: .8; }
.bubble.family .when { color: inherit; opacity: .7; }
.bubble.corrected-entry { opacity: .7; }
.bubble.ask .log-asked { margin: 0; }
.bubble.ask .log-asked > summary { color: var(--ink2); font-size: 12px; font-weight: 600; }

/* Tabs, for one panel that does a thing several ways (the student file's
   Contact a parent). portal.js unhides the bar and hides all but one panel. */
.tabbar { display: flex; gap: 4px; margin: 8px 0 12px; border-bottom: 1px solid var(--rule); }
.tabbar[hidden] { display: none; }
.tabbar [role="tab"] {
  margin: 0 0 -1px; padding: 7px 12px; background: none; border: 0; border-bottom: 2px solid transparent;
  color: var(--ink2); font: inherit; font-size: 13.5px; font-weight: 500; cursor: pointer;
}
.tabbar [role="tab"][aria-selected="true"] { color: var(--blue); border-bottom-color: var(--blue); font-weight: 600; }
.tab-title { margin: 14px 0 6px; font-size: 13px; }
.tab-title[hidden] { display: none; }
.calls > .notice { margin: 10px 0 0; }
.notice.sent { background: var(--okbg); border-color: var(--okrule); color: var(--ok); font-weight: 500; }

/* The student file, 3 Nov 2026: a tile with nothing in it is hollow, a strip of
   anchors under the header, a warning inside the red banner keeps its own
   colour, the courses table reads by grade and fits a narrow panel, and the
   admin folds share one panel. */
.filehead .meta > div:has(.dash) { background: none; border: 1px dashed var(--rule2); }
.filehead .meta .dash { color: var(--ink3); }
.file-nav { grid-column: 1 / -1; display: flex; flex-wrap: wrap; gap: 4px 18px; margin: 16px 0 0; padding-top: 14px; border-top: 1px solid var(--rule); font-size: 13px; }
.file-nav a { color: var(--ink2); font-weight: 500; text-decoration: none; }
.file-nav a:hover { color: var(--ink); text-decoration: underline; }
.verdict.alarm .issues > li.warn { border-left: 3px solid var(--warnstripe); padding-left: 12px; }
table.courses code { white-space: nowrap; }
table.courses tr.grade-head th { padding: 7px 12px 5px; background: var(--ice2); color: var(--ink3); font-size: 11px; font-weight: 600; letter-spacing: .05em; text-transform: uppercase; text-align: left; border-bottom: 1px solid var(--rule); }
table.courses tr.grade-head + tr.newgrade td { border-top: none; }
table.courses .cat { display: none; }
.tablewrap.fit-courses { container-type: inline-size; }
@container (max-width: 720px) {
  .fit-courses table.courses { min-width: 0; }
  .fit-courses table.courses th:nth-child(4), .fit-courses table.courses td:nth-child(4),
  .fit-courses table.courses th:nth-child(5), .fit-courses table.courses td:nth-child(5) { display: none; }
  .fit-courses table.courses .cat { display: block; margin-top: 2px; color: var(--ink3); font-size: 12px; }
  .fit-courses th, .fit-courses td { padding-inline: 8px; }
  .fit-courses th:first-child, .fit-courses td:first-child { padding-left: 14px; }
}
.manage .fold { padding: 10px 0; border-top: 1px solid var(--rule); }
.manage h2 + .fold { margin-top: 6px; }
.manage .fold > summary h3 { display: inline-block; margin: 0; font-size: 15px; }
.manage .fold[open] > summary { margin-bottom: 4px; }
#sessions .form-fold h4 { margin: 0 0 4px; font-size: 13.5px; }

/* "Before you start": the documents a parent signs before their family page
   (onboarding.py). */
.start-documents .start-student { margin-top: 18px; }
.start-documents h2 { margin: 0 0 8px; font-size: 18px; }
.start-list { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--rule); }
.start-list li { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; padding: 12px 0; border-bottom: 1px solid var(--rule); }
.start-list .start-title { flex: 1 1 220px; font-weight: 600; }

/* Ask Core16 on the student file: where it stands, and how much it's used. */
.ask-card .ask-state { margin: 0 0 6px; }
.ask-card-head { display: flex; align-items: center; gap: 8px; }
.ask-card-head img { flex: none; width: 22px; height: 22px; border-radius: 22.5%; }
.ask-card .ask-footnote { margin: 8px 0 0; font-size: 12.5px; }
.ask-usage { list-style: none; margin: 12px 0 0; padding: 0; border-top: 1px solid var(--rule); }
.ask-usage li { display: grid; gap: 2px; padding: 10px 0; border-bottom: 1px solid var(--rule); font-size: 14px; }
.ask-usage .ask-figures { color: var(--ink); }
.ask-head { color: var(--ink); font-weight: 500; }
.ask-head::before { content: ""; display: inline-block; width: 7px; height: 7px; margin: 0 6px 1px 0; border-radius: 50%; background: var(--ink3); }
.ask-head-on { color: var(--ok); }
.ask-head-on::before { background: var(--ok); }
.ask-head-waiting_parent, .ask-head-waiting_student { color: var(--warn); }
.ask-head-waiting_parent::before, .ask-head-waiting_student::before { background: var(--warn); }
.ask-link { text-decoration: none; }
.ask-link:hover .ask-head { text-decoration: underline; }

/* A team's schedule (team_schedule.html, team_event.html). */
.staff-form fieldset.choices { border: 0; margin: 0; padding: 0; display: grid; gap: 6px; }
.staff-form fieldset.choices legend { font-size: 12.5px; color: var(--ink2); font-weight: 500; padding: 0; margin-bottom: 4px; }
.staff-form fieldset.choices label { display: flex; gap: 8px; align-items: center; font-weight: 400; color: var(--ink); font-size: 14px; }
.cal-wrap .cal .ev.cancelled { text-decoration: line-through; opacity: .6; }
.import-problems { margin: 8px 0 0; padding-left: 20px; }
.import-problems b { margin-right: 6px; }

/* Notes to players (team_event.html, parent.html, student_hockey.html). */
.notes { list-style: none; margin: 0 0 12px; padding: 0; display: grid; gap: 12px; }
.notes > li { border-left: 3px solid var(--hockey); padding: 4px 0 4px 12px; }
.notes > li.old { opacity: .65; border-left-color: var(--rule); }
.note-head { margin: 0; font-size: 13px; }
.note-head span { color: var(--ink2); }
.note-body { margin: 4px 0 0; white-space: pre-line; }
.note-edit summary { cursor: pointer; font-size: 13px; color: var(--blue); }
.note-actions { display: flex; flex-wrap: wrap; gap: 4px 16px; align-items: baseline; margin-top: 4px; }
.note-actions .note-edit[open] { flex-basis: 100%; }
.note-actions form { margin: 0; }
/* A player's page (team_player.html): notes grouped under the game or
   practice they were about. */
.notes.by-event { gap: 18px; }
.note-event { margin: 0 0 6px; font-size: 14px; }
.note-event a { color: inherit; text-decoration: none; }
.note-event a:hover b { text-decoration: underline; }
.note-event > span { display: block; color: var(--ink3); font-size: 12.5px; }
.event-notes { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.event-notes .note-head span { color: var(--ink2); }
.player-school p { margin: 6px 0; }
.who .file-link { font-size: 12px; font-weight: 400; margin-left: 6px; }
/* Its calendar: a filter, games bolder than practices, a tick where the
   player has a note, the chosen one ringed. The list stands in for the grid
   on a phone only. */
.seg { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 10px; }
.seg a { padding: 4px 12px; border: 1px solid var(--rule2); border-radius: 999px; font-size: 13px; color: var(--ink2); text-decoration: none; }
.seg a:hover { border-color: var(--blue); color: var(--blue); }
.seg a[aria-current] { background: var(--blue); border-color: var(--blue); color: var(--surface); font-weight: 600; }
.player-cal .cal td { height: 84px; }
.player-cal .cal .ev { color: var(--ink); text-decoration: none; }
.player-cal .cal a.ev:hover { text-decoration: underline; }
.player-cal .cal .ev.ev-game { font-weight: 600; }
.player-cal .cal .ev.unpickable { color: var(--ink3); background: none; }
.player-cal .cal .ev.picked { box-shadow: inset 0 0 0 2px var(--blue); }
.player-cal .cal .ev.cancelled { text-decoration: line-through; }
.noted { font-style: normal; font-weight: 700; color: var(--ok); margin-right: 3px; }
.player-cal-list { display: none; }
.writing-about { margin: 0 0 10px; }
.writing-about span { color: var(--ink2); }
.writing-about a { margin-left: 8px; font-size: 13px; }
@media (max-width: 720px) {
  .player-cal-list { display: block; }
}
td.standing .chip { white-space: nowrap; }

/* A team's staff chat (team_chat.html): the channels down the side, the
   conversation beside them. When there isn't room for both, the channels sit
   above it, folded into one bar (portal.js). */
.chat-wrap { container-type: inline-size; }
/* The Core16 Portal app's own chat (team_chat_native.html): the page keeps its
   nav and leaves this space, which portal.js sizes to the window and the app
   draws the chat in. The page doesn't scroll, since the app's chat does. */
body.native-chat { overflow: hidden; }
body.native-chat footer.build-foot { display: none; }
.native-chat-slot { min-height: 240px; }
.chat { display: flex; gap: 20px; align-items: flex-start; }
nav.chat-side { display: block; flex: 0 0 260px; background: var(--surface); border: 1px solid var(--rule); border-radius: var(--radius); padding: 14px 12px; position: sticky; top: 16px; max-height: calc(100vh - 32px); overflow: auto; }
.chat-side h2 { font-size: 12px; text-transform: uppercase; letter-spacing: .06em; color: var(--ink3); margin: 6px 8px 6px; }
.chat-side h2 ~ h2 { margin-top: 18px; }
.chat-side h3 { font-size: 12px; color: var(--ink2); margin: 10px 8px 2px; font-weight: 600; }
.chat-side ul { list-style: none; margin: 0; padding: 0; }
/* It's a nav, so undo the top bar's `nav a` padding for every link in it;
   the rows below put back their own. */
nav.chat-side a { padding: 0; border-bottom: 0; font-weight: inherit; }
.chat-side > p.quiet { margin: 4px 8px 0; font-size: 13px; }
.chat-side li a { border: 0; display: flex; align-items: baseline; gap: 6px; padding: 5px 8px; border-radius: var(--radius-s); color: var(--ink2); text-decoration: none; font-size: 14px; }
.chat-side li a:hover { background: var(--ice2); color: var(--ink); }
.chat-side li a[aria-current="page"] { background: var(--ink); color: var(--onink); }
.chat-side li a.unread { color: var(--ink); font-weight: 700; }
.chat-side li a .badge { margin-left: auto; }
.chat-side .chat-when { font-size: 12px; color: var(--ink3); white-space: nowrap; min-width: 66px; }
.chat-side li a[aria-current="page"] .chat-when, .chat-side li a[aria-current="page"] .quiet { color: inherit; opacity: .75; }
.chat-side .note { margin: 10px 8px 0; font-size: 12px; }
.chat-side details { margin: 8px 0 0; }
.chat-side summary { cursor: pointer; padding: 5px 8px; font-size: 14px; color: var(--blue); }
.chat-side .staff-form { padding: 6px 8px; display: grid; gap: 8px; }
.chat-hash { color: var(--ink3); margin-right: 2px; }
/* On a team's chat, for Core16 staff: the way back to their staff room. */
.chat-side .chat-all { margin: 0 0 10px; font-size: 13px; }
/* nav.chat-side is a nav, so the top bar's `nav a` padding would otherwise
   indent this link's first line and not the second. Lined up with the
   channel rows below it, the arrow hanging beside a wrapped line. */
.chat-side .chat-all a { display: flex; gap: 6px; padding: 5px 8px; border: 0; color: var(--blue); }
.chat-side .chat-all a:hover { text-decoration: underline; }
/* "New message", under the direct messages. Lined up with the rows above. */
.chat-side .chat-new-dm { margin: 2px 0 0; font-size: 14px; }
.chat-side .chat-new-dm a { display: block; padding: 5px 8px; border: 0; color: var(--blue); }
.chat-side .chat-new-dm a:hover { text-decoration: underline; }
.chat-main .direct-pick { max-width: 420px; margin: 16px 0 8px; display: grid; gap: 12px; }
/* Room between the page's heading and the chat, as .sec gets. */
.pagehead + .chat-wrap, .notice + .chat-wrap { margin-top: 18px; }
.chat-main { flex: 1 1 0; background: var(--surface); border: 1px solid var(--rule); border-radius: var(--radius); padding: 8px 20px 16px; min-width: 0; }
.chat-log { min-height: 200px; }
/* An event's channel: the coach's notes to players about it, above the talk. */
.chat-notes { margin: 8px 0 4px; padding: 0 0 12px; border-bottom: 1px solid var(--rule); }
.chat-notes summary { cursor: pointer; padding: 6px 0; font-size: 14px; font-weight: 600; }
.chat-notes .notes { margin: 8px 0 8px; max-height: 320px; overflow: auto; }
.chat-notes .note { margin: 0; font-size: 12px; }
.chat-more { text-align: center; margin: 12px 0 0; font-size: 13px; }
.chat-day { display: flex; align-items: center; gap: 10px; font-size: 12px; font-weight: 600; color: var(--ink3); margin: 18px 0 6px; }
.chat-day::before, .chat-day::after { content: ""; flex: 1; border-top: 1px solid var(--rule); }
.chat-msgs { list-style: none; margin: 0; padding: 0; }
.chat-msg { padding: 8px 10px; border-radius: var(--radius-s); }
.chat-msg:hover { background: var(--ice2); }
.chat-msg:target { background: var(--infobg); }
.chat-by { margin: 0; font-size: 13.5px; }
.chat-role { color: var(--ink3); font-size: 12px; }
.chat-by time, .chat-edited { color: var(--ink3); font-size: 12px; }
.chat-body { margin: 2px 0 0; white-space: pre-line; overflow-wrap: anywhere; }
.chat-body a { color: var(--blue); }
.chat-msg.removed .chat-body.quiet { font-style: italic; }
.chat-old { color: var(--ink3); text-decoration: line-through; font-size: 13.5px; }
.chat-history summary { font-size: 12px; color: var(--ink3); cursor: pointer; }
.chat-actions { display: flex; flex-wrap: wrap; gap: 4px 12px; align-items: flex-start; margin-top: 2px; font-size: 12px; opacity: .7; }
.chat-msg:hover .chat-actions, .chat-actions:focus-within { opacity: 1; }
.chat-actions summary { cursor: pointer; color: var(--blue); }
.chat-actions .linkbtn { font-size: 12px; }
.chat-actions .chat-reply-btn { color: var(--blue); }
/* A reply's quote of the message it answers, linked to it. */
.chat-quote {
  display: block; margin: 4px 0 2px; padding: 2px 0 2px 10px; border-left: 3px solid var(--rule2);
  font-size: 13px; color: var(--ink2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  text-decoration: none;
}
.chat-quote:hover { border-left-color: var(--blue); color: var(--ink); }
.chat-quote b { color: var(--ink); font-weight: 600; }
.chat-quote.removed .quiet { font-style: italic; }
/* The composer's "Replying to" bar, over the box. */
.chat-replying {
  flex-basis: 100%; display: flex; align-items: center; gap: 12px; min-width: 0;
  padding: 6px 10px; border-left: 3px solid var(--blue); background: var(--ice2);
  border-radius: var(--radius-s); font-size: 13px;
}
.chat-replying[hidden] { display: none; }
.chat-replying p { flex: 1; min-width: 0; margin: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.chat-replying-text { color: var(--ink2); }
.chat-replying .linkbtn { font-size: 12px; flex: none; }
.chat-edit[open] { flex-basis: 100%; }
.chat-edit .staff-form { display: grid; gap: 8px; margin-top: 6px; }
.chat-empty { padding: 40px 0; text-align: center; }
.chat-compose { display: flex; gap: 10px; align-items: stretch; flex-wrap: wrap; border-top: 1px solid var(--rule); padding-top: 14px; margin-top: 10px; }
.chat-compose .grow { flex: 1; min-width: 0; margin: 0; }
.chat-compose textarea {
  display: block; width: 100%; min-height: 48px; font: inherit; font-size: 16px; padding: 9px 11px;
  color: var(--ink); background: var(--surface); border: 1px solid var(--rule2);
  border-radius: var(--radius-s); resize: vertical;
}
.chat-compose button { height: auto; align-self: stretch; }
.chat-compose .form-error { flex-basis: 100%; margin: 0; }
.chat-compose.archived { display: block; }
/* The @-mention list (portal.js), above the composer so the keyboard and the
   page's foot don't cover it. */
.chat-compose:not(.archived) { position: relative; }
.chat-suggest {
  position: absolute; left: 0; bottom: 100%; z-index: 5; margin: 0 0 6px; padding: 4px 0;
  min-width: 240px; max-width: min(420px, 100%); list-style: none;
  background: var(--surface); border: 1px solid var(--rule2); border-radius: var(--radius-s);
  box-shadow: 0 4px 14px rgba(14, 35, 64, 0.14);
}
.chat-suggest[hidden] { display: none; }
.chat-suggest li { display: flex; gap: 10px; align-items: baseline; padding: 6px 12px; cursor: pointer; }
.chat-suggest li[aria-selected="true"] { background: var(--ice); }
.chat-suggest-name { font-weight: 600; color: var(--ink); }
.chat-suggest-job { color: var(--ink3); font-size: 0.85em; margin-left: auto; white-space: nowrap; }
.chat-who { margin: 8px 0 0; font-size: 12px; }
.chat-archive { margin-top: 10px; text-align: right; }
.chat-archive .linkbtn { font-size: 12px; color: var(--ink3); }
/* The bar the channels fold into when there isn't room beside the
   conversation (portal.js adds it). Hidden when they're side by side. */
.chat-side-toggle {
  display: none; width: 100%; align-items: center; gap: 8px; padding: 8px 10px;
  border: 0; border-radius: var(--radius-s); background: none; font: inherit; font-size: 14px;
  font-weight: 600; color: var(--blue); cursor: pointer; text-align: left;
}
.chat-side-toggle:hover { background: var(--ice2); }
.chat-side-toggle .badge[hidden] { display: none; }
.chat-side-toggle .chat-side-chevron { margin-left: auto; font-size: 16px; line-height: 1; transition: transform .15s; }
.chat-side-toggle[aria-expanded="true"] .chat-side-chevron { transform: rotate(180deg); }
/* Too narrow for both side by side, as on a phone, a small window, or beside
   an iPad's side menu: the channels go above the conversation, full width,
   and stop following the page down. With scripts they fold into the bar
   until it's opened, so the conversation starts near the top; without, the
   whole list is there. A container query, as the roster's is, because the
   side menu takes room on some screens and none on others. */
@container (max-width: 720px) {
  .chat { flex-direction: column; align-items: stretch; gap: 12px; }
  nav.chat-side { flex-basis: auto; position: static; max-height: none; }
  nav.chat-side.folding { padding: 4px; }
  nav.chat-side.folding .chat-side-toggle { display: flex; }
  nav.chat-side.folding:not(.open) > :not(.chat-side-toggle) { display: none; }
  nav.chat-side.folding.open > .chat-side-toggle { margin-bottom: 8px; }
  nav.chat-side.folding.open { padding-bottom: 12px; }
}

/* The team page's "Next 7 days": a bar filled green to red by how much school
   work is due this week (coach_summary.Load). The gradient spans the whole
   track, so the colour at the end of the fill is the week's colour. */
.load { display: inline-flex; align-items: center; gap: 10px; white-space: nowrap; }
.load-bar { flex: none; display: block; }
.load-track { fill: var(--rule); }
.load-low { stop-color: var(--loadlow); }
.load-mid { stop-color: var(--loadmid); }
.load-high { stop-color: var(--loadhigh); }
.load-label { font-size: .92em; }
.load-label em { font-style: normal; color: var(--ink3); margin-left: 2px; }
.load-cell[title] { cursor: help; }
/* An ⓘ in a table heading keeps its own case and size, not the heading's caps. */
th .ask-why { text-transform: none; letter-spacing: 0; margin-left: 4px; }
/* A channel the reader has muted: its count stays, quietly. */
.chat-side li a.muted, .chat-side li a.muted.unread { color: var(--ink3); font-weight: inherit; }
.chat-side li a.muted .badge { background: var(--ice2); color: var(--ink3); }
.chat-side .chat-muted { font-size: 11px; color: var(--ink3); }
.chat-side li a[aria-current="page"] .chat-muted { color: inherit; opacity: .75; }
.chat-mute { margin: 8px 0 0; }
.chat-mute .note { margin: 0; }
/* An @-mention in a chat message, and a stronger one when it's the reader. */
.chat-mention { background: var(--ice2); color: var(--ink); border-radius: 3px; padding: 0 2px; font-weight: 600; }
.chat-mention.chat-mention-me { background: var(--warnbg); color: var(--ink); }
/* Searching a chat: the box at the top of its channels, and the results page. */
.chat-search { margin: 0 8px 10px; }
.chat-search input { width: 100%; font: inherit; font-size: 14px; padding: 6px 10px; border: 1px solid var(--rule); border-radius: var(--radius-s); background: var(--surface); color: var(--ink); }
.chat-search.wide { display: flex; gap: 8px; margin: 12px 0 16px; max-width: 640px; }
.chat-search.wide label { flex: 1; }
.chat-found { list-style: none; margin: 0; padding: 0; max-width: 820px; }
.chat-found li { padding: 12px 0; border-bottom: 1px solid var(--rule); }
.chat-found .chat-body { margin: 4px 0 0; }
.chat-hit { background: var(--warnbg); color: var(--ink); border-radius: 2px; padding: 0 1px; }

/* A team's players on a phone (team.html): a card per player instead of a table
   wider than the screen. Name, school and standing first, then position, grade
   and province under the name, then the school-work figures with their labels.
   The cells keep their classes, so the desktop table is untouched. */
.card-only { display: none; }
@media (max-width: 600px) {
  table.players { min-width: 0; }
  table.players thead {
    position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
  }
  table.players, table.players tbody { display: block; }
  table.players tr {
    display: grid; grid-template-columns: 2.4rem minmax(0, 1fr) auto; column-gap: 8px;
    grid-template-areas:
      "jersey who standing"
      ". overdue overdue"
      ". load load"
      ". next next"
      ". actions actions";
    padding: 14px 14px 14px 10px; border-bottom: 1px solid var(--rule);
  }
  table.players tbody tr:last-child { border-bottom: none; }
  table.players td { display: block; padding: 0; border: none; text-align: left; white-space: normal; }
  table.players .card-only { display: inline; }
  table.players td.jersey { grid-area: jersey; color: var(--ink2); font-weight: 600; }
  table.players td.who { grid-area: who; }
  table.players td.who .meta { display: block; margin-top: 3px; font-size: 13px; font-weight: 400; color: var(--ink2); }
  table.players td.pos, table.players td.grade, table.players td.prov { display: none; }
  table.players td.standing { grid-area: standing; justify-self: end; }
  table.players td.standing .chip { white-space: nowrap; }
  table.players td.overdue { grid-area: overdue; }
  table.players td.load-cell { grid-area: load; }
  table.players td.next { grid-area: next; }
  table.players td.overdue, table.players td.load-cell, table.players td.next {
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    margin-top: 8px; font-size: 13px;
  }
  table.players td.overdue { margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--rule); }
  table.players td[data-label]::before { content: attr(data-label); color: var(--ink3); }
  table.players td.actions { grid-area: actions; margin-top: 10px; }
  table.players td.actions form { margin-left: 0; }
}

/* A phone's top bar in two rows, not three: the brand with Sign out and the
   appearance switch beside it, then the nav on a row of its own. The signed-in
   name goes, since it doesn't fit beside them and the person knows who they
   are. The page under it starts closer to the bar. */
@media (max-width: 600px) {
  .topbar-in { gap: 4px 8px; padding-top: 6px; padding-bottom: 0; min-height: 0; }
  .topbar-in > nav { order: 3; flex-basis: 100%; margin-left: -12px; }
  .brand { gap: 7px; }
  .me > span { display: none; }
  .me { flex-wrap: nowrap; gap: 8px; }
  .theme button { padding-inline: 6px; }
  .back { margin-top: 12px; }
  .pagehead { margin-top: 16px; }
  .back + .pagehead { margin-top: 12px; }
  .pagehead h1 { font-size: 24px; }
  .pagehead + .sec, .sec { margin-top: 18px; }
}

/* A staff phone's nav is a drawer from the left behind a menu button, so the
   page (and the app's native chat) gets the height the nav's row used to
   take. portal.js opens and closes it with body.nav-open. Wider than a phone
   it is the strip or the side menu above, and the button isn't shown. */
.nav-toggle, .nav-scrim, .foot-signout { display: none; }

/* A phone's top bar on one row: the menu button, the brand and the appearance
   switch. Sign out moves to the foot of the page (.foot-signout in base.html). */
@media (max-width: 600px) {
  .topbar-in { flex-wrap: nowrap; }
  .brand { min-width: 0; }
  .brand div { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .me { flex: none; }
  .me .me-signout { display: none; }
  .foot-signout { display: block; flex-basis: 100%; margin: 4px 0 0; font-size: 14px; }
}
@media (max-width: 600px) {
  body.shell .topbar-in { padding-bottom: 6px; }
  body.shell .nav-toggle {
    display: inline-flex; align-items: center; justify-content: center; flex: none;
    width: 40px; height: 40px; margin-left: -8px; padding: 0;
    border: none; border-radius: var(--radius-s); background: none; color: var(--ink); cursor: pointer;
  }
  body.shell .nav-toggle svg { width: 22px; height: 22px; }
  body.shell .topbar-in > nav[aria-label="Portal"] {
    /* Past the bottom edge, and the dim layer below with it: the Portal app
       runs the page behind the home bar without viewport-fit=cover, so
       WebKit's fixed-position box ends above the home bar, and bottom: 0 left
       a strip of page showing under the drawer. The padding keeps the last
       link clear of the overhang. Off the screen in a browser. */
    position: fixed; top: 0; bottom: -120px; left: 0; z-index: 51;
    width: min(280px, 82vw); box-sizing: border-box; margin: 0;
    flex-direction: column; flex-wrap: nowrap; flex-basis: auto; gap: 2px;
    padding: max(16px, env(safe-area-inset-top)) 12px calc(120px + max(16px, env(safe-area-inset-bottom)));
    background: var(--surface); border-right: 1px solid var(--rule);
    box-shadow: 0 0 32px rgba(0, 0, 0, .2);
    overflow-y: auto; overscroll-behavior: contain;
    transform: translateX(-105%); visibility: hidden;
  }
  body.shell nav[aria-label="Portal"] a {
    display: flex; gap: 10px; min-height: 44px; padding: 0 12px;
    border-bottom: none; border-radius: var(--radius-s);
  }
  body.shell nav[aria-label="Portal"] a[aria-current="page"] { background: var(--ice); font-weight: 600; }
  body.shell nav[aria-label="Portal"] .badge { margin-left: auto; }
  body.shell.nav-open nav[aria-label="Portal"] { transform: none; visibility: visible; }
  body.shell.nav-open { overflow: hidden; }
  body.shell.nav-open .nav-scrim {
    display: block; position: fixed; inset: 0 0 -120px; z-index: 50; margin: 0; padding: 0;
    border: none; background: rgba(8, 20, 35, .4); cursor: default;
    -webkit-tap-highlight-color: transparent;
  }
}
@media (max-width: 600px) and (prefers-reduced-motion: no-preference) {
  body.shell .topbar-in > nav[aria-label="Portal"] { transition: transform .22s ease, visibility 0s linear .22s; }
  body.shell.nav-open .topbar-in > nav[aria-label="Portal"] { transition: transform .22s ease; }
}

/* A team's events on a phone: the date, time and links on one line, then the
   event under them at the full width, rather than three narrow columns that
   wrap every detail onto three or four lines. */
@media (max-width: 600px) {
  .agenda.team-agenda li {
    grid-template-columns: 1fr auto;
    grid-template-areas: "when extras" "what what";
    gap: 2px 10px; padding: 8px 8px 8px 10px; align-items: center;
  }
  .agenda.team-agenda .when { grid-area: when; flex-direction: row; gap: 8px; align-items: baseline; white-space: nowrap; }
  .agenda.team-agenda .when + span { grid-area: what; }
  /* The title already starts "Cancelled:", so the chip only crowds the links. */
  .agenda.team-agenda .item-extras { grid-area: extras; flex-wrap: nowrap; }
  .agenda.team-agenda .item-extras .chip.warn { display: none; }
  .agenda.team-agenda .edit-link { padding-block: 2px; }
}

/* The player cards, tighter on a phone: less padding, and the name's lines
   and the figures sit closer together. */
@media (max-width: 600px) {
  table.players tr { padding: 10px 12px 10px 10px; }
  table.players td.who { line-height: 1.3; }
  table.players td.who .meta { margin-top: 1px; font-size: 12.5px; }
  table.players td.overdue, table.players td.load-cell, table.players td.next { margin-top: 3px; line-height: 1.35; }
  table.players td.overdue { margin-top: 8px; padding-top: 7px; }
  table.players td.actions { margin-top: 6px; }
}

/* A team's event list on a phone: no blank band above and below it inside
   its card. */
@media (max-width: 600px) {
  .agenda.team-agenda { margin: 0; }
  .agenda.team-agenda li:last-child { margin-bottom: 0; }
  .panel:has(> .agenda.team-agenda:first-child) { padding: 6px 8px; }
}

/* The banner on a server that isn't production (SERVER_LABEL, base.html).
   The same in light and dark, so it never blends in. */
.server-label { background: #B45309; color: #FFFFFF; text-align: center; font-size: 13px; font-weight: 600; padding: 4px 16px; letter-spacing: .02em; }
