/* Pottery Studio — the front end's one stylesheet (spec §4.3).
 *
 * Direction: a studio daybook. Warm paper and fired clay in the light theme,
 * a kiln-dark umber in the dark one; an old-style serif for the things a
 * teacher reads at arm's length (the date, the slot) and the phone's own sans
 * for everything they tap. No web fonts: the app must open on a bad signal.
 *
 * Rules this file keeps, each from §4.3 / §4.6:
 *  - Every colour is a token on :root, redefined for dark mode, and EVERY
 *    text element gets an explicit colour — inherited defaults are what give
 *    dark-on-dark text on a phone in dark mode.
 *  - The shell is pinned to the viewport and only .pane scrolls; html and
 *    body carry the page colour in both themes with overscroll-behavior:
 *    none, so an iOS rubber-band never shows a white band.
 *  - 100dvh with a 100vh fallback; safe-area padding on all four edges.
 *  - Tap targets are at least 44px; nothing changes size on state change.
 *  - Table columns drop by data-priority: 3 below 1366px, 2 below 1024px.
 */

/* ---------- tokens ---------- */

:root {
  color-scheme: light dark;

  /* --bg and --accent are the manifest's background_color and theme_color
     (frontend/pwa.py); a test holds them equal. */
  --bg: #f7f1e8;
  --surface: #fffcf7;
  --surface-sunk: #efe6da;
  --text: #2b211b;
  --text-quiet: #5c4d42;
  --rule: #d8cbbb;
  --rule-strong: #b9a794;
  --accent: #a34126;
  --on-accent: #ffffff;
  --accent-soft: #f3dfd4;
  --link: #8f3a20;
  --topbar-bg: #2b211b;
  --topbar-text: #f7f1e8;
  --focus: #1d5a9e;
  --table-row-hover: #efe6da;

  --info: #1d5a9e;
  --warning: #8a4a00;
  --error: #b0261c;
  --error-soft: #fbe4e0;
  /* Text on --error-soft / --warning-soft. The fill colours above are meant
     for white text on a solid alert; used as text on a soft tint they are
     under 4.5:1 in dark mode, where the tint is dark too (§4.6). */
  --error-text: #b0261c;
  --warning-soft: #fdf0dc;
  --warning-text: #8a4a00;
  --on-alert: #ffffff;
  --success-bg: #e1e9d8;
  --success-text: #284020;

  --closed-bg: #ece4d9;
  /* A session whose capacity was changed by hand: "(usually 4)". */
  --changed: #5b3f8c;
  /* Booking statuses and the week's tags (§4.3): each a text colour on the
     surface and a fill under --on-status, both at least 4.5:1. */
  /* Attendance statuses by what they mean for the money (James, 2026-10-21:
     "Attended free should be red, missed charged should be orange"): green
     paid and came, red came and paid nothing, orange paid and did not come,
     quiet colours for the rest. */
  --st-attended: #2f6b2f;
  --st-booked: #1d5a9e;
  --st-free: #b0261c;
  --st-missed: #a14a00;
  --st-holiday: #6b4c9a;
  --st-skipped: #5c4d42;
  --st-appt: #0f6466;
  --on-status: #ffffff;
  --tag-moved: #a1401f;
  --tag-catch-up: #4a5d0f;
  --tag-expected: #5c4d42;
  /* Away from the usual day (James, 2026-10-21): a tint under --text and the
     status colours, and a strong edge; every pairing at least 4.5:1. */
  --away-bg: #fbe3d3;
  --away-edge: #a1401f;
  --shadow: 0 1px 0 rgba(43, 33, 27, 0.06), 0 6px 18px -10px rgba(43, 33, 27, 0.35);

  --font-ui: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
  --font-read: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua", Georgia, serif;

  --text-base: 1rem;
  --text-small: 0.875rem;
  --text-title: clamp(1.75rem, 1.4rem + 1.6vw, 2.5rem);

  --gutter: 16px;
  --topbar-height: 48px;
  --tap: 44px;
  --radius: 10px;
  --radius-small: 6px;

  /* One colour per weekday, Monday first (James, 2026-10-21: "colour code
     the days to make it easier to read"). Edges and bars only, never text. */
  --day-0: #2f6fb0;
  --day-1: #2e8b57;
  --day-2: #8e44ad;
  --day-3: #c06014;
  --day-4: #b0306a;
  --day-5: #127a7a;
  --day-6: #7a6a12;
}

@media (prefers-color-scheme: dark) {
  :root {
    --error-soft: #3d1c18;
    --error-text: #ff9c8f;
    --warning-soft: #3a2a12;
    --warning-text: #f2b872;
    --day-0: #7fb2ec;
    --day-1: #6fcf97;
    --day-2: #c39be0;
    --day-3: #f0a35e;
    --day-4: #ec7fb0;
    --day-5: #5fc9c9;
    --day-6: #d4c46a;
    --bg: #1c1612;
    --surface: #261f1a;
    --surface-sunk: #15100d;
    --text: #f2e9df;
    --text-quiet: #c7b8aa;
    --rule: #3e332b;
    --rule-strong: #5a4b40;
    --accent: #e0875f;
    --on-accent: #1c1210;
    --accent-soft: #3a2519;
    --link: #f0a27e;
    --topbar-bg: #120d0a;
    --topbar-text: #f2e9df;
    --focus: #8fb8f0;
    --table-row-hover: #332922;

    --success-bg: #26331f;
    --success-text: #d3e6c6;

    --closed-bg: #211b17;
    --changed: #c9b2f0;
    --st-attended: #8fd18f;
    --st-booked: #8fb8f0;
    --st-free: #f0938a;
    --st-missed: #f0b070;
    --st-holiday: #c6a8ef;
    --st-skipped: #c7b8aa;
    --st-appt: #7fd3cf;
    --on-status: #1c1210;
    --tag-moved: #f0a27e;
    --tag-catch-up: #c8d98a;
    --tag-expected: #c7b8aa;
    --away-bg: #4a2616;
    --away-edge: #f0a27e;
    --shadow: 0 1px 0 rgba(0, 0, 0, 0.4), 0 8px 20px -12px rgba(0, 0, 0, 0.8);
  }
}

/* ---------- the pinned shell ---------- */

html,
body {
  height: 100%;
  margin: 0;
  overscroll-behavior: none;
  background: var(--bg);
  color: var(--text);
}

body {
  font: var(--text-base) / 1.5 var(--font-ui);
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

.shell {
  display: flex;
  flex-direction: column;
  height: 100vh; /* fallback for browsers without dvh */
  height: 100dvh;
  overflow: hidden;
  background: var(--bg);
}

/* ---------- top bar: at most 48px, the studio's name and the menu ---------- */

.topbar {
  flex: 0 0 auto;
  position: relative;
  z-index: 20;
  padding: env(safe-area-inset-top) env(safe-area-inset-right) 0 env(safe-area-inset-left);
  background: var(--topbar-bg);
  color: var(--topbar-text);
}

.topbar-inner {
  display: flex;
  align-items: center;
  gap: 8px;
  height: var(--topbar-height);
  padding: 0 4px 0 var(--gutter);
}

.topbar-name {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  font: 600 1.0625rem / 1.2 var(--font-read);
  letter-spacing: 0.01em;
  color: var(--topbar-text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.menu {
  flex: 0 0 auto;
  position: static;
}

.menu-button {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-width: var(--tap);
  height: var(--tap);
  padding: 0 12px;
  border-radius: var(--radius-small);
  list-style: none;
  cursor: pointer;
  color: var(--topbar-text);
  font: 500 var(--text-small) / 1 var(--font-ui);
  -webkit-tap-highlight-color: transparent;
}

.menu-button::-webkit-details-marker {
  display: none;
}

.menu-glyph,
.menu-glyph::before,
.menu-glyph::after {
  display: block;
  width: 16px;
  height: 2px;
  border-radius: 1px;
  background: var(--topbar-text);
}

.menu-glyph {
  position: relative;
}

.menu-glyph::before,
.menu-glyph::after {
  content: "";
  position: absolute;
  left: 0;
}

.menu-glyph::before {
  top: -5px;
}

.menu-glyph::after {
  top: 5px;
}

.menu-word {
  color: var(--topbar-text);
}

.menu[open] > .menu-button {
  background: rgba(255, 255, 255, 0.12);
}

.menu-panel {
  position: absolute;
  top: 100%;
  right: max(8px, env(safe-area-inset-right));
  width: min(18rem, calc(100vw - 16px));
  padding: 8px;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow);
}

.menu-who {
  margin: 4px 8px 8px;
  font-size: var(--text-small);
  color: var(--text-quiet);
  overflow-wrap: anywhere;
}

.menu-panel form {
  margin: 0;
}

.menu-item {
  display: flex;
  align-items: center;
  width: 100%;
  min-height: var(--tap);
  padding: 0 12px;
  border: 0;
  border-radius: var(--radius-small);
  background: transparent;
  color: var(--text);
  font: 500 var(--text-base) / 1.2 var(--font-ui);
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}

.menu-item:hover,
.menu-item:focus-visible {
  background: var(--surface-sunk);
  color: var(--text);
}

.menu-item-button {
  border-top: 1px solid var(--rule);
  border-radius: 0 0 var(--radius-small) var(--radius-small);
  margin-top: 4px;
}

/* ---------- the stage: the scroll pane, and the strip over its foot ---------- */

.stage {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
}

.pane {
  position: absolute;
  inset: 0;
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  padding: 20px max(var(--gutter), env(safe-area-inset-right)) 0
    max(var(--gutter), env(safe-area-inset-left));
  background: var(--bg);
  color: var(--text);
}

/* Room at the foot of the page so the last line clears the message strip and,
   with no save bar below, the home indicator. */
.pane::after {
  content: "";
  display: block;
  height: calc(72px + env(safe-area-inset-bottom));
}

.has-sticky .pane::after {
  height: 72px;
}

/* One centred column at every width; components keep their own margins. */
.page {
  max-width: 44rem;
  margin: 0 auto;
}

.narrow {
  max-width: 26rem;
  margin: 0 auto;
}

/* ---------- type ---------- */

h1,
h2,
h3,
p,
li,
dt,
dd,
td,
th,
label,
legend,
summary,
small,
time,
span {
  color: inherit;
}

p,
li {
  color: var(--text);
}

p {
  margin: 0 0 1rem;
}

a {
  color: var(--link);
  text-underline-offset: 0.18em;
}

a:hover {
  color: var(--text);
}

:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

.page-head {
  margin-bottom: 20px;
}

.eyebrow {
  margin: 0 0 2px;
  font: 600 0.75rem / 1.4 var(--font-ui);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent);
}

@media (prefers-color-scheme: dark) {
  .eyebrow {
    color: var(--accent);
  }
}

.page-title {
  margin: 0;
  font: 600 var(--text-title) / 1.1 var(--font-read);
  letter-spacing: -0.01em;
  color: var(--text);
  overflow-wrap: anywhere;
}

.section-title {
  margin: 0 0 12px;
  font: 600 1.25rem / 1.25 var(--font-read);
  color: var(--text);
}

.lede {
  font-size: 1.0625rem;
  color: var(--text);
}

.when-age {
  display: block;
  font-size: var(--text-small);
  color: var(--text-quiet);
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ---------- buttons ---------- */

.btn {
  display: inline-grid;
  place-items: center;
  min-height: var(--tap);
  min-width: var(--tap);
  padding: 10px 20px;
  border: 2px solid transparent;
  border-radius: var(--radius);
  font: 600 var(--text-base) / 1.2 var(--font-ui);
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background-color 120ms ease, border-color 120ms ease, opacity 120ms ease;
}

/* The label and "Saving…" share one cell, so the button is as wide as the
   longer from the start and the swap moves nothing (§4.6). */
.btn > .btn-label,
.btn > .btn-busy {
  grid-area: 1 / 1;
}

.btn > .btn-busy {
  visibility: hidden;
}

.btn.is-busy > .btn-label {
  visibility: hidden;
}

.btn.is-busy > .btn-busy {
  visibility: visible;
}

.btn.is-guarded {
  pointer-events: none;
  opacity: 0.72;
}

.btn-primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
}

.btn-primary:hover {
  color: var(--on-accent);
  filter: brightness(1.06);
}

.btn-primary:active {
  filter: brightness(0.94);
}

.btn-quiet {
  background: var(--surface);
  border-color: var(--rule-strong);
  color: var(--text);
}

.btn-quiet:hover {
  border-color: var(--accent);
  color: var(--text);
}

.btn-danger {
  background: var(--error);
  border-color: var(--error);
  color: var(--on-alert);
}

.btn-danger:hover {
  color: var(--on-alert);
  filter: brightness(1.06);
}

.btn-danger:active {
  filter: brightness(0.94);
}

/* ---------- forms ---------- */

.form {
  margin: 0;
}

.field {
  margin-bottom: 18px;
}

.field-label {
  display: block;
  margin-bottom: 6px;
  font-weight: 600;
  color: var(--text);
}

.input {
  display: block;
  width: 100%;
  min-height: var(--tap);
  padding: 10px 12px;
  border: 2px solid var(--rule-strong);
  border-radius: var(--radius-small);
  background: var(--surface);
  color: var(--text);
  font: 1.0625rem / 1.3 var(--font-ui); /* ≥16px: iOS does not zoom on focus */
}

.input:focus {
  border-color: var(--accent);
  outline: none;
  box-shadow: 0 0 0 3px var(--accent-soft);
}

.field-error {
  margin: 6px 0 0;
  font-size: var(--text-small);
  font-weight: 600;
  color: var(--error);
}

@media (prefers-color-scheme: dark) {
  .field-error {
    color: #ff9c8f;
  }
}

.field-hint {
  font-size: var(--text-small);
  color: var(--text-quiet);
}

.form-actions .btn {
  width: 100%;
}

/* ---------- alerts: solid, white text (§4.3) ---------- */

.alert {
  margin: 0 0 16px;
  padding: 12px 14px;
  border-radius: var(--radius);
  color: var(--on-alert);
}

.alert p {
  margin: 0;
  font-weight: 600;
  color: var(--on-alert);
}

.alert-info {
  background: var(--info);
}

.alert-warning {
  background: var(--warning);
}

.alert-error {
  background: var(--error);
}

/* ---------- the one message strip (§4.6) ---------- */

.strip-dock {
  position: absolute;
  left: max(8px, env(safe-area-inset-left));
  right: max(8px, env(safe-area-inset-right));
  bottom: calc(8px + env(safe-area-inset-bottom));
  z-index: 10;
  pointer-events: none; /* taps go through, except to the text and the ✕ */
}

.has-sticky .strip-dock {
  bottom: 8px;
}

.strip-toggle {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.strip-toggle:checked + .message-strip {
  display: none;
}

.message-strip {
  display: flex;
  align-items: flex-start;
  max-width: 44rem;
  margin: 0 auto;
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  color: var(--on-alert);
}

.message-strip.tone-info,
.message-strip.tone-debug {
  background: var(--info);
}

.message-strip.tone-warning {
  background: var(--warning);
}

.message-strip.tone-error {
  background: var(--error);
}

/* The commonest kind is the quietest (§4.6). */
.message-strip.tone-success {
  background: var(--success-bg);
  border: 1px solid var(--rule-strong);
  color: var(--success-text);
}

.strip-text {
  flex: 1 1 auto;
  min-width: 0;
  pointer-events: auto;
}

.strip-text > summary {
  display: block;
  min-height: var(--tap);
  padding: 12px 4px 12px 14px;
  list-style: none;
  font-weight: 600;
  line-height: 20px;
  color: inherit;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  cursor: pointer;
}

.strip-text > summary::-webkit-details-marker {
  display: none;
}

.strip-text[open] > summary {
  white-space: normal;
}

.strip-close {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: var(--tap);
  height: var(--tap);
  pointer-events: auto;
  cursor: pointer;
  font-size: 1.125rem;
  color: inherit;
}

/* ---------- software update notice (#182) ---------- */

.update-dock {
  z-index: 20;
}

.update-strip {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  max-width: 44rem;
  margin: 0 auto;
  padding: 8px 12px 8px 16px;
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  background: var(--warning);
  color: var(--on-alert);
  pointer-events: auto;
}

.update-text {
  font-weight: 600;
  font-size: 0.9375rem;
  line-height: 1.3;
  color: var(--on-alert);
}

.update-reload-btn {
  flex: 0 0 auto;
  min-height: 38px;
  padding: 0 16px;
  border-radius: var(--radius-small);
  cursor: pointer;
}

/* ---------- the sticky save bar (§4.3) ---------- */

.sticky-actions {
  flex: 0 0 auto;
  display: flex;
  justify-content: flex-end;
  padding: 10px max(var(--gutter), env(safe-area-inset-right))
    calc(10px + env(safe-area-inset-bottom)) max(var(--gutter), env(safe-area-inset-left));
  border-top: 1px solid var(--rule);
  background: var(--surface);
  color: var(--text);
}

.sticky-actions .btn {
  width: 100%;
  max-width: 44rem;
  margin: 0 auto;
}

/* ---------- Today: session cards ---------- */

.cards {
  display: grid;
  gap: 12px;
  margin: 0 0 24px;
  padding: 0;
  list-style: none;
}

@media (min-width: 700px) {
  .cards {
    grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
  }
}

.cards > li {
  margin: 0;
}

.card {
  position: relative;
  height: 100%;
  padding: 16px 18px 18px;
  border: 1px solid var(--rule);
  border-left: 6px solid var(--accent);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow);
}

.card-slot {
  margin: 0 0 6px;
  font: 600 1.5rem / 1.15 var(--font-read);
  color: var(--text);
}

.card-places {
  margin: 0;
  font-weight: 600;
  color: var(--text-quiet);
}

.card-over {
  border-left-color: var(--warning);
}

.card-places-over {
  display: inline-block;
  padding: 2px 8px;
  border-radius: var(--radius-small);
  background: var(--warning);
  color: var(--on-alert);
}

.card-closed {
  border-left-color: var(--rule-strong);
  background: var(--closed-bg);
  box-shadow: none;
}

.card-closed .card-slot {
  color: var(--text-quiet);
}

.card-closed-why {
  margin: 0;
  color: var(--text);
}

/* ---------- empty states ---------- */

.empty-state {
  margin: 0 0 24px;
  padding: 20px;
  border: 1px dashed var(--rule-strong);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
}

.empty-title {
  margin: 0 0 4px;
  font: 600 1.25rem / 1.3 var(--font-read);
  color: var(--text);
}

.empty-detail {
  margin: 0;
  color: var(--text-quiet);
}

.empty-link {
  margin: 12px 0 0;
}

/* ---------- tables (§4.6) ---------- */

.table-wrap {
  margin: 0 0 24px;
}

.data-table {
  width: 100%;
  border-collapse: collapse;
  background: var(--surface);
  color: var(--text);
  font-size: var(--text-small);
}

.data-table th,
.data-table td {
  padding: 0 10px;
  height: var(--tap);
  border-bottom: 1px solid var(--rule);
  text-align: left;
  vertical-align: middle;
  color: var(--text);
}

.data-table th {
  font-weight: 700;
  background: var(--surface-sunk);
  color: var(--text);
  white-space: nowrap;
}

.data-table td:first-child {
  white-space: nowrap;
}

/* On a phone the name is the widest thing in the table and `nowrap` above
   sizes its column to the longest one — 346px of a 358px pane in the reports,
   which pushed every other column off the side. The name is the content, so it
   wraps rather than being shortened (§4.6). */
@media (max-width: 600px) {
  .data-table td:first-child,
  .data-table td:first-child .cell-link {
    white-space: normal;
    word-break: break-word;
  }

  /* `inline-flex` sizes the link to its text's max-content, so `white-space`
     alone does not make a long name wrap. A block-level flex takes the cell's
     width instead, and `min-width: 0` lets the text inside it break. The
     min-height that makes it a 44px tap target is kept. */
  .data-table td:first-child .cell-link {
    display: flex;
    min-width: 0;
  }

  /* The same `inline-flex` in running prose: "show all 58 “Open session with
     nobody booked or suggested”" is one unbreakable 541px box on a 390px
     screen. A link inside a sentence is inline — and WCAG 2.5.5 exempts it
     from the 44px target, which is why it does not need the flex box. */
  .issue-kinds-list .cell-link,
  .report-kind-note .cell-link,
  .report-note .cell-link {
    display: inline;
    min-height: 0;
    white-space: normal;
  }
}

.data-table tbody tr {
  transition: background-color 120ms ease;
}

.data-table tbody tr:hover,
.data-table tbody tr:focus-within,
table:not(.month-table) tbody tr:hover,
table:not(.month-table) tbody tr:focus-within {
  background: var(--table-row-hover);
}

.data-table tbody tr:hover td.table-empty,
table:not(.month-table) tbody tr:hover td.table-empty {
  background: var(--surface);
}

.data-table .num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.sort-link,
.sort-static,
.cell-link {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  min-height: var(--tap);
  color: var(--text);
}

.sort-link {
  text-decoration: none;
  /* A short heading ("Day", "Slot") is still a control, not a link inside a
     sentence, so WCAG 2.5.5's inline exemption does not cover it: it needs
     the full 44px across as well as down. */
  min-width: var(--tap);
}

.sort-link:hover {
  color: var(--link);
}

.cell-link {
  color: var(--link);
  font-weight: 600;
  white-space: nowrap;
}

.sort-mark {
  display: inline-block;
  width: 1em;
  font-size: 0.75em;
  color: var(--accent);
}

.table-empty {
  color: var(--text-quiet);
}

.table-count {
  margin: 8px 0 0;
  font-size: var(--text-small);
  color: var(--text-quiet);
}

.table-see-all {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  font-weight: 600;
}

/* Column priority: no sideways scroll at iPad widths (§4.6). */
@media (max-width: 1365.98px) {
  .data-table [data-priority="3"] {
    display: none;
  }
}

@media (max-width: 1023.98px) {
  .data-table [data-priority="2"] {
    display: none;
  }
}

/* ---------- Today: the card is the link to attendance ---------- */

.card-link {
  display: block;
  height: 100%;
  border-radius: var(--radius);
  color: var(--text);
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
}

.card-link:hover {
  color: var(--text);
}

.card-link:hover .card,
.card-link:focus-visible .card {
  border-color: var(--accent);
}

.card-link:active .card {
  background: var(--surface-sunk);
}

.card-go {
  margin: 10px 0 0;
  font-weight: 600;
  color: var(--link);
}

/* ---------- attendance (§4.3, screen 2) ---------- */

.session-nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 0 0 12px;
}

.session-nav .btn {
  padding: 8px 14px;
}

.session-nav-next {
  margin-left: auto;
}

.session-line {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 12px;
  margin: 6px 0 0;
  color: var(--text);
}

.session-slot {
  font: 600 1.375rem / 1.2 var(--font-read);
  color: var(--text);
}

.session-places {
  font-weight: 600;
  color: var(--text-quiet);
}

.session-places-over {
  padding: 2px 8px;
  border-radius: var(--radius-small);
  background: var(--warning);
  color: var(--on-alert);
}

.attendance-section {
  margin: 0 0 28px;
}

.section-note {
  margin: -6px 0 12px;
  font-size: var(--text-small);
  color: var(--text-quiet);
}

.list-count,
.search-empty {
  margin: 4px 0 0;
  font-size: var(--text-small);
  font-weight: 600;
  color: var(--text-quiet);
}

.student-row {
  margin: 0 0 12px;
  padding: 12px 12px 14px;
  border: 1px solid var(--rule);
  border-left: 6px solid var(--rule-strong);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
}

.student-row.has-error {
  border-left-color: var(--error);
}

.row-head {
  display: flex;
  align-items: flex-start;
  gap: 8px 12px;
  margin-bottom: 10px;
}

.student-row .student-name {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  font: 600 1.1875rem / 1.25 var(--font-read);
  color: var(--text);
  overflow-wrap: anywhere;
}

.row-link {
  color: var(--link);
}

/* The balance always takes its place, so a row never changes shape (§4.3). */
.row-balance {
  flex: 0 0 auto;
  margin: 0;
  padding: 2px 8px;
  border-radius: var(--radius-small);
  font-size: var(--text-small);
  font-weight: 600;
  line-height: 1.5;
  white-space: nowrap;
  color: var(--text-quiet);
}

/* A student who owes (James, 2026-10-21: "those that owe should have a red
   background"): the whole row is tinted red and the balance is solid red. */
.row-balance-owes {
  background: var(--error);
  color: var(--on-alert);
}

.student-row.is-owing,
.today-row.is-owing {
  border-left-color: var(--error);
  background: var(--error-soft);
}

/* Booked away from the usual day: tinted, with a strong ring. An owing row
   keeps its red tint and edge, and the ring still shows. */
.student-row.is-away-from-usual {
  border-color: var(--away-edge);
  border-left-color: var(--away-edge);
  box-shadow: inset 0 0 0 1px var(--away-edge);
  background: var(--away-bg);
}

.student-row.is-away-from-usual.is-owing {
  border-left-color: var(--error);
  background: var(--error-soft);
}

.away-sample {
  display: inline-block;
  width: 1.25em;
  height: 0.9em;
  margin-right: 6px;
  border: 2px solid var(--away-edge);
  border-radius: 3px;
  background: var(--away-bg);
  vertical-align: -0.1em;
}

.row-error {
  margin: -2px 0 10px;
  font-size: var(--text-small);
  font-weight: 600;
  color: var(--error);
}

@media (prefers-color-scheme: dark) {
  .row-error {
    color: #ff9c8f;
  }
}

/* Two to a row at 375px; a label wraps, it is never cut (§4.6). */
.status-buttons {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
}

@media (min-width: 700px) {
  .status-buttons {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

.status-choice {
  position: relative;
  display: flex;
}

/* Transparent and out of the way of the finger: the label takes the tap and
   checks it. Still focusable, and focus is drawn on the label. */
.status-input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  pointer-events: none;
}

.status-button {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 52px;
  padding: 8px 10px;
  border: 2px solid var(--rule-strong);
  border-radius: var(--radius-small);
  background: var(--surface);
  color: var(--text);
  font: 600 0.9375rem / 1.25 var(--font-ui);
  text-align: center;
  overflow-wrap: anywhere;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background-color 120ms ease, border-color 120ms ease;
}

.status-button:hover {
  border-color: var(--accent);
}

.status-input:focus-visible + .status-button {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

/* Chosen: colour and border change, the size never does. */
.status-input:checked + .status-button {
  border-color: var(--text);
  background: var(--text);
  color: var(--bg);
}

/* Each choice in its status colour (the --st tokens, as on the calendar
   and the tags): its border always, filled when chosen. */
.status-choice[class*="st-"]:not(.st-none) .status-button {
  border-color: var(--st);
}

.status-choice[class*="st-"]:not(.st-none) .status-input:checked + .status-button {
  border-color: var(--st);
  background: var(--st);
  color: var(--on-status);
}

/* Charged on top, free beneath (James, 2026-10-21). Two columns on a phone:
   Attended | Missed, then Attended free | Cancelled with notice, then the rest. */
.status-choice.st-attended { order: 1; }
.status-choice.st-missed { order: 2; }
.status-choice.st-free { order: 3; }
.status-choice.st-skipped { order: 4; }
.status-choice.st-booked { order: 5; }
.status-choice.st-appt { order: 6; }
.status-choice.st-holiday { order: 7; }
.status-choice.st-none { order: 8; }

/* Four columns: Attended, Missed, Booked, Appointment over Attended free,
   Cancelled with notice, On holiday, Not booked. */
@media (min-width: 700px) {
  .status-choice.st-booked { order: 3; }
  .status-choice.st-appt { order: 4; }
  .status-choice.st-free { order: 5; }
  .status-choice.st-skipped { order: 6; }
}

.status-input:checked + .status-none {
  border-color: var(--text);
  background: var(--surface-sunk);
  color: var(--text);
}

.search {
  margin: 0 0 16px;
}

.search-line {
  display: flex;
  gap: 8px;
}

.search-input {
  flex: 1 1 auto;
  min-width: 0;
}

.search-button {
  flex: 0 0 auto;
}

/* Results as you type (D16). The note floats over the top of the results, so
   it moves nothing under the finger, and lets taps through to them. */
.live-wrap {
  position: relative;
}

.live-note {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 2;
  margin: 0;
  padding: 8px 12px;
  border-radius: var(--radius-small);
  background: var(--warning);
  color: var(--on-alert);
  font-weight: 600;
  pointer-events: none;
}

.live-note[hidden] {
  display: none;
}

/* ---------- calendar (§4.3 screen 3): one queryset, two drawings ---------- */

/* The month table needs more room than a reading column. */
.page.page-wide {
  max-width: 76rem;
}

/* Wider than a form, narrower than a calendar: the student card, so Call,
   WhatsApp and Email sit on one line on a desktop (James, 2026-10-21). */
.page.page-medium {
  max-width: 62rem;
}

.month-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0 0 20px;
}

.month-nav .btn {
  flex: 1 1 auto;
}

@media (min-width: 768px) {
  .month-nav .btn {
    flex: 0 0 auto;
  }
}

.today-tag {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 8px;
  border-radius: var(--radius-small);
  background: var(--accent);
  color: var(--on-accent);
  font: 700 0.75rem / 1.5 var(--font-ui);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  vertical-align: middle;
}

/* A slot entry: a block link at least 44px tall, in both drawings. */
.slot-entry {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  column-gap: 8px;
  min-height: var(--tap);
  padding: 6px 12px;
  border: 1px solid var(--rule);
  border-left: 5px solid var(--accent);
  border-radius: var(--radius-small);
  background: var(--surface);
  color: var(--text);
  text-decoration: none;
}

.slot-entry:hover,
.slot-entry:focus-visible {
  border-color: var(--accent);
  color: var(--text);
}

.slot-name {
  font-weight: 700;
  color: var(--text);
}

.slot-state {
  color: var(--text-quiet);
  font-size: var(--text-small);
  font-weight: 600;
}

.slot-entry.is-over {
  border-left-color: var(--warning);
}

.slot-entry.is-over .slot-state {
  padding: 0 6px;
  border-radius: 4px;
  background: var(--warning);
  color: var(--on-alert);
}

.slot-entry.is-closed {
  border-left-color: var(--rule-strong);
  background: var(--closed-bg);
}

.slot-entry.is-closed .slot-name,
.slot-entry.is-closed .slot-state {
  color: var(--text-quiet);
}

/* A day's closure line: a bank holiday or a closure, sessions or not. Words,
   not colour alone; the closed form uses the closed tokens, the "open by
   choice" form stays neutral. Long names wrap rather than clip. */
.day-mark {
  display: block;
  margin-top: 4px;
  padding: 2px 8px;
  border: 1px dashed var(--rule-strong);
  border-radius: var(--radius-small);
  background: var(--surface);
  color: var(--text);
  font: 600 var(--text-small) / 1.35 var(--font-ui);
  overflow-wrap: anywhere;
}

.day-mark.is-closed {
  border-style: solid;
  border-left-width: 4px;
  background: var(--closed-bg);
  color: var(--text);
}

.month-mark {
  margin: 0;
}

.month-mark .day-mark {
  margin-top: 0;
  padding: 2px 6px;
  font-size: 0.8125rem;
}

/* The week view: all seven days, one list at every width. */
.term-band {
  margin: 4px 0 0;
  color: var(--text-quiet);
  font-weight: 600;
}

.week {
  margin: 0 0 24px;
  padding: 0;
  list-style: none;
}

.week-day {
  margin: 0 0 16px;
  padding: 0 0 12px;
  border-bottom: 1px solid var(--rule);
  color: var(--text);
}

.week-day.is-today .week-date {
  color: var(--accent);
}

/* A day with nothing on: one line, never a gap. */
.week-day.is-quiet {
  margin-bottom: 8px;
  padding-bottom: 8px;
}

.week-day.is-quiet .week-date {
  margin: 0;
  font-size: 1rem;
}

.quiet-words {
  margin-left: 6px;
  color: var(--text-quiet);
  font: 600 var(--text-small) / 1.3 var(--font-ui);
}

.week-sessions {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 17rem), 1fr));
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.week-sessions > li {
  margin: 0;
  min-width: 0;
}

.slot-usual {
  color: var(--changed);
  font-size: var(--text-small);
  font-weight: 700;
}

/* The slot filter: links, a drawn ✓/＋ in a fixed box, counts taken before
   the filter, so a chip keeps its width when tapped. */
.slot-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0 0 16px;
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: var(--tap);
  padding: 4px 14px 4px 10px;
  border: 1px solid var(--rule-strong);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text);
  font-weight: 600;
  text-decoration: none;
}

.chip.is-active {
  border-color: var(--accent);
  background: var(--accent-soft);
}

.chip:hover,
.chip:focus-visible {
  border-color: var(--accent);
  color: var(--text);
}

.chip-mark {
  display: inline-block;
  width: 1.25em;
  font-weight: 700;
  text-align: center;
}

.chip-count {
  min-width: 2ch;
  color: var(--text-quiet);
  font-size: var(--text-small);
  font-variant-numeric: tabular-nums;
}

/* A day already past folds to one line; it opens to show who came. */
.week-past > summary {
  min-height: var(--tap);
  cursor: pointer;
}

.week-past > summary .week-date {
  display: inline;
  margin: 0;
}

.week-past[open] > summary {
  margin-bottom: 8px;
}

/* Names under a week's session: words first, the colour backs them up. */
.expected-line {
  margin: 4px 0 0;
  color: var(--text-quiet);
  font-size: var(--text-small);
  font-weight: 600;
}

/* Two names to a row on a phone, where a session spans the screen; one to a
   row from 1024 px, where sessions sit side by side (James, 2026-10-21: "on
   2 cols to reduce the height", then "2 col view doesn't look good on
   desktop — please go back to 1 for desktop"). */
.who-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 8.25rem), 1fr));
  align-items: start;
  gap: 4px;
  margin: 6px 0 0;
  padding: 0;
  list-style: none;
}

.who {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 2px 8px;
  min-height: var(--tap);
  padding: 6px 10px;
  border: 1px solid var(--rule);
  border-left: 4px solid var(--st);
  border-radius: var(--radius-small);
  background: var(--surface);
  color: var(--text);
  text-decoration: none;
  overflow-wrap: anywhere;
}

a.who:hover,
a.who:focus-visible {
  border-color: var(--accent);
  color: var(--text);
}

.who-name {
  min-width: 0;
  font-weight: 400;
}

.week .who-name,
.week-session .who-name {
  font-weight: 400;
}

.who-status,
.tag {
  padding: 0 6px;
  border: 2px solid var(--st);
  border-radius: 4px;
  color: var(--st);
  font-size: var(--text-small);
  font-weight: 700;
}

.tag {
  border-width: 1px;
}

.who.is-usual .who-status {
  background: var(--st);
  color: var(--on-status);
}

/* Faded: listed but holding no place. The 4px edge stays solid (a dashed
   thick edge breaks into fragments); the thin rule round it goes dashed. */
.who.is-faded {
  border-top-style: dashed;
  border-right-style: dashed;
  border-bottom-style: dashed;
  background: transparent;
}

.who.is-faded .who-name {
  color: var(--text-quiet);
  font-weight: 400;
}

.who-mark {
  font-weight: 700;
}

.st-attended {
  --st: var(--st-attended);
}

.st-booked {
  --st: var(--st-booked);
}

.st-free {
  --st: var(--st-free);
}

.st-missed {
  --st: var(--st-missed);
}

.st-holiday {
  --st: var(--st-holiday);
}

.st-skipped {
  --st: var(--st-skipped);
}

.st-appt {
  --st: var(--st-appt);
}

.st-expected,
.tag-expected {
  --st: var(--tag-expected);
}

.tag-moved {
  --st: var(--tag-moved);
}

.tag-catch-up {
  --st: var(--tag-catch-up);
}

/* Away from the usual day: the name is tinted with a strong edge all round
   (its status edge stays on the left). */
.who.is-away-from-usual {
  border-width: 2px 2px 2px 4px;
  border-style: solid;
  border-color: var(--away-edge) var(--away-edge) var(--away-edge) var(--st);
  background: var(--away-bg);
}

/* The month's *Show names* (James, 2026-10-22): one compact line per name
   under its session, its status as the left edge; away from the usual day
   tinted with a strong edge, as in the week, and saying the usual class. */
.month-who-list {
  display: grid;
  gap: 2px;
  margin: 2px 0 4px;
  padding: 0;
  list-style: none;
}

.month-who {
  display: block;
  padding: 1px 6px;
  border: 1px solid var(--rule);
  border-left: 3px solid var(--st);
  border-radius: var(--radius-small);
  background: var(--surface);
  color: var(--text);
  font-size: var(--text-small);
  line-height: 1.3;
  text-decoration: none;
  overflow-wrap: anywhere;
}

a.month-who:hover,
a.month-who:focus-visible {
  border-color: var(--accent);
  border-left-color: var(--st);
}

.month-who .who-name {
  font-weight: 600;
}

.month-who.is-away-from-usual {
  border: 2px solid var(--away-edge);
  border-left: 3px solid var(--st, var(--away-edge));
  background: var(--away-bg);
}

.who-usual {
  color: var(--away-edge);
  font-size: 0.85em;
  font-weight: 700;
  white-space: nowrap;
}

.key-line .month-who {
  display: inline-block;
}

.key-line {
  margin: 0 0 16px;
  font-size: var(--text-small);
  color: var(--text-quiet);
}

.tag-key-list .who.is-away-from-usual {
  padding: 2px 6px;
  border-width: 2px 2px 2px 4px;
  border-style: solid;
  border-color: var(--away-edge) var(--away-edge) var(--away-edge) var(--st);
  background: var(--away-bg);
}

.tag-key {
  margin: 0 0 16px;
  padding: 0 12px;
  border: 1px solid var(--rule);
  border-radius: var(--radius-small);
  background: var(--surface);
  color: var(--text);
}

.tag-key summary {
  min-height: var(--tap);
  padding: 10px 0;
  font-weight: 700;
  cursor: pointer;
}

.tag-key-list {
  display: grid;
  gap: 8px;
  margin: 0 0 12px;
  padding: 0;
  list-style: none;
  font-size: var(--text-small);
}

/* The key's samples are the pills alone, not whole name rows. */
.tag-key-list .who {
  display: inline-flex;
  min-height: 0;
  padding: 0;
  border: 0;
  background: none;
}

.view-switch {
  margin-left: auto;
}

/* Jump to a term (James, 2026-10-21): a GET form, the select and Go on one row. */
.term-jump {
  margin: 0 0 16px;
}

.term-jump-label {
  display: block;
  margin-bottom: 6px;
  font-weight: 600;
}

.term-jump-row {
  display: flex;
  gap: 8px;
  max-width: 28rem;
}

.term-jump-row .input {
  flex: 1 1 auto;
  min-width: 0;
}

.term-jump-row .btn {
  flex: 0 0 auto;
}

/* Hide weekends (James, 2026-10-21): the sentence that says what it hides. */
.weekend-hidden {
  margin: 0 0 16px;
  color: var(--text-quiet);
}

.weekend-hidden a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  font-weight: 600;
}

/* Narrow: the agenda, one row per day with sessions or a closure. */
.agenda {
  margin: 0 0 24px;
  padding: 0;
  list-style: none;
}

.agenda-day {
  margin: 0 0 16px;
  color: var(--text);
}

.agenda-date {
  margin: 0 0 8px;
  font: 600 1.125rem / 1.3 var(--font-read);
  color: var(--text);
}

.agenda-day.is-today .agenda-date {
  color: var(--accent);
}

.slot-list {
  display: grid;
  gap: 6px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.slot-list > li {
  margin: 0;
}

/* Wide: the month table. */
.month-table {
  display: none;
  width: 100%;
  table-layout: fixed;
  border-collapse: collapse;
  margin: 0 0 24px;
  background: var(--surface);
  color: var(--text);
}

.month-table th {
  padding: 8px 6px;
  border-bottom: 2px solid var(--rule-strong);
  background: var(--surface-sunk);
  color: var(--text);
  font: 700 var(--text-small) / 1.2 var(--font-ui);
  text-align: left;
}

.month-day {
  height: 7.5rem;
  padding: 6px;
  border: 1px solid var(--rule);
  vertical-align: top;
  color: var(--text);
}

.month-day.is-outside {
  background: var(--surface-sunk);
}

.month-day.is-today {
  box-shadow: inset 0 0 0 2px var(--accent);
}

.month-date {
  margin: 0 0 4px;
  font: 600 1rem / 1.2 var(--font-read);
  color: var(--text);
}

.month-day .slot-entry {
  margin-top: 4px;
  padding: 4px 8px;
  border-left-width: 4px;
  font-size: var(--text-small);
}

@media (min-width: 768px) {
  .agenda {
    display: none;
  }

  .month-table {
    display: table;
  }
}

/* ---------- student lookup and card (§4.3 screen 4) ---------- */

.search-form {
  margin: 0 0 8px;
}

.search-row {
  display: flex;
  gap: 8px;
}

.search-row .input {
  flex: 1 1 auto;
  min-width: 0;
}

.search-row .btn {
  flex: 0 0 auto;
}

.search-hint {
  font-size: var(--text-small);
  color: var(--text-quiet);
  margin: 0 0 12px;
}

.search-scope {
  font-size: var(--text-small);
  color: var(--text-quiet);
}

.inline-action {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  font-weight: 600;
}

.search-offer {
  margin: 0 0 16px;
}

.status-tag {
  display: inline-block;
  margin: 8px 0 0;
  padding: 2px 10px;
  border-radius: var(--radius-small);
  font-weight: 700;
}

/* On holiday now or soon (#152): the calendar's "On holiday" fill, so the
   two screens say it in one colour. It wraps rather than clips at 375px. */
.holiday-tag,
.cell-tag.holiday-tag {
  background: var(--st-holiday);
  color: var(--on-status);
}

.cell-tag {
  display: block;
  width: fit-content;
  margin: 4px 0 0;
  padding: 1px 8px;
  border-radius: var(--radius-small);
  font-size: var(--text-small);
  font-weight: 700;
  white-space: normal;
}

.cell-tag.tag-note {
  background: var(--surface-sunk);
  color: var(--text-muted);
  font-weight: 500;
}

.holiday-list {
  margin: 0 0 20px;
}

.holiday-box {
  margin: 0 0 20px;
  padding: 14px 16px;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow);
}

.holiday-box-title {
  margin: 0 0 12px;
}

.holiday-box-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.holiday-box-item {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 16px;
  padding: 8px 12px;
  border: 1px solid var(--rule);
  border-radius: var(--radius-small);
  background: var(--bg);
  color: var(--text);
}

.holiday-box-date {
  font-weight: 600;
  min-width: 8rem;
}

.holiday-box-session {
  color: var(--text);
  flex: 1 1 auto;
}

.badge-holiday {
  background: var(--st-holiday);
  color: var(--on-status);
  border: 1px solid var(--st-holiday);
  font-weight: 700;
  padding: 2px 8px;
  border-radius: var(--radius-small);
  font-size: var(--text-small);
}

.badge-appt {
  background: var(--st-appt);
  color: var(--on-status);
  border: 1px solid var(--st-appt);
  font-weight: 700;
  padding: 2px 8px;
  border-radius: var(--radius-small);
  font-size: var(--text-small);
}

.holiday-sessions {
  margin: 4px 0 0;
}

.status-inactive {
  background: var(--closed-bg);
  border: 1px solid var(--rule-strong);
  color: var(--text);
}

.record {
  margin: 0 0 20px;
  padding: 14px 16px;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow);
}

.balance-line {
  margin: 0 0 10px;
  font: 600 1.25rem / 1.25 var(--font-read);
  color: var(--text);
}

.balance-line.is-owing {
  display: inline-block;
  padding: 2px 10px;
  border-radius: var(--radius-small);
  background: var(--error);
  color: var(--on-alert);
}

.record-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 12px;
  margin-bottom: 12px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--rule);
}

.record-toolbar .record-action,
.record-toolbar .contact-actions {
  margin: 0;
}

.contact-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0 0 12px;
}

.contact-link {
  max-width: 100%;
  overflow-wrap: anywhere;
}

.record-action {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0 0 12px;
}

.facts {
  display: grid;
  gap: 8px 20px;
  margin: 0;
}

@media (min-width: 580px) {
  .facts {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 820px) {
  .facts {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

.fact-wide {
  grid-column: 1 / -1;
}

.facts hr,
.facts-rule {
  grid-column: 1 / -1;
  border: 0;
  border-top: 1px solid var(--rule);
  margin: 12px 0 6px;
  width: 100%;
}

.fact dt {
  font-size: var(--text-small);
  font-weight: 700;
  color: var(--text-quiet);
}

.fact dd {
  margin: 2px 0 0;
  color: var(--text);
  overflow-wrap: anywhere;
}

.card-section {
  margin: 0 0 8px;
}

/* ---------- payment forms (§4.3 screen 5) ---------- */

select.input {
  appearance: auto;
}

textarea.input {
  min-height: 5rem;
  resize: vertical;
}

.consequence {
  margin: 0 0 20px;
  padding: 16px 18px;
  border: 2px solid var(--accent);
  border-radius: var(--radius);
  background: var(--accent-soft);
  color: var(--text);
}

.consequence p {
  margin: 0 0 6px;
  font-weight: 600;
  color: var(--text);
}

.consequence p:first-child {
  font: 600 1.25rem / 1.3 var(--font-read);
}

.consequence p:last-child {
  margin-bottom: 0;
}

#confirm-form {
  margin-bottom: 12px;
}

.back-link {
  margin: 20px 0 0;
}

.back-link-top {
  margin: 0 0 4px;
}

.back-link-top a {
  gap: 6px;
}

.back-link a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  font-weight: 600;
}

/* ---------- UI kit (development only) ---------- */

.kit-section {
  margin-bottom: 28px;
}

.kit-links {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.name-list {
  margin: 0 0 12px;
  padding-left: 1.25rem;
}

.student-name {
  color: var(--text);
  font-weight: 600;
}

/* ---------- the no-studio page (tenants/no_studio.html) ---------- */

.refusal {
  max-width: 34rem;
  margin: 0 auto;
  padding: calc(32px + env(safe-area-inset-top)) max(20px, env(safe-area-inset-right)) 32px
    max(20px, env(safe-area-inset-left));
  color: var(--text);
}

.refusal h1 {
  margin: 0 0 1rem;
  font: 600 1.75rem / 1.2 var(--font-read);
  color: var(--text);
}

.refusal p {
  color: var(--text);
}

.refusal .quiet {
  font-size: var(--text-small);
  color: var(--text-quiet);
}

.refusal hr {
  border: 0;
  border-top: 1px solid var(--rule);
  margin: 1.5rem 0;
}

@media (prefers-reduced-motion: reduce) {
  * {
    transition: none !important;
  }
}

/* ---------- development-only demo sign-in (frontend/demo_logins.py) ---------- */

.demo-logins {
  margin-top: 2.5rem;
  padding-top: 1.25rem;
  border-top: 1px dashed var(--rule-strong);
}

.demo-logins-note {
  color: var(--text-quiet);
  font-size: var(--text-small);
  margin: 0.25rem 0 1rem;
}

.demo-login {
  margin: 0 0 0.75rem;
}

.demo-login .btn {
  width: 100%;
  justify-content: flex-start;
  text-align: left;
}

/* ---------- help pages (§1) ---------- */

.help-layout {
  display: flex;
  flex-direction: column;
  gap: 24px;
}

@media (min-width: 840px) {
  .help-layout {
    display: grid;
    grid-template-columns: 240px minmax(0, 1fr);
    gap: 36px;
    align-items: start;
  }

  .help-sidebar {
    position: sticky;
    top: calc(var(--topbar-height) + 16px);
    max-height: calc(100vh - var(--topbar-height) - 32px);
    overflow-y: auto;
  }
}

.help-sidebar {
  padding: 14px 16px;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  font-size: var(--text-small);
  box-shadow: var(--shadow);
}

.help-nav-group {
  margin-bottom: 20px;
}

.help-nav-group:last-child {
  margin-bottom: 0;
}

.help-nav-heading {
  margin: 0 0 8px;
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-quiet);
}

.help-nav-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.help-nav-link {
  display: block;
  padding: 6px 10px;
  border-radius: var(--radius-small);
  color: var(--text);
  text-decoration: none;
  font-weight: 500;
  transition: background-color 120ms ease, color 120ms ease;
}

.help-nav-link:hover {
  background: var(--surface-sunk);
  color: var(--link);
}

.help-nav-link.is-current {
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: 700;
}

.help-sections-list .help-nav-link {
  padding-left: 14px;
  font-size: 0.8125rem;
  color: var(--text-quiet);
}

.help-sections-list .help-nav-link:hover {
  color: var(--text);
}

.help-content {
  min-width: 0;
}

.help h2 {
  margin-top: 28px;
}

.help ol,
.help ul {
  margin: 0 0 1rem;
  padding-left: 1.25rem;
}

.help li {
  margin: 0 0 0.5rem;
}

.help .facts {
  margin: 0 0 1rem;
}

/* The contents: each page a full-width row, a tap target in its own right. */
.help .help-nav {
  list-style: none;
  margin: 0 0 1.5rem;
  padding: 0;
  border-top: 1px solid var(--rule);
}

.help .help-nav li {
  margin: 0;
  padding: 6px 0;
  border-bottom: 1px solid var(--rule);
}

.help-nav a {
  display: flex;
  align-items: center;
  min-height: var(--tap);
  font-weight: 600;
}

.help-nav-note {
  display: block;
  color: var(--text-quiet);
  font-size: var(--text-small);
}

.help-foot {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin: 32px 0 0;
}

/* ---------- changelog ---------- */

.changelog-release {
  margin-top: 28px;
  padding-bottom: 24px;
  border-bottom: 1px solid var(--rule);
}

.changelog-release:last-of-type {
  border-bottom: none;
}

.changelog-release-title {
  margin-bottom: 16px;
}

.changelog-date {
  font-family: var(--font-read);
  font-weight: 700;
  color: var(--text);
}

.changelog-entry {
  margin-bottom: 20px;
}

.changelog-item-title {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  font-size: 1.0625rem;
  font-weight: 600;
  margin: 0 0 6px;
  color: var(--text);
}

.badge {
  display: inline-block;
  padding: 2px 7px;
  font-size: var(--text-small);
  font-weight: 700;
  border-radius: var(--radius-small);
  line-height: 1.2;
}

.badge-feature {
  background: var(--accent-soft);
  color: var(--accent);
}

.badge-perf {
  background: var(--success-bg);
  color: var(--success-text);
}

.badge-fix {
  background: var(--surface-sunk);
  color: var(--text-quiet);
}

/* ---------- Today: confirming attendance (D12, §4.3 screen 1) ----------
 * Each open card lists everyone expected. A row is two buttons that swap
 * their words and colours when it is marked — never their size — and the
 * alternatives open over the rows below rather than pushing them down. */

:root {
  --here-bg: #2f6b2a;
  --on-here: #ffffff;
  --here-tint: #eef4e8;
  --missed-tint: #f8ece0;
  --away-tint: #ece4d9;
}

@media (prefers-color-scheme: dark) {
  :root {
    --here-bg: #8fcf7f;
    --on-here: #10210c;
    --here-tint: #1f2a1a;
    --missed-tint: #2e2117;
    --away-tint: #211b17;
  }
}

.card-today {
  height: auto;
}

.card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.card-head .card-slot {
  margin: 0;
}

.card-more {
  display: inline-grid;
  place-items: center;
  min-height: var(--tap);
  padding: 0 12px;
  border-radius: var(--radius-small);
  font-weight: 600;
  color: var(--link);
  white-space: nowrap;
}

.card-today > .card-places {
  margin: 0 0 12px;
}

.card-note,
.card-more-regulars,
.card-foot {
  margin: 8px 0 0;
  font-size: var(--text-small);
  color: var(--text-quiet);
}

.card-foot a,
.card-more-regulars a,
.card-note a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  font-weight: 600;
  color: var(--link);
}

.today-rows {
  display: grid;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.today-row {
  margin: 0;
  padding: 10px 10px 10px 12px;
  border: 1px solid var(--rule);
  border-left: 6px solid var(--rule-strong);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
  transition: background-color 120ms ease, border-color 120ms ease;
}

.today-row.is-here {
  border-left-color: var(--here-bg);
  background: var(--here-tint);
}

.today-row.is-missed {
  border-left-color: var(--warning);
  background: var(--missed-tint);
}

.today-row.is-away {
  border-left-color: var(--rule-strong);
  background: var(--away-tint);
}

.today-row .row-head {
  display: flex;
  align-items: flex-start;
  gap: 4px 10px;
  margin-bottom: 8px;
}

.today-row .student-name {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  font: 600 1.125rem / 1.3 var(--font-read);
  color: var(--text);
  overflow-wrap: anywhere;
}

.usual-tag {
  display: inline-block;
  margin-left: 2px;
  padding: 0 6px;
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius-small);
  font: 600 0.75rem / 1.5 var(--font-ui);
  vertical-align: 2px;
  color: var(--text-quiet);
  white-space: nowrap;
}

/* Two buttons of fixed proportions: a label swap cannot move the other. */
.mark-controls {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 8px;
}

.mark-form {
  display: flex;
  margin: 0;
}

.mark-here,
.mark-other-button {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 52px;
  margin: 0;
  padding: 6px 8px;
  border: 2px solid var(--rule-strong);
  border-radius: var(--radius-small);
  background: var(--surface);
  color: var(--text);
  font: 600 0.9375rem / 1.25 var(--font-ui);
  text-align: center;
  overflow-wrap: anywhere;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background-color 120ms ease, border-color 120ms ease;
}

.mark-here {
  border-color: var(--here-bg);
  font-size: 1.0625rem;
}

.mark-here[aria-pressed="true"] {
  background: var(--here-bg);
  color: var(--on-here);
}

.mark-here:focus-visible,
.mark-other-button:focus-visible,
.mark-choice:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

.mark-here:disabled,
.mark-other-button.is-disabled {
  border-style: dashed;
  border-color: var(--rule-strong);
  background: transparent;
  color: var(--text-quiet);
  cursor: default;
}

.mark-other {
  position: relative;
  margin: 0;
}

.mark-other-button {
  list-style: none;
}

.mark-other-button::-webkit-details-marker {
  display: none;
}

.mark-other[open] > .mark-other-button {
  border-color: var(--text);
}

.is-missed .mark-other-button.is-chosen {
  border-color: var(--warning);
  background: var(--warning);
  color: var(--on-alert);
}

.is-away .mark-other-button.is-chosen {
  border-color: var(--text);
  background: var(--text);
  color: var(--bg);
}

.is-here .mark-other-button.is-chosen {
  border-color: var(--here-bg);
  background: var(--here-bg);
  color: var(--on-here);
}

/* Floats over the rows below: opening it moves nothing (§4.6). */
.mark-menu {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 5;
  display: grid;
  gap: 6px;
  width: min(17rem, calc(100vw - 48px));
  margin: 0;
  padding: 8px;
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow);
}

.mark-choice {
  min-height: var(--tap);
  padding: 8px 12px;
  border: 2px solid var(--rule);
  border-radius: var(--radius-small);
  background: var(--surface);
  color: var(--text);
  font: 600 0.9375rem / 1.25 var(--font-ui);
  text-align: left;
  cursor: pointer;
}

.mark-choice:hover {
  border-color: var(--accent);
}

.mark-choice.is-current {
  border-color: var(--text);
  background: var(--surface-sunk);
  color: var(--text);
}

/* A session where everyone is marked folds to one line; "Edit" opens it. */
.card-done {
  margin: 0;
}

.card-done-line {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: var(--tap);
  padding: 6px 12px;
  border: 1px solid var(--rule);
  border-left: 6px solid var(--here-bg);
  border-radius: var(--radius);
  background: var(--here-tint);
  color: var(--text);
  font-weight: 600;
  list-style: none;
  cursor: pointer;
}

.card-done-line::-webkit-details-marker {
  display: none;
}

.card-done-words {
  min-width: 0;
  color: var(--text);
}

.card-done-edit {
  flex: 0 0 auto;
  color: var(--link);
}

.card-done-edit::after {
  content: "Edit";
}

.card-done[open] > .card-done-line {
  margin-bottom: 8px;
}

.card-done[open] .card-done-edit::after {
  content: "Close";
}

/* "Everyone's here": one press for the whole session, its count beside it. */
.all-here {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 12px;
  margin: 0 0 12px;
}

.all-here-button {
  flex: 0 0 auto;
}

.all-here-note {
  flex: 1 1 10rem;
  min-width: 0;
  margin: 0;
  font-size: var(--text-small);
  color: var(--text-quiet);
}

/* The Undo a message offers (D12): it takes taps, like the text and the ✕. */
.strip-action {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  margin: 0;
  pointer-events: auto;
}

.strip-undo {
  min-height: var(--tap);
  min-width: var(--tap);
  margin: 0;
  padding: 4px 12px;
  border: 2px solid currentColor;
  border-radius: var(--radius-small);
  background: transparent;
  color: inherit;
  font: 700 var(--text-base) / 1.2 var(--font-ui);
  cursor: pointer;
}

.strip-undo:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

/* ---------- terms (§4.3 screen 6, revision 10) ---------- */

.term-dates {
  margin: 0 0 8px;
  color: var(--text);
}

.term-facts {
  margin: 0;
  padding: 0;
  list-style: none;
  color: var(--text-quiet);
}

.term-facts li {
  color: var(--text-quiet);
}

.progress-list {
  margin: 0 0 12px;
  padding: 0;
  list-style: none;
}

.progress-line {
  margin: 0 0 6px;
  padding: 6px 10px;
  border-left: 4px solid var(--accent);
  border-radius: var(--radius-small);
  background: var(--surface-sunk);
  color: var(--text);
  font-weight: 600;
  overflow-wrap: anywhere;
}

.progress-line.is-short {
  border-left-color: var(--warning);
  background: var(--warning);
  color: var(--on-alert);
}

/* the new-term steps: the weekly pattern grid, the week list */

.pattern {
  margin: 0 0 18px;
  padding: 0;
  border: 0;
}

.pattern-day {
  padding: 8px 0;
  border-top: 1px solid var(--rule);
}

.pattern-weekday {
  margin: 0 0 6px;
  font-weight: 700;
  color: var(--text);
}

.pattern-cells {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;
}

.pattern-cell .places {
  margin-top: 4px;
}

/* The slot's name under its box, never broken mid-word at 375px. */
.pattern-cell .check {
  flex-direction: column;
  align-items: flex-start;
  gap: 0;
}

.pattern-cell .check span {
  overflow-wrap: normal;
}

.check {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: var(--tap);
  color: var(--text);
  cursor: pointer;
}

.check span {
  color: var(--text);
  overflow-wrap: anywhere;
}

/* A full 44px tap target, drawn as a 24px box inside it (a transparent 10px
   border): hollow when clear, filled with a tick when ticked — a change of
   shape, not colour alone. */
.check-input {
  flex: 0 0 auto;
  box-sizing: border-box;
  width: var(--tap);
  height: var(--tap);
  margin: 0 -6px 0 -10px;
  border: 10px solid transparent;
  border-radius: 16px;
  background: var(--surface) center / 18px no-repeat;
  background-clip: padding-box;
  box-shadow: inset 0 0 0 2px var(--text-quiet);
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
}

.check-input:checked {
  background-color: var(--accent);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7' fill='none' stroke='%23ffffff' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  box-shadow: inset 0 0 0 2px var(--accent);
}

@media (prefers-color-scheme: dark) {
  .check-input:checked {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7' fill='none' stroke='%231c1210' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  }
}

.check-input:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: -8px;
}

.weeks {
  margin: 0 0 18px;
  padding: 0;
  border: 0;
}

/* ---------- what-if term planning preview ---------- */

.what-if-panel {
  margin-top: 32px;
  padding-top: 24px;
  border-top: 2px solid var(--rule);
}

.what-if-card,
.what-if-holidays {
  margin-bottom: 20px;
  padding: 16px;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
}

.what-if-overview-disclosure {
  margin-top: 16px;
}

.what-if-overview-disclosure > summary {
  margin-bottom: 12px;
  cursor: pointer;
}

.what-if-overview-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

.plan-start-drawer {
  margin: 16px 0;
}

.plan-start-drawer > summary {
  cursor: pointer;
}

.plan-start-form {
  margin-top: 12px;
  padding: 12px 16px;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
}

.week-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.week-row {
  margin: 0 0 8px;
  padding: 4px 12px 8px;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
}

.week-row.is-ticked {
  border-color: var(--accent);
  background: var(--accent-soft);
}

.week-label {
  flex: 1 1 auto;
  font-weight: 700;
}

.week-hint {
  font-size: var(--text-small);
}

.week-lines {
  margin: 0;
  padding: 0 0 0 32px;
  list-style: none;
}

.week-line {
  font-size: var(--text-small);
  color: var(--text);
}

.week-line.is-closed,
.week-line.is-holiday {
  font-weight: 700;
  color: var(--text);
}

.week-line.is-after {
  color: var(--text-quiet);
}

.form-actions-stack {
  display: grid;
  gap: 10px;
}

/* Screen 7, studio hours (revision 13): per weekday, three slot rows, each a
   tick, a start–end pair and its places. At a phone's width the times sit on
   their own line under the tick; wider, one line. Nothing changes size when a
   slot is ticked: an on slot is tinted, never resized. */

.hours {
  margin: 0 0 18px;
  padding: 0;
  border: 0;
}

.hours-now {
  margin: 0 0 18px;
}

.hours-day {
  padding: 8px 0;
  border-top: 1px solid var(--rule);
}

.hours-slot {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 4px;
  margin: 0 0 6px;
  padding: 4px 8px 8px;
  border-radius: var(--radius-small);
  background: var(--surface);
}

.hours-slot.is-on {
  background: var(--accent-soft);
}

.hours-times {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  min-width: 0;
}

/* Wide enough for a 12-hour clock's "AM"/"PM" where WebKit shows one: a
   narrower box dropped it, and 19:00 read as "07:00". */
.input.hours-time {
  flex: 1 1 6.75rem;
  min-width: 6.75rem;
  max-width: 8.5rem;
  width: auto;
  padding: 8px 6px;
}

.hours-dash {
  flex: 0 0 auto;
  color: var(--text);
}

.hours-places-label {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  gap: 4px;
  color: var(--text);
  font-size: var(--text-small);
}

.input.hours-places {
  width: 3.5em;
  padding: 8px 6px;
  text-align: center;
}

@media (min-width: 700px) {
  .hours-slot {
    grid-template-columns: 7.5rem minmax(0, 1fr);
    align-items: center;
  }

  .hours-slot .field-error {
    grid-column: 1 / -1;
  }
}

/* A class's times under its tick on the new term's step 1 (revision 13). */
.pattern-time {
  margin: 0;
  font-size: var(--text-small);
  font-variant-numeric: tabular-nums;
  color: var(--text-quiet);
}

/* A session's times beside its slot (revision 13): the same weight as the
   slot, in figures that line up, and never broken across a line — in a month
   cell only the start is shown, so it fits. */
.slot-time {
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  color: inherit;
}

/* ---------- terms on a calendar (revision 14, D15) ---------- */

/* A draft term on the list: dashed, in the accent, so it reads as unfinished. */
.card-draft {
  border: 2px dashed var(--accent);
  box-shadow: none;
}

.card-draft .card-go {
  color: var(--link);
  font-weight: 600;
}

.plan-class {
  font-weight: 700;
  color: var(--text);
}

/* The term overview (§4.3 screen 6): week rows, Monday first. A phone gets
   an agenda — one row per day with something on it — and from 768px the
   same markup is a grid, as the calendar screen switches. */
:root {
  --ov-bank-bg: #f6e3cc;
  --ov-bank-text: #6b3a00;
  --ov-holiday-bg: #e8def4;
  --ov-holiday-text: #4b2f7a;
}

@media (prefers-color-scheme: dark) {
  :root {
    --ov-bank-bg: #3a2a14;
    --ov-bank-text: #f3c98f;
    --ov-holiday-bg: #2e2440;
    --ov-holiday-text: #d9c7f6;
  }
}

.plan-end {
  margin: 0 0 12px;
  font-weight: 700;
  color: var(--text);
}

.ov {
  margin: 0 0 24px;
}

.ov-toolbar {
  margin: 0 0 12px;
}

.ov-heads {
  display: none;
}

.ov-month {
  margin: 20px 0 8px;
  font-size: 1.125rem;
  color: var(--text);
}

.ov-week {
  margin: 0 0 12px;
  padding: 8px;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--surface);
}

.ov-week.is-extra {
  border: 2px solid var(--accent);
  background: var(--accent-soft);
}

.ov-week-label {
  margin: 0 0 6px;
  font-size: var(--text-small);
  color: var(--text-quiet);
}

.ov-extra {
  margin: 0 0 8px;
  padding: 6px 10px;
  border-radius: var(--radius-small);
  background: var(--accent);
  color: var(--on-accent);
  font-weight: 700;
}

.ov-days,
.ov-cells {
  margin: 0;
  padding: 0;
  list-style: none;
}

.ov-day {
  display: grid;
  grid-template-columns: 7.5rem minmax(0, 1fr);
  gap: 8px;
  padding: 6px 0;
  border-top: 1px solid var(--rule);
}

.ov-day:first-child {
  border-top: 0;
}

.ov-day.is-empty,
.ov-day.is-outside:not(.is-bank):not(.is-holiday) {
  display: none;
}

.ov-date,
.ov-title {
  margin: 0;
  font-size: var(--text-small);
  color: var(--text);
}

.ov-date {
  font-weight: 700;
}

.ov-day.is-bank .ov-title {
  color: var(--ov-bank-text);
  font-weight: 700;
}

.ov-day.is-holiday .ov-title,
.ov-day.is-closed .ov-title {
  color: var(--ov-holiday-text);
  font-weight: 700;
}

.ov-cells {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  min-width: 0;
}

.ov-cell {
  flex: 1 1 8.5rem;
  min-width: 0;
}

.ov-tap {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 2px 6px;
  box-sizing: border-box;
  width: 100%;
  min-height: var(--tap);
  padding: 6px 8px;
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius-small);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: var(--text-small);
  text-align: left;
  text-decoration: none;
}

.ov-label {
  font-weight: 700;
  white-space: nowrap;
}

.ov-note,
.ov-places {
  color: var(--text-quiet);
  font-variant-numeric: tabular-nums;
}

.ov-cell.is-extra .ov-tap {
  border: 2px solid var(--accent);
}

.ov-cell.is-bank .ov-tap {
  border-style: dashed;
  background: var(--ov-bank-bg);
  color: var(--ov-bank-text);
}

.ov-cell.is-holiday .ov-tap,
.ov-cell.is-closed .ov-tap {
  border-style: dashed;
  background: var(--ov-holiday-bg);
  color: var(--ov-holiday-text);
}

.ov-cell.is-bank .ov-note,
.ov-cell.is-holiday .ov-note,
.ov-cell.is-closed .ov-note {
  color: inherit;
}

@media (min-width: 768px) {
  .plan-counts {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
    gap: 6px 12px;
  }

  .ov-heads,
  .ov-days {
    display: grid;
    gap: 6px;
  }

  .ov-cols-5 {
    grid-template-columns: repeat(5, minmax(0, 1fr));
  }

  .ov-cols-7 {
    grid-template-columns: repeat(7, minmax(0, 1fr));
  }

  .ov-heads {
    margin: 0 0 6px;
    padding: 0 9px;
    list-style: none;
    font-size: var(--text-small);
    font-weight: 700;
    color: var(--text-quiet);
  }

  .ov-day,
  .ov-day.is-empty,
  .ov-day.is-outside:not(.is-bank):not(.is-holiday) {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
    padding: 6px;
    border: 1px solid var(--rule);
    border-radius: var(--radius-small);
  }

  .ov-day:first-child {
    border-top: 1px solid var(--rule);
  }

  .ov-day.is-outside {
    background: var(--surface-sunk);
  }

  .ov-day.is-bank {
    background: var(--ov-bank-bg);
  }

  .ov-day.is-holiday,
  .ov-day.is-closed {
    background: var(--ov-holiday-bg);
  }

  .ov-cells {
    flex-direction: column;
  }

  .ov-cell {
    flex: none;
  }
}

/* The planner's taps (§4.3 screen 6): a day's heading and a session cell are
   buttons, at least 44px, that look like the text they replace. */
.ov-form {
  margin: 0;
}

.ov-date,
.ov-title {
  display: block;
}

button.ov-tap {
  cursor: pointer;
}

.ov-day-tap {
  display: block;
  box-sizing: border-box;
  width: 100%;
  min-height: var(--tap);
  padding: 4px 6px;
  border: 1px dashed var(--rule-strong);
  border-radius: var(--radius-small);
  background: transparent;
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.ov-day-hint {
  display: block;
  font-size: var(--text-small);
  color: var(--link);
  text-decoration: underline;
}

.holiday-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.holiday-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 8px 0;
  border-top: 1px solid var(--rule);
  color: var(--text);
}

.holiday-words {
  min-width: 0;
  overflow-wrap: anywhere;
}

.range-slots {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 16px;
  margin: 0 0 16px;
  padding: 0;
  border: 0;
}

.range-slots .field-hint {
  flex-basis: 100%;
}

@media (min-width: 700px) {
  .range-dates {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0 16px;
  }
}

/* The class counts above a term's calendar stay compact: on a phone six
   classes in two lines each pushed the calendar off the first screen. */
.plan-counts .progress-line {
  padding-top: 6px;
  padding-bottom: 6px;
  font-size: var(--text-small);
}

.ov-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

/* A class's summary (revision 16, D17): its name and dates, then its facts on
   a line of their own, so a narrow screen never breaks it mid-phrase. */
.plan-facts {
  display: block;
  font-weight: 400;
  color: var(--text);
}

/* A class's card at the top of a live term jumps to its next session in the
   calendar (James, 2026-10-21): the whole card is the link, and the cell it
   lands on is outlined so the eye finds it. */
.plan-jump {
  display: block;
  margin: -6px -10px;
  padding: 6px 10px;
  color: inherit;
  text-decoration: none;
}

.plan-jump:hover .plan-class,
.plan-jump:focus-visible .plan-class {
  text-decoration: underline;
}

.ov-cell {
  scroll-margin-top: 16px;
}

.ov-cell:target .ov-tap {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}

/* Each weekday has its colour (--day-0 Monday … --day-6 Sunday): the class
   cards at the top of a term and its calendar's sessions and day headings
   carry it, so a day's classes are found by colour. */
.wd-0 { --day: var(--day-0); }
.wd-1 { --day: var(--day-1); }
.wd-2 { --day: var(--day-2); }
.wd-3 { --day: var(--day-3); }
.wd-4 { --day: var(--day-4); }
.wd-5 { --day: var(--day-5); }
.wd-6 { --day: var(--day-6); }

.plan-counts .progress-line[class*="wd-"] {
  border-left-color: var(--day);
}

.ov-day[class*="wd-"] .ov-head {
  box-shadow: inset 0 3px 0 var(--day);
}

.ov-day[class*="wd-"] .ov-cell.is-session .ov-tap {
  border-left: 5px solid var(--day);
}

/* A booked student away from their usual time is tagged "Added — usually …"
   on the attendance screen, so a hand-added name still reads as added. */
.tag-added {
  --st: var(--st-booked);
}

.row-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 6px;
  margin: 0 0 10px;
}

/* "Usually Tue morning" under a name the attendance search found. */
.row-usual {
  margin: -6px 0 10px;
  font: 400 var(--text-small) / 1.3 var(--font-ui);
  color: var(--text-quiet);
}

/* ---------- screen 8, Activity (revision 17, D18) ----------
   The studio's audit log as a daybook: one column of entries at every width,
   so nothing scrolls sideways. Each entry is one request — when and who, then
   its lines. From 1024px the when/who column sits beside the lines. Every
   link is a full-width 44px row; text-only lines keep the same rhythm. */

.when-presets {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0 0 10px;
}

.when-chip {
  padding-left: 14px;
}

.activity-for {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 16px;
  margin: 0 0 16px;
  color: var(--text);
}

.activity-count {
  margin: 0 0 8px;
  font-size: var(--text-small);
  font-variant-numeric: tabular-nums;
  color: var(--text-quiet);
}

/* The Activity screen's column filters (#198): one chip group per column,
   folded away until wanted, open while any is on. */
.activity-more {
  margin: 0 0 12px;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
}

.activity-more-summary {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: var(--tap);
  padding: 0 12px;
  font-weight: 600;
  cursor: pointer;
  color: var(--text);
}

.activity-more-count {
  font-size: var(--text-small);
  color: var(--accent);
}

.activity-more-body {
  display: grid;
  gap: 4px 24px;
  padding: 0 12px 8px;
}

.activity-filter-title {
  display: block;
  margin: 4px 0 6px;
  font-size: var(--text-small);
  font-weight: 700;
  color: var(--text-quiet);
}

.activity-term {
  margin: 0 0 10px;
}

@media (min-width: 1024px) {
  .activity-more-body {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* The Activity table (#198): Date | Who | Attendee | Session | Action |
   Result. Every column fits 1100px and above; below that (a phone, an iPad
   upright) Who
   stacks under the date, Session under the attendee and Result under the
   action — in the cells and in the headers, so each sort is still one tap —
   and the date is the short one. */
.activity-table th,
.activity-table td {
  vertical-align: top;
  padding: 8px 10px;
  height: auto;
}

.activity-table th {
  padding-top: 0;
  padding-bottom: 0;
  vertical-align: middle;
}

.activity-table td {
  overflow-wrap: break-word;
}

.act-1 {
  width: 11.5rem;
}

@media (min-width: 1100px) {
  .act-6 .act-result,
  .act-4 .act-link {
    white-space: nowrap;
  }
}

.act-when {
  display: block;
  font-weight: 600;
  white-space: nowrap;
}

.act-age {
  display: block;
  color: var(--text-quiet);
}

.act-short,
.act-stack {
  display: none;
}

.act-link {
  color: var(--link);
  font-weight: 600;
}

.act-text.is-blank {
  color: var(--text-quiet);
}

.act-result {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.act-result.is-blank {
  font-weight: 400;
  color: var(--text-quiet);
}

.act-result.is-down {
  color: var(--st-missed);
}

.act-result.is-up {
  color: var(--st-attended);
}

.act-result.is-refused {
  color: var(--error);
}

@media (prefers-color-scheme: dark) {
  .act-result.is-refused {
    color: var(--st-free);
  }
}

/* Stacked below 1100px, not only on a phone: from 700 to 1099px (an iPad
   upright, split view) six columns scrolled 265px sideways inside the table. */
@media (max-width: 1099.98px) {
  .activity-table th,
  .activity-table td {
    padding-left: 6px;
    padding-right: 6px;
  }

  .activity-table .act-2,
  .activity-table .act-4,
  .activity-table .act-6 {
    display: none;
  }

  .act-1 {
    width: 6.5rem;
  }

  .act-long {
    display: none;
  }

  .act-short,
  .act-stack {
    display: block;
  }

  .act-stack.act-who,
  .act-age {
    font-size: 0.8125rem;
  }

  .activity-table th {
    vertical-align: top;
    padding-top: 2px;
    padding-bottom: 2px;
  }

  .activity-table th .sort-link {
    min-height: var(--tap);
  }

  /* A long session ("Wed 21 Oct 2026 AM") or name wraps rather than
     pushing the table past a phone's edge. */
  .activity-table td a,
  .activity-table td .act-text {
    overflow-wrap: anywhere;
  }
}

.pager {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0 0 24px;
}

.pager-older {
  margin-left: auto;
}

.activity-pager {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin: 16px 0 24px;
}

.pager-nav-links {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.pager-pages {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px;
  list-style: none;
  margin: 0;
  padding: 0;
}

.pager-page-link,
.pager-current {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 38px;
  min-height: var(--tap);
  padding: 0 8px;
  border-radius: var(--radius-small);
  font-weight: 600;
  font-size: var(--text-small);
  text-align: center;
  text-decoration: none;
}

.pager-current {
  background: var(--accent);
  color: var(--on-accent);
  font-weight: 700;
}

.pager-dots {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  color: var(--text-quiet);
}

.pager-status {
  margin: 0;
  font-size: var(--text-small);
  color: var(--text-quiet);
}

/* On a phone the list gets the screen: shorter preset labels ("7 days") and
   tighter chips, so the filters take three rows rather than six. */
@media (max-width: 699px) {
  .when-long {
    display: none;
  }

  .when-presets .chip,
  .activity-results-chips .chip {
    padding: 4px 12px 4px 8px;
    gap: 4px;
    font-size: 0.9375rem;
  }

  .when-presets .chip {
    padding-left: 12px;
  }
}

/* The calendar's controls in two rows (James, 2026-10-21: "jump to term
   should be on the same row as the week selector. Hide weekends should be
   on the filter toggle row"). Row one: the weeks or months, the term jump
   and the other view; row two: the slot chips and Hide weekends. On a phone
   each part takes its own line, as before. */
.cal-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 16px;
  margin: 0 0 16px;
}

.cal-bar > .month-nav,
.cal-bar > .slot-chips,
.cal-bar > .term-jump {
  margin: 0;
}

.cal-bar > * {
  flex: 1 1 100%;
  min-width: 0;
}

@media (min-width: 1024px) {
  .cal-bar > * {
    flex: 0 1 auto;
  }

  .cal-bar > .view-switch,
  .cal-bar > .weekend-toggle,
  .cal-bar > .cal-toggles {
    margin-left: auto;
  }

  .cal-bar .term-jump {
    display: flex;
    align-items: center;
    gap: 8px;
  }

  .cal-bar .term-jump-label {
    margin: 0;
    white-space: nowrap;
  }

  .cal-bar .term-jump-row .input {
    width: 19rem;
  }
}

@media (min-width: 1024px) {
  .who-list {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* Hide weekends is a filter: while weekends are hidden its button is
   coloured like an active chip, so the state shows at a glance (James,
   2026-10-21: "hide/show weekends should change colour!"). */
.weekend-toggle.is-hiding {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--text);
}

/* A control the script stands in for (the term jump's Go): hidden once the
   script runs, whatever display its button class gives it. */
[data-hide-with-script][hidden] {
  display: none;
}

/* A tag's short form on a phone ("Moved · Tue AM", "Catch-up ×2"), its full
   words from 1024 px. A screen reader always hears the full words. */
.tag-short {
  display: none;
}

@media (max-width: 1023px) {
  .tag-long {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .tag-short {
    display: inline;
  }
}

/* Hide names and Hide weekends side by side, at the end of the filter row. */
.cal-toggles {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.cal-toggles .btn {
  flex: 1 1 auto;
}

/* The main screens in the top bar from 1024 px, the ☰ menu keeping only who
   is signed in, Admin, Help and Log out (James, 2026-10-21: "in desktop mode
   show the menu not the hamburger", #173). Below 1024 px the bar is as
   before: the name and ☰ Menu with every screen inside. */
.topnav {
  display: none;
}

@media (min-width: 1024px) {
  .topbar-name {
    flex: 0 1 auto;
  }

  .topnav {
    display: flex;
    flex: 1 1 auto;
    justify-content: flex-end;
    gap: 2px;
    min-width: 0;
  }

  .topnav-item {
    display: inline-flex;
    align-items: center;
    min-height: var(--tap);
    padding: 0 12px;
    border-radius: var(--radius-small);
    color: var(--topbar-text);
    font: 600 var(--text-small) / 1 var(--font-ui);
    text-decoration: none;
    white-space: nowrap;
  }

  .topnav-item:hover,
  .topnav-item:focus-visible {
    background: rgba(255, 255, 255, 0.12);
    color: var(--topbar-text);
  }

  .topnav-item[aria-current="page"] {
    box-shadow: inset 0 -3px 0 var(--accent);
  }

  .menu-screens {
    display: none;
  }
}

/* A fact's small form on the card: its fields and Save on one row; the notes'
   textarea takes the row. */
.fact-edit-form {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 4px;
}

.fact-edit-form select {
  flex: 1 1 8rem;
  min-width: 0;
  min-height: var(--tap);
}

/* A slot's times and places on one line on a phone too (James, 2026-10-21:
   "can the time and places be on the same row (decreases the height)"):
   tighter boxes and gaps, no wrap. Checked at 375 px with WebKit's 12-hour
   "AM"/"PM" still showing. */
@media (max-width: 699px) {
  .hours-times {
    flex-wrap: nowrap;
    gap: 4px;
  }

  .input.hours-time {
    flex: 1 1 0;
    min-width: 0;
    max-width: none;
    padding: 8px 4px;
  }

  .input.hours-places {
    width: 2.75em;
    padding: 8px 4px;
  }

  .hours-places-label {
    gap: 3px;
  }
}

/* The favourite session reads as words with an Edit button; Edit opens the
   day and time selects (James, 2026-10-21: "I would rather have an edit
   button to change it"). A <details>, so no script is needed. */
.fact-edit > summary {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  list-style: none;
  cursor: pointer;
}

.fact-edit > summary::-webkit-details-marker {
  display: none;
}

.fact-edit-button {
  min-height: 36px;
  padding: 4px 12px;
}

.fact-edit[open] .fact-edit-button {
  border-color: var(--accent);
  background: var(--accent-soft);
}

.fact-edit-form.is-wide textarea {
  flex: 1 1 100%;
}

/* A day's sessions on a desktop: three equal columns filled from the left,
   so nothing is squeezed into a quarter of the row (James, 2026-10-21:
   "widen the boxes in the day ... it all looks squashed"). Not pinned by
   slot: an evening-only day sat at the right edge ("the calendar has gone
   right justified which looks wrong"). */
@media (min-width: 1024px) {
  .week-sessions {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* ==========================================================================
   UX review, 2026-10-21 (James: "make pages consistent. The desktop should
   use the space and it should also work well on a iphone"). Each block below
   is one commit; they sit together at the foot of the file so a rebase over
   the rules above stays easy.
   ========================================================================== */

/* ---------- UX 1: one page width ----------
   Every screen shares one column, so the title and the content start at the
   same place whichever screen is open. Before, four widths (26, 44, 62 and
   76rem) made the page jump as the teacher moved between screens, and Today,
   Students and Terms sat in a 704px strip on a 1440px desktop. Forms keep a
   short line on a phone; from 1024px they line up with the page's left edge
   and lay their fields two to a row, so a form uses the desktop too. Prose
   (the help pages) keeps a reading measure. Sign-in and the offline pages
   name no screens, so they stay a centred card. */

:root {
  --page-max: 76rem;
  --form-max: 60rem;
  --read-max: 44rem;
}

.page,
.page.page-medium,
.page.page-wide {
  max-width: var(--page-max);
}

.help {
  max-width: var(--read-max);
}

@media (min-width: 1024px) {
  .page > .narrow:not(.narrow-centred) {
    max-width: var(--form-max);
    margin-left: 0;
  }

  /* Two fields to a row; a fieldset and the buttons take the whole row. */
  .narrow .form {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: 24px;
    align-items: start;
  }

  .narrow .form > :not(.field) {
    grid-column: 1 / -1;
  }

  .narrow .form-actions .btn {
    width: auto;
    min-width: 16rem;
  }

  /* A new term's classes: two days to a row. The studio hours keep one day
     to a row, so a slot's tick, times and places stay on one line. */
  .narrow .pattern {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: 24px;
  }

  .narrow .pattern > legend {
    float: left;
    grid-column: 1 / -1;
  }

  /* A list of classes in words: two columns, read down then across. */
  .narrow .progress-list {
    columns: 2;
    column-gap: 12px;
  }

  .narrow .progress-line {
    break-inside: avoid;
  }
}

/* Today's sessions share the row between them: three sessions, three
   columns, rather than two cards and a gap where a fourth would go. */
@media (min-width: 1024px) {
  .cards {
    grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
  }
}

/* The attendance sheet: two students to a row on a wide desktop, so a row's
   status buttons keep a button's size rather than stretching across 1300px.
   An iPad (1180px) keeps one to a row. Headings, notes and the search take
   the whole row. */
@media (min-width: 1366px) {
  .attendance-section {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: 16px;
  }

  .attendance-section > :not(.student-row) {
    grid-column: 1 / -1;
  }
}

/* ---------- UX 2: a switch shows its state ----------
   Hide weekends and Hide names were buttons whose words flipped ("Show
   weekends") while their colour flipped too, and the term page's copy had no
   tooltip: two signals pointing different ways. They are now the shared
   toggle chip (_toggle_chip.html): the slot chips' shape, the same words in
   both states, a drawn ✓ while on and ＋ while off. They follow the slot
   chips on the filter row instead of sitting against the right edge. */

.toggle-chip {
  flex: 0 0 auto;
}

@media (min-width: 1024px) {
  .cal-bar > .toggle-chip,
  .cal-bar > .cal-toggles {
    margin-left: 0;
  }
}

/* ---------- UX 3: fewer rows of controls on a phone ----------
   At 375px the calendar's ‹ previous and next › weeks took a row each, so
   eight rows of controls came before the first session; they now share one
   row, a long label wrapping inside its button rather than pushing the next
   one down. On the student card Call (its number never split) and WhatsApp
   share a row with Email under them at full width (it was three ragged
   rows), and the Edit
   buttons are full 44px tap targets (they were 36px). */

@media (max-width: 767.98px) {
  .month-nav {
    flex-wrap: nowrap;
  }

  .month-nav .btn {
    flex: 1 1 0;
    min-width: 0;
    padding: 8px 8px;
  }

  .contact-actions > .contact-link {
    flex: 1 1 auto;
    padding-left: 12px;
    padding-right: 12px;
    white-space: nowrap;
  }

  .contact-actions > .contact-link[href^="mailto:"] {
    flex-basis: 100%;
    white-space: normal;
  }
}

.fact-edit-button {
  min-height: var(--tap);
}

/* ---------- UX 4: a class carries its day's colour everywhere ----------
   A live term's class cards and its confirmation already wore the weekday's
   colour; the planner's step 2 and the studio hours list wore the accent
   for every class. Both now carry `wd-N`, so Monday is blue on every screen
   that lists classes. */
.hours-now .progress-line[class*="wd-"] {
  border-left-color: var(--day);
}

/* ---------- UX 5: the Activity table on a phone ----------
   Each stacked sort header is a full 44px tap (it was 32px), as every
   other control on a phone. */
@media (max-width: 699.98px) {
  .activity-table th .sort-link {
    min-height: var(--tap);
  }
}

/* ---------- UX 6: filters fold away on a phone ----------
   James, 2026-10-21: "for mobile, can we collapse some sections like the
   filters". _filters.html: from 700px the body is simply shown and its line
   and checkbox are not drawn. Below 700px the body folds behind one 44px
   line, "Filters · Morning, Hide weekends", which says what is on, so a
   filter is never hidden silently; a tap opens it, with "All" one tap away.
   A checkbox carries the open state: no script. */

.filters-toggle,
.filters-line {
  display: none;
}

@media (max-width: 699.98px) {
  .filters {
    position: relative;
    margin: 0 0 16px;
  }

  .filters-toggle {
    display: block;
    position: absolute;
    top: 0;
    left: 0;
    width: 1px;
    height: 1px;
    opacity: 0;
  }

  .filters-line {
    display: flex;
    align-items: center;
    gap: 6px;
    min-height: var(--tap);
    padding: 8px 12px;
    border: 1px solid var(--rule-strong);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--text);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }

  .filters-title {
    font-weight: 700;
    color: var(--text);
  }

  .filters-on {
    flex: 1 1 auto;
    min-width: 0;
    color: var(--text-quiet);
    font-weight: 600;
    overflow-wrap: anywhere;
  }

  /* A drawn chevron: down while folded, up while open. */
  .filters-mark::before {
    content: "▾";
    color: var(--text);
  }

  .filters-toggle:checked ~ .filters-line .filters-mark::before {
    content: "▴";
  }

  .filters-toggle:checked ~ .filters-line {
    border-color: var(--accent);
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
  }

  .filters-toggle:focus-visible ~ .filters-line {
    outline: 3px solid var(--focus);
    outline-offset: 2px;
  }

  .filters-body {
    display: none;
    padding: 12px;
    border: 1px solid var(--accent);
    border-top: 0;
    border-radius: 0 0 var(--radius) var(--radius);
    background: var(--surface);
    color: var(--text);
  }

  .filters-toggle:checked ~ .filters-body {
    display: grid;
    gap: 12px;
  }

  .filters-body > * {
    margin: 0;
  }
}

/* The calendar's bar: on a phone the weeks (or months), the other view and
   the folded filters, one to a row. From 700px the panel's wrappers step
   aside (display: contents) and the bar reads as before: the weeks, the term
   jump and the other view on one row; the slot chips and switches on the
   next. */
.cal-bar-all .month-nav,
.cal-bar-all .slot-chips,
.cal-bar-all .term-jump {
  margin: 0;
}

@media (max-width: 699.98px) {
  .cal-bar-all > .filters {
    margin: 0;
  }
}

@media (min-width: 700px) {
  .cal-bar-all .filters,
  .cal-bar-all .filters-body {
    display: contents;
  }

  .cal-bar-all > .month-nav {
    order: 1;
  }

  .cal-bar-all .term-jump {
    order: 2;
  }

  .cal-bar-all > .view-switch {
    order: 3;
  }

  .cal-bar-all::after {
    content: "";
    order: 4;
    flex: 1 1 100%;
    height: 0;
  }

  .cal-bar-all .slot-chips {
    order: 5;
  }

  .cal-bar-all .cal-toggles,
  .cal-bar-all .filters-body > .toggle-chip {
    order: 6;
  }

  .cal-bar-all .filters-body > * {
    flex: 1 1 100%;
    min-width: 0;
  }
}

@media (min-width: 1024px) {
  .cal-bar-all .filters-body > * {
    flex: 0 1 auto;
  }
}

/* ---------- UX 7: the calendar on a phone reads like a term's page ----------
   James, 2026-10-21: "on mobile, the /term detail view is better than the
   calendar with a block per week and a row per day". Below 700px the week
   view and the month's agenda take the term overview's shape (.ov-week,
   .ov-day, .ov-head, .ov-tap above): a bordered block per week; a row per
   day with its date on the left under the weekday's colour bar and its
   sessions beside it, each edged in that colour, names under a session. The
   measures and tokens are the overview's; the markup stays the calendar's,
   so the desktop drawings are untouched. A past day and a day with nothing
   on stay one full-width line. */
@media (max-width: 699.98px) {
  .week,
  .agenda-week {
    padding: 8px;
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    background: var(--surface);
  }

  .agenda {
    display: grid;
    gap: 12px;
  }

  .agenda-days {
    margin: 0;
    padding: 0;
    list-style: none;
  }

  .week-day,
  .agenda-day {
    display: grid;
    grid-template-columns: 6.5rem minmax(0, 1fr);
    gap: 8px;
    margin: 0;
    padding: 6px 0;
    border-top: 1px solid var(--rule);
    border-bottom: 0;
  }

  .week-day:first-child,
  .agenda-day:first-child {
    border-top: 0;
  }

  .week-day.is-quiet,
  .week-day.is-past {
    display: block;
    margin: 0;
    padding: 6px 0;
  }

  .week-day > .week-date,
  .agenda-date {
    align-self: start;
    margin: 0;
    padding-top: 6px;
    box-shadow: inset 0 3px 0 var(--day, var(--rule-strong));
    font: 700 var(--text-small) / 1.35 var(--font-ui);
    color: var(--text);
    overflow-wrap: anywhere;
  }

  .week-day.is-quiet > .week-date {
    box-shadow: none;
    font-size: var(--text-small);
  }

  .week-past > summary .week-date {
    font: 700 var(--text-small) / 1.35 var(--font-ui);
  }

  .week-day.is-today .week-date,
  .agenda-day.is-today .agenda-date {
    color: var(--accent);
  }

  .week-day .day-mark,
  .agenda-day .day-mark {
    font-size: 0.8125rem;
  }

  .week-day .week-sessions,
  .agenda-day .slot-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 0;
  }

  .week-day .slot-entry,
  .agenda-day .slot-entry {
    column-gap: 6px;
    padding: 6px 8px;
    border-color: var(--rule-strong);
    font-size: var(--text-small);
  }

  [class*="wd-"] .slot-entry:not(.is-closed):not(.is-over) {
    border-left-color: var(--day);
  }

  /* Names sit a step in from their session, so a name is never read as a slot. */
  .week-day .who-list {
    grid-template-columns: minmax(0, 1fr);
    margin-left: 12px;
  }

  .week-day .who {
    padding: 4px 8px;
    font-size: var(--text-small);
  }
}

/* The student card's term filter: "Show [All terms]" above its lists. */
.card-term {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 24px 0 8px;
}

.card-term .field-label {
  margin: 0;
}

.card-term .input {
  flex: 0 1 20rem;
  min-width: 0;
}

/* Today's two parts (James, 2026-10-21: '"today" should show now (today)
   and next (tomorrow or next session)'): Now, the cards to mark; Next, the
   next day's sessions as the calendar draws them. */
.today-now {
  margin: 0 0 12px;
}

.today-next {
  margin-top: 32px;
  padding-top: 16px;
  border-top: 1px solid var(--rule);
}

.today-past-booked {
  margin-top: 32px;
  padding-top: 16px;
  border-top: 1px solid var(--rule);
}

.past-booked-row {
  margin: 0;
  padding: 10px 10px 10px 12px;
  border: 1px solid var(--rule);
  border-left: 6px solid var(--warning);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
}

.past-booked-row .row-head {
  display: flex;
  align-items: flex-start;
  gap: 4px 10px;
  margin-bottom: 4px;
}

.past-booked-row .student-name {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  font: 600 1.125rem / 1.3 var(--font-read);
  color: var(--text);
  overflow-wrap: anywhere;
}

.past-booked-session {
  margin: 0 0 8px;
  font-size: var(--text-small);
}

.past-booked-session a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  font-weight: 600;
  color: var(--link);
}

.past-booked-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 52px;
  margin: 0;
  padding: 6px 8px;
  border: 2px solid var(--rule-strong);
  border-radius: var(--radius-small);
  background: var(--surface);
  color: var(--text);
  font: 600 0.9375rem / 1.25 var(--font-ui);
  text-align: center;
  overflow-wrap: anywhere;
  cursor: pointer;
}

.past-booked-attended {
  border-color: var(--here-bg);
}

.past-booked-missed {
  border-color: var(--warning);
}

.past-booked-btn:disabled {
  border-style: dashed;
  border-color: var(--rule-strong);
  background: transparent;
  color: var(--text-quiet);
  cursor: default;
}

/* Tables on the narrowest phones (QA, 2026-10-21: the Students list and the
   card's payments spilled 5–14px past a 343px screen, more with long
   names): headings may wrap, cells break long words, padding is tighter. */
@media (max-width: 479.98px) {
  .data-table th {
    white-space: normal;
  }

  .data-table th,
  .data-table td {
    padding-left: 6px;
    padding-right: 6px;
  }

  .data-table td {
    overflow-wrap: anywhere;
  }
}

/* Birthdays this week on Today (#52). */
.today-birthdays {
  margin: 0 0 16px;
  color: var(--text);
}

.today-birthdays a {
  font-weight: 600;
}

/* Notes on the attendance screen (revision 19, D20). A <details> per booked
   row and one for the session: no script. The summary is the 44px tap
   target and shows each note's first line, so a note is seen unopened. */
.row-notes,
.session-note {
  margin-top: 10px;
}

.session-note {
  margin: 0 0 16px;
}

.row-notes-summary,
.session-note-summary {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 2px;
  min-height: var(--tap);
  padding: 6px 12px;
  border: 1px solid var(--rule);
  border-radius: var(--radius-small);
  background: var(--surface-sunk);
  color: var(--text);
  list-style: none;
  cursor: pointer;
  overflow-wrap: anywhere;
}

.session-note-summary {
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-start;
  gap: 4px 6px;
  margin: 0;
  font: 400 var(--text-base) / 1.35 var(--font-read);
}

.session-note-summary.is-static {
  margin: 0 0 16px;
  cursor: auto;
}

.row-notes-summary::-webkit-details-marker,
.session-note-summary::-webkit-details-marker {
  display: none;
}

.row-notes[open] > .row-notes-summary,
.session-note[open] > .session-note-summary {
  border-color: var(--accent);
  background: var(--accent-soft);
}

.row-notes-label {
  font-weight: 600;
}

.row-notes-mark {
  color: var(--accent);
  font-weight: 700;
}

.session-note-add {
  color: var(--link);
  font: 600 var(--text-small) / 1.3 var(--font-ui);
}

.row-note-line {
  font-size: var(--text-small);
  color: var(--text-quiet);
}

.row-note-who {
  font-weight: 600;
  color: var(--text);
}

.row-notes-fields {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 10px 0 0;
}

.row-notes-fields .field-label:not(:first-child) {
  margin-top: 8px;
}

.row-notes-fields .field-hint {
  margin: 0;
}

.note-input {
  width: 100%;
  min-height: var(--tap);
  box-sizing: border-box;
}

/* ---------- session override (issue #51) ---------- */

.session-override {
  margin: 0 0 16px;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--surface);
  overflow: hidden;
}

.session-override-summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: var(--tap);
  padding: 8px 14px;
  font-weight: 600;
  cursor: pointer;
  user-select: none;
  list-style: none;
}

.session-override-summary::-webkit-details-marker {
  display: none;
}

.session-override[open] > .session-override-summary {
  border-bottom: 1px solid var(--rule);
  background: var(--accent-soft);
}

.session-override-label {
  color: var(--text);
}

.session-override-current {
  color: var(--text-quiet);
  font-size: var(--text-small);
  font-weight: 500;
}

.session-override-fields {
  padding: 12px 14px;
  background: var(--surface-sunk);
}

.session-override-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

.session-override-grid .field-pair {
  flex: 1 1 120px;
}

/* Group messaging (issue #54) */
.recipient-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 10px 0 16px;
}

.recipient-list {
  list-style: none;
  padding: 0;
  margin: 0 0 20px;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--surface);
  overflow: hidden;
}

.recipient-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  padding: 10px 14px;
  border-bottom: 1px solid var(--rule);
  gap: 8px;
  font-size: var(--text-small);
}

.recipient-row:last-child {
  border-bottom: none;
}

.recipient-name {
  font-weight: 600;
  flex: 1 1 120px;
}

.recipient-email {
  color: var(--text-quiet);
  flex: 1 1 160px;
}

.recipient-status {
  font-size: 0.8rem;
  padding: 2px 6px;
  border-radius: 4px;
  white-space: nowrap;
}

.recipient-status.is-ok {
  background: var(--surface-pop);
  color: var(--accent);
  border: 1px solid var(--accent);
}

.recipient-status.is-unreachable {
  background: var(--surface-sunk);
  color: var(--text-quiet);
  border: 1px solid var(--rule);
}

.recipient-empty {
  padding: 14px;
  color: var(--text-quiet);
  font-style: italic;
}

/* Term locking and visibility controls */
.term-status-badges {
  display: inline-flex;
  gap: 6px;
  align-items: center;
}

.term-card-toggles,
.term-detail-toggles {
  display: flex;
  gap: 8px;
  margin-top: 8px;
  flex-wrap: wrap;
}

.toggle-form {
  display: inline-block;
  margin: 0;
}

.term-locked-notice {
  color: var(--accent);
  font-weight: 600;
}

.head-title-row {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
}

.record-action-header {
  margin: 0 0 0 auto;
}

/* Student list: term standing tags & badges */
.tag-under {
  background: var(--error-soft);
  color: var(--error);
}

.tag-over {
  background: var(--accent-soft);
  color: var(--accent);
}

.tag-ontrack {
  background: var(--success-bg);
  color: var(--success-text);
}

.tag-noclass {
  color: var(--text-quiet);
  font-size: var(--text-small);
}

.standing-cell {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
  padding: 4px 0;
}

.standing-main {
  font-weight: 700;
  color: var(--text);
}

.standing-summary {
  display: block;
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--text-quiet);
  line-height: 1.25;
  white-space: nowrap;
}

.term-breakdown {
  margin: 0 0 16px;
  padding: 12px 14px;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
}

.term-breakdown-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 10px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--rule);
}

.term-breakdown-title {
  margin: 0;
  font: 700 1.15rem / 1.25 var(--font-read);
  color: var(--text);
}

.term-breakdown-status {
  display: flex;
  align-items: center;
}

.term-breakdown-groups {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.term-breakdown-group {
  padding: 10px 12px;
  border: 1px solid var(--rule);
  border-radius: var(--radius-small);
  background: var(--surface-sunk);
  color: var(--text);
}

.term-breakdown-label {
  margin: 0 0 8px;
  font-size: 0.72rem;
  font-weight: 700;
  color: var(--text-quiet);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.term-breakdown-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(95px, 1fr));
  gap: 8px;
  margin: 0;
  padding: 0;
}

@media (min-width: 820px) {
  .term-breakdown-stats {
    grid-template-columns: repeat(6, minmax(0, 1fr));
  }
}

.term-stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 8px 6px;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--radius-small);
  min-height: 4.5rem;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.02);
  transition: border-color 0.15s, background-color 0.15s;
}

.term-stat:hover {
  border-color: var(--accent);
}

.term-stat dt {
  order: 2;
  margin-top: 5px;
  font-size: 0.7rem;
  font-weight: 600;
  color: var(--text-quiet);
  line-height: 1.15;
  text-align: center;
}

.term-stat dd {
  order: 1;
  margin: 0;
  font-size: 1.5rem;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  color: var(--text);
}

.term-stat-credits {
  border-color: var(--accent);
  background: var(--surface);
}

.term-stat-credits dd {
  color: var(--accent);
}

.term-stat-needed {
  border-color: var(--rule-strong);
}

.term-stat-status dd {
  font-size: 1.1rem;
  font-weight: 700;
  line-height: 1.15;
  white-space: nowrap;
}

.term-stat-ontrack {
  background: var(--success-bg);
  border-color: var(--st-attended);
}

.term-stat-ontrack dd {
  color: var(--st-attended);
}

.term-stat-ontrack dt {
  color: var(--success-text);
  font-weight: 700;
}

.term-stat-ontrack:hover {
  border-color: var(--st-attended);
  box-shadow: 0 2px 6px rgba(47, 107, 47, 0.2);
}

.term-stat-under {
  background: var(--error-soft);
  border-color: var(--error);
}

.term-stat-under dd {
  color: var(--error);
}

.term-stat-under dt {
  color: var(--error);
  font-weight: 700;
}

.term-stat-under:hover {
  border-color: var(--error);
  box-shadow: 0 2px 6px rgba(176, 38, 28, 0.2);
}

.term-stat-over {
  background: var(--accent-soft);
  border-color: var(--accent);
}

.term-stat-over dd {
  color: var(--accent);
}

.term-stat-over dt {
  color: var(--accent);
  font-weight: 700;
}

.term-stat-over:hover {
  border-color: var(--accent);
  box-shadow: 0 2px 6px rgba(161, 64, 31, 0.2);
}

.term-stat-noclass dd {
  color: var(--text-quiet);
  font-size: 0.95rem;
}

/* Student list filter bar: Name search, Term dropdown, and Detail toggle on the same row. */
.student-filter-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 14px;
  margin: 0 0 16px;
}

.student-filter-name {
  flex: 1 1 18rem;
  min-width: 180px;
}

.card-term.student-term-picker {
  margin: 0;
  flex: 0 1 16rem;
  min-width: 160px;
}

.card-term.student-term-picker .input {
  flex: 1 1 auto;
  width: 100%;
}

.student-filter-detail {
  flex: 0 0 auto;
}

/* Missing contact tags in student list */
.tag-missing {
  display: inline-block;
  font-size: 0.72rem;
  line-height: 1.2;
  font-weight: 600;
  padding: 2px 6px;
  border-radius: 4px;
  background: var(--error-soft);
  color: var(--error);
  margin-left: 6px;
  vertical-align: middle;
}


/* "This week" / "This month" stays put while showing it (James, 2026-10-22:
   "do not hide the this week/this month button"), drawn as the current
   place rather than a link, so the neighbours never jump sideways. */
.month-nav .btn.is-current {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--text);
  cursor: default;
}

/* Terms screen layout improvements and expandable closure drawer */
.term-cards > li {
  display: flex;
  flex-direction: column;
}

.term-cards .card-link {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  height: auto;
}

.term-cards .card {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
}

.term-cards .term-facts {
  flex: 1 1 auto;
}

.term-cards .card-go {
  margin-top: auto;
  padding-top: 8px;
}

.term-card-toggles {
  display: flex;
  gap: 8px;
  margin-top: 10px;
  flex-wrap: wrap;
}

.term-card-toggles .toggle-form {
  flex: 1 1 calc(50% - 4px);
  min-width: 120px;
}

.term-card-toggles .btn {
  width: 100%;
  font-size: 0.85rem;
  padding: 6px 10px;
  text-align: center;
}

.closure-section {
  margin-top: 32px;
  border-top: 1px solid var(--rule);
  padding-top: 24px;
}

.closure-section-head {
  margin-bottom: 16px;
}

.empty-closures-hint {
  font-style: italic;
  color: var(--text-quiet);
}

.closure-drawer {
  margin-top: 18px;
}

.closure-drawer > summary.closure-drawer-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
  list-style: none;
}

.closure-drawer > summary::-webkit-details-marker {
  display: none;
}

.closure-drawer[open] > summary.closure-drawer-btn {
  margin-bottom: 16px;
}

.closure-form-card {
  padding: 18px 20px;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  margin-top: 8px;
  max-width: 36rem;
}

.closure-form-title {
  margin: 0 0 14px;
  font-size: 1.15rem;
  font-weight: 600;
  color: var(--text);
}

.closure-overlap-alert {
  margin-bottom: 16px;
  padding: 10px 14px;
  border-radius: var(--radius);
  background: var(--accent-soft, #fef3c7);
  border: 1px solid var(--accent, #f59e0b);
  color: var(--accent-dark, #92400e);
  font-size: 0.9rem;
  line-height: 1.4;
}

/* Future away highlighted badge in student detailed table */
.badge.tag-future-away {
  background: var(--st-holiday, #f59e0b);
  color: var(--on-status, #1c1612);
  font-weight: 700;
  display: inline-block;
  padding: 1px 7px;
  border-radius: 9999px;
  line-height: 1.3;
}

/* ---------- Front-end reports (issue #200) ---------- */

.reports-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 16px;
  margin: 0 0 32px;
}

.report-card {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 18px 20px;
  border-radius: var(--radius);
  background: var(--surface);
  border: 1px solid var(--rule);
  color: var(--text);
  text-decoration: none;
  box-shadow: var(--shadow);
  transition: border-color 150ms ease, box-shadow 150ms ease;
}

.report-card:hover,
.report-card:focus-visible {
  border-color: var(--accent);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}

.report-card-title {
  margin: 0 0 6px;
  font: 600 var(--text-base) / 1.2 var(--font-read);
  color: var(--text);
}

.report-card-desc {
  margin: 0;
  font-size: var(--text-small);
  color: var(--text-quiet);
  line-height: 1.4;
}

.report-card-arrow {
  font-size: 1.25rem;
  color: var(--accent);
  flex-shrink: 0;
}

.reports-shortcuts {
  margin: 32px 0 0;
}

.shortcuts-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin: 12px 0 0;
}

.shortcut-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 16px;
  border-radius: 9999px;
  background: var(--surface);
  border: 1px solid var(--rule);
  color: var(--text);
  text-decoration: none;
  font-size: var(--text-small);
  font-weight: 500;
  min-height: var(--tap);
}

.shortcut-chip:hover {
  border-color: var(--accent);
  color: var(--link);
}

.report-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0 0 20px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--rule);
}

.report-nav-item {
  display: inline-flex;
  align-items: center;
  padding: 6px 14px;
  border-radius: 9999px;
  font: 500 var(--text-small) / 1 var(--font-ui);
  color: var(--text);
  text-decoration: none;
  background: var(--surface-sunk);
  min-height: var(--tap);
}

.report-nav-item:hover {
  background: var(--surface);
  color: var(--link);
}

.report-nav-item.is-active {
  background: var(--accent);
  /* Not #fff: --accent is a light orange in dark mode, where white on it is
     2.69:1. --on-accent is white in light and near-black in dark. */
  color: var(--on-accent);
  font-weight: 600;
}

.report-intro {
  margin: 0 0 16px;
  font-size: var(--text-base);
}

.report-filters {
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  padding: 16px;
  margin: 0 0 24px;
}

.report-filters-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 14px 16px;
}

/* The report filters are back-office forms (`IssueFilterForm` and the report
   forms), whose widgets carry no class — the desk styles them by element. In
   the front end that left them at the browser's own 32–34px, under the 44px
   the standard asks for, so they are given the `.input` treatment here by
   element instead of by class. */
.report-filters input[type="date"],
.report-filters input[type="text"],
.report-filters input[type="number"],
.report-filters input[type="search"],
.report-filters select {
  display: block;
  width: 100%;
  min-height: var(--tap);
  padding: 10px 12px;
  border: 2px solid var(--rule-strong);
  border-radius: var(--radius-small);
  background: var(--surface);
  color: var(--text);
  font: 1.0625rem / 1.3 var(--font-ui); /* ≥16px: iOS does not zoom on focus */
}

.report-filters input:focus,
.report-filters select:focus {
  border-color: var(--accent);
  outline: 2px solid var(--focus);
  outline-offset: 1px;
}

/* A grid item is `min-width: auto`, so one long option name (a student's) can
   push the whole grid wider than the phone. */
.report-filters .field {
  min-width: 0;
}

.report-filter-actions {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 16px;
}

.report-notes {
  margin: 0 0 20px;
}

.report-note {
  margin: 0 0 8px;
  color: var(--text);
  font-weight: 500;
}

.report-export {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 12px;
  margin: 12px 0 0;
}

.report-section {
  margin: 0 0 28px;
}

.issue-kinds {
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  padding: 14px 16px;
  margin: 0 0 20px;
}

.issue-kinds-title {
  margin: 0 0 4px;
  font-size: 1rem;
  font-weight: 700;
}

.issue-kinds-list {
  margin: 8px 0 0;
  padding-left: 1.25rem;
}

/* Severity reads in both themes (§4.6): tokens, not fixed hex, and the word
   is written out beside the colour. The desk's own badges are built the same
   way (`desk.css`, `.desk-badge.severity-*`). */
.cell-tag.severity-critical,
.cell-tag.severity-high {
  background: var(--error-soft);
  color: var(--error-text);
  font-weight: 700;
}

.cell-tag.severity-medium {
  background: var(--warning-soft);
  color: var(--warning-text);
  font-weight: 600;
}

.cell-tag.severity-low {
  background: var(--surface-sunk);
  color: var(--text);
}

