/* =============================================================================
   Koinonia Homeschool Group — registration, shared stylesheet
   =============================================================================

   Styled to sit alongside koinoniaphx.com: PT Sans throughout, the same blue
   (#1279BE) for anything actionable, the same slate (#2E4453) for headings,
   and #303030 body text on white. Headings are bold PT Sans rather than a
   contrasting serif, which is what that site does and is the single biggest
   reason the two now read as related.

   PT Sans ships 400 and 700 only. Weights are written accordingly — asking for
   500 or 600 gets a synthesised face that looks subtly wrong next to the real
   bold, which is exactly the sort of thing that makes a page feel off without
   anyone being able to say why.

   Unlike the marketing site this follows the visitor's OS theme. That site is a
   reading experience; this is a dense data application a parent may be filling
   in on a phone with a child on their hip.
   ============================================================================= */

:root {
  --accent:        #1279be;   /* koinoniaphx.com link + button blue */
  --accent-strong: #0f5f96;
  --accent-soft:   rgba(18, 121, 190, 0.10);
  --heading:       #2e4453;   /* their slate */

  --bg:        #f4f7f9;
  --surface:   #ffffff;
  --surface-2: #eef2f5;
  --text:      #303030;
  --text-muted:#5f6b73;
  --text-faint:#8a959c;
  --border:    #dde5ea;
  --border-strong: #c3ced6;

  --ok:      #2e7d32;
  --ok-bg:   rgba(46, 125, 50, 0.10);
  --warn:    #a15c00;
  --warn-bg: rgba(161, 92, 0, 0.12);
  --danger:  #c02626;
  --danger-bg: rgba(192, 38, 38, 0.10);
  --info-bg: rgba(18, 121, 190, 0.08);

  --radius: 6px;
  --radius-sm: 4px;
  --shadow: 0 1px 2px rgba(46, 68, 83, 0.06), 0 4px 12px rgba(46, 68, 83, 0.06);
  --shadow-lg: 0 8px 32px rgba(46, 68, 83, 0.20);

  --font-sans: 'PT Sans', -apple-system, system-ui, 'Segoe UI', Roboto,
               'Helvetica Neue', sans-serif;
  --font-heading: var(--font-sans);

  --topbar-h: 56px;
}

@media (prefers-color-scheme: dark) {
  :root {
    --accent:        #55a8e0;
    --accent-strong: #7cc0ec;
    --accent-soft:   rgba(85, 168, 224, 0.14);
    --heading:       #d7e5ef;

    --bg:        #121a20;
    --surface:   #1a242c;
    --surface-2: #222f38;
    --text:      #e6edf2;
    --text-muted:#a2b0ba;
    --text-faint:#7b8b96;
    --border:    #2b3942;
    --border-strong: #3d4d58;

    --ok:      #6fbf73;
    --ok-bg:   rgba(111, 191, 115, 0.12);
    --warn:    #dda15e;
    --warn-bg: rgba(221, 161, 94, 0.14);
    --danger:  #e57373;
    --danger-bg: rgba(229, 115, 115, 0.12);
    --info-bg: rgba(85, 168, 224, 0.12);

    --shadow: 0 1px 2px rgba(0,0,0,.4), 0 4px 12px rgba(0,0,0,.3);
    --shadow-lg: 0 8px 32px rgba(0,0,0,.55);
  }
}

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

/* The `hidden` attribute only sets `display: none` at user-agent priority, so
   any later `display` rule silently defeats it. .topbar sets display:flex, so
   without this a hidden topbar would still be on screen. */
[hidden] { display: none !important; }

html { -webkit-text-size-adjust: 100%; }

body {
  font-family: var(--font-sans);
  font-size: 15px;
  line-height: 1.55;
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 {
  font-family: var(--font-heading); font-weight: 700;
  line-height: 1.25; color: var(--heading);
}
h1 { font-size: 1.85rem; letter-spacing: -0.01em; }
h2 { font-size: 1.35rem; }
h3 { font-size: 1.1rem; }
h4 { font-size: 1rem; }

a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-strong); text-decoration: underline; }

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

/* --- Layout ---------------------------------------------------------------- */
.wrap { max-width: 1080px; margin: 0 auto; padding: 0 1.25rem; }
.wrap-narrow { max-width: 720px; margin: 0 auto; padding: 0 1.25rem; }

.topbar {
  position: sticky; top: 0; z-index: 50;
  height: var(--topbar-h);
  display: flex; align-items: center;
  background: color-mix(in srgb, var(--surface) 92%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border);
}
.topbar .wrap { display: flex; align-items: center; gap: 1.5rem; width: 100%; }

.brand {
  display: inline-flex; align-items: center; gap: .55rem;
  font-family: var(--font-heading); font-size: 1.15rem; font-weight: 700;
  color: var(--heading); white-space: nowrap;
}
.brand:hover { color: var(--accent); text-decoration: none; }

/* The co-op's own mark, so families recognise where they have landed before
   reading a word. Decorative beside the name, hence the empty alt. */
.brand-mark { border-radius: 50%; flex: none; object-fit: cover; }
.brand-sub { font-weight: 400; color: var(--text-muted); }

.brand-hero {
  border-radius: 50%; display: block; margin: 0 auto 1rem;
  box-shadow: var(--shadow);
}
.centered .lede {
  font-size: 1.05rem; color: var(--text-muted); margin-top: -.25rem;
}

@media (max-width: 600px) {
  /* On a phone the mark carries the identity; the words would crowd the nav. */
  .brand span { display: none; }
}

.mainnav { display: flex; gap: .25rem; flex: 1; flex-wrap: wrap; }
.mainnav a {
  padding: .4rem .7rem; border-radius: var(--radius-sm);
  font-size: .82rem; letter-spacing: .04em;
  text-transform: uppercase; color: var(--text-muted);
}
.mainnav a:hover { color: var(--text); background: var(--surface-2); text-decoration: none; }
.mainnav a.active { color: var(--accent); background: var(--accent-soft); }

/* padding-block, not the padding shorthand: `.wrap .page` land on the same
   element, and a shorthand here would silently wipe .wrap's side padding and
   push content flush to the screen edge on phones. */
.page { padding-block: 2rem 5rem; }

.page-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap; margin-bottom: 1.5rem;
}
.page-head .sub { color: var(--text-muted); font-size: .92rem; margin-top: .15rem; }

.crumbs { font-size: .85rem; color: var(--text-faint); margin-bottom: .5rem; }
.crumbs a { color: var(--text-muted); }
.crumbs span { margin: 0 .4rem; }

/* --- Cards ----------------------------------------------------------------- */
.card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 1.15rem 1.25rem;
}
.card + .card { margin-top: .75rem; }
.card-link { display: block; color: inherit; transition: border-color .15s, transform .15s; }
.card-link:hover {
  text-decoration: none; color: inherit;
  border-color: var(--border-strong); box-shadow: var(--shadow);
}
.card-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: .75rem; margin-bottom: .9rem; flex-wrap: wrap;
}
.card-head h2, .card-head h3 { margin: 0; }

.grid { display: grid; gap: .75rem; }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.grid-3 { grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); }

/* --- Stat tiles ------------------------------------------------------------ */
.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: .7rem; }
.stat {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: .9rem 1rem;
}
.stat .n {
  font-family: var(--font-heading); font-size: 1.8rem; font-weight: 700;
  line-height: 1.1; display: block;
}
.stat .l {
  font-size: .76rem; text-transform: uppercase; letter-spacing: .06em;
  color: var(--text-faint); margin-top: .2rem;
}
.stat.attn .n { color: var(--warn); }
.stat.bad .n  { color: var(--danger); }

/* --- Buttons --------------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .4rem;
  font-family: inherit; font-size: .88rem; font-weight: 700; line-height: 1;
  padding: .58rem 1rem; border-radius: var(--radius-sm);
  border: 1px solid var(--border-strong); background: var(--surface);
  color: var(--text); cursor: pointer; white-space: nowrap;
  transition: background .12s, border-color .12s, opacity .12s;
}
.btn:hover:not(:disabled) { background: var(--surface-2); text-decoration: none; }
.btn:disabled { opacity: .5; cursor: not-allowed; }

.btn-primary {
  background: var(--accent); border-color: var(--accent); color: #fff;
}
.btn-primary:hover:not(:disabled) { background: var(--accent-strong); border-color: var(--accent-strong); }
@media (prefers-color-scheme: dark) { .btn-primary { color: #0e1519; } }

.btn-danger { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 40%, transparent); }
.btn-danger:hover:not(:disabled) { background: var(--danger-bg); }

.btn-ghost { border-color: transparent; background: transparent; color: var(--text-muted); }
.btn-ghost:hover:not(:disabled) { background: var(--surface-2); color: var(--text); }

.btn-sm { padding: .35rem .65rem; font-size: .8rem; }
.btn-block { width: 100%; }
.btn-row { display: flex; gap: .5rem; flex-wrap: wrap; }

/* --- Forms ----------------------------------------------------------------- */
.field { margin-bottom: .9rem; }
.field label, .lbl {
  display: block; font-size: .8rem;
  color: var(--text-muted); margin-bottom: .3rem;
}
.field .hint { font-size: .78rem; color: var(--text-faint); margin-top: .25rem; }

input[type=text], input[type=email], input[type=date], input[type=time],
input[type=number], input[type=search], input[type=datetime-local],
select, textarea {
  width: 100%; font-family: inherit; font-size: .92rem; color: var(--text);
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm); padding: .5rem .65rem;
}
textarea { min-height: 80px; resize: vertical; }
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
input::placeholder, textarea::placeholder { color: var(--text-faint); }

.field-row { display: grid; gap: .75rem; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); }

.check { display: flex; align-items: center; gap: .5rem; font-size: .9rem; }
.check input { width: auto; }

/* --- Badges ---------------------------------------------------------------- */
.badge {
  display: inline-flex; align-items: center; gap: .3rem;
  font-size: .72rem; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; padding: .2rem .5rem; border-radius: 100px;
  background: var(--surface-2); color: var(--text-muted); white-space: nowrap;
}
.badge-ok     { background: var(--ok-bg);     color: var(--ok); }
.badge-warn   { background: var(--warn-bg);   color: var(--warn); }
.badge-danger { background: var(--danger-bg); color: var(--danger); }
.badge-accent { background: var(--accent-soft); color: var(--accent); }

/* --- Tables ---------------------------------------------------------------- */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
table { width: 100%; border-collapse: collapse; font-size: .9rem; }
th {
  text-align: left; font-size: .74rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .05em; color: var(--text-faint);
  padding: .5rem .6rem; border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
td { padding: .55rem .6rem; border-bottom: 1px solid var(--border); vertical-align: middle; }
tbody tr:last-child td { border-bottom: none; }
tbody tr:hover { background: var(--surface-2); }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }

/* --- Messages -------------------------------------------------------------- */
.note {
  padding: .7rem .85rem; border-radius: var(--radius-sm); font-size: .88rem;
  background: var(--info-bg); border: 1px solid transparent; margin-bottom: .75rem;
}
.note-ok     { background: var(--ok-bg);     color: var(--ok); }
.note-warn   { background: var(--warn-bg);   color: var(--warn); }
.note-danger { background: var(--danger-bg); color: var(--danger); }
.note ul { margin: .35rem 0 0 1.1rem; }

.empty {
  text-align: center; padding: 3rem 1rem; color: var(--text-faint);
  border: 1px dashed var(--border-strong); border-radius: var(--radius);
}
.empty h3 { color: var(--text-muted); margin-bottom: .35rem; }

.muted { color: var(--text-muted); }
.faint { color: var(--text-faint); }
.small { font-size: .85rem; }
.tiny  { font-size: .78rem; }
.mono  { font-variant-numeric: tabular-nums; }
.right { text-align: right; }
.nowrap { white-space: nowrap; }
.mt  { margin-top: .75rem; }
.mt2 { margin-top: 1.5rem; }
.mb  { margin-bottom: .75rem; }
.spacer { flex: 1; }

/* --- Dialog ---------------------------------------------------------------- */
dialog {
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface); color: var(--text);
  padding: 0; max-width: 540px; width: calc(100vw - 2rem);
  box-shadow: var(--shadow-lg);
  /* A modal dialog is centred by the UA's `margin: auto`, which the global
     `* { margin: 0 }` reset above would otherwise strip, leaving every dialog
     stuck in the top-left corner. */
  margin: auto;
}
dialog::backdrop { background: rgba(20, 18, 16, .55); backdrop-filter: blur(2px); }
.dialog-head { padding: 1.1rem 1.25rem .25rem; }
.dialog-head h3 { margin: 0; }
.dialog-body { padding: .85rem 1.25rem; max-height: 65vh; overflow-y: auto; }
.dialog-foot {
  padding: .9rem 1.25rem; border-top: 1px solid var(--border);
  display: flex; gap: .5rem; justify-content: flex-end; flex-wrap: wrap;
}

/* --- Toasts ---------------------------------------------------------------- */
#toasts {
  position: fixed; bottom: 1rem; right: 1rem; z-index: 200;
  display: flex; flex-direction: column; gap: .5rem; max-width: min(380px, calc(100vw - 2rem));
}
.toast {
  background: var(--surface); border: 1px solid var(--border-strong);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-sm); padding: .7rem .9rem; font-size: .88rem;
  box-shadow: var(--shadow-lg); animation: toast-in .18s ease-out;
}
.toast.ok  { border-left-color: var(--ok); }
.toast.err { border-left-color: var(--danger); }
@keyframes toast-in { from { opacity: 0; transform: translateY(8px); } }

/* --- Loading --------------------------------------------------------------- */
.spinner {
  width: 18px; height: 18px; border: 2px solid var(--border-strong);
  border-top-color: var(--accent); border-radius: 50%;
  animation: spin .7s linear infinite; display: inline-block; vertical-align: -3px;
}
@keyframes spin { to { transform: rotate(360deg); } }
.loading { padding: 3rem 1rem; text-align: center; color: var(--text-faint); }

/* =============================================================================
   Semester builder
   ============================================================================= */
.period-card { border-left: 3px solid var(--accent); }
.period-time { font-variant-numeric: tabular-nums; color: var(--text-muted); font-size: .9rem; }

.class-list { display: grid; gap: .5rem; }
.class-row {
  display: flex; align-items: center; gap: .85rem;
  padding: .7rem .85rem; background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  color: inherit;
}
.class-row:hover { border-color: var(--border-strong); text-decoration: none; color: inherit; }
.class-row .cr-main { flex: 1; min-width: 0; }
.class-row .cr-name { font-weight: 700; }
.class-row .cr-meta { font-size: .82rem; color: var(--text-muted); }
.class-row .cr-seats { text-align: right; font-size: .84rem; white-space: nowrap; }
.class-row.archived { opacity: .55; }

.seatbar {
  height: 4px; border-radius: 2px; background: var(--surface-2);
  overflow: hidden; margin-top: .35rem; min-width: 70px;
}
.seatbar > i { display: block; height: 100%; background: var(--accent); }
.seatbar.full > i { background: var(--warn); }
.seatbar.over > i { background: var(--danger); }

/* =============================================================================
   Family registration
   ============================================================================= */
.reg-layout { display: grid; gap: 1.5rem; grid-template-columns: 1fr; }
@media (min-width: 900px) {
  .reg-layout { grid-template-columns: 1fr 290px; align-items: start; }
  .reg-summary { position: sticky; top: calc(var(--topbar-h) + 1.5rem); }
}

.childtabs {
  display: flex; gap: .4rem; overflow-x: auto; padding-bottom: .5rem;
  margin-bottom: 1.25rem; border-bottom: 1px solid var(--border);
  -webkit-overflow-scrolling: touch;
}
.childtab {
  flex: none; padding: .5rem .9rem; border-radius: var(--radius-sm);
  border: 1px solid var(--border-strong); background: var(--surface);
  color: var(--text-muted); cursor: pointer; font-family: inherit; font-size: .9rem;
}
.childtab .age { display: block; font-size: .74rem; color: var(--text-faint); }
.childtab[aria-selected="true"] {
  background: var(--accent); border-color: var(--accent); color: #fff;
}
.childtab[aria-selected="true"] .age { color: rgba(255,255,255,.8); }
@media (prefers-color-scheme: dark) {
  .childtab[aria-selected="true"] { color: #0e1519; }
  .childtab[aria-selected="true"] .age { color: rgba(14,21,25,.72); }
}
.childtab .dot {
  display: inline-block; width: 6px; height: 6px; border-radius: 50%;
  background: var(--warn); margin-left: .35rem; vertical-align: middle;
}

/* --- "Is this child taking classes?" ---------------------------------------
   Sits above the periods, because it decides whether the periods are relevant
   at all. Deliberately quiet when the answer is yes, and clearly marked when
   the answer is no. */
.participation {
  border: 1px solid var(--border); border-radius: var(--radius);
  padding: .85rem 1rem; margin-bottom: 1.5rem; background: var(--surface);
}
.participation legend { padding: 0 0 .5rem; margin: 0; }
.participation.is-out {
  border-color: color-mix(in srgb, var(--warn) 45%, transparent);
  background: var(--warn-bg);
}
.participation-choices { display: flex; gap: .5rem; flex-wrap: wrap; }

.pill { display: inline-flex; }
.pill input { position: absolute; opacity: 0; pointer-events: none; }
.pill span {
  display: inline-block; padding: .45rem .8rem; font-size: .88rem;
  border: 1px solid var(--border-strong); border-radius: 100px;
  background: var(--surface); cursor: pointer; transition: background .12s, border-color .12s;
}
.pill span:hover { border-color: var(--accent); }
.pill input:checked + span {
  background: var(--accent); border-color: var(--accent); color: #fff;
}
.pill input:focus-visible + span { outline: 2px solid var(--accent); outline-offset: 2px; }
.pill input:disabled + span { opacity: .55; cursor: not-allowed; }
@media (prefers-color-scheme: dark) { .pill input:checked + span { color: #0e1519; } }

/* A child sitting out reads as set aside, not as an error. */
.childtab.is-out { opacity: .6; border-style: dashed; }
.childtab.is-out[aria-selected="true"] { opacity: 1; }

.period-block { margin-bottom: 1.5rem; }
/* The fieldset is there to group the period's options for assistive tech; it
   should carry none of the browser's default chrome. */
.period-block fieldset { border: 0; padding: 0; margin: 0; min-width: 0; }
.period-block legend { padding: 0; width: 100%; }
.period-block h3 {
  display: flex; align-items: baseline; gap: .6rem;
  margin-bottom: .6rem; flex-wrap: wrap;
}

/* A class the parent can choose. Built on a real radio input so keyboard and
   screen-reader behaviour is the browser's, not ours. */
.opt { display: block; position: relative; }
.opt input { position: absolute; opacity: 0; pointer-events: none; }
.opt > .body {
  display: flex; align-items: flex-start; gap: .8rem;
  padding: .8rem .9rem; border: 1px solid var(--border);
  border-radius: var(--radius-sm); background: var(--surface);
  cursor: pointer; transition: border-color .12s, background .12s;
}
.opt + .opt { margin-top: .5rem; }
.opt > .body:hover { border-color: var(--border-strong); }
.opt input:focus-visible + .body { outline: 2px solid var(--accent); outline-offset: 2px; }
.opt input:checked + .body {
  border-color: var(--accent); background: var(--accent-soft);
}

.opt .mark {
  flex: none; width: 18px; height: 18px; border-radius: 50%; margin-top: .12rem;
  border: 2px solid var(--border-strong); background: var(--surface);
  display: grid; place-items: center;
}
.opt input:checked + .body .mark { border-color: var(--accent); }
.opt input:checked + .body .mark::after {
  content: ''; width: 8px; height: 8px; border-radius: 50%; background: var(--accent);
}
.opt .info { flex: 1; min-width: 0; }
/* Each of these is its own line — a class with a description and an
   ineligibility reason has three things to say, and they must not run together. */
.opt .name, .opt .meta, .opt .why { display: block; }
.opt .name { font-weight: 700; }
.opt .meta { font-size: .82rem; color: var(--text-muted); margin-top: .1rem; }
.opt .why  { font-size: .82rem; color: var(--warn); margin-top: .25rem; }

/* Full, but joinable as a waitlist */
.opt.full > .body { background: var(--surface-2); }
.opt.full .mark { border-radius: 4px; }
.opt.full input:checked + .body .mark::after { border-radius: 1px; }

/* --- Ticked waitlist ---------------------------------------------------------
   The default checked style is the accent colour, which reads as "sorted". A
   waitlist is not sorted, so it must not borrow that reassurance.

   Two states, deliberately different: stranded (waitlisted with no seat that
   period) is red and loud, because the child has nowhere to be; covered
   (waitlisted alongside a confirmed class) is a calm amber, because nothing is
   wrong. Painting both red would train families to ignore the red. */
.opt.wl-stranded input:checked + .body {
  background: var(--danger-bg);
  border-color: var(--danger);
  box-shadow: inset 3px 0 0 var(--danger);
}
.opt.wl-stranded input:checked + .body .mark { border-color: var(--danger); }
.opt.wl-stranded input:checked + .body .mark::after { background: var(--danger); }
.opt.wl-stranded input:checked + .body .name { color: var(--danger); }

.opt.wl-covered input:checked + .body {
  background: var(--warn-bg);
  border-color: color-mix(in srgb, var(--warn) 55%, transparent);
}
.opt.wl-covered input:checked + .body .mark { border-color: var(--warn); }
.opt.wl-covered input:checked + .body .mark::after { background: var(--warn); }

.opt .why-alarm {
  display: block; margin-top: .4rem; padding: .4rem .55rem;
  font-size: .84rem; line-height: 1.45;
  color: var(--danger); background: var(--danger-bg);
  border-radius: var(--radius-sm);
}
.opt .why-alarm strong { font-weight: 700; }

/* Ineligible: visible with an explanation (§17 Option B), never selectable. */
.opt.inelig > .body { opacity: .58; cursor: not-allowed; background: transparent; }
.opt.inelig > .body:hover { border-color: var(--border); }
.opt.inelig .mark { opacity: .4; }

.opt .clear { margin-top: .5rem; }

/* --- Second choice ---------------------------------------------------------
   One line under the period's options, and only once a first choice exists —
   a parent who wants one class never sees it. */
.second { margin-top: .6rem; padding-left: .1rem; }
.second label {
  display: block; font-size: .82rem; color: var(--text-muted); margin-bottom: .25rem;
}
.second select { font-size: .86rem; padding: .4rem .55rem; }

/* --- Volunteering ---------------------------------------------------------- */
.volunteer {
  border: 1px solid var(--border); border-radius: var(--radius);
  padding: .85rem 1rem; margin-top: 1.5rem; background: var(--surface);
}
.volunteer legend { padding: 0 0 .5rem; margin: 0; }
.volunteer.is-on { border-color: color-mix(in srgb, var(--accent) 45%, transparent); }
.volunteer-detail { margin-top: .9rem; padding-top: .8rem; border-top: 1px solid var(--border); }

.vol-period { margin-top: .7rem; }
.vol-period > .check { margin-bottom: .35rem; }
.vol-classes { display: flex; flex-wrap: wrap; gap: .35rem; padding-left: 1.6rem; }

/* Compact multi-select: a wrapped row of tick-able chips rather than a column
   of checkboxes, so eight classes take two lines instead of eight. */
.chip { display: inline-flex; }
.chip input { position: absolute; opacity: 0; pointer-events: none; }
.chip span {
  display: inline-block; padding: .25rem .6rem; font-size: .8rem;
  border: 1px solid var(--border-strong); border-radius: 100px;
  background: var(--surface); cursor: pointer;
}
.chip span:hover { border-color: var(--accent); }
.chip input:checked + span {
  background: var(--accent-soft); border-color: var(--accent); color: var(--accent);
}
.chip input:focus-visible + span { outline: 2px solid var(--accent); outline-offset: 2px; }
.chip input:disabled + span { opacity: .45; cursor: not-allowed; }

.sum-row .alt { color: var(--text-faint); font-size: .8rem; }

/* Schedule summary */
.reg-summary .card { position: relative; }
.sum-child + .sum-child { margin-top: .9rem; padding-top: .9rem; border-top: 1px solid var(--border); }
.sum-child .who { font-weight: 700; margin-bottom: .25rem; }
.sum-row { display: flex; gap: .5rem; font-size: .88rem; padding: .12rem 0; }
.sum-row .p { color: var(--text-faint); flex: none; width: 1.2rem; }
.sum-row .c { flex: 1; }
.sum-row.none .c { color: var(--text-faint); font-style: italic; }
.sum-row .wl { color: var(--warn); font-size: .8rem; }
.sum-row .wl.danger { color: var(--danger); }
.sum-row.stranded { background: var(--danger-bg); border-radius: var(--radius-sm);
  margin: .15rem -.35rem; padding: .2rem .35rem; }
.review-row.danger { background: var(--danger-bg); }

.review-child { margin-bottom: 1.1rem; }
.review-child .who { font-weight: 700; margin-bottom: .3rem; }
.review-row {
  display: flex; gap: .75rem; padding: .35rem .6rem;
  background: var(--surface-2); border-radius: var(--radius-sm); margin-bottom: .25rem;
}

.centered { max-width: 520px; margin: 4rem auto; text-align: center; padding: 0 1.25rem; }
.centered .big { font-size: 2.6rem; margin-bottom: .5rem; }

@media (max-width: 600px) {
  body { font-size: 15px; }
  h1 { font-size: 1.55rem; }
  .page { padding-block: 1.25rem 4rem; }
  .topbar .wrap { gap: .75rem; }
  .mainnav a { padding: .35rem .5rem; font-size: .76rem; }
}

/* =============================================================================
   Printable roster
   =============================================================================
   Black on white with no reliance on colour, because these go through
   photocopiers and get read in bad light. The allergy panel sits above the
   table rather than only inside it, so nothing important depends on a teacher
   scanning across a row. */

.print-toolbar {
  display: flex; align-items: center; gap: .75rem;
  padding: .75rem 1.25rem; border-bottom: 1px solid var(--border);
  background: var(--surface); position: sticky; top: 0; z-index: 10;
}

.sheet {
  max-width: 7.9in; margin: 1.5rem auto 4rem; padding: 0 1.25rem;
  color: var(--text);
}

.sheet-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 1.5rem; padding-bottom: .75rem; border-bottom: 2px solid var(--text);
}
.sheet-title { display: flex; align-items: flex-start; gap: .75rem; }
.sheet-mark { border-radius: 50%; flex: none; }
.sheet-head h1 { font-size: 1.6rem; margin-bottom: .35rem; }
.sheet-meta {
  display: flex; flex-wrap: wrap; gap: 1.1rem;
  font-size: .86rem; color: var(--text-muted); margin-top: .15rem;
}
.sheet-meta strong { color: var(--text-faint); font-weight: 700; margin-right: .2rem; }
.sheet-count { text-align: right; flex: none; }
.sheet-count .n { font-family: var(--font-heading); font-size: 2.1rem; font-weight: 700; display: block; line-height: 1; }
.sheet-count .l { font-size: .74rem; text-transform: uppercase; letter-spacing: .06em; color: var(--text-faint); }

.alerts {
  margin-top: 1rem; padding: .75rem .9rem;
  border: 1.5px solid var(--text); border-radius: 4px;
}
.alerts h2 {
  font-family: var(--font-sans); font-size: .74rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .08em; margin-bottom: .4rem;
}
.alert-row { font-size: .88rem; padding: .15rem 0; }
.alert-row .tag {
  display: inline-block; font-size: .66rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .06em;
  border: 1px solid currentColor; border-radius: 2px;
  padding: 0 .25rem; margin: 0 .25rem 0 .35rem;
}

.sheet-table { width: 100%; border-collapse: collapse; margin-top: 1.1rem; font-size: .86rem; }
.sheet-table th {
  text-align: left; font-size: .68rem; text-transform: uppercase; letter-spacing: .06em;
  border-bottom: 1.5px solid var(--text); padding: .3rem .4rem; color: var(--text);
}
.sheet-table td {
  padding: .42rem .4rem; border-bottom: 1px solid var(--border-strong);
  vertical-align: top;
}
.sheet-table .sub { font-size: .76rem; color: var(--text-muted); }
.sheet-table .num { text-align: right; font-variant-numeric: tabular-nums; }

.helpers-print { margin-top: 1.4rem; }
.helpers-print h2 {
  font-family: var(--font-sans); font-size: .74rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .08em; margin-bottom: .2rem;
}
.helpers-print .helpers-note { font-size: .76rem; color: var(--text-muted); margin-bottom: .3rem; }
.helpers-print .sheet-table { margin-top: 0; }
.helpers-print .sheet-table td { border-bottom: 1px dotted var(--border-strong); }

.waitlist-print { margin-top: 1.4rem; }
.waitlist-print h2 {
  font-family: var(--font-sans); font-size: .74rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .08em; margin-bottom: .4rem;
}
.waitlist-print ol { margin-left: 1.2rem; font-size: .88rem; }
.waitlist-print .sub { color: var(--text-muted); font-size: .78rem; }

.empty-print { margin-top: 1.5rem; color: var(--text-muted); }

.sheet-foot {
  margin-top: 1.6rem; padding-top: .5rem; border-top: 1px solid var(--border-strong);
  font-size: .72rem; color: var(--text-faint);
}

/* Each roster after the first starts on its own sheet of paper. */
.sheet.page-break { border-top: 1px dashed var(--border-strong); margin-top: 3rem; padding-top: 2rem; }

@media print {
  .topbar, .btn, .no-print, #toasts, .print-toolbar { display: none !important; }
  .sheet.page-break { break-before: page; border-top: 0; margin-top: 0; padding-top: 0; }

  /* Force plain black-on-white regardless of the viewer's OS theme — a roster
     printed from a dark-mode laptop must not come out as a black rectangle. */
  :root {
    --text: #000; --text-muted: #333; --text-faint: #555;
    --border: #bbb; --border-strong: #888;
    --bg: #fff; --surface: #fff; --surface-2: #fff;
  }
  html, body { background: #fff !important; color: #000 !important; }

  @page { margin: 12mm; }

  .sheet { max-width: none; margin: 0; padding: 0; }
  .sheet-head { border-bottom-width: 1.5pt; }
  .alerts { border-width: 1pt; break-inside: avoid; }

  /* Keep the header row on every page and never split a student across a break. */
  .sheet-table thead { display: table-header-group; }
  .sheet-table tr { break-inside: avoid; }
  .waitlist-print, .sheet-foot { break-inside: avoid; }

  .card { border-color: #ccc; break-inside: avoid; }
  a { color: #000 !important; text-decoration: none !important; }
}

/* =============================================================================
   Sign-in
   =============================================================================
   The first thing every family sees, and for many the only page they will look
   at closely. One column, one decision, nothing else on screen. */

.signin-page {
  min-height: 100vh;
  display: flex; align-items: center; justify-content: center;
  padding: 2rem 1.25rem;
}

.signin-card {
  width: 100%; max-width: 26rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 2.25rem 2rem;
  text-align: center;
}

.signin-mark { border-radius: 50%; margin-bottom: 1rem; }
.signin-card h1 { font-size: 1.5rem; margin-bottom: .5rem; }
.signin-sub { color: var(--text-muted); font-size: .95rem; margin-bottom: 1.25rem; }
.signin-card .field { text-align: left; margin-bottom: 1rem; }
.signin-card .note { text-align: left; margin-bottom: 1.25rem; }

.signin-foot {
  margin-top: 1.5rem; font-size: .85rem; color: var(--text-faint);
  line-height: 1.5;
}

.btn-block { width: 100%; justify-content: center; }

/* "or enter the code" — a rule with the label sitting in it. */
.or-rule {
  display: flex; align-items: center; gap: .75rem;
  margin: 1.5rem 0 1.25rem;
  color: var(--text-faint); font-size: .8rem;
}
.or-rule::before, .or-rule::after {
  content: ""; flex: 1; height: 1px; background: var(--border);
}

/* Six digits, spaced so they can be read back off a phone screen without
   losing your place. */
/* Sized for a code of unknown length — Supabase projects issue anywhere from
   six to ten digits, and this one sends eight. Roomy enough to read back off a
   phone, narrow enough that ten still fit inside the card. */
.code-input {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 1.35rem !important;
  letter-spacing: .28em;
  text-align: center;
  text-indent: .28em;     /* re-centres against the trailing letter-space */
  padding: .6rem .4rem !important;
}

/* Week navigation — the arrows either side of a date. */
.weekbar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; margin-bottom: 1.25rem;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: .6rem .75rem;
}
.weekbar-date { text-align: center; flex: 1; }
.weekbar-date strong { font-size: 1.05rem; }
.btn.is-disabled { opacity: .35; pointer-events: none; }

/* A posted note or handout. */
.post { padding: .75rem 0; border-bottom: 1px solid var(--border); }
.post:last-child { border-bottom: 0; padding-bottom: 0; }
.post-head { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; }

/* A table row that behaves as a link. */
.rowlink { cursor: pointer; }
.rowlink:hover { background: var(--surface-2); }
.rowlink:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

.modal-wide { max-width: 34rem; }
.namelist > div { padding: .2rem 0; }

/* =============================================================================
   The public site
   =============================================================================
   The pages a family reads before they are a family. Roomier than the
   application behind the sign-in: this is prose to be read, not a table to be
   scanned. */

.sitebar {
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  position: sticky; top: 0; z-index: 50;
}
.sitebar-inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1.5rem; padding-block: .7rem; flex-wrap: wrap;
}
.sitebrand { display: inline-flex; align-items: center; gap: .7rem; color: var(--heading); }
.sitebrand:hover { text-decoration: none; }
.sitebrand img { border-radius: 50%; flex: none; }
.sitebrand span { display: flex; flex-direction: column; line-height: 1.2; }
.sitebrand strong { font-size: 1.2rem; }
.sitebrand em { font-style: normal; font-size: .75rem; color: var(--text-faint); }

.sitenav { display: flex; align-items: center; gap: .3rem; flex-wrap: wrap; }
.sitenav > a:not(.btn) {
  padding: .4rem .6rem; border-radius: var(--radius-sm);
  font-size: .92rem; color: var(--text-muted);
}
.sitenav > a:not(.btn):hover { color: var(--text); background: var(--surface-2); text-decoration: none; }
.sitenav > a.active { color: var(--accent); font-weight: 700; }

.hero {
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
  padding: 3.5rem 0 3rem;
  text-align: center;
}
.hero-mark { border-radius: 50%; box-shadow: var(--shadow); margin-bottom: 1.25rem; }
.hero h1 { font-size: clamp(1.9rem, 5vw, 2.75rem); }
.hero-lede {
  font-size: 1.15rem; color: var(--text-muted);
  max-width: 34rem; margin: .75rem auto 1.75rem;
}

.section { padding-block: 2.75rem 3.5rem; }
.section h2 { margin-top: 2rem; }
.section h2:first-of-type { margin-top: 0; }
.section p { margin-bottom: 1rem; max-width: 46rem; }

/* Long-form pages — the statement of faith runs to a couple of thousand words,
   and default line length would make it hard going. */
.prose p { max-width: 42rem; }
.prose h2 { font-size: 1.15rem; margin-top: 1.75rem; }

.quote {
  border-left: 3px solid var(--accent);
  padding: .25rem 0 .25rem 1.25rem;
  margin: 2rem 0;
  color: var(--text-muted); font-style: italic;
}
.quote cite {
  display: block; margin-top: .5rem;
  font-style: normal; font-size: .8rem; letter-spacing: .08em;
  text-transform: uppercase; color: var(--text-faint);
}

.cardrow {
  display: grid; gap: .9rem; margin-top: 2rem;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}
.cardrow .card h3 { margin-bottom: .35rem; }

.btn-lg { padding: .7rem 1.5rem; font-size: 1rem; }

.sitefoot {
  border-top: 1px solid var(--border);
  background: var(--surface);
  padding-block: 2rem 2.5rem;
  font-size: .88rem; color: var(--text-muted);
}
.sitefoot p { margin-bottom: .3rem; }

/* The honeypot. Off-screen rather than display:none — some bots skip anything
   hidden, and the point is that they fill it in. */
.hp {
  position: absolute; left: -9999px; width: 1px; height: 1px;
  overflow: hidden;
}

@media (max-width: 700px) {
  .sitebar-inner { justify-content: center; }
  .sitenav { justify-content: center; }
  .sitebrand em { display: none; }
}

/* A dialog holding prose rather than a question. */
.dialog-wide { max-width: 44rem; }
.dialog-wide .dialog-body { max-height: 70vh; overflow-y: auto; }

/* =============================================================================
   Website editor (Admin → Website).

   One card per paragraph on the public page. The text box is the loudest thing
   in the card because it is the only thing anybody came here to touch; the tag
   name, the previous wording and the buttons all sit quietly around it.
   ============================================================================= */
.blocks { display: flex; flex-direction: column; gap: .85rem; }

.block-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: .75rem; margin-bottom: .5rem;
}

.block-text {
  display: block;
  width: 100%;
  padding: .65rem .75rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: 1rem;
  line-height: 1.5;
  resize: vertical;
}
.block-text:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  border-color: var(--accent);
}

/* The wording before it was edited. Indented and quiet: it is there to be
   compared against, not read first. */
.was {
  margin-top: .5rem;
  padding: .55rem .75rem;
  border-left: 3px solid var(--border);
  background: var(--surface-2);
  color: var(--text-muted);
  font-size: .92rem;
  line-height: 1.5;
}

.block summary { cursor: pointer; font-size: .88rem; }

.block-state { font-size: .88rem; }
.block-state.warn { color: var(--warn); font-weight: 700; }

.block .hint {
  margin-top: .45rem;
  font-size: .86rem;
  color: var(--text-muted);
  line-height: 1.45;
}
.block .hint code {
  font-size: .85em;
  padding: .1rem .3rem;
  border-radius: 3px;
  background: var(--accent-soft);
}

/* =============================================================================
   Class proposals
   ============================================================================= */
.cards { display: flex; flex-direction: column; gap: .85rem; }

/* The description, cut to a few lines on the list. Enough to recognise a
   proposal by; the whole thing is one click away and nobody decides from a
   summary. */
.clamp {
  margin-top: .5rem; color: var(--text-muted); font-size: .92rem; line-height: 1.5;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
  overflow: hidden;
}

/* One question and its answer, reading down. The question is quiet and the
   answer is not: the reader already knows what was asked, and is here for what
   somebody wrote back. */
.qa { padding: .7rem 0; border-bottom: 1px solid var(--border); }
.qa:last-child { border-bottom: 0; }
.qa .q { font-size: .82rem; color: var(--text-muted); margin-bottom: .2rem; }
.qa .a { line-height: 1.55; white-space: pre-wrap; }

/* "required", beside a label rather than a bare asterisk nobody can read on a
   phone. */
.req {
  font-size: .72rem; font-weight: 400; color: var(--text-faint);
  text-transform: uppercase; letter-spacing: .04em; margin-left: .35rem;
}

/* =============================================================================
   Portal sub-navigation.

   The admin's .mainnav lives in the top bar; this sits inside the page, under
   the family's name, because that is the thing a parent is orienting by. Same
   visual language deliberately — one system, two placements.
   ============================================================================= */
.subnav {
  display: flex;
  gap: .25rem;
  flex-wrap: wrap;
  margin: 0 0 1rem;
  border-bottom: 1px solid var(--border);
  padding-bottom: .5rem;
}
.subnav a {
  padding: .4rem .7rem;
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  font-size: .92rem;
  font-weight: 700;
}
.subnav a:hover {
  color: var(--text);
  background: var(--surface-2);
  text-decoration: none;
}
.subnav a.active { color: var(--accent); background: var(--accent-soft); }

/* Thumb-sized targets, and never a horizontal scroll on a narrow phone. */
@media (max-width: 560px) {
  .subnav { gap: .15rem; }
  .subnav a { padding: .45rem .55rem; font-size: .86rem; }
}

/* =============================================================================
   Cross-section links in the admin top bar.

   Administration is the only section that had no way back. The portal and the
   teaching pages have linked to each other and to here from the start, so an
   administrator who is also a mother could get in but not out without editing
   the address bar. Empty for somebody who is only an administrator.
   ============================================================================= */
.crosslinks { display: inline-flex; gap: .4rem; flex: none; }
.crosslinks:empty { display: none; }

@media (max-width: 700px) {
  /* The nav wraps to its own line on a phone; these should sit with the
     sign-out button rather than being pushed off the end of it. */
  .crosslinks { gap: .3rem; }
  .crosslinks .btn { padding: .3rem .5rem; font-size: .76rem; }
}

/* =============================================================================
   Registration desk
   ============================================================================= */
.regblock .checks {
  display: flex; flex-direction: column; gap: .1rem;
  margin-top: .75rem; padding: .6rem .75rem;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface-2);
}
.checkrow {
  display: flex; align-items: center; gap: .7rem;
  padding: .4rem 0;
}
.checkrow + .checkrow { border-top: 1px solid var(--border); }
.checkrow .ck-l { flex: 1; min-width: 0; }

/* The tick. Big enough to scan a column of sixty families by. */
.ck {
  flex: none; width: 1.6rem; height: 1.6rem;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%; font-size: .9rem; font-weight: 700;
  background: var(--surface); border: 1px solid var(--border);
  color: var(--text-faint);
}
.ck.on { background: var(--ok, #2e7d32); border-color: transparent; color: #fff; }

/* Registered anyway, with something outstanding — worth seeing, not worth
   shouting about. */
.note-warn { border-left-color: var(--warn); }

/* What is already on file, shown rather than asked. */
.onfile {
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface-2); padding: .5rem .7rem;
}
.onfile-row { display: flex; flex-wrap: wrap; gap: .6rem; padding: .25rem 0; }

.kids { display: flex; flex-direction: column; gap: .5rem; }
.kid {
  display: flex; align-items: center; gap: 1rem; flex-wrap: wrap;
  padding: .6rem .75rem;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
}
.kid-name { flex: 1; min-width: 9rem; display: flex; flex-direction: column; }
.kid .field { margin: 0; width: 8rem; }

/* A child or parent being described for the first time. */
.newrow {
  display: grid; gap: .6rem; align-items: end;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  padding: .7rem .75rem; margin-top: .5rem;
  border: 1px dashed var(--border-strong); border-radius: var(--radius-sm);
}
.newrow .field { margin: 0; }

@media (max-width: 560px) {
  .checkrow { flex-wrap: wrap; }
  .kid .field { width: 100%; }
}

/* =============================================================================
   The administration top bar, in two rows.

   The single-row bar worked with seven sections. At twelve — plus the links
   across to the family and teaching sides — the navigation wrapped onto a
   second line inside a bar with a fixed 56px height, so the last few items were
   cut off by its own bottom edge.

   Splitting it gives the navigation the full width of the page rather than
   whatever is left over beside the name and the sign-out button, which is room
   enough for twelve on a laptop and honest wrapping on anything narrower.
   ============================================================================= */
.topbar-stacked {
  height: auto;               /* was a fixed --topbar-h, which did the cutting */
  display: block;
  padding: .5rem 0 0;
}
.topbar-stacked .topbar-top {
  display: flex; align-items: center; gap: 1rem;
}
.topbar-stacked .topbar-bottom {
  margin-top: .4rem;
  border-top: 1px solid var(--border);
  padding-top: .35rem;
  padding-bottom: .1rem;
}
.topbar-stacked .mainnav {
  flex: 1;
  gap: .1rem;
  /* Wrapping is right here: an administrator should see every section at once
     rather than discovering half of them by dragging sideways. */
  flex-wrap: wrap;
}
/* Twelve sections come to 1081px at the inherited spacing, against 1040px of
   row — forty pixels short, and forty pixels is the difference between one
   tidy row and two. Trimmed rather than left to wrap. */
.topbar-stacked .mainnav a {
  padding: .35rem .45rem;
  letter-spacing: .02em;
}

@media (max-width: 700px) {
  .topbar-stacked { padding-top: .4rem; }
  .topbar-stacked .mainnav a { padding: .3rem .45rem; font-size: .74rem; }
}

/* =============================================================================
   Family setup — a family editing its own record.

   One block per person, rather than a table of inputs. A row of tiny boxes is
   fine for a registrar working through sixty families; it is miserable for a
   mother on a phone trying to add an allergy for one child.
   ============================================================================= */
.people { display: flex; flex-direction: column; gap: .75rem; }

.person {
  display: grid; gap: .6rem;
  grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
  padding: .8rem .85rem;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface-2);
}
.person .field { margin: 0; }

/* Allergies and the note to teachers run the width — they are sentences, not
   values, and a 10rem box invites a one-word answer. */
.person .field.wide { grid-column: 1 / -1; }

.person-head {
  grid-column: 1 / -1;
  display: flex; align-items: baseline; gap: .6rem;
  padding-bottom: .1rem;
}

.famcard h4 {
  margin-bottom: .5rem;
  padding-bottom: .35rem;
  border-bottom: 1px solid var(--border);
}

@media (max-width: 560px) {
  .person { grid-template-columns: 1fr; }
}

/* =============================================================================
   The agreement line on a registration record.

   Loud, and at the top. "Did this family agree to the Code of Conduct" is the
   one question on this page with a legal flavour, and it was previously a row
   in a table of timestamps indistinguishable from "payment received".
   ============================================================================= */
.agreement {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: .5rem;
  margin: 0 0 1.25rem;
  padding: .7rem .9rem;
  border-radius: var(--radius-sm);
  border-left: 4px solid var(--ok, #2e7d32);
  background: rgba(46, 125, 50, .08);
}
.agreement.no {
  border-left-color: var(--danger);
  background: rgba(192, 38, 38, .08);
}

/* Sub-headings inside a record. h2 names the section, h3 names the table. */
.sheet h3 {
  margin: 1.1rem 0 .4rem;
  font-size: .95rem; letter-spacing: .04em; text-transform: uppercase;
  color: var(--text-muted);
}
.dialog-body h3 {
  margin: 1.1rem 0 .4rem;
  font-size: .95rem; letter-spacing: .04em; text-transform: uppercase;
  color: var(--text-muted);
}
.dialog-body h2 {
  margin: 1.4rem 0 .5rem; font-size: 1.05rem;
  padding-bottom: .3rem; border-bottom: 1px solid var(--border);
}
.dialog-body .sheet-table { width: 100%; }
.dialog-body .sheet-table.bordered th,
.dialog-body .sheet-table.bordered td { padding: .4rem .5rem; }

@media print { .agreement { break-inside: avoid; } }

/* One proposal per sheet when a stack is printed for a meeting. */
@media print {
  .page-break { break-before: page; page-break-before: always; }
}
.contents-sheet { margin-bottom: 1.5rem; }

/* =============================================================================
   Website photographs.

   The picture is the control. A row of filenames would be useless to somebody
   deciding whether this is last year's group photo or this year's.
   ============================================================================= */
.imagelist { display: flex; flex-direction: column; gap: 1rem; }

.imagerow {
  display: flex; gap: 1rem; align-items: flex-start; flex-wrap: wrap;
  padding: .85rem;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface-2);
}

.imagethumb {
  width: 190px; height: 128px; object-fit: cover; flex: none;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--surface);
}

.imagemeta { flex: 1; min-width: 12rem; }

/* A file input dressed as a button — the native control is ugly and says
   "No file chosen" in a way that reads like an error. */
.imagemeta label.btn { cursor: pointer; }

@media (max-width: 560px) {
  .imagethumb { width: 100%; height: 150px; }
}

/* A block that has been taken off the website. Dimmed rather than removed —
   it is still here, and still editable, it simply is not published. */
.block.is-hidden { opacity: .62; border-style: dashed; }
.block.is-hidden .block-text { background: var(--surface-2); }

/* =============================================================================
   Class helpers — the board of parents.

   The colour is the feature. Somebody placing sixty parents is scanning for
   red, not reading; the state has to carry at arm's length and must never
   require counting.
   ============================================================================= */
.helper-layout { display: grid; grid-template-columns: 1fr 20rem; gap: 1.25rem; align-items: start; }
.helper-board { display: grid; grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr)); gap: .8rem; }

.helper-rect {
  border: 1px solid var(--border);
  border-left: 5px solid var(--danger);
  border-radius: var(--radius-sm);
  background: var(--surface);
  padding: .75rem .85rem;
}
.helper-rect.is-part { border-left-color: var(--warn); }
.helper-rect.is-done { border-left-color: var(--ok, #2e7d32); background: rgba(46,125,50,.05); }

.hr-head { display: flex; justify-content: space-between; align-items: baseline; gap: .6rem; }
.hr-count {
  flex: none; font-variant-numeric: tabular-nums; font-weight: 700;
  padding: .1rem .45rem; border-radius: 999px; font-size: .82rem;
  background: var(--surface-2); color: var(--text-muted);
}
.helper-rect.is-done .hr-count { background: var(--ok, #2e7d32); color: #fff; }

.hr-wants { margin-top: .5rem; font-size: .84rem; }
.chip-sm {
  display: inline-block; margin: .1rem .2rem .1rem 0; padding: .05rem .4rem;
  border-radius: 3px; background: var(--accent-soft); color: var(--accent-strong);
  font-size: .78rem;
}
.hr-note {
  margin-top: .45rem; padding-left: .5rem; border-left: 2px solid var(--border);
  font-size: .82rem; color: var(--text-muted); font-style: italic;
}
.hr-slots { display: flex; flex-direction: column; gap: .35rem; margin-top: .6rem; }
.hr-slot { display: flex; flex-direction: column; gap: .1rem; }
.hr-slot select { width: 100%; font-size: .88rem; padding: .25rem .35rem; }

/* The reference pane. Sticky, because its whole job is to be glanceable while
   you work down the board. */
.helper-ref {
  position: sticky; top: calc(var(--topbar-h) + 1rem);
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface-2); padding: .85rem;
  max-height: calc(100vh - var(--topbar-h) - 3rem); overflow-y: auto;
}
.helper-ref h3 { margin-bottom: .1rem; }
.helper-ref h4 { margin: .9rem 0 .25rem; font-size: .8rem; text-transform: uppercase;
                 letter-spacing: .04em; color: var(--text-muted); }
.ref-table { width: 100%; font-size: .82rem; border-collapse: collapse; }
.ref-table th { font-weight: 400; color: var(--text-faint); font-size: .74rem; text-align: left; }
.ref-table td { padding: .18rem 0; border-top: 1px solid var(--border); }
.ref-table td.ok   { color: var(--ok, #2e7d32); font-weight: 700; }
.ref-table td.bad  { color: var(--danger); font-weight: 700; }
.ref-table td.warn { color: var(--warn); }

/* The parent's own page. */
.helper-classes { display: grid; grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr)); gap: .5rem; }
.helper-class {
  display: flex; gap: .55rem; align-items: flex-start;
  padding: .6rem .7rem; border: 1px solid var(--border);
  border-radius: var(--radius-sm); cursor: pointer; background: var(--surface);
}
.helper-class:hover { border-color: var(--accent); }
.helper-class.is-on { border-color: var(--accent); background: var(--accent-soft); }
.helper-class input { margin-top: .15rem; flex: none; }
.hc-body { display: flex; flex-direction: column; gap: .1rem; }
.hc-need { font-size: .78rem; color: var(--text-muted); }
.hc-need.is-full { color: var(--ok, #2e7d32); }
.hc-desc { margin-top: .15rem; }

@media (max-width: 900px) {
  .helper-layout { grid-template-columns: 1fr; }
  .helper-ref { position: static; max-height: none; }
}

/* =============================================================================
   Email preview on the send screen.

   Deliberately plain — it shows the WORDS, not a mock of Gmail. The thing
   being checked is whether {semester} was typed correctly, not whether the
   button is the right blue.
   ============================================================================= */
.email-preview {
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface); padding: .9rem 1rem;
  font-size: .92rem; line-height: 1.55;
}
.email-preview p { margin: 0 0 .7rem; }
.email-preview p:last-child { margin-bottom: 0; }
.ep-subject {
  font-weight: 700; color: var(--heading);
  padding-bottom: .5rem; margin-bottom: .7rem;
  border-bottom: 1px solid var(--border);
}
.ep-button {
  display: inline-block; padding: .4rem .9rem; border-radius: 4px;
  background: var(--accent); color: #fff; font-size: .88rem;
}
.field .hint code {
  padding: .05rem .25rem; border-radius: 3px;
  background: var(--accent-soft); font-size: .9em;
}

/* =============================================================================
   The paper release form.

   Shown on screen so a parent can see what they are about to print — a print
   button that opens a dialog onto something unseen is a button people do not
   press.
   ============================================================================= */
.waiver-sheet {
  max-width: 48rem; margin: 0 auto 1.5rem;
  padding: 2rem 2.25rem;
  background: #fff; color: #1a1a1a;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  font-size: .92rem; line-height: 1.55;
}
.waiver-sheet p { margin: 0 0 .85rem; }
.waiver-sheet h1 { font-size: 1.2rem; margin: 0; color: #1a1a1a; }
.waiver-sheet h2 {
  font-size: 1.05rem; margin: 0 0 .9rem; color: #1a1a1a;
  padding-bottom: .35rem; border-bottom: 2px solid #1a1a1a;
}

.wv-head { display: flex; gap: 1rem; align-items: center; margin-bottom: 1.25rem;
           padding-bottom: .8rem; border-bottom: 2px solid #1a1a1a; }
.wv-head img { flex: none; border-radius: 50%; }
.wv-sub { font-size: .82rem; color: #555; margin-top: .15rem; }

.wv-kids { width: 100%; border-collapse: collapse; margin: 0 0 1.25rem; }
.wv-kids th { text-align: left; font-size: .74rem; text-transform: uppercase;
              letter-spacing: .04em; color: #555; border-bottom: 1px solid #1a1a1a;
              padding: .25rem .4rem; }
.wv-kids td { padding: .45rem .4rem; border-bottom: 1px solid #bbb; }
.wv-kids tr.wv-blank td { height: 1.7rem; }

.wv-aside { font-size: .84rem; color: #555; font-style: italic; }

.wv-sign { margin-top: 1.5rem; display: flex; flex-direction: column; gap: .95rem; }
.wv-line { display: flex; align-items: baseline; gap: .6rem; }
.wv-label { flex: none; width: 13rem; font-size: .84rem; color: #333; }
.wv-rule { flex: 1; border-bottom: 1px solid #1a1a1a; min-height: 1.3rem; }

@media print {
  /* Only the forms, and one per sheet. Scoped to the class the print button
     adds, so the administration side's own print views are untouched. */
  .printing-waiver .topbar,
  .printing-waiver .subnav,
  .printing-waiver .page-head,
  .printing-waiver .card,
  .printing-waiver .crumbs { display: none !important; }

  .printing-waiver .waiver-sheet {
    border: 0; padding: 0; margin: 0; max-width: none;
    background: #fff; color: #000;
  }
  .printing-waiver .wv-break { break-before: page; page-break-before: always; }
}
