/* ==========================================================================
   Ayanda Infant School — Staff Portal
   Brand tokens taken from the official letterhead:
     Navy   #16304f   Gold   #b08d34
     Ink    #1f2937   Muted  #6b7280   Faint #9ca3af
   Headings: Georgia Bold   Body: Calibri
   ========================================================================== */

:root {
  --navy: #16304f;
  --navy-800: #112640;
  --navy-900: #0c1b2e;
  --navy-600: #24466f;
  --navy-100: #e8edf3;
  --navy-50: #f3f6f9;

  /* Fractal noise, stretched into strands and sharpened into veins. */
  --marble: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='600' height='300'%3E%3Cfilter id='m'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.004 0.021' numOctaves='4' seed='11'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0'/%3E%3CfeComponentTransfer%3E%3CfeFuncA type='table' tableValues='0 0 0 .15 .9 1 .35 0 0 0'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='600' height='300' filter='url(%23m)'/%3E%3C/svg%3E");
  --gold: #b08d34;
  /* 4.01 on paper at the 10–11px the eyebrows use; 4.68 now. */
  --gold-600: #876a1e;
  --gold-300: #d9c27e;
  --gold-100: #f5edd7;
  --gold-50: #faf6ea;

  --ink: #1f2937;
  /* Re-based for WCAG 1.4.3. Measured on all three grounds the site puts text
     on — #ffffff, the warm band #f6f5f1 and the page #faf9f6 — because the old
     values passed on white and failed on the bands:
       muted #6b7280  4.43 on the warm band  ->  #5d6472  5.45 worst case
       faint #9ca3af  2.41 anywhere          ->  #666d7b  4.6  worst case
     Two steps are kept so the hierarchy survives the correction. */
  --muted: #5d6472;
  --faint: #666d7b;
  --line: #e5e7eb;
  --line-strong: #d1d5db;
  --paper: #ffffff;
  --bg: #f7f6f2;

  --green: #2f7d4f;
  --green-100: #e3f1e8;
  --red: #b03a2e;
  --red-100: #f8e4e1;
  --amber: #b8791a;
  --amber-100: #fbeed3;
  --blue: #2d5f9e;
  --blue-100: #e3ecf7;

  --serif: Georgia, "Times New Roman", Times, serif;
  --sans: Calibri, "Segoe UI", -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;

  --radius: 10px;
  --radius-sm: 6px;
  --shadow: 0 1px 2px rgba(22, 48, 79, 0.06), 0 4px 14px rgba(22, 48, 79, 0.06);
  --shadow-lg: 0 10px 30px rgba(22, 48, 79, 0.16);
  --sidebar-w: 248px;
  --sidebar-rail: 64px;
}

* { box-sizing: border-box; }
/* iOS Safari resizes text of its own accord when a phone is turned to
   landscape — it decides a column is too narrow and inflates it, which on a
   register or a fee table breaks the column widths the layout depends on.
   100% means "leave it as the stylesheet says". */
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
html, body { height: 100%; }
body {
  margin: 0;
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.45;
  color: var(--ink);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
}
h1, h2, h3, h4 { font-family: var(--serif); color: var(--navy); margin: 0; font-weight: 700; letter-spacing: 0.01em; }
h1 { font-size: 26px; }
h2 { font-size: 20px; }
h3 { font-size: 16px; }
p { margin: 0 0 10px; }
a { color: var(--navy); }
button, input, select, textarea { font: inherit; color: inherit; }
img { max-width: 100%; }
[hidden] { display: none !important; }
svg.ico { width: 16px; height: 16px; flex: none; vertical-align: -3px; }
.notice svg.ico { margin-right: 4px; }
.pill svg.ico { width: 12px; height: 12px; }
.empty svg.ico { width: 40px; height: 40px; }

.eyebrow {
  font-family: var(--sans);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--gold);
  font-weight: 700;
}
.muted { color: var(--muted); }
.faint { color: var(--faint); }
.small { font-size: 13px; }
.tiny { font-size: 12px; }
.bold { font-weight: 700; }
.serif { font-family: var(--serif); }
.nowrap { white-space: nowrap; }
.right { text-align: right; }
.center { text-align: center; }
.mt-8 { margin-top: 8px; } .mt-16 { margin-top: 16px; } .mt-24 { margin-top: 24px; }
.mb-8 { margin-bottom: 8px; } .mb-16 { margin-bottom: 16px; }
.flex { display: flex; gap: 10px; align-items: center; }
.flex.between { justify-content: space-between; }
.flex.wrap { flex-wrap: wrap; }
.grow { flex: 1; }
/* min-width:0 because a flex item starts at min-content and a card holding a
   wide table has a large one. Without it the stack refuses to be narrower
   than its widest table, pushes its grid track past the container, and takes
   the whole page sideways with it — the table's own scroll wrapper never gets
   a chance, because by then the card around it has already grown. */
.stack { display: flex; flex-direction: column; gap: 10px; min-width: 0; }

/* Letterhead rule motif: thick navy + thin gold */
.rule {
  height: 3px; background: var(--navy); border: 0; margin: 0;
  position: relative;
}
.rule::after {
  content: ""; position: absolute; left: 0; right: 0; top: 7px; height: 1px; background: var(--gold);
}

/* --------------------------------------------------------------------------
   Login
   -------------------------------------------------------------------------- */
.login {
  /* dvh after vh: old browsers take the first, current ones the second. On
     iOS 100vh means the viewport with the URL bar hidden, so a sign-in page
     sized to it hangs below the screen until you scroll. */
  min-height: 100vh;
  min-height: 100dvh;
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
}
.login-brand {
  background: var(--navy);
  color: #fff;
  position: relative;
  overflow: hidden;
  padding: 48px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}
.login-brand::before {
  content: ""; position: absolute; inset: 0;
  background: url("../assets/logo-watermark-280.png") no-repeat right -80px bottom -60px / 560px auto;
  opacity: 0.08;
}
.login-brand > * { position: relative; }
.login-brand .crest { width: 120px; }
.login-brand h1 { color: #fff; font-size: 34px; line-height: 1.15; margin-top: 18px; }
.login-brand .tagline { color: var(--gold-300); font-family: var(--sans); text-transform: uppercase; letter-spacing: 0.18em; font-size: 12px; font-weight: 700; margin-top: 8px; }
.login-brand .address { color: rgba(255,255,255,0.7); font-size: 13px; line-height: 1.6; }
.login-brand .gold-line { width: 64px; height: 2px; background: var(--gold); margin: 22px 0; }
.login-panel { display: flex; align-items: center; justify-content: center; padding: 40px 32px; }
.login-card { width: 100%; max-width: 480px; }
.login-card h2 { font-size: 24px; }
.user-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; margin: 18px 0; max-height: 52vh; overflow: auto; padding-right: 4px; }
.user-tile {
  display: flex; gap: 10px; align-items: center;
  background: var(--paper); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 10px; cursor: pointer; text-align: left; transition: border-color .15s, box-shadow .15s;
}
.user-tile:hover { border-color: var(--gold); box-shadow: var(--shadow); }
.user-tile.selected { border-color: var(--navy); box-shadow: 0 0 0 2px var(--navy-100); }
.user-tile .name { font-weight: 700; font-size: 14px; }
.user-tile .role { font-size: 12px; color: var(--muted); }

/* --------------------------------------------------------------------------
   App shell
   -------------------------------------------------------------------------- */
.shell { display: grid; grid-template-columns: var(--sidebar-w) 1fr; min-height: 100vh; min-height: 100dvh; }
.sidebar {
  background: var(--navy);
  color: rgba(255,255,255,0.86);
  display: flex; flex-direction: column;
  position: sticky; top: 0; height: 100vh; height: 100svh;
}
.sidebar-brand { display: flex; gap: 12px; align-items: center; padding: 18px 18px 14px; border-bottom: 1px solid rgba(255,255,255,0.08); }
.sidebar-brand img { width: 44px; height: auto; }
.sidebar-brand .school { font-family: var(--serif); font-weight: 700; color: #fff; font-size: 15px; line-height: 1.2; }
.sidebar-brand .tag { color: var(--gold-300); font-size: 9.5px; letter-spacing: 0.14em; text-transform: uppercase; font-weight: 700; }
.nav { padding: 12px 10px; flex: 1; overflow: auto; }
.nav-section { font-size: 10.5px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--gold-300); font-weight: 700; padding: 14px 10px 6px; }
.nav a {
  display: flex; align-items: center; gap: 10px;
  color: rgba(255,255,255,0.82); text-decoration: none;
  padding: 9px 10px; border-radius: 8px; font-size: 14px; font-weight: 600;
}
.nav a:hover { background: rgba(255,255,255,0.07); color: #fff; }
.nav a.active { background: rgba(176,141,52,0.18); color: #fff; box-shadow: inset 3px 0 0 var(--gold); }
.nav a .ico { width: 18px; height: 18px; flex: none; opacity: 0.9; }
.nav a .badge { margin-left: auto; background: var(--gold); color: var(--navy-900); font-size: 11px; font-weight: 700; padding: 1px 7px; border-radius: 99px; }
.sidebar-user { border-top: 1px solid rgba(255,255,255,0.08); padding: 14px 16px; display: flex; gap: 10px; align-items: center; }
.sidebar-user .name { color: #fff; font-weight: 700; font-size: 14px; }
.sidebar-user .role { font-size: 12px; color: var(--gold-300); }
.sidebar-user button { margin-left: auto; }

/* --- narrowing the menu to a rail ----------------------------------------
   The button lives in the brand row and stays put at both widths, so the way
   back is always in the same place as the way out. Everything that goes is a
   label; nothing that goes is a destination. */
.nav-shut-btn {
  margin-left: auto; flex: none; width: 30px; height: 30px; display: inline-flex;
  align-items: center; justify-content: center; cursor: pointer;
  background: rgba(255,255,255,0.06); border: 1px solid rgba(255,255,255,0.14);
  border-radius: 8px; color: rgba(255,255,255,0.86); padding: 0;
}
.nav-shut-btn:hover { background: rgba(255,255,255,0.14); color: #fff; }
.nav-shut-btn .ico { width: 16px; height: 16px; }

.shell.nav-shut { grid-template-columns: var(--sidebar-rail) 1fr; }
.shell.nav-shut .sidebar-brand { padding: 14px 0 12px; flex-direction: column; gap: 8px; }
.shell.nav-shut .sidebar-brand img { width: 30px; }
.shell.nav-shut .sidebar-brand > div,
.shell.nav-shut .sidebar-user > div,
.shell.nav-shut .nav-section,
.shell.nav-shut .nav a > span:not(.badge) { display: none; }
.shell.nav-shut .nav-shut-btn { margin: 0; }
.shell.nav-shut .nav { padding: 10px 8px; }
.shell.nav-shut .nav a { justify-content: center; padding: 11px 0; position: relative; }
/* The count still has to show, so it becomes a dot on the icon. A teacher
   with four unread messages needs to know that at a glance; which four is
   what opening it is for. */
.shell.nav-shut .nav a .badge {
  position: absolute; top: 5px; right: 11px; margin: 0;
  min-width: 8px; height: 8px; padding: 0; font-size: 0; line-height: 0;
  border: 2px solid var(--navy); border-radius: 99px;
}
.shell.nav-shut .sidebar-user { padding: 12px 0; flex-direction: column; gap: 8px; }
.shell.nav-shut .sidebar-user button { margin: 0; }

.avatar {
  width: 36px; height: 36px; border-radius: 50%; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--gold-100); color: var(--navy); font-weight: 700; font-size: 13px; font-family: var(--serif);
}
.avatar.lg { width: 56px; height: 56px; font-size: 20px; }
.avatar.sm { width: 28px; height: 28px; font-size: 11px; }
.avatar.navy { background: var(--navy); color: var(--gold-300); }

.main { min-width: 0; display: flex; flex-direction: column; }
.topbar {
  background: var(--paper); border-bottom: 1px solid var(--line);
  padding: 14px 28px; display: flex; align-items: center; gap: 16px;
  position: sticky; top: 0; z-index: 5;
}
.topbar .crumbs { font-size: 13px; color: var(--muted); }
.topbar h1 { font-size: 22px; }
.topbar .spacer { flex: 1; }
.content { padding: 24px 28px 48px; }

/* --------------------------------------------------------------------------
   Components
   -------------------------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; gap: 8px;
  border: 1px solid var(--navy); background: var(--navy); color: #fff;
  padding: 8px 14px; border-radius: 8px; font-weight: 700; font-size: 14px; cursor: pointer;
  text-decoration: none; line-height: 1.2; white-space: nowrap;
}
.btn:hover { background: var(--navy-800); }
.btn.gold { background: var(--gold); border-color: var(--gold); color: #fff; }
.btn.gold:hover { background: var(--gold-600); }
.btn.ghost { background: transparent; color: var(--navy); border-color: var(--line-strong); }
.btn.ghost:hover { background: var(--navy-50); }
.btn.danger { background: var(--red); border-color: var(--red); }
.btn.sm { padding: 5px 10px; font-size: 13px; }
.btn.xs { padding: 3px 8px; font-size: 12px; }
.btn:disabled { opacity: 0.45; cursor: not-allowed; }
.btn .ico { width: 16px; height: 16px; }

.card { background: var(--paper); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow); }
.card-head { padding: 14px 18px; border-bottom: 1px solid var(--line); display: flex; align-items: center; gap: 12px; }
.card-head h2, .card-head h3 { flex: 1; }
.card-body { padding: 18px; }
.card-body.tight { padding: 0; }
.card-foot { padding: 12px 18px; border-top: 1px solid var(--line); background: var(--navy-50); border-radius: 0 0 var(--radius) var(--radius); }

.grid { display: grid; gap: 18px; }
.grid.cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid.cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid.cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.grid.side { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }
.grid.side-left { grid-template-columns: 280px minmax(0, 1fr); }

.stat { padding: 16px 18px; }
.stat .label { font-size: 12px; text-transform: uppercase; letter-spacing: 0.1em; color: var(--muted); font-weight: 700; }
.stat .value { font-family: var(--serif); font-size: 30px; color: var(--navy); line-height: 1.1; margin-top: 6px; }
.stat .sub { font-size: 13px; color: var(--muted); margin-top: 4px; }
.stat.accent { border-top: 3px solid var(--gold); }

.pill {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; font-weight: 700; padding: 2px 9px; border-radius: 99px;
  background: var(--navy-100); color: var(--navy); white-space: nowrap;
}
.pill.gold { background: var(--gold-100); color: var(--gold-600); }
.pill.green { background: var(--green-100); color: var(--green); }
.pill.red { background: var(--red-100); color: var(--red); }
.pill.amber { background: var(--amber-100); color: var(--amber); }
.pill.blue { background: var(--blue-100); color: var(--blue); }
.pill.grey { background: #eef0f3; color: var(--muted); }
.dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }

table { width: 100%; border-collapse: collapse; font-size: 14px; }
th { text-align: left; font-size: 11.5px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--muted); padding: 10px 14px; border-bottom: 1px solid var(--line); background: var(--navy-50); font-weight: 700; }
td { padding: 10px 14px; border-bottom: 1px solid var(--line); vertical-align: middle; }
tr:last-child td { border-bottom: 0; }
tr.clickable { cursor: pointer; }
tr.clickable:hover td { background: var(--gold-50); }
/* A table too wide for a phone scrolls sideways, which works and which nobody
   discovers: the fee table's last two columns are the amounts, and on a 375px
   screen a parent saw "Per term, ECD A, ECD B" and no reason to think there
   was more. These four backgrounds put a soft shadow against whichever edge
   still has content behind it, and take it away at the end of the travel.
   background-attachment does the work — the two white panels scroll with the
   content (local) and the two shadows stay with the box (scroll), so each
   shadow is covered exactly when that side is fully shown. No script, and
   nothing to keep in sync with the scroll position. */
.table-wrap {
  overflow-x: auto;
  background:
    linear-gradient(to right, var(--paper) 30%, rgba(255, 255, 255, 0)) left center,
    linear-gradient(to left,  var(--paper) 30%, rgba(255, 255, 255, 0)) right center,
    radial-gradient(farthest-side at 0 50%,    rgba(22, 48, 79, .16), rgba(22, 48, 79, 0)) left center,
    radial-gradient(farthest-side at 100% 50%, rgba(22, 48, 79, .16), rgba(22, 48, 79, 0)) right center;
  background-repeat: no-repeat;
  background-size: 34px 100%, 34px 100%, 12px 100%, 12px 100%;
  background-attachment: local, local, scroll, scroll;
}

label.field { display: block; font-size: 13px; font-weight: 700; color: var(--navy); margin-bottom: 4px; }
.input, select.input, textarea.input {
  width: 100%; border: 1px solid var(--line-strong); border-radius: 8px; padding: 8px 10px;
  background: #fff; font-size: 14px; outline: none;
}
.input:focus { border-color: var(--navy); box-shadow: 0 0 0 3px var(--navy-100); }
textarea.input { min-height: 90px; resize: vertical; }
.form-row { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: 12px; }
.form-row.three { grid-template-columns: repeat(3, minmax(0,1fr)); }
.help { font-size: 12px; color: var(--muted); margin-top: 4px; }

.toolbar { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin-bottom: 16px; }
.toolbar .input { width: auto; min-width: 180px; }
.search { position: relative; }
.search .input { padding-left: 32px; min-width: 240px; }
.search .ico { position: absolute; left: 10px; top: 50%; transform: translateY(-50%); width: 16px; color: var(--faint); }

/* More tabs than fit is normal on a phone — six document categories will never
   sit across 375px. The strip scrolls; the page does not. */
.tabs { display: flex; gap: 2px; border-bottom: 1px solid var(--line); margin-bottom: 18px;
  overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch; }
.tabs::-webkit-scrollbar { display: none; }
.tabs button { flex: none; }
/* Nine sections do not fit on one line of a laptop, and a row that scrolls
   sideways hides the ones at the end. These wrap instead. */
.tabs.wrap { flex-wrap: wrap; overflow: visible; }
.tabs button { background: none; border: 0; padding: 10px 14px; font-weight: 700; color: var(--muted); cursor: pointer; border-bottom: 2px solid transparent; margin-bottom: -1px; }
.tabs button.active { color: var(--navy); border-bottom-color: var(--gold); }

.empty { text-align: center; padding: 40px 20px; color: var(--muted); }
.empty .ico { width: 40px; height: 40px; color: var(--faint); margin-bottom: 8px; }

.notice { padding: 12px 14px; border-radius: 8px; font-size: 14px; border: 1px solid; }
.notice.info { background: var(--blue-100); border-color: #c3d4ea; color: var(--navy); }
.notice.warn { background: var(--amber-100); border-color: #ecd6a6; color: #6b4a0f; }
.notice.gold { background: var(--gold-50); border-color: var(--gold-300); color: var(--navy); }
.notice.ok { background: var(--green-100); border-color: #bfdfcb; color: var(--green); }
.notice.err { background: var(--red-100); border-color: #efc6c1; color: var(--red); }

/* Attendance register */
.status-group { display: inline-flex; border: 1px solid var(--line-strong); border-radius: 8px; overflow: hidden; }
.status-group button { border: 0; background: #fff; padding: 5px 10px; font-size: 12.5px; font-weight: 700; color: var(--muted); cursor: pointer; border-right: 1px solid var(--line); }
.status-group button:last-child { border-right: 0; }
.status-group button:hover { background: var(--navy-50); }
.status-group button.P.on { background: var(--green); color: #fff; }
.status-group button.A.on { background: var(--red); color: #fff; }
.status-group button.L.on { background: var(--amber); color: #fff; }
.status-group button.E.on { background: var(--blue); color: #fff; }
.status-group[aria-disabled="true"] button { cursor: not-allowed; opacity: 0.7; }
.bar { height: 8px; background: var(--navy-100); border-radius: 99px; overflow: hidden; }
.bar > span { display: block; height: 100%; background: var(--gold); }
.bar.green > span { background: var(--green); }
.bar.navy > span { background: var(--navy); }
.heat { display: grid; grid-auto-flow: column; gap: 3px; }
.heat span { width: 14px; height: 14px; border-radius: 3px; background: var(--line); }
.heat span.P { background: var(--green); } .heat span.A { background: var(--red); } .heat span.L { background: var(--amber); } .heat span.E { background: var(--blue); }

/* Charts (pure CSS) */
.barchart { display: grid; gap: 8px; }
.barchart .row { display: grid; grid-template-columns: 150px 1fr 56px; gap: 10px; align-items: center; font-size: 13px; }
.barchart .row .bar { height: 14px; }
.cols { display: flex; align-items: flex-end; gap: 6px; height: 160px; padding-top: 10px; }
.cols .col { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 4px; height: 100%; justify-content: flex-end; }
.cols .col span.fill { width: 100%; background: var(--navy); border-radius: 4px 4px 0 0; min-height: 2px; }
.cols .col .lbl { font-size: 11px; color: var(--muted); }
.cols .col .val { font-size: 11px; color: var(--navy); font-weight: 700; }

/* Messages */
.msg-layout { display: grid; grid-template-columns: 260px minmax(0, 1fr); min-height: 560px; }
.channel-list { border-right: 1px solid var(--line); padding: 10px; }
.channel-list .item { display: flex; align-items: center; gap: 8px; padding: 8px 10px; border-radius: 8px; cursor: pointer; font-size: 14px; }
.channel-list .item:hover { background: var(--navy-50); }
.channel-list .item.active { background: var(--gold-100); color: var(--navy); font-weight: 700; }
.channel-list .item .badge { margin-left: auto; background: var(--gold); color: #fff; font-size: 11px; border-radius: 99px; padding: 0 6px; font-weight: 700; }
.thread { display: flex; flex-direction: column; }
.thread-head { padding: 12px 18px; border-bottom: 1px solid var(--line); }
.thread-body { flex: 1; padding: 18px; display: flex; flex-direction: column; gap: 14px; overflow: auto; max-height: 520px; }
.msg { display: flex; gap: 10px; }
.msg .bubble { background: var(--navy-50); border-radius: 10px; padding: 8px 12px; max-width: 78%; }
.msg.mine { flex-direction: row-reverse; }
.msg.mine .bubble { background: var(--gold-100); }
.msg .meta { font-size: 12px; color: var(--muted); margin-bottom: 2px; }
.msg.broadcast .bubble { background: var(--navy); color: #fff; border-left: 3px solid var(--gold); }
.msg.broadcast .meta { color: var(--gold-300); }
.thread-compose { border-top: 1px solid var(--line); padding: 12px 18px; display: flex; gap: 10px; align-items: flex-end; }
.thread-compose textarea { min-height: 44px; }

/* Documents */
.doc-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 14px; }
.doc { padding: 14px; display: flex; flex-direction: column; gap: 8px; }
.doc .type { width: 38px; height: 38px; border-radius: 8px; display: flex; align-items: center; justify-content: center; font-size: 11px; font-weight: 800; color: #fff; font-family: var(--sans); }
.doc .type.pdf { background: var(--red); } .doc .type.doc { background: var(--blue); } .doc .type.sheet { background: var(--green); } .doc .type.slide { background: var(--amber); } .doc .type.folder { background: var(--gold); } .doc .type.form { background: #6d4c9f; }
.doc .name { font-weight: 700; font-size: 14px; line-height: 1.3; }
.doc .name a { text-decoration: none; }
.doc .name a:hover { text-decoration: underline; }

/* Permissions matrix */
.perm-group { border: 1px solid var(--line); border-radius: 8px; overflow: hidden; margin-bottom: 12px; }
.perm-group .ph { background: var(--navy-50); padding: 8px 14px; font-weight: 700; color: var(--navy); font-size: 13px; display: flex; align-items: center; gap: 8px; }
.perm-row { display: grid; grid-template-columns: 1fr auto; gap: 10px; align-items: center; padding: 8px 14px; border-top: 1px solid var(--line); font-size: 14px; }
.perm-row .desc { font-size: 12px; color: var(--muted); }
.switch { position: relative; width: 40px; height: 22px; background: var(--line-strong); border-radius: 99px; border: 0; cursor: pointer; flex: none; }
.switch::after { content: ""; position: absolute; top: 3px; left: 3px; width: 16px; height: 16px; border-radius: 50%; background: #fff; transition: left .15s; }
.switch.on { background: var(--green); }
.switch.on::after { left: 21px; }
.switch.override { box-shadow: 0 0 0 2px var(--gold); }
.switch:disabled { opacity: 0.4; cursor: not-allowed; }
.role-tier { display: flex; align-items: center; gap: 10px; padding: 10px 14px; border-bottom: 1px solid var(--line); }
.role-tier .n { width: 26px; height: 26px; border-radius: 50%; background: var(--navy); color: var(--gold-300); font-family: var(--serif); font-weight: 700; display: flex; align-items: center; justify-content: center; font-size: 13px; }

/* Calendar */
/* Seven equal columns that are allowed to be narrower than the longest event
   title in them. With a bare 1fr the widest day set the width of all seven and
   the month came out at 836px on a 375px phone, taking the page sideways. */
.cal { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); border-left: 1px solid var(--line); border-top: 1px solid var(--line); }
.cal .dow { background: var(--navy-50); font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; padding: 6px; color: var(--muted); font-weight: 700; border-right: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.cal .day { min-height: 84px; border-right: 1px solid var(--line); border-bottom: 1px solid var(--line); padding: 6px; font-size: 12px; min-width: 0; overflow: hidden; }
.cal .day.other { background: #fafafa; color: var(--faint); }
.cal .day.today .num { background: var(--gold); color: #fff; }
.cal .day .num { display: inline-block; width: 22px; height: 22px; border-radius: 50%; text-align: center; line-height: 22px; font-weight: 700; }
.cal .ev { display: block; margin-top: 3px; padding: 2px 6px; border-radius: 4px; background: var(--navy-100); color: var(--navy); font-size: 11px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cal .ev.gold { background: var(--gold-100); color: var(--gold-600); }
.cal .ev.red { background: var(--red-100); color: var(--red); }
.cal .ev.green { background: var(--green-100); color: var(--green); }

/* Timeline */
.timeline { list-style: none; margin: 0; padding: 0; }
.timeline li { display: grid; grid-template-columns: 64px 1fr; gap: 12px; padding: 8px 0; border-bottom: 1px dashed var(--line); font-size: 14px; }
.timeline li:last-child { border-bottom: 0; }
.timeline .t { font-size: 12px; color: var(--muted); padding-top: 2px; }

/* Modal & toast */
.modal-backdrop { position: fixed; inset: 0; background: rgba(12, 27, 46, 0.55); display: flex; align-items: center; justify-content: center; z-index: 50; padding: 20px; }
.modal { background: var(--paper); border-radius: 12px; width: 100%; max-width: 640px; max-height: 90vh; overflow: auto; box-shadow: var(--shadow-lg); }
.modal.wide { max-width: 860px; }
.modal-head { padding: 16px 20px; border-bottom: 1px solid var(--line); display: flex; align-items: center; gap: 10px; }
.modal-head h2 { flex: 1; }
.modal-body { padding: 20px; }
.modal-foot { padding: 14px 20px; border-top: 1px solid var(--line); display: flex; gap: 10px; justify-content: flex-end; }
.iconbtn { border: 0; background: none; cursor: pointer; padding: 6px; border-radius: 6px; color: var(--muted); display: inline-flex; }
.iconbtn:hover { background: var(--navy-50); color: var(--navy); }
.iconbtn svg { width: 18px; height: 18px; }
.toast-wrap { position: fixed; right: 20px; bottom: 20px; display: flex; flex-direction: column; gap: 8px; z-index: 60; }
.toast { background: var(--navy); color: #fff; padding: 10px 14px; border-radius: 8px; box-shadow: var(--shadow-lg); font-size: 14px; border-left: 3px solid var(--gold); animation: pop .2s ease; }
.toast.err { border-left-color: var(--red); }
@keyframes pop { from { transform: translateY(8px); opacity: 0; } to { transform: none; opacity: 1; } }

.kv { display: grid; grid-template-columns: 140px 1fr; gap: 6px 12px; font-size: 14px; }
.kv dt { color: var(--muted); }
.kv dd { margin: 0; }

.forbidden { text-align: center; padding: 60px 20px; }
.forbidden .ico { width: 48px; height: 48px; color: var(--gold); margin-bottom: 10px; }

@media (max-width: 1080px) {
  .grid.cols-4 { grid-template-columns: repeat(2, 1fr); }
  .grid.cols-3 { grid-template-columns: repeat(2, 1fr); }
  /* minmax(0, 1fr), never a bare 1fr. `1fr` is shorthand for minmax(auto, 1fr)
     and that auto floor is the content's min-content width, so one wide table
     drags the track past the viewport and the page scrolls sideways. The
     desktop rules above already guard against this; the mobile collapses did
     not, which is exactly backwards — the narrow screen is where it bites. */
  .grid.side, .grid.side-left { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 860px) {
  .shell { grid-template-columns: minmax(0, 1fr); }
  .login { grid-template-columns: minmax(0, 1fr); }
  .login-brand { padding: 28px; }
  .grid.cols-2, .grid.cols-3, .grid.cols-4 { grid-template-columns: minmax(0, 1fr); }
  .form-row, .form-row.three { grid-template-columns: minmax(0, 1fr); }
  .msg-layout { grid-template-columns: minmax(0, 1fr); }
  .channel-list { border-right: 0; border-bottom: 1px solid var(--line); }
  .content { padding: 16px; }
  .topbar { padding: 12px 16px; }
}
@media print {
  .sidebar, .topbar, .toolbar, .btn, .toast-wrap { display: none !important; }
  .shell { grid-template-columns: minmax(0, 1fr); }
  body { background: #fff; }
}

/* Timetable */
table.tt th.today, table.tt td.today { background: var(--gold-50); }
table.tt th .tt-ev { display: block; margin-top: 4px; font-size: 10.5px; font-weight: 600; text-transform: none; letter-spacing: 0; padding: 2px 6px; border-radius: 4px; background: var(--navy-100); color: var(--navy); white-space: normal; }
table.tt th .tt-ev.gold { background: var(--gold-100); color: var(--gold-600); } table.tt th .tt-ev.red { background: var(--red-100); color: var(--red); } table.tt th .tt-ev.green { background: var(--green-100); color: var(--green); }
table.tt tr.tt-break td { background: #fafaf7; }
.tt-cell { width: 100%; text-align: left; border: 1px solid transparent; border-radius: 6px; padding: 7px 9px; font-size: 12.5px; font-weight: 700; cursor: pointer; line-height: 1.25; }
.tt-cell:disabled { cursor: default; }
.tt-cell.blue { background: var(--blue-100); color: var(--blue); } .tt-cell.green { background: var(--green-100); color: var(--green); } .tt-cell.amber { background: var(--amber-100); color: var(--amber); }
.tt-cell.gold { background: var(--gold-100); color: var(--gold-600); } .tt-cell.navy { background: var(--navy-100); color: var(--navy); } .tt-cell.grey { background: #eef0f3; color: var(--muted); } .tt-cell.red { background: var(--red-100); color: var(--red); }
.tt-cell:not(:disabled):hover { border-color: var(--navy); }
.pill.navy { background: var(--navy); color: #fff; }

/* Recruitment board */
.board { display: grid; grid-template-columns: repeat(7, minmax(150px, 1fr)); gap: 0; overflow-x: auto; }
.board .col { padding: 12px; border-right: 1px solid var(--line); min-height: 220px; }
.board .col:last-child { border-right: 0; }
.board .col-head { display: flex; justify-content: space-between; align-items: center; font-weight: 700; font-size: 12.5px; color: var(--navy); margin-bottom: 2px; }
.cand { background: var(--paper); border: 1px solid var(--line); border-radius: 8px; padding: 10px; margin-bottom: 8px; cursor: pointer; box-shadow: var(--shadow); }
.cand:hover { border-color: var(--gold); }
.status-group .score { display: inline-block; padding: 5px 11px; font-size: 12.5px; font-weight: 700; color: var(--muted); cursor: pointer; border-right: 1px solid var(--line); }
.status-group label:last-child .score { border-right: 0; }
.status-group .score.on { background: var(--navy); color: #fff; }
.status-group .score:hover { background: var(--navy-50); }
@media (max-width: 1080px) { .board { grid-template-columns: repeat(7, 170px); } }

/* Register period chips */
.reg-chips { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 8px; }
.reg-chip { display: flex; flex-direction: column; gap: 2px; text-align: left; background: var(--paper); border: 1px solid var(--line); border-radius: 8px; padding: 8px 10px; cursor: pointer; min-width: 0; }
.reg-chip .t { font-size: 11px; color: var(--muted); font-weight: 700; }
.reg-chip .l { font-size: 12.5px; font-weight: 700; color: var(--navy); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.reg-chip .s { font-size: 11px; font-weight: 700; }
.reg-chip.done .s { color: var(--green); } .reg-chip.missed .s { color: var(--red); } .reg-chip.open .s, .reg-chip.partial .s { color: var(--gold-600); } .reg-chip.upcoming .s, .reg-chip.none .s { color: var(--faint); }
.reg-chip.open { border-color: var(--gold); background: var(--gold-50); } .reg-chip.missed { border-color: #efc6c1; background: var(--red-100); } .reg-chip.done { background: var(--green-100); border-color: #bfdfcb; }
.reg-chip.sel { box-shadow: 0 0 0 2px var(--navy); border-color: var(--navy); }
.sel-row { background: var(--gold-50); }
.tt-cell.plain { background: transparent; padding: 4px 2px; display: flex; flex-direction: column; gap: 3px; align-items: flex-start; }
.tt-cell.plain:not(:disabled):hover { background: var(--navy-50); border-color: var(--line); }
.tt-sub { display: inline-block; padding: 3px 8px; border-radius: 5px; font-size: 12px; font-weight: 700; }
.tt-sub.blue { background: var(--blue-100); color: var(--blue); } .tt-sub.green { background: var(--green-100); color: var(--green); } .tt-sub.amber { background: var(--amber-100); color: var(--amber); }
.tt-sub.gold { background: var(--gold-100); color: var(--gold-600); } .tt-sub.navy { background: var(--navy-100); color: var(--navy); } .tt-sub.grey { background: #eef0f3; color: var(--muted); } .tt-sub.red { background: var(--red-100); color: var(--red); }
.tt-who { font-size: 11px; color: var(--muted); }
.tt-cell .tt-sub { background: transparent; padding: 0; color: inherit; font-size: 12.5px; }
.tt-cell .tt-who { color: inherit; opacity: .75; display: block; font-weight: 600; }
.tt-free { display: block; font-size: 11.5px; color: var(--faint); font-style: italic; padding: 8px 6px; }
@media (max-width: 1080px) { .reg-chips { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

/* ==========================================================================
   Student Information System (2.0)
   ========================================================================== */

/* admissions stage strip */
.steps { display: flex; flex-wrap: wrap; gap: 4px; }
.steps .step { font-size: 11.5px; font-weight: 700; padding: 4px 10px; border-radius: 99px; background: #eef0f3; color: var(--faint); white-space: nowrap; }
.steps .step.done { background: var(--navy-100); color: var(--navy); }
.steps .step.on { background: var(--navy); color: #fff; }

/* checkbox rows (document checklists, consents, fee item scope) */
.check { display: flex; align-items: center; gap: 8px; font-size: 13.5px; cursor: pointer; }
.check input { width: 16px; height: 16px; accent-color: var(--navy); flex: none; }

/* one logged guardian message */
.comm { padding: 14px 18px; border-bottom: 1px solid var(--line); }
.comm:last-child { border-bottom: 0; }
.comm.auto { background: var(--gold-50); }

/* record tabs */
.tabs button.on { color: var(--navy); border-bottom-color: var(--gold); }

/* full pupil timeline */
.timeline.full li { display: grid; grid-template-columns: 66px 74px 1fr; gap: 10px; align-items: baseline; padding: 7px 0; border-bottom: 1px dashed var(--line); }
.timeline.full li:last-child { border-bottom: 0; }
.timeline.full .pill { justify-self: start; text-transform: capitalize; }

/* two-column definition list on the report card */
.kv.cols2 { display: grid; grid-template-columns: auto 1fr auto 1fr; column-gap: 14px; }

/* printable report card */
.report { border: 1px solid var(--line); border-radius: 10px; padding: 24px; background: var(--paper); }
.report-head { display: flex; align-items: center; gap: 16px; border-bottom: 2px solid var(--navy); padding-bottom: 14px; }
.report-head img { width: 58px; height: 58px; object-fit: contain; }
.report-head h2 { margin: 0; font-size: 20px; }

/* inline API sample */
.code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; line-height: 1.9; background: var(--navy-50); border: 1px solid var(--line); border-radius: 6px; padding: 10px 12px; color: var(--navy); overflow-x: auto; }

.input.right { text-align: right; }
@media (max-width: 900px) { .kv.cols2 { grid-template-columns: auto 1fr; } }

/* sign-in: the governance tier gets its own group on the login screen */
.tile-group { margin-bottom: 18px; }
.tile-group:last-child { margin-bottom: 0; }
.tile-head { display: flex; align-items: center; gap: 8px; font-size: 11px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); padding-bottom: 8px; border-bottom: 1px solid var(--line); margin-bottom: 10px; }
.tile-head .tiny { font-weight: 600; letter-spacing: 0; text-transform: none; color: var(--faint); }
.tile-group.gov .tile-head { color: var(--gold-600); border-bottom-color: var(--gold); }
.user-tile.gov { border-color: var(--gold-100); background: var(--gold-50); }
.user-tile.gov.selected { border-color: var(--gold); }
.avatar.gold { background: var(--gold); color: #fff; }

/* someone else's change arriving over the live connection */
.toast.live { border-left: 3px solid var(--gold); }
.center { text-align: center; }

/* ==========================================================================
   The public page — what anyone sees before signing in
   ========================================================================== */

.site { background: var(--bg); min-height: 100vh; min-height: 100dvh; }
.site .wrap { max-width: 1180px; margin: 0 auto; padding: 0 28px; }
.site .wrap.narrow { max-width: 860px; }
.site h2 { font-size: 30px; line-height: 1.2; margin: 6px 0 0; }
.site .lead { font-size: 15.5px; }
.eyebrow.center, .center { text-align: center; }

/* --- top bar --- */
.site-bar { position: sticky; top: 0; z-index: 40; display: flex; align-items: center; gap: 24px;
  padding: 12px 28px; background: rgba(12, 27, 46, .94); backdrop-filter: blur(8px);
  border-bottom: 1px solid rgba(217, 194, 126, .28); }
.site-brand { display: flex; align-items: center; gap: 12px; text-decoration: none; }
/* The wordmark and the tagline sit in a wrapper span, and that span is a flex
   item, so it starts at min-width:auto — it will not shrink below its text
   however narrow the bar gets. Everything above it was already allowed to
   shrink and .n already carried the ellipsis, but neither could do anything
   while this one link in the chain held its full width: on a phone the brand
   simply overflowed its grid column and drew straight over the buttons in the
   next one. A flex or grid child that is meant to truncate has to be told it
   may be smaller than its contents, the whole way down. */
.site-brand > span { min-width: 0; }
.site-brand img { width: 38px; height: 38px; object-fit: contain; }
.site-brand .n { display: block; font-family: Georgia, "Times New Roman", serif; font-weight: 700; color: #fff; font-size: 16px; line-height: 1.15; }
.site-brand .t { display: block; font-size: 10.5px; letter-spacing: .16em; text-transform: uppercase; color: var(--gold-300); }
.site-nav { display: flex; gap: 22px; margin-left: auto; }
.site-nav a { color: #cbd5e1; text-decoration: none; font-size: 14px; font-weight: 600; }
.site-nav a:hover { color: var(--gold-300); }
.site-bar .btn.ghost { color: #e5e7eb; border-color: rgba(229, 231, 235, .35); background: transparent; }
.site-bar .btn.ghost:hover { border-color: var(--gold-300); color: var(--gold-300); }

/* --- hero --- */
.hero { background: var(--navy-900); }
.hero-banner { display: block; width: 100%; height: auto; }
.hero-copy { max-width: 1180px; margin: 0 auto; padding: 40px 28px 56px; text-align: center; }
.hero-copy h1 { font-family: Georgia, "Times New Roman", serif; color: #fff; font-size: 38px; line-height: 1.18; margin: 0; letter-spacing: -.01em; }
.hero-copy p { color: #c7d2de; font-size: 16.5px; line-height: 1.65; max-width: 720px; margin: 16px auto 0; }
.hero-cta { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; margin-top: 28px; }
.btn.lg { padding: 12px 22px; font-size: 15px; }
.hero .btn.ghost { color: #fff; border-color: rgba(255, 255, 255, .4); background: transparent; }
.hero .btn.ghost:hover { border-color: var(--gold-300); color: var(--gold-300); }
.hero-note { margin-top: 18px; font-size: 12.5px; color: #93a4b8; display: flex; gap: 7px; align-items: center; justify-content: center; }

/* --- bands --- */
.band { padding: 64px 0; }
.band.alt { background: var(--paper); border-block: 1px solid var(--line); }
.pillar { padding: 22px; }
.pillar .gold-line { width: 34px; height: 3px; background: var(--gold); border-radius: 2px; }
.pillar h3 { margin: 14px 0 6px; font-size: 16px; }
.pillar .lead { color: var(--ink); font-weight: 600; font-size: 14px; margin: 0 0 8px; }

/* --- the look-inside panel --- */
.shot-wrap { border: 1px solid var(--line); border-radius: 12px; overflow: hidden; background: var(--paper); box-shadow: 0 10px 30px rgba(12, 27, 46, .07); }
.shot-tabs { display: flex; gap: 2px; padding: 8px 8px 0; background: var(--navy-50); border-bottom: 1px solid var(--line); flex-wrap: wrap; }
.shot-tab { border: 0; background: none; padding: 9px 14px; font-weight: 700; font-size: 13px; color: var(--muted); cursor: pointer; border-radius: 7px 7px 0 0; }
.shot-tab.on { background: var(--paper); color: var(--navy); box-shadow: 0 -2px 0 var(--gold) inset; }
.shot { padding: 22px; min-height: 250px; }
.shot-head { display: flex; justify-content: space-between; align-items: center; gap: 12px; padding-bottom: 12px; margin-bottom: 14px; border-bottom: 1px solid var(--line); flex-wrap: wrap; }
.reg-chips.mini { grid-template-columns: repeat(5, minmax(0, 1fr)); }
.board.mini { grid-template-columns: repeat(5, minmax(120px, 1fr)); }
.board.mini .col { min-height: 120px; padding: 10px; }
.tabs.mini { border-bottom: 1px solid var(--line); margin-bottom: 12px; }
.tabs.mini .tab { padding: 8px 12px; font-weight: 700; font-size: 13px; color: var(--muted); border-bottom: 2px solid transparent; margin-bottom: -1px; }
.tabs.mini .tab.on { color: var(--navy); border-bottom-color: var(--gold); }
.timeline.full.mini li { padding: 6px 0; }
table.mini td { padding: 7px 0; border-bottom: 1px solid var(--line); }

/* --- module grid --- */
.mod { display: flex; gap: 11px; padding: 14px; background: var(--navy-50); border-radius: 9px; }
.mod svg { width: 19px; height: 19px; flex: none; color: var(--gold-600); margin-top: 1px; }
.mod p { margin: 3px 0 0; line-height: 1.5; }

/* --- sign in / request --- */
.access-grid { display: grid; grid-template-columns: 1.15fr 1fr; gap: 22px; align-items: start; }
.access-card { scroll-margin-top: 80px; }
.notice.ok { background: var(--green-100); border-color: #bfdfcb; color: var(--green); }

/* --- footer --- */
.site-foot { background: var(--navy-900); color: #93a4b8; padding: 40px 0; }
.site-foot .bold { color: #fff; }
.site-foot .tiny { line-height: 1.7; }

@media (max-width: 980px) {
  .site-nav { display: none; }
  .site-bar { gap: 12px; padding: 10px 16px; }
  .site-brand { min-width: 0; }
  .site-brand .n { font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .site-bar .flex { margin-left: auto; flex: none; }
  .access-grid { grid-template-columns: minmax(0, 1fr); }
  .hero-copy h1 { font-size: 28px; }
  .band { padding: 44px 0; }
  .site .wrap { padding: 0 18px; }
  .reg-chips.mini { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .board.mini { grid-template-columns: repeat(2, minmax(120px, 1fr)); }
  .hero-copy { padding: 28px 18px 40px; }
  .hero-copy p { font-size: 15px; }
  .site h2 { font-size: 23px; }
  .mod { padding: 12px; }
}

/* On a phone the school's name is the crest; the wordmark would crowd out the
   two things anyone actually came here to press. */
@media (max-width: 560px) {
  .site-brand .n { display: none; }
  .site-brand .t { font-size: 11px; letter-spacing: .12em; }
  .site-brand img { width: 32px; height: 32px; }
  .site-bar .btn { padding: 7px 11px; font-size: 12.5px; }
  .site-bar .btn svg { display: none; }
  .hero-copy h1 { font-size: 24px; }
  .hero-cta .btn.lg { width: 100%; justify-content: center; }
  .shot { padding: 14px; }
  .shot-tabs { padding: 6px 6px 0; }
  .shot-tab { padding: 8px 10px; font-size: 12px; }
}

/* password field with a show/hide control */
.pw { position: relative; }
.pw .input { padding-right: 62px; }
.pw-toggle { position: absolute; right: 6px; top: 50%; transform: translateY(-50%); border: 0; background: none;
  font-size: 12px; font-weight: 700; color: var(--muted); cursor: pointer; padding: 6px 8px; border-radius: 6px; }
.pw-toggle:hover { color: var(--navy); background: var(--navy-50); }
code { background: var(--navy-50); border: 1px solid var(--line); border-radius: 4px; padding: 1px 5px; font-size: 11.5px; }

/* ==========================================================================
   The public page — movement and depth
   --------------------------------------------------------------------------
   Restrained on purpose. Every transition here either shows where you are or
   softens a change; none of it is decoration, and all of it stops dead under
   prefers-reduced-motion.
   ========================================================================== */

html:has(.site) { scroll-behavior: smooth; }
.site [id] { scroll-margin-top: 78px; }

/* --- sections arriving --- */
[data-reveal] { opacity: 0; transform: translateY(14px); transition: opacity .55s ease, transform .55s cubic-bezier(.22, .61, .36, 1); }
[data-reveal].in { opacity: 1; transform: none; }
.grid [data-reveal]:nth-child(2) { transition-delay: .06s; }
.grid [data-reveal]:nth-child(3) { transition-delay: .12s; }
.grid [data-reveal]:nth-child(4) { transition-delay: .18s; }
.grid [data-reveal]:nth-child(5) { transition-delay: .24s; }
.grid [data-reveal]:nth-child(6) { transition-delay: .30s; }
.grid [data-reveal]:nth-child(7) { transition-delay: .36s; }
.grid [data-reveal]:nth-child(8) { transition-delay: .42s; }

/* --- the bar --- */
.site-bar { transition: box-shadow .3s ease, background-color .3s ease, padding .3s ease; }
.site-bar.scrolled { box-shadow: 0 6px 24px rgba(12, 27, 46, .35); background: rgba(12, 27, 46, .98); padding-block: 9px; }
.site-nav a { position: relative; padding: 4px 0; transition: color .2s ease; }
.site-nav a::after { content: ""; position: absolute; left: 0; right: 0; bottom: -2px; height: 2px;
  background: var(--gold); border-radius: 2px; transform: scaleX(0); transform-origin: left; transition: transform .28s cubic-bezier(.22, .61, .36, 1); }
.site-nav a:hover::after, .site-nav a.on::after { transform: scaleX(1); }
.site-nav a.on { color: #fff; }

/* --- hero --- */
.hero { position: relative; overflow: hidden; }
.hero::after { content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(120% 80% at 50% 0%, transparent 55%, rgba(12, 27, 46, .55) 100%); }
.hero-copy { position: relative; z-index: 1; }
.hero-copy h1, .hero-copy p, .hero-cta, .hero-note { animation: rise .7s cubic-bezier(.22, .61, .36, 1) both; }
.hero-copy p { animation-delay: .08s; } .hero-cta { animation-delay: .16s; } .hero-note { animation-delay: .24s; }
@keyframes rise { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: none; } }

/* --- buttons --- */
.btn { transition: transform .14s ease, box-shadow .2s ease, background-color .2s ease, border-color .2s ease, color .2s ease; }
.btn:not(:disabled):hover { transform: translateY(-1px); }
.btn:not(:disabled):active { transform: translateY(0); }
.btn.lg { box-shadow: 0 6px 18px rgba(12, 27, 46, .28); }
.btn.lg:not(:disabled):hover { box-shadow: 0 10px 26px rgba(12, 27, 46, .36); }

/* --- the plain facts --- */
.strip { background: var(--navy); color: #fff; padding: 30px 0; }
.strip .wrap { display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; text-align: center; }
.fact .n { font-family: Georgia, "Times New Roman", serif; font-size: 40px; line-height: 1; color: var(--gold-300); font-variant-numeric: tabular-nums; }
.fact .l { font-size: 12px; letter-spacing: .14em; text-transform: uppercase; color: #fff; margin-top: 8px; font-weight: 700; }
.fact .s { font-size: 12px; color: #9fb0c4; margin-top: 4px; }

/* --- cards that respond --- */
.pillar { transition: transform .25s cubic-bezier(.22, .61, .36, 1), box-shadow .25s ease, border-color .25s ease; }
.pillar:hover { transform: translateY(-4px); box-shadow: 0 14px 34px rgba(12, 27, 46, .12); border-color: var(--gold-100); }
.pillar .gold-line { transition: width .3s cubic-bezier(.22, .61, .36, 1); }
.pillar:hover .gold-line { width: 56px; }
.mod { transition: background-color .2s ease, transform .2s ease; }
.mod:hover { background: var(--gold-50); transform: translateX(3px); }

/* --- the look-inside panel --- */
.shot-wrap { transition: box-shadow .3s ease; }
.shot-wrap:hover { box-shadow: 0 16px 44px rgba(12, 27, 46, .11); }
.shot-tab { transition: background-color .2s ease, color .2s ease; }
.shot-tab:hover:not(.on) { color: var(--navy); background: rgba(255, 255, 255, .6); }
.shot.swap { animation: swap .32s cubic-bezier(.22, .61, .36, 1) both; }
@keyframes swap { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

/* the register that is open right now, quietly asking to be taken */
.shot .reg-chip.open { animation: breathe 2.6s ease-in-out infinite; }
@keyframes breathe {
  0%, 100% { box-shadow: 0 0 0 0 rgba(176, 141, 52, .34); }
  50%      { box-shadow: 0 0 0 7px rgba(176, 141, 52, 0); }
}

/* --- fields --- */
.site .input { transition: border-color .2s ease, box-shadow .2s ease, background-color .2s ease; }
.site .input:focus { border-color: var(--navy); box-shadow: 0 0 0 3px rgba(22, 48, 79, .12); outline: none; }
.access-card { transition: box-shadow .3s ease; }
.access-card:focus-within { box-shadow: 0 14px 38px rgba(12, 27, 46, .13); }

/* a keyboard user must always be able to see where they are */
.site a:focus-visible, .site button:focus-visible, .site .input:focus-visible,
.shot-tab:focus-visible, .pw-toggle:focus-visible {
  outline: 2px solid var(--gold); outline-offset: 2px; border-radius: 6px;
}

/* --- the menu on small screens --- */
.menu-btn { display: none; flex-direction: column; gap: 4px; background: none; border: 0; padding: 8px; cursor: pointer; }
.menu-btn span { display: block; width: 20px; height: 2px; background: #e5e7eb; border-radius: 2px; transition: transform .25s ease, opacity .2s ease; }
.site.menu-open .menu-btn span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.site.menu-open .menu-btn span:nth-child(2) { opacity: 0; }
.site.menu-open .menu-btn span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

.site-drawer { position: fixed; inset: var(--bar-h, 56px) 0 auto; z-index: 39; background: rgba(12, 27, 46, .99);
  border-bottom: 1px solid rgba(217, 194, 126, .28); transform: translateY(-120%); transition: transform .3s cubic-bezier(.22, .61, .36, 1);
  visibility: hidden; }
.site.menu-open .site-drawer { transform: none; visibility: visible; }
.site-drawer nav { display: flex; flex-direction: column; padding: 8px 18px 18px; }
.site-drawer a { color: #cbd5e1; text-decoration: none; font-weight: 600; padding: 14px 4px; border-bottom: 1px solid rgba(255, 255, 255, .08); }
.site-drawer a:last-child { border-bottom: 0; }
.site-drawer a.strong { color: var(--gold-300); }

@media (max-width: 980px) {
  .menu-btn { display: flex; }
  .site-actions { display: none; }
  .strip .wrap { grid-template-columns: repeat(2, 1fr); gap: 26px; }
}
@media (max-width: 560px) { .fact .n { font-size: 32px; } }

/* --- anyone who has asked for less movement gets none of it --- */
@media (prefers-reduced-motion: reduce) {
  html:has(.site) { scroll-behavior: auto; }
  [data-reveal] { opacity: 1; transform: none; transition: none; }
  .hero-copy h1, .hero-copy p, .hero-cta, .hero-note, .shot.swap { animation: none; }
  .shot .reg-chip.open { animation: none; }
  .btn:hover, .pillar:hover, .mod:hover { transform: none; }
  .site-drawer { transition: none; }
  * { scroll-behavior: auto !important; }
}

/* ==========================================================================
   The school's page — values, how we work, the day, the curriculum
   ========================================================================== */

/* how we work */
.work-grid { gap: 22px 28px; }
.work { display: flex; gap: 14px; align-items: flex-start; }
.work-ico { flex: none; width: 40px; height: 40px; border-radius: 10px; display: grid; place-items: center;
  background: var(--gold-50); border: 1px solid var(--gold-100); color: var(--gold-600); }
.work-ico svg { width: 19px; height: 19px; }
.work h3 { margin: 2px 0 6px; font-size: 15.5px; }
.work p { margin: 0; line-height: 1.65; }

/* the school day, as a line */
.day-line { list-style: none; margin: 0; padding: 0; display: grid;
  grid-template-columns: repeat(auto-fit, minmax(96px, 1fr)); gap: 0; border-radius: 10px; overflow: hidden;
  border: 1px solid var(--line); background: var(--paper); }
.day-line li { padding: 16px 10px; text-align: center; border-right: 1px solid var(--line); position: relative; }
.day-line li:last-child { border-right: 0; }
.day-line .t { display: block; font-family: Georgia, "Times New Roman", serif; font-size: 16px; color: var(--navy); }
.day-line .d { display: block; font-size: 11.5px; color: var(--muted); margin-top: 4px; line-height: 1.35; }
.day-line li.lesson { background: var(--navy-50); }
.day-line li.admin { background: var(--gold-50); }
.day-line li.admin .t { color: var(--gold-600); }
.day-line li.break { background: var(--paper); }
.day-line li.break .d { font-style: italic; }

/* curriculum */
.stage .card-body .pill { font-size: 11.5px; }

/* how a place is offered */
.steps-line { list-style: none; margin: 0; padding: 0; display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 18px; }
.steps-line li { display: flex; gap: 12px; align-items: flex-start; padding: 16px; background: var(--paper);
  border: 1px solid var(--line); border-radius: 10px; }
.steps-line .n { flex: none; width: 26px; height: 26px; border-radius: 50%; background: var(--navy); color: #fff;
  display: grid; place-items: center; font-size: 12.5px; font-weight: 800; }
.steps-line strong { font-size: 14px; }
.steps-line p { margin: 4px 0 0; line-height: 1.5; }

.ticks { list-style: none; margin: 0; padding: 0; }
.ticks li { display: flex; gap: 9px; align-items: center; padding: 7px 0; font-size: 13.5px; border-bottom: 1px dashed var(--line); }
.ticks li:last-child { border-bottom: 0; }
.ticks svg { width: 15px; height: 15px; color: var(--green); flex: none; }

/* the staff section is deliberately quieter than the rest of the page */
.staff-band { background: var(--navy-50); border-top: 1px solid var(--line); }
.staff-band .shot-wrap { background: var(--paper); }

.foot-links { display: flex; flex-direction: column; gap: 7px; }
.foot-links a { color: #93a4b8; text-decoration: none; }
.foot-links a:hover { color: var(--gold-300); }
.foot-links .bold { margin-bottom: 4px; }

@media (max-width: 980px) {
  .work-grid { grid-template-columns: minmax(0, 1fr); }
  .day-line { grid-template-columns: repeat(3, 1fr); }
  .day-line li { border-bottom: 1px solid var(--line); }
}
@media (max-width: 560px) {
  .day-line { grid-template-columns: repeat(2, 1fr); }
  .site-nav { gap: 14px; }
}

/* ==========================================================================
   The staff page and its tour
   ========================================================================== */

.staff-hero { background: var(--navy-900); color: #fff; padding: 52px 0 46px; }
.staff-hero .eyebrow { color: var(--gold-300); }
.staff-hero h1 { font-family: Georgia, "Times New Roman", serif; font-size: 34px; margin: 8px 0 0; line-height: 1.2; }
.staff-hero p { color: #c7d2de; max-width: 680px; margin: 14px 0 0; line-height: 1.65; font-size: 15.5px; }

/* the school page's quiet pointer to it */
.staff-strip { padding: 44px 0; }
.staff-card { display: flex; align-items: center; justify-content: space-between; gap: 24px; flex-wrap: wrap;
  padding: 24px 28px; border: 1px solid var(--line); border-left: 3px solid var(--gold); border-radius: 12px; background: var(--paper); }
.staff-card h3 { margin: 6px 0 6px; }
.staff-card p { margin: 0; max-width: 520px; }

/* the tour */
.tour { display: grid; grid-template-columns: 260px 1fr; gap: 24px; align-items: start; }
.tour-list { list-style: none; margin: 0; padding: 0; position: sticky; top: 76px; }
.tour-step { display: flex; align-items: center; gap: 11px; width: 100%; text-align: left; background: none;
  border: 0; border-left: 2px solid var(--line); padding: 10px 12px; cursor: pointer; color: var(--muted);
  font-size: 13.5px; font-weight: 600; transition: color .2s ease, border-color .2s ease, background-color .2s ease; }
.tour-step:hover { color: var(--navy); background: var(--navy-50); }
.tour-step.on { color: var(--navy); border-left-color: var(--gold); background: var(--gold-50); font-weight: 800; }
.tour-step .n { flex: none; width: 21px; height: 21px; border-radius: 50%; display: grid; place-items: center;
  background: var(--navy-100); color: var(--navy); font-size: 11px; font-weight: 800; }
.tour-step.on .n { background: var(--gold); color: #fff; }

.tour-stage { border: 1px solid var(--line); border-radius: 12px; background: var(--paper); overflow: hidden;
  box-shadow: 0 10px 30px rgba(12, 27, 46, .07); }
.tour-bar { height: 3px; background: var(--navy-100); }
.tour-bar span { display: block; height: 100%; background: var(--gold); transition: width .5s cubic-bezier(.22,.61,.36,1); }
.tour-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; flex-wrap: wrap;
  padding: 18px 22px 0; }
.tour-head h3 { margin: 4px 0 0; font-size: 18px; }
.tour-say { padding: 12px 22px 0; margin: 0; color: var(--ink); line-height: 1.7; font-size: 14.5px; max-width: 70ch; }
.tour-stage .shot { border-top: 1px solid var(--line); margin-top: 18px; }

/* a read-only stand-in for a field, used in the tour */
.input.faux { color: var(--faint); background: var(--navy-50); user-select: none; }
table.tt.mini th, table.tt.mini td { padding: 6px 8px; font-size: 12px; }

@media (max-width: 980px) {
  .tour { grid-template-columns: minmax(0, 1fr); }
  .tour-list { position: static; display: flex; gap: 6px; overflow-x: auto; padding-bottom: 6px; }
  .tour-list li { flex: none; }
  .tour-step { border-left: 0; border-bottom: 2px solid var(--line); white-space: nowrap; }
  .tour-step.on { border-bottom-color: var(--gold); }
  .staff-hero h1 { font-size: 25px; }
  .staff-card { flex-direction: column; align-items: flex-start; }
}

/* a recording, if the school makes one */
.tour-video { margin: 28px 0 0; }
.tour-video video { width: 100%; display: block; border-radius: 12px; border: 1px solid var(--line); background: #000; }
.tour-video figcaption { margin-top: 8px; text-align: center; }

/* ==========================================================================
   On a phone: a drawer, a bottom bar, and thumbs in mind
   --------------------------------------------------------------------------
   The sidebar used to stack on top of the page, so every visit began with a
   wall of links. It now slides in from the left, and the few things a teacher
   reaches for during a lesson sit along the bottom where a thumb lands.
   ========================================================================== */

.drawer-btn, .topbar-mobile, .tabbar, .scrim { display: none; }

@media (max-width: 860px) {
  /* --- the drawer --- */
  .sidebar {
    position: fixed; inset: 0 auto 0 0; z-index: 60; width: min(80vw, 300px); height: 100dvh;
    transform: translateX(-102%); transition: transform .28s cubic-bezier(.22, .61, .36, 1);
    padding-bottom: env(safe-area-inset-bottom); overflow-y: auto; overscroll-behavior: contain;
  }
  .shell.drawer-open .sidebar { transform: none; box-shadow: 0 0 40px rgba(0, 0, 0, .5); }
  /* On a phone the menu is a drawer that is either open or not there at all,
     so a rail has nothing to narrow. Whatever width was chosen on a laptop is
     ignored here and remembered for when they go back to it. */
  .shell.nav-shut { grid-template-columns: 1fr; }
  .shell.nav-shut .sidebar-brand { padding: 18px 18px 14px; flex-direction: row; }
  .shell.nav-shut .sidebar-brand img { width: 44px; }
  .shell.nav-shut .sidebar-brand > div,
  .shell.nav-shut .sidebar-user > div,
  .shell.nav-shut .nav-section,
  .shell.nav-shut .nav a > span:not(.badge) { display: revert; }
  .shell.nav-shut .nav a { justify-content: flex-start; padding: 9px 10px; }
  .shell.nav-shut .nav a .badge { position: static; margin-left: auto; min-width: 0;
    height: auto; padding: 1px 7px; font-size: 11px; line-height: normal; border: 0; }
  .shell.nav-shut .sidebar-user { padding: 14px 16px; flex-direction: row; }
  .nav-shut-btn { display: none; }
  .scrim { display: block; position: fixed; inset: 0; z-index: 59; background: rgba(6, 14, 24, .5);
    opacity: 0; pointer-events: none; transition: opacity .28s ease; }
  .shell.drawer-open .scrim { opacity: 1; pointer-events: auto; }

  .drawer-btn { display: flex; flex-direction: column; justify-content: center; gap: 4px; flex: none;
    width: 40px; height: 40px; padding: 0 9px; background: none; border: 0; cursor: pointer; margin-right: 2px; }
  .drawer-btn span { display: block; height: 2px; background: var(--navy); border-radius: 2px; }

  /* --- the top bar becomes an app bar --- */
  .topbar { position: sticky; top: 0; z-index: 40; gap: 4px; padding: 10px 12px;
    padding-top: calc(10px + env(safe-area-inset-top)); background: var(--paper); }
  .topbar .crumbs { font-size: 11px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .topbar h1 { font-size: 18px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .topbar-act { display: none; }
  .topbar-mobile { display: inline-flex; flex: none; }

  /* --- the bottom bar --- */
  .tabbar { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; position: sticky; bottom: 0; z-index: 45;
    background: var(--paper); border-top: 1px solid var(--line);
    padding-bottom: env(safe-area-inset-bottom); box-shadow: 0 -2px 14px rgba(12, 27, 46, .06); }
  .tabbar a, .tabbar button {
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
    min-height: 56px; padding: 7px 4px; background: none; border: 0; cursor: pointer;
    color: var(--muted); font-size: 10.5px; font-weight: 700; text-decoration: none; position: relative;
  }
  .tabbar svg { width: 21px; height: 21px; }
  .tabbar a.on, .tabbar button.on { color: var(--navy); }
  .tabbar a.on::before, .tabbar button.on::before { content: ""; position: absolute; top: 0; left: 22%; right: 22%; height: 2px; background: var(--gold); border-radius: 0 0 3px 3px; }
  .tabbar .dot { position: absolute; top: 9px; left: 54%; width: 7px; height: 7px; border-radius: 50%; background: var(--gold); }

  .content { padding: 14px 12px 20px; }

  /* A row of controls that does not fit should fall onto a second line rather
     than hang off the side of the phone. .flex is the portal's general-purpose
     row and it defaults to nowrap, which is right on a desktop and wrong here:
     the timetable's week navigation came to 432px of buttons in a 349px card. */
  .flex { flex-wrap: wrap; }

  /* The small action links in a card header — "Edit", "See all" — came out
     around 23x19, which is a control, not a word in a sentence, so the inline
     exception in WCAG 2.5.8 does not cover it. Padding plus an equal negative
     margin grows the area a thumb can hit without moving the text a pixel. */
  .card-head a { padding: 11px 8px; margin: -11px -8px; }

  /* --- room to breathe, and targets big enough to hit ---
     44x44 is the figure WCAG 2.5.5 asks for and the one both phone makers
     publish. These four were under it on a real handset: the password Show
     toggle at 31px high, the icon-only button in the bar at 42 wide, the
     "back to the school website" link at 21 high, and buttons generally at
     38. The toggle and the back link are the ones that matter — both are
     small text a thumb has to find, and the toggle is used while typing a
     password, which is exactly when a mis-tap costs the most. */
  .toolbar { gap: 8px; }
  .toolbar .input, .toolbar .btn { min-height: 44px; }
  .btn { min-height: 44px; }
  .site-bar .btn { min-width: 44px; }
  .pw-toggle { min-height: 44px; min-width: 44px; }
  .back-link { display: inline-block; padding: 12px 2px; }
  .status-group button { min-width: 40px; min-height: 40px; font-size: 15px; }
  .input, .input:is(select) { font-size: 16px; }        /* 16px stops iOS zooming on focus */
  table th, table td { padding: 9px 10px; }
  .card-head { flex-wrap: wrap; gap: 8px; }

  /* --- modals become sheets --- */
  .modal { position: fixed; inset: auto 0 0 0; width: 100%; max-width: none; max-height: 92dvh;
    border-radius: 16px 16px 0 0; animation: sheet .26s cubic-bezier(.22, .61, .36, 1); }
  .modal-body { max-height: calc(92dvh - 130px); }
  .modal-foot { padding-bottom: calc(14px + env(safe-area-inset-bottom)); }
  @keyframes sheet { from { transform: translateY(100%); } to { transform: none; } }

  /* --- wide things scroll inside themselves rather than stretching the page --- */
  .table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .reg-chips { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .board { grid-template-columns: repeat(7, 78vw); }
}

@media (max-width: 420px) {
  .reg-chips { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .grid.cols-4, .grid.cols-3, .grid.cols-2 { grid-template-columns: minmax(0, 1fr); }
}

/* A phone that has installed the app has no browser chrome to scroll away. */
@media (display-mode: standalone) {
  .site-bar, .topbar { padding-top: calc(10px + env(safe-area-inset-top)); }
}

/* the offer to install, on the staff page */
.install-card { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin-top: 26px; padding: 14px 16px;
  background: rgba(255, 255, 255, .06); border: 1px solid rgba(217, 194, 126, .3); border-radius: 12px; max-width: 620px; }
.install-card strong { color: #fff; font-size: 14.5px; }
.install-card p { margin: 3px 0 0; color: #a9b8c9; max-width: 400px; }
.install-card .install-ico img { display: block; border-radius: 9px; }
.install-card .btn { margin-left: auto; }
@media (max-width: 560px) { .install-card .btn { margin-left: 0; width: 100%; justify-content: center; } }

/* ==========================================================================
   THE PUBLIC PAGES — editorial
   --------------------------------------------------------------------------
   Rebuilt in the idiom of the independent-school prospectus: one serif doing
   all the work, headlines large and light with the leading pulled tight,
   square corners everywhere, hairline rules in place of most buttons, wide
   bands of navy and paper, and a great deal of air.

   Ayanda's own navy and gold are kept. The gold is now almost entirely a
   hairline: a rule, a bracket, an underline. Restraint is the whole effect.

   This supersedes the earlier public-page rules further up the file.
   ========================================================================== */

.site {
  --measure: 1180px;
  --ink-navy: #16304f;
  --paper-warm: #f6f5f1;
  font-family: Georgia, "Times New Roman", serif;
  font-size: 17px;
  line-height: 1.62;
  color: var(--ink-navy);
  background: var(--paper);
}

/* --- one serif, one scale ------------------------------------------------ */
.site h1, .site h2, .site h3, .site .h {
  font-family: Georgia, "Times New Roman", serif;
  font-weight: 400;
  letter-spacing: -0.012em;
  color: var(--ink-navy);
}
.site h1 { font-size: clamp(38px, 6.2vw, 78px); line-height: 1.04; margin: 0; }
.site h2 { font-size: clamp(27px, 3.6vw, 44px); line-height: 1.16; margin: 0; }
.site h3 { font-size: clamp(19px, 1.5vw, 23px); line-height: 1.28; margin: 0; }
.site p  { font-size: 17px; line-height: 1.68; margin: 0; }
.site .lead { font-size: clamp(18px, 1.5vw, 21px); line-height: 1.6; }
.site .small { font-size: 15px; line-height: 1.62; }
.site .tiny { font-size: 13px; line-height: 1.6; }

/* the only sans on the page: labels, and the portal previews */
.site .eyebrow, .site .tile-head, .site .fact .l, .site .btn, .site .field, .site .input,
.site .pill, .site .shot, .site .tour-step, .site .site-nav, .site .site-brand .t {
  font-family: var(--sans, Calibri, Candara, Segoe, "Segoe UI", sans-serif);
}
.site .eyebrow {
  font-size: 11px; font-weight: 700; letter-spacing: .24em; text-transform: uppercase;
  color: var(--gold-600);
}

/* --- corners come off ---------------------------------------------------- */
.site .card, .site .btn, .site .input, .site .pill, .site .shot-wrap, .site .tour-stage,
.site .install-card, .site .staff-card, .site .day-line, .site .steps-line li, .site .mod,
.site .tour-video video, .site .notice { border-radius: 0; }

/* --- bands --------------------------------------------------------------- */
.site .wrap { max-width: var(--measure); padding: 0 40px; }
.site .wrap.narrow { max-width: 780px; }
.band { padding: clamp(56px, 8vw, 118px) 0; }
.band.alt { background: var(--paper-warm); border-block: 0; }
.band.ink { background: var(--ink-navy); color: #fff; }
.band.ink h1, .band.ink h2, .band.ink h3 { color: #fff; }
.band.ink .muted, .band.ink p { color: #b9c6d6; }
.band.ink .eyebrow { color: var(--gold-300); }

/* --- the bar: wordmark centred, everything else pared back --------------- */
.site-bar {
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 20px;
  padding: 16px 40px; background: var(--ink-navy); border-bottom: 0; backdrop-filter: none;
}
.site-bar.scrolled { background: var(--ink-navy); box-shadow: none; border-bottom: 1px solid rgba(217,194,126,.22); }
.site-brand { justify-self: center; grid-column: 2; flex-direction: column; gap: 6px; text-align: center; }
.site-brand img { width: 34px; height: 34px; }
.site-brand .n { font-size: 15px; letter-spacing: .06em; font-family: Georgia, serif; }
.site-brand .t { font-size: 9px; letter-spacing: .3em; color: var(--gold-300); }
.site-nav { grid-column: 1; margin-left: 0; gap: 26px; }
.site-nav a { font-size: 12px; letter-spacing: .12em; text-transform: uppercase; font-weight: 600; color: #c6d2df; }
.site-nav a::after { background: var(--gold-300); }
.site-actions { grid-column: 3; justify-self: end; }

/* --- buttons: squared, quiet, lettered ----------------------------------- */
.site .btn {
  font-size: 12px; letter-spacing: .13em; text-transform: uppercase; font-weight: 700;
  padding: 15px 26px; border-width: 1px; box-shadow: none;
}
.site .btn.lg { padding: 18px 34px; font-size: 12.5px; }
.site .btn.sm { padding: 11px 18px; font-size: 11px; }
.site .btn:not(:disabled):hover { transform: none; box-shadow: none; }
.site .btn.ghost { background: transparent; border-color: currentColor; }
.hero .btn.ghost, .band.ink .btn.ghost, .site-bar .btn.ghost { color: #fff; border-color: rgba(255,255,255,.55); }
.hero .btn.ghost:hover, .band.ink .btn.ghost:hover { background: #fff; color: var(--ink-navy); border-color: #fff; }

/* a link between two hairlines — the reference's main call to action */
.rule-link {
  display: block; padding: 22px 0; border-top: 1px solid currentColor; border-bottom: 1px solid currentColor;
  text-decoration: none; color: inherit; font-size: 15px; letter-spacing: .04em;
  display: flex; justify-content: space-between; align-items: center; gap: 20px;
  transition: padding-left .3s cubic-bezier(.22,.61,.36,1), opacity .2s ease;
}
.rule-link:hover { padding-left: 12px; }
.rule-link .go { font-size: 20px; line-height: 1; opacity: .5; }
.rule-link + .rule-link { border-top: 0; }

/* --- hero ---------------------------------------------------------------- */
.hero { background: var(--ink-navy); }
.hero::after { display: none; }
.hero-copy { max-width: var(--measure); padding: clamp(48px, 7vw, 96px) 40px clamp(52px, 8vw, 104px); text-align: left; }
.hero-copy h1 { color: #fff; max-width: 15ch; }
.hero-copy p { color: #b9c6d6; font-size: clamp(17px, 1.5vw, 20px); max-width: 56ch; margin-top: 26px; }
.hero-cta { justify-content: flex-start; margin-top: 38px; gap: 14px; }
.hero-note { justify-content: flex-start; color: #8ea0b5; margin-top: 30px; font-size: 12.5px; letter-spacing: .04em; }

/* --- a statement, set large and narrow ----------------------------------- */
.statement { text-align: center; }
.statement p { font-size: clamp(21px, 2.5vw, 31px); line-height: 1.42; max-width: 22ch; margin: 0 auto; }
.statement .wide { max-width: 34ch; }

/* --- facts: no boxes, just figures and rules ----------------------------- */
.strip { background: var(--paper-warm); color: var(--ink-navy); padding: clamp(44px, 5vw, 76px) 0; }
.strip .wrap { gap: 0; }
.fact { padding: 0 24px; border-left: 1px solid var(--line); }
.fact:first-child { border-left: 0; }
.fact .n { font-size: clamp(40px, 4.6vw, 62px); color: var(--ink-navy); font-weight: 400; line-height: 1; }
.fact .l { font-size: 10.5px; letter-spacing: .22em; color: var(--gold-600); margin-top: 14px; }
.fact .s { font-size: 13px; color: var(--muted); margin-top: 6px; }

/* --- values: numbered, ruled, no cards ----------------------------------- */
.site .card.pillar { background: none; border: 0; border-top: 1px solid rgba(255,255,255,.22); padding: 26px 0 0; box-shadow: none; }
.site .card.pillar:hover { transform: none; box-shadow: none; border-color: var(--gold-300); }
.pillar .gold-line { display: none; }
.pillar h3 { margin: 0 0 12px; }
.pillar .lead { font-size: 15px; font-weight: 400; font-style: italic; color: var(--gold-300); margin-bottom: 12px; }
.band.ink .pillar .small.muted { color: #a9b8c9; }

/* --- how we work --------------------------------------------------------- */
.work { gap: 20px; padding: 30px 0; border-top: 1px solid var(--line); }
.work-ico { width: 34px; height: 34px; border: 0; background: none; color: var(--gold-600); align-items: flex-start; }
.work h3 { margin: 0 0 8px; }
.mod { background: none; border-top: 1px solid var(--line); padding: 18px 0; }
.mod:hover { background: none; transform: none; }

/* --- the day ------------------------------------------------------------- */
.day-line { border: 0; border-top: 1px solid var(--line); background: none; }
.day-line li { border-right: 1px solid var(--line); border-bottom: 1px solid var(--line); background: none !important; padding: 22px 10px; }
.day-line .t { font-size: 19px; }
.day-line li.admin .t, .day-line li.admin .d { color: var(--gold-600); }

/* --- steps --------------------------------------------------------------- */
.steps-line li { background: none; border: 0; border-top: 1px solid var(--line); padding: 22px 0; }
.steps-line .n { background: none; color: var(--gold-600); border: 1px solid var(--gold); width: 28px; height: 28px; font-family: Georgia, serif; }

/* --- forms --------------------------------------------------------------- */
.site .card { border-color: var(--line); box-shadow: none; }
.site .input { border-width: 0 0 1px; padding-left: 0; padding-right: 0; background: none; font-size: 16px; }
.site .input:focus { box-shadow: none; border-bottom-color: var(--gold); }
.site .pw .input { padding-right: 60px; }
.site .field { font-size: 10.5px; letter-spacing: .16em; text-transform: uppercase; color: var(--muted); }
.site textarea.input { border: 1px solid var(--line); padding: 12px; }
.site .card-head { border-bottom: 1px solid var(--line); }

/* --- staff page ---------------------------------------------------------- */
.staff-hero { background: var(--ink-navy); padding: clamp(54px, 8vw, 104px) 0 clamp(48px, 7vw, 88px); }
.staff-hero h1 { font-size: clamp(32px, 4.4vw, 56px); }
.staff-hero p { font-size: 17.5px; }
.staff-card { border: 0; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); border-left: 0; padding: 36px 0; }
.staff-band, .staff-strip { background: var(--paper-warm); }
.tour-step { font-family: var(--sans, Calibri, sans-serif); }
.tour-stage { box-shadow: none; }
.tour-say { font-family: Georgia, serif; font-size: 17px; }

/* --- footer -------------------------------------------------------------- */
.site-foot { background: var(--ink-navy); padding: clamp(48px, 6vw, 80px) 0 40px; }
.site-foot .bold { font-family: Georgia, serif; font-weight: 400; font-size: 17px; letter-spacing: .04em; }

@media (max-width: 980px) {
  .site .wrap { padding: 0 22px; }
  .site-bar { grid-template-columns: auto 1fr auto; padding: 12px 18px; }
  .site-brand { grid-column: 2; justify-self: start; flex-direction: row; text-align: left; }
  .site-brand .n { font-size: 12.5px; letter-spacing: .04em; }
  .site-actions { grid-column: 3; }
  .hero-copy { padding: 40px 22px 48px; }
  .strip .wrap { grid-template-columns: repeat(2, 1fr); row-gap: 34px; }
  .fact { border-left: 0; padding: 0 12px; }
  .statement p { max-width: none; }
}

/* The banner already carries the full lockup, so the bar shows only the crest
   until it is scrolled past — then the wordmark arrives to keep the identity. */
/* Scrolled, the bar gets out of the way: the stacked wordmark folds to one
   line so the page keeps its height. */
.site-bar.scrolled .site-brand { flex-direction: row; gap: 10px; }
.site-bar.scrolled .site-brand img { width: 26px; height: 26px; }
.site-bar.scrolled .site-brand .t { display: none; }
.site-bar { transition: padding .45s var(--e-expo), background-color .35s var(--e-quart), box-shadow .35s var(--e-quart); }

.site-brand .n, .site-brand .t { transition: opacity .3s ease, max-height .3s ease; }
/* The name stays. That rule was written when the banner sat at the top of the
   page and carried the full lockup; the banner is now below the hero, and the
   headline opens on the school's initials — so hiding the wordmark leaves a
   first-time visitor with a crest and three letters to decode.

   The tagline still waits: "Where Excellence Begins" directly above a headline
   about excellence being built is the same word three times in one screen. */
.site:not(.staff-site) .site-bar:not(.scrolled) .site-brand .t { opacity: 0; max-height: 0; overflow: hidden; }
.site-bar:not(.scrolled) .site-brand img { width: 40px; height: 40px; }

/* Headings default to navy, so anything sitting on a navy ground must say so. */
.staff-hero h1, .staff-hero h2, .staff-hero h3, .site-foot h3, .hero-copy h1 { color: #fff; }
.staff-hero .eyebrow { color: var(--gold-300); }

/* The reset above zeroes paragraph margins, so the places that need air ask. */
.staff-hero p { margin-top: 22px; max-width: 62ch; }
.staff-hero .eyebrow { margin-bottom: 18px; display: block; }
.site .card-body p + p, .site .work p, .site .pillar p { margin-top: 0; }
.site .mt-8 { margin-top: 8px; } .site .mt-16 { margin-top: 16px; } .site .mt-24 { margin-top: 24px; }
.statement .eyebrow { display: block; margin-bottom: 26px; }

/* An earlier rule dropped the school's name on small screens and kept the
   tagline, which reads as a motto with nothing to attach it to. Reverse it. */
@media (max-width: 560px) {
  .site-brand .n { display: block; font-size: 11px; letter-spacing: .03em; }
  .site-brand .t { display: none; }
  .site .btn.lg { width: 100%; justify-content: center; }
  .site h1 { font-size: clamp(30px, 9vw, 40px); }
  .rule-link { padding: 18px 0; font-size: 14px; }
}

/* ==========================================================================
   The family & student portal
   --------------------------------------------------------------------------
   Built on the staff portal's own shell, cards and pills — a parent and a
   teacher are looking at the same records, and there is no reason for them to
   look like two different products. What is added here is the handful of
   shapes the family side needs and the staff side does not.
   ========================================================================== */

.portal-shell .sidebar-brand .tag { color: var(--gold); }

.portal-hello h2 { font: 300 30px/1.15 Georgia, "Times New Roman", serif; letter-spacing: -.01em; }
.portal-hello p { max-width: 62ch; margin-top: 8px; }

/* A child, and the four things a parent looks for first. */
.child-card .card-head { align-items: center; gap: 14px; }
.child-head { display: flex; align-items: center; gap: 14px; margin-bottom: 18px; }
.child-head h2 { font: 300 26px/1.15 Georgia, "Times New Roman", serif; }

.tiles { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px; background: var(--line); border: 1px solid var(--line); }
.tiles .tile { display: block; padding: 16px; background: #fff; text-decoration: none; color: inherit; transition: background .15s ease; }
.tiles .tile:hover { background: var(--paper); }
.tiles .k { font-size: 11px; letter-spacing: .09em; text-transform: uppercase; color: var(--muted); }
.tiles .v { font: 300 28px/1.1 Georgia, "Times New Roman", serif; margin-top: 8px; color: var(--navy); }
.tiles .v.good { color: var(--green); }
.tiles .v.bad { color: var(--red); }
.tiles .s { font-size: 12px; color: var(--muted); margin-top: 6px; line-height: 1.4; }

.big-figure { font: 300 40px/1 Georgia, "Times New Roman", serif; text-align: center; color: var(--navy); }
.big-figure.good { color: var(--green); }
.big-figure.bad { color: var(--red); }

.bar.big { display: block; height: 10px; }
.donut-line { margin-bottom: 4px; }

/* A row of one thing and its date: notices, diary entries, children. */
.notice-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px;
  padding: 12px 16px; border-bottom: 1px solid var(--line); text-decoration: none; color: inherit; }
.notice-row:last-child { border-bottom: 0; }
a.notice-row:hover { background: var(--paper); }

.subject-card .card-head { align-items: flex-start; }
.week td { vertical-align: top; }

/* The conversation between a family and the school. */
.portal-thread { max-height: 52vh; overflow-y: auto; display: flex; flex-direction: column; gap: 14px; }
/* `.msg` is a flex row in the staff message view; here it is a block, and the
   reset has to be explicit or it inherits that layout. */
.portal-thread .msg { display: block; max-width: 76%; border: 1px solid var(--line); padding: 12px 14px; background: #fff; }
.portal-thread .msg.mine { margin-left: auto; flex-direction: row; background: var(--paper); border-color: #d9dee6; }
.portal-thread .msg-head { display: flex; justify-content: space-between; gap: 12px; align-items: baseline; }
.portal-thread .msg-subject { font-weight: 600; margin-top: 6px; }
.portal-thread .msg-body { margin-top: 6px; white-space: pre-wrap; font-size: 14px; line-height: 1.55; }

.portal-compose { display: grid; grid-template-columns: 1fr auto; gap: 8px; align-items: end; }
.portal-compose input[name="subject"] { grid-column: 1 / -1; }
.portal-compose textarea { resize: vertical; }

/* A temporary password, on the one screen it is ever readable. */
.cred { border: 1px solid var(--line); }
.cred > div { padding: 12px 14px; border-bottom: 1px solid var(--line); }
.cred > div:last-child { border-bottom: 0; }
.cred .k { font-size: 11px; letter-spacing: .09em; text-transform: uppercase; color: var(--muted); }
.cred .v { font-family: "SF Mono", Menlo, Consolas, monospace; font-size: 15px; margin-top: 4px; word-break: break-all; }
.cred .v.big { font-size: 21px; letter-spacing: .02em; color: var(--navy); font-weight: 600; }

.card.stat .card-body { padding: 18px; }
.card.stat .k { font-size: 11px; letter-spacing: .09em; text-transform: uppercase; color: var(--muted); }
.card.stat .v { font: 300 32px/1 Georgia, "Times New Roman", serif; color: var(--navy); margin: 8px 0 4px; }

.family-site .staff-hero { background: var(--navy); }

@media (max-width: 900px) {
  .tiles { grid-template-columns: repeat(2, 1fr); }
  .portal-thread .msg { max-width: 90%; }
}
@media (max-width: 560px) {
  .portal-hello h2 { font-size: 24px; }
  .child-head h2 { font-size: 21px; }
  .portal-compose { grid-template-columns: minmax(0, 1fr); }
  .portal-compose button { width: 100%; justify-content: center; }
  .tiles .v { font-size: 23px; }
}

/* A password is read off the screen and typed somewhere else, so it is set in
   a face where l, 1, O and 0 are not the same shape. */
.input.mono, .cred .v { font-family: "SF Mono", Menlo, Consolas, "Liberation Mono", monospace; letter-spacing: .01em; }
.pw .pw-toggle { white-space: nowrap; }

/* ==========================================================================
   The door
   --------------------------------------------------------------------------
   One thing on the screen, centred, with a field big enough to hit with a
   thumb. Whoever reaches this page came here to type six digits and get on.
   ========================================================================== */
.gate-band { min-height: calc(100vh - 66px); min-height: calc(100svh - 66px); display: grid; place-items: center; padding: 40px 0; }
.gate-wrap { width: 100%; }
.gate-card { max-width: 420px; margin: 0 auto; background: #fff; border: 1px solid var(--line); padding: 40px 32px; text-align: center; }
.gate-card h1 { font: 300 30px/1.15 Georgia, "Times New Roman", serif; margin: 6px 0 12px; }
.gate-card .field { display: block; text-align: center; }
.gate-mark { width: 54px; height: 54px; margin: 0 auto 20px; display: grid; place-items: center;
  border: 1px solid var(--line); color: var(--navy); }
.gate-mark .ico { width: 24px; height: 24px; }
.gate-form { margin-top: 26px; }
/* The one thing on the page you are meant to type into, so it is drawn as a
   box rather than the hairline rule the editorial styling uses elsewhere.
   Scoped to .site as well, because that layer sets the hairline and would
   otherwise win on specificity. */
.site .gate-pin, .gate-pin {
  text-align: center; font: 600 26px/1.2 "SF Mono", Menlo, Consolas, monospace;
  letter-spacing: .5em; text-indent: .5em; padding: 16px 10px;
  border: 1px solid var(--line); background: var(--paper);
}
.site .gate-pin:focus, .gate-pin:focus {
  border-color: var(--navy); background: #fff;
  box-shadow: 0 0 0 3px rgba(22, 48, 79, .12); outline: none;
}
.gate-pin::placeholder { letter-spacing: normal; text-indent: 0; }
/* The gate has no menu button, so its one way back must survive the phone
   breakpoint that hides the header actions everywhere else. */
.gate-site .site-actions { display: flex !important; }
.gate-site .site-bar { justify-content: space-between; }

.gate-set { padding-top: 16px; border-top: 1px solid var(--line); }
.gate-set .input { letter-spacing: .12em; }
.gate-set:first-of-type { border-top: 0; }

/* Something new, on either side of the school. */
.notice-row.fresh { background: rgba(176, 141, 52, .07); box-shadow: inset 3px 0 0 var(--gold); }
.notice-row.clickable { cursor: pointer; }
.tiles .v.alert { color: var(--gold-600); }
.msg-state { margin-top: 8px; color: var(--muted); display: flex; align-items: center; gap: 5px; }
.msg-state .ico { width: 13px; height: 13px; }
.msg-state.read { color: var(--green); }

@media (max-width: 560px) {
  .gate-card { padding: 32px 20px; border-left: 0; border-right: 0; }
  .gate-card h1 { font-size: 25px; }
  .gate-pin { font-size: 22px; letter-spacing: .38em; text-indent: .38em; }
  .gate-set .flex { flex-wrap: wrap; }
  .gate-set .flex .input { min-width: 100%; }
  .gate-set .flex .btn { flex: 1; justify-content: center; }
}

/* ==========================================================================
   Phone
   --------------------------------------------------------------------------
   The register is taken standing up, on a phone, in a room full of children.
   Everything below is about that: nothing important off the right edge,
   nothing important under the thumb bar, and targets big enough to hit
   without looking twice.
   ========================================================================== */
@media (max-width: 560px) {
  /* A card footer with a message and two buttons does not fit across 375px. */
  .card-foot.flex.between { flex-wrap: wrap; gap: 10px; }
  .card-foot.flex.between > .flex { width: 100%; gap: 8px; }
  .card-foot.flex.between > .flex .btn { flex: 1; justify-content: center; }

  /* Toolbars wrap instead of squeezing every control to nothing. */
  .toolbar { flex-wrap: wrap; gap: 8px; }
  .toolbar .search, .toolbar .search .input { width: 100%; min-width: 0; }
  .toolbar > .btn { flex: 1; justify-content: center; }

  /* Status buttons are the thing most often pressed in this app. */
  .status-group button { min-width: 40px; min-height: 40px; }

  /* Modals become sheets, so a long form is scrolled rather than clipped. */
  .modal-foot { flex-wrap: wrap; gap: 8px; }
  .modal-foot .btn { flex: 1; justify-content: center; }

  /* Nothing sits under the tab bar at the bottom of the screen. */
  .content { padding-bottom: calc(76px + env(safe-area-inset-bottom)); }

  /* Two columns of tiles is the most a phone can read at a glance. */
  .grid.cols-3, .grid.cols-4 { grid-template-columns: minmax(0, 1fr); }
  .grid.side, .grid.cols-2 { grid-template-columns: minmax(0, 1fr); }
}

/* A tap target below 44px is a missed tap on a phone. */
@media (pointer: coarse) {
  .btn.xs, .btn.sm { min-height: 38px; }
  .iconbtn { min-width: 40px; min-height: 40px; }
  .tabbar a, .tabbar button { min-height: 52px; }
  table td .btn.xs { min-height: 34px; }
}

/* ==========================================================================
   THE IMMERSIVE LAYER
   --------------------------------------------------------------------------
   Same navy, same gold, same Georgia. What changes is the scale, the pacing
   and the choreography.

   The argument this school makes is that it notices every child — a register
   every period, two adults in every lesson, a parent told the same morning.
   So the design is built around attention: type large enough to stop someone
   mid-scroll, a day you move through rather than read, and motion that only
   ever moves to show you where to look.

   Everything degrades. With JavaScript off the page is the static one; with
   prefers-reduced-motion the choreography collapses to nothing and the
   content is identical. Only transform and opacity animate.
   ========================================================================== */

.site {
  /* Curves. Nothing here uses ease, ease-in, ease-out or linear. */
  --e-expo:   cubic-bezier(0.16, 1, 0.3, 1);
  --e-quart:  cubic-bezier(0.25, 1, 0.5, 1);
  --e-inout:  cubic-bezier(0.87, 0, 0.13, 1);

  /* A 12:1 scale, display to caption. The old one was 4.6:1, which is why
     nothing on the page could carry a room. */
  --t-hero:    clamp(52px, 13vw, 168px);
  --t-display: clamp(38px, 7.2vw, 96px);
  --t-section: clamp(29px, 4.4vw, 58px);
  --t-lead:    clamp(19px, 1.7vw, 23px);
  --t-body:    17px;
  --t-caption: 13px;

  /* #ffffff is a screen; #f9f8f5 is paper. The difference is felt, not seen. */
  --paper-warm: #f6f5f1;
  --paper-true: #faf9f6;
  background: var(--paper-true);
}

/* Branded selection, on both grounds. */
/* Anchors land below the sticky bar rather than underneath it. */
html:has(.site) { scroll-padding-top: calc(var(--bar-h, 96px) + 24px); }
.site { scroll-padding-top: calc(var(--bar-h, 96px) + 24px); }

.site ::selection { background: var(--gold-300); color: #16304f; }
.band.ink ::selection, .hero ::selection { background: var(--gold); color: #0c1b2e; }

/* --- type: the gap between the monument and the whisper ------------------ */
.site h1 {
  font-size: var(--t-hero);
  line-height: 0.92;
  letter-spacing: -0.035em;
  text-wrap: balance;
  hanging-punctuation: first;
}
.site h2 {
  font-size: var(--t-section);
  line-height: 1.04;
  letter-spacing: -0.025em;
  text-wrap: balance;
}
.site h3 { letter-spacing: -0.015em; }
.site .lead { font-size: var(--t-lead); line-height: 1.52; }

/* --- page-load choreography ---------------------------------------------
   Structure, then the headline word by word, then the line under it, then
   the way in, then the bar. Nothing arrives at the same time as anything
   else, because simultaneous arrival reads as a page that has merely
   appeared rather than one that has been composed. */
.mask { display: inline-block; overflow: hidden; vertical-align: bottom; padding-bottom: 0.08em; }
.mask > i {
  display: inline-block; font-style: inherit;
  transform: translate3d(0, 110%, 0);
  will-change: transform;
}
.site.lit .mask > i {
  transform: translate3d(0, 0, 0);
  transition: transform 1.05s var(--e-expo);
  transition-delay: calc(var(--i, 0) * 62ms + 180ms);
}

.lift { opacity: 0; transform: translate3d(0, 26px, 0); }
.site.lit .lift {
  opacity: 1; transform: none;
  transition: opacity .9s var(--e-quart), transform .9s var(--e-expo);
  transition-delay: var(--d, 0ms);
}

/* --- hero: the banner is the room, the sentence stands in it ------------- */
.hero {
  position: relative;
  min-height: min(92vh, 860px);
  min-height: min(92svh, 860px);
  display: flex; align-items: flex-end;
  overflow: clip;

  /* A classroom, behind the words.
     ----------------------------------------------------------------------
     It was flat --ink-navy. The photograph earns its place by answering the
     one question the headline cannot: what does this actually look like.

     The scrim is the whole craft of it. White type over a photograph is
     unreadable without one, and an overlay dark enough to fix that hides the
     children — which is the only reason the photograph is here. So it is two
     gradients, weighted at where the type actually sits. The hero is
     bottom-anchored and left-aligned, so the dense part is the bottom-left
     corner and it clears towards the top right, where the faces and the
     blocks are. Measured, not guessed: an earlier weighting left the proof
     paragraph at 3.1:1, which fails AA against the bright window in the
     picture.

     --ink-navy stays as the background-color beneath, so a hero whose image
     has not arrived — or will not — is the navy panel it has always been
     rather than unreadable white-on-white. */
  background-color: var(--ink-navy);
  background-image:
    /* Two scrims, and the numbers come from measuring rather than taste.
       The text here runs from 8% to 90% of the hero's height, so there is no
       clear corner to leave alone — and the brightest tenth of the picture
       behind the kicker is luminance .98, which is the window. Composited
       against that, these weightings leave the thinnest point at about .75
       alpha and 7.6:1, so the 11px kicker clears AA with room on it. */
    linear-gradient(to top,
      rgba(12, 27, 46, .96) 0%,
      rgba(12, 27, 46, .92) 30%,
      rgba(13, 30, 51, .85) 58%,
      rgba(16, 36, 60, .78) 80%,
      rgba(18, 40, 66, .72) 100%),
    linear-gradient(100deg,
      rgba(12, 27, 46, .35) 0%,
      rgba(12, 27, 46, .26) 42%,
      rgba(14, 32, 54, .16) 70%,
      rgba(18, 40, 66, .10) 100%),
    image-set(url("../assets/hero-classroom.webp") type("image/webp"),
              url("../assets/hero-classroom.jpg") type("image/jpeg"));
  background-size: cover, cover, cover;
  background-position: center, center, 70% 26%;   /* keeps the faces in frame */
  background-repeat: no-repeat;
}
/* A phone is too narrow for a side-weighted scrim to do anything useful, and
   has no business downloading the wide cut either. */
@media (max-width: 760px) {
  .hero {
    background-image:
      linear-gradient(to top,
        rgba(12, 27, 46, .96) 0%,
        rgba(12, 27, 46, .93) 46%,
        rgba(14, 32, 54, .84) 74%,
        rgba(18, 40, 66, .78) 100%),
      image-set(url("../assets/hero-classroom-sm.jpg") type("image/jpeg"));
    background-position: center, 64% 24%;
  }
}
/* The hero's ground is the school's own crest, enormous and almost not there:
   laurel, star and the two silhouettes. It is the one brand asset with no
   lettering in it, so type can be set across it without two logotypes
   fighting. The banner — which is a full lockup, wordmark and all — gets its
   own band below, presented as itself rather than used as a texture. */
/* A hairline of gold at the very top, the way the banner itself is ruled. */
.hero::after {
  content: ""; display: block; position: absolute; inset: 0 0 auto 0; height: 2px;
  background: linear-gradient(to right, var(--gold) 0%, var(--gold-300) 38%, rgba(217,194,126,0) 100%);
}

/* --- the banner, as itself ----------------------------------------------- */


.hero-copy {
  position: relative;
  width: 100%;
  max-width: 1480px;
  margin: 0 auto;
  padding: clamp(40px, 7vw, 92px) clamp(22px, 5vw, 64px) clamp(44px, 6vw, 84px);
}
.hero-copy h1 { color: #fff; max-width: 13ch; }
.hero-copy p {
  color: #c3d0df; font-size: var(--t-lead);
  /* the paragraph is deliberately narrow against a very wide headline */
  max-width: 44ch; margin-top: clamp(22px, 2.4vw, 34px);
}
.hero-cta { margin-top: clamp(26px, 3vw, 40px); }
.hero-note { color: #8ea0b5; margin-top: clamp(22px, 2.6vw, 34px); }

/* The rule the headline sits on — a hairline of gold, drawn on load. */
.hero-rule {
  height: 1px; background: var(--gold-300); opacity: .55;
  transform: scaleX(0); transform-origin: left;
  margin-bottom: clamp(24px, 3vw, 40px);
}
.site.lit .hero-rule { transform: scaleX(1); transition: transform 1.4s var(--e-inout) 120ms; }

/* --- scroll cue: it moves because it is telling you the page continues --- */
.scroll-cue {
  position: absolute; right: clamp(22px, 5vw, 64px); bottom: clamp(44px, 6vw, 84px);
  display: flex; flex-direction: column; align-items: center; gap: 12px;
  color: #8ea0b5; font-size: 10px; letter-spacing: .26em; text-transform: uppercase;
  writing-mode: vertical-rl;
}
.scroll-cue i { display: block; width: 1px; height: 54px; background: currentColor; opacity: .4; overflow: hidden; position: relative; }
.scroll-cue i::after {
  content: ""; position: absolute; inset: 0; background: var(--gold-300);
  transform: translateY(-100%); animation: cueRun 2.4s var(--e-inout) infinite;
}
@keyframes cueRun { 0% { transform: translateY(-100%); } 55%, 100% { transform: translateY(100%); } }

/* --- reveals: further, slower, and on a real curve ----------------------- */
[data-reveal] {
  opacity: 0; transform: translate3d(0, 44px, 0);
  transition: opacity .95s var(--e-quart), transform 1.05s var(--e-expo);
}
[data-reveal].in { opacity: 1; transform: none; }

/* --- composition: the centre line is broken on purpose ------------------- */
.site .wrap { max-width: 1320px; padding: 0 clamp(22px, 5vw, 64px); }
.site .wrap.narrow { max-width: 820px; }
.band { padding: clamp(72px, 11vw, 168px) 0; }

/* A heading that starts where the grid does and a paragraph that starts
   a column later: the offset is what makes the eye travel. */
.offset-head { display: grid; grid-template-columns: minmax(0, 1fr); gap: clamp(18px, 2.4vw, 34px); }
.offset-head > .lead { max-width: 52ch; }
@media (min-width: 900px) {
  .offset-head { grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); align-items: end; gap: clamp(32px, 5vw, 80px); }
  .offset-head > h2 { margin-left: -0.04em; }      /* optical, not mathematical */
  .offset-head > .lead { padding-bottom: .5em; }
}

/* --- values: numbered plates, staggered down the page -------------------- */
@media (min-width: 900px) {
  .site .card.pillar:nth-child(even) { transform: translateY(clamp(20px, 3.5vw, 54px)); }
  .site .card.pillar:nth-child(even)[data-reveal] { transform: translate3d(0, calc(44px + clamp(20px, 3.5vw, 54px)), 0); }
  .site .card.pillar:nth-child(even)[data-reveal].in { transform: translateY(clamp(20px, 3.5vw, 54px)); }
}
.pillar .eyebrow { font-size: clamp(30px, 3vw, 46px); letter-spacing: -0.02em; font-family: Georgia, serif;
  font-weight: 400; color: var(--gold-300); text-transform: none; opacity: .55; line-height: 1; }

/* --- statement: set as a monument, not a caption ------------------------- */
.statement { text-align: left; }
.statement .wrap { max-width: 1100px; }
/* Large, but still a sentence: display scale is for three to seven words, and
   this is a paragraph. Bigger than it was, nowhere near the hero. */
.statement p {
  font-size: clamp(24px, 3.3vw, 42px); line-height: 1.22; letter-spacing: -0.02em;
  max-width: 26ch; margin: 0;
}
.statement .eyebrow { margin-bottom: clamp(26px, 3vw, 44px); }
.statement .mt-24 { margin-top: clamp(34px, 4vw, 60px) !important; }

/* --- facts: one figure carries, the rest support ------------------------- */
/* The band where the school's name assembles.

   The canvas is laid over the real markup rather than replacing it. Without
   JavaScript, without canvas, or under prefers-reduced-motion the crest and
   the heading underneath are simply what shows — which is also what a screen
   reader reads, in every case, because the canvas is aria-hidden and the
   heading is only ever *visually* hidden. */
.strip { background: var(--ink-navy); color: #fff; padding: clamp(56px, 7vw, 104px) 0; }
.strip .wrap { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0; }
.fact { border-left: 1px solid rgba(217,194,126,.24); padding: 0 clamp(14px, 2vw, 34px); }
.fact:first-child { border-left: 0; padding-left: 0; }
.fact .n { font-size: clamp(46px, 6.4vw, 96px); line-height: .86; letter-spacing: -0.04em; color: #fff; }
.fact .l { color: var(--gold-300); }
.fact .s { color: #8ea0b5; }

/* The values banner used to be a photograph of the sign on the wall. It is
   the name assembling now, so the band has to supply its own height — an
   image brought its own.

   --------------------------------------------------------------------------
   THE GOLD MARBLE

   Veining, not a texture file. feTurbulence is how procedural marble has
   always been made: fractal noise stretched far wider than it is tall gives
   strands rather than clouds, and a steep table on the alpha channel turns
   the soft gradient between them into an edge. The SVG supplies only that
   shape — it carries no colour at all — and is used as a mask, so the gold is
   a CSS gradient underneath and follows the palette rather than being baked
   into an asset. Nothing is downloaded: it is a data URI, which img-src
   already allows, and it costs about 400 bytes.

   Two things keep it an accent rather than a wallpaper. It is screened over
   the navy, so it lifts the dark rather than sitting on top of it as paint.
   And ::after lays the navy back over the middle, so the veining is strongest
   at the edges and the centre stays clear for the name — gold strands running
   through the letters would be a worse version of both.
   -------------------------------------------------------------------------- */
.banner-band {
  background: var(--ink-navy);
  padding: 0; overflow: clip;
  position: relative; isolation: isolate;
}
.banner-band::before,
.banner-band::after { content: ""; position: absolute; inset: 0; pointer-events: none; }

.banner-band::before {
  background: linear-gradient(112deg,
    var(--gold-600) 0%, var(--gold-300) 26%, var(--gold) 48%,
    var(--gold-300) 68%, var(--gold-600) 100%);
  -webkit-mask-image: var(--marble); mask-image: var(--marble);
  -webkit-mask-size: cover; mask-size: cover;
  opacity: .34;
  mix-blend-mode: screen;
}

/* The navy, laid back over the middle. */
.banner-band::after {
  background: radial-gradient(118% 82% at 50% 50%,
    var(--ink-navy) 0%, var(--ink-navy) 38%, rgba(22, 48, 79, .55) 62%, rgba(22, 48, 79, 0) 100%);
}

/* A hairline of gold top and bottom, which is what stops the band from
   reading as a hole in the page. */
.banner-band { border-top: 1px solid rgba(217, 194, 126, .34); border-bottom: 1px solid rgba(217, 194, 126, .34); }

.banner-band > .wrap { position: relative; z-index: 1; }
.crest-stage {
  position: relative;
  min-height: clamp(230px, 27vw, 360px);
  display: grid; place-items: center;
}
.crest-stage canvas {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  opacity: 0; transition: opacity .5s var(--e-quart);
}
.crest-stage.assembled canvas { opacity: 1; }

.crest-fallback { display: grid; place-items: center; gap: 14px; }
.crest-fallback img { width: clamp(72px, 9vw, 104px); height: auto; }
.crest-fallback h2 {
  margin: 0; color: #fff; font-weight: 400;
  font-size: clamp(26px, 4.4vw, 50px); letter-spacing: -0.02em; line-height: 1;
}
.crest-fallback p {
  margin: 0; color: var(--gold-300);
  font-family: var(--sans, Calibri, sans-serif);
  font-size: clamp(10px, 1vw, 12px); letter-spacing: .24em; text-transform: uppercase;
}
/* Taken out of sight, not out of the document. */
.crest-stage.assembled .crest-fallback {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
}

/* --- micro-interactions -------------------------------------------------- */
/* transform is off the list: it was here to ease the magnetic buttons back
   to centre, and with that gone a half-second transform transition is a
   half second of nothing. Colour still eases. */
.site .btn { transition: background-color .35s var(--e-quart), color .35s var(--e-quart), border-color .35s var(--e-quart); }

/* A link between hairlines, with an arrow that actually travels. */
.rule-link { transition: padding-left .55s var(--e-expo), border-color .4s var(--e-quart); }
.rule-link:hover { padding-left: 20px; }
.rule-link .go { transition: transform .55s var(--e-expo), opacity .35s var(--e-quart); }
.rule-link:hover .go { transform: translateX(10px); opacity: 1; }

/* Underlines that draw from the side you came from. */
.site-nav a, .foot-links a {
  background-image: linear-gradient(currentColor, currentColor);
  background-position: 0 100%; background-repeat: no-repeat; background-size: 0% 1px;
  transition: background-size .5s var(--e-expo), color .3s var(--e-quart);
}
.site-nav a:hover, .site-nav a.on, .foot-links a:hover { background-size: 100% 1px; }
.site-nav a::after { display: none; }

/* Focus is on-brand and unmistakable — gold on navy, navy on paper. */
.site a:focus-visible, .site button:focus-visible, .site .input:focus-visible {
  outline: 2px solid var(--gold); outline-offset: 3px; border-radius: 1px;
}
.band.ink a:focus-visible, .hero a:focus-visible, .site-bar a:focus-visible,
.site-bar button:focus-visible { outline-color: var(--gold-300); }

/* --- phone --------------------------------------------------------------- */
@media (max-width: 900px) {
  .strip .wrap { grid-template-columns: repeat(2, 1fr); row-gap: clamp(30px, 6vw, 48px); }
  .fact { border-left: 0; padding: 0; }
  .fact:nth-child(even) { padding-left: clamp(14px, 4vw, 28px); border-left: 1px solid rgba(217,194,126,.24); }
  .scroll-cue { display: none; }
  .hero { min-height: min(86vh, 720px); min-height: min(86svh, 720px); }
}
@media (max-width: 560px) {
  .site h1 { font-size: clamp(38px, 12.5vw, 60px); }
  .statement p { max-width: none; }
}

/* --- the whole choreography is optional ---------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .mask > i, .site.lit .mask > i { transform: none; transition: none; }
  .lift, .site.lit .lift { opacity: 1; transform: none; transition: none; }
  .hero-rule, .site.lit .hero-rule { transform: scaleX(1); transition: none; }
  .scroll-cue i::after { animation: none; }
  [data-reveal] { opacity: 1; transform: none; transition: none; }
  .site .card.pillar:nth-child(even) { transform: none; }
}

/* ==========================================================================
   The signature moment: the school day, scrolled
   --------------------------------------------------------------------------
   Every other school website lists its timetable. This one is the argument
   the school actually makes — a register every period — so it is the one
   thing on the page you move through rather than read past.

   The stage is `position: sticky`. Scroll is never taken from the reader:
   they move at their own pace and the day advances with them, and if they
   scroll straight past, they have simply read a list.
   ========================================================================== */

/* Before script: two plain ordered lists, one per band. This is also the
   no-JS page — both days simply show, rather than one being unreachable. */
.day-seq { list-style: none; margin: 0; padding: 0; }
.day-slide { padding: 26px 0; border-top: 1px solid var(--line); display: grid; gap: 6px; }
.day-time { font-size: clamp(26px, 3vw, 38px); line-height: 1; letter-spacing: -0.02em; }
.day-label { font-size: 15px; color: var(--muted); }
.day-note { font-size: 14px; color: var(--faint); }
.day-rail { display: none; }

/* After script: the stage. */
.day-track.seq-on { height: calc(var(--slides, 9) * 62vh); position: relative; }
/* The bar is sticky and tall, so the stage has to begin underneath it or the
   standing label is set behind the navigation. --bar-h is measured once. */
.day-track.seq-on .day-stage {
  position: sticky; top: 0;
  height: 100vh; height: 100svh;
  padding-top: var(--bar-h, 96px);
  display: flex; align-items: center;
  overflow: clip;
}
/* The stage is a room, not a line: a standing label at the top, the hour
   anchored to the floor of it, and the rail down the right. The emptiness
   above the number is the point — it is what makes the hour feel large. */
.day-track.seq-on .day-stage-inner {
  width: 100%; position: relative;
  height: calc(100svh - var(--bar-h, 96px) - clamp(40px, 8vh, 90px));
  display: grid;
  grid-template-rows: auto 1fr;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: clamp(20px, 3vw, 40px);
  align-items: start;
}
.day-track.seq-on .day-standing {
  grid-column: 1 / -1;
  display: flex; align-items: stretch; gap: clamp(10px, 2vw, 28px); flex-wrap: wrap;
  border-top: 1px solid var(--line-strong); padding-top: 14px;
}

/* --------------------------------------------------------------------------
   The band switch

   Two buttons rather than one line of text, because the two days differ in
   two ways a parent actually asks about — when it ends, and how long a lesson
   is — and a switch that states both answers them whether or not anybody
   presses it. The one not in use is not hidden, only quieted: the comparison
   is the point.
   -------------------------------------------------------------------------- */
.day-switch {
  appearance: none; background: none; border: 0; cursor: pointer;
  display: grid; gap: 3px; justify-items: start; text-align: left;
  padding: 4px 0 6px; min-height: 44px;
  border-top: 2px solid transparent; margin-top: -14px; padding-top: 12px;
  font-family: var(--sans, Calibri, sans-serif);
  transition: border-color .3s var(--e-quart);
}
/* The one not in use is marked by the rule above it and by the colour of its
   name, never by fading it out. Dimming was tried and measured 2.1:1 against
   the band — and this is not decoration being quieted, it is the other band's
   hours and lesson count, which is the whole reason the switch says more than
   two words. Something a parent is meant to read has to stay readable. */
.day-switch b {
  font-size: 11px; letter-spacing: .24em; text-transform: uppercase;
  font-weight: 700; color: var(--muted);
  transition: color .3s var(--e-quart);
}
.day-switch span { font-size: 12px; letter-spacing: .04em; color: var(--muted); }
.day-switch:hover { border-top-color: var(--gold-300); }
.day-switch:hover b { color: var(--ink-navy); }
.day-switch:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
.day-switch.on { border-top-color: var(--gold); }
.day-switch.on b { color: var(--gold-600); }

/* The two bands are stacked in one cell, so the stage does not change size
   when the switch is pressed — only what is in it. */
.day-track.seq-on .day-seqs { position: relative; grid-row: 2; grid-column: 1; align-self: end; min-height: 0; }
.day-track.seq-on .day-seq { position: absolute; inset: auto auto 0 0; width: 100%; display: none; }
.day-track.seq-on .day-seq.on { display: block; }

.day-track.seq-on .day-slide {
  position: absolute; inset: auto auto 0 0; width: 100%;
  border: 0; padding: 0; display: block;
  opacity: 0; transform: translate3d(0, 34px, 0);
  /* leaving is quicker than arriving, so two hours never sit on top of one
     another at equal weight */
  transition: opacity .3s var(--e-quart), transform .45s var(--e-expo);
  pointer-events: none;
}
.day-track.seq-on .day-slide.on {
  opacity: 1; transform: none; pointer-events: auto;
  transition: opacity .55s var(--e-quart) 90ms, transform .85s var(--e-expo) 40ms;
}

/* The time is the monument: this is the largest thing on the whole site. */
.day-track.seq-on .day-time {
  display: block;
  font-size: clamp(76px, 20vw, 260px);
  line-height: .82;
  letter-spacing: -0.055em;
  color: var(--ink-navy);
  font-variant-numeric: lining-nums tabular-nums;
}
.day-track.seq-on .day-label {
  display: block; margin-top: clamp(14px, 2vw, 26px);
  font-family: var(--sans, Calibri, sans-serif);
  font-size: clamp(12px, 1.1vw, 14px); letter-spacing: .24em; text-transform: uppercase;
  color: var(--gold-600);
}
.day-track.seq-on .day-note {
  display: block; margin-top: 14px;
  font-size: var(--t-lead); line-height: 1.5; color: var(--muted); max-width: 34ch;
}
/* Registration and the breaks are the beats that are not lessons. The
   register is the school's whole argument, so it is gold rather than grey —
   it is the one non-lesson that is a claim. */
.day-track.seq-on .day-slide.admin .day-time { color: var(--gold-600); }
.day-track.seq-on .day-slide.break .day-time { color: var(--faint); }

/* --------------------------------------------------------------------------
   The rail

   It used to be a progress indicator and nothing else, which is why the first
   version of this section was abandoned: ten lessons is six screens, and a
   parent who only wanted the finishing time had to scroll the whole morning
   to reach it. Every mark is a button now. The hit area is the full height of
   the row — a 1px line is not a target — so each button is padded and the
   line inside it is a ::before, which also keeps the padding from showing as
   a gap in the rail.
   -------------------------------------------------------------------------- */
.day-track.seq-on .day-rails { grid-column: 2; grid-row: 2; align-self: end; display: grid; }
.day-track.seq-on .day-rail { display: none; flex-direction: column; padding-bottom: 6px; }
.day-track.seq-on .day-rail.on { display: flex; }
/* The mark is one pixel tall; the button around it is not. A 30x13 target is
   below the 24x24 minimum and nowhere near a thumb, so the button carries the
   height and the line inside it is a ::before. No gap between them either —
   a gap in a stack of targets is a dead strip where a near miss does nothing
   instead of choosing the nearer of two periods. */
.day-rail button {
  appearance: none; background: none; border: 0; cursor: pointer;
  display: flex; align-items: center; justify-content: flex-end;
  width: 48px; min-height: 24px; padding: 0 0 0 8px;
  border-radius: 2px;
}
.day-rail button::before {
  content: ""; display: block;
  width: 26px; height: 1px; background: var(--line-strong);
  transform-origin: right;
  transition: transform .5s var(--e-expo), background-color .4s var(--e-quart), width .4s var(--e-quart);
}
.day-rail button:hover::before { background: var(--gold-300); width: 34px; }
.day-rail button:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
.day-rail button.past::before { background: var(--gold-300); }
.day-rail button.on::before { background: var(--gold); transform: scaleX(2.1); }

.day-close {
  font-size: var(--t-section); line-height: 1.12; letter-spacing: -0.025em;
  max-width: 26ch; margin-top: clamp(40px, 6vw, 90px);
  color: var(--ink-navy);
}

.day-section { padding-bottom: clamp(72px, 10vw, 150px); }

@media (max-width: 900px) {
  .day-track.seq-on { height: calc(var(--slides, 9) * 56vh); }
  .day-track.seq-on .day-stage-inner { height: calc(100svh - var(--bar-h, 84px) - clamp(28px, 5vh, 56px)); }
  /* Centred, not floored — on a small screen the emptiness above a 76px
     number reads as a gap rather than as composed space. */
  .day-track.seq-on .day-seqs { align-self: center; }
  .day-track.seq-on .day-seq { inset: 0 auto auto 0; }
  .day-track.seq-on .day-slide { inset: auto auto auto 0; top: 50%; transform: translate3d(0, calc(-50% + 34px), 0); }
  .day-track.seq-on .day-slide.on { transform: translate3d(0, -50%, 0); }
  .day-track.seq-on .day-rails { align-self: center; }
  .day-switch { flex: 1 1 100%; }
  .day-rail button { width: 38px; }
  .day-rail button::before { width: 16px; }
  .day-rail button:hover::before { width: 22px; }
}

@media (prefers-reduced-motion: reduce) {
  /* No sticky stage at all: the day is the list it was before script ran. The
     rail stays, because with every period on the page at once it stops being
     a progress indicator and becomes what it now also is — a way to jump
     straight to one of them. */
  .day-track.seq-on { height: auto; }
  .day-track.seq-on .day-stage { position: static; height: auto; display: block; padding-top: 0; }
  .day-track.seq-on .day-seqs { position: static; min-height: 0; }
  .day-track.seq-on .day-seq { position: static; }
  .day-track.seq-on .day-slide {
    position: static; opacity: 1; transform: none; pointer-events: auto;
    padding: 24px 0; border-top: 1px solid var(--line); display: grid; gap: 6px;
  }
  .day-track.seq-on .day-time { font-size: clamp(26px, 3vw, 38px); }
  .day-track.seq-on .day-stage-inner { height: auto; display: block; }
  .day-track.seq-on .day-rail.on { flex-direction: row; flex-wrap: wrap; margin-top: 18px; }
  .day-rail button::before { transition: none; }
}

/* ==========================================================================
   The two things that float: back to top, and the question box
   --------------------------------------------------------------------------
   Both are fixed to the bottom right, stacked rather than overlapping, and
   both sit above env(safe-area-inset-bottom) so an iPhone's home indicator
   does not cover them. They are hidden from print.
   ========================================================================== */
/* A button that has to look like the link beside it. A stored file cannot be
   an <a href> — its URL does not exist until the server has checked who is
   asking — but to a reader it is the same thing as a linked document, so it
   should not look like a different thing. */
.linklike {
  appearance: none; background: none; border: 0; padding: 0;
  font: inherit; color: var(--navy); text-align: left; cursor: pointer;
  text-decoration: underline; text-underline-offset: 2px;
}
.linklike:hover { color: var(--gold-600); }
.linklike:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.site-tools {
  position: fixed; z-index: 60;
  right: clamp(14px, 3vw, 28px);
  bottom: calc(clamp(14px, 3vw, 28px) + env(safe-area-inset-bottom, 0px));
  display: flex; flex-direction: column; align-items: flex-end; gap: 10px;
}

/* --- back to top ---------------------------------------------------------- */
.to-top {
  appearance: none; cursor: pointer;
  width: 44px; height: 44px; border-radius: 50%;
  display: grid; place-items: center;
  background: #fff; color: var(--ink-navy);
  /* The hairline this had measured 1.4:1 against the page, and 1.4.11 wants
     3:1 for the edge of a control — on a near-white background a near-white
     button is a button you have to already know is there. Navy at the full
     weight is the same ink as the icon inside it, so it reads as one object
     rather than as a ring. */
  border: 1.5px solid var(--ink-navy);
  box-shadow: 0 6px 20px rgba(16, 32, 52, .14);
  /* Out of the way until there is something above you. It is translated and
     faded rather than display:none so it arrives rather than appears, and
     pointer-events keeps it unclickable while it is invisible. */
  opacity: 0; transform: translateY(10px) scale(.92); pointer-events: none;
  transition: opacity .3s var(--e-quart), transform .4s var(--e-expo), border-color .3s var(--e-quart);
}
.site-tools.lifted .to-top { opacity: 1; transform: none; pointer-events: auto; }
.to-top:hover { border-color: var(--gold); }
.to-top:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; opacity: 1; transform: none; pointer-events: auto; }
.to-top svg { width: 20px; height: 20px; }

/* --- the question box ----------------------------------------------------- */
.ask { display: flex; flex-direction: column; align-items: flex-end; gap: 10px; }

.ask-launch {
  appearance: none; cursor: pointer;
  display: inline-flex; align-items: center; gap: 8px;
  min-height: 48px; padding: 0 18px; border-radius: 26px;
  background: var(--ink-navy); color: #fff; border: 0;
  box-shadow: 0 8px 24px rgba(16, 32, 52, .26);
  font-family: var(--sans, Calibri, sans-serif);
  font-size: 14px; letter-spacing: .02em;
  transition: transform .3s var(--e-expo), background-color .3s var(--e-quart);
}
.ask-launch svg { width: 19px; height: 19px; }
.ask-launch:hover { transform: translateY(-2px); background: #1d3d63; }
.ask-launch:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }
.ask.on .ask-launch { display: none; }

.ask-panel {
  width: min(380px, calc(100vw - 2 * clamp(14px, 3vw, 28px)));
  max-height: min(560px, calc(100vh - 120px));
  display: flex; flex-direction: column;
  background: var(--paper, #f6f5f1);
  border: 1px solid var(--line-strong);
  border-radius: 14px; overflow: hidden;
  box-shadow: 0 18px 50px rgba(16, 32, 52, .26);
}
.ask-head {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 14px 10px 12px 16px;
  background: #fff; border-bottom: 1px solid var(--line);
}
.ask-head .grow, .ask-head > div:first-child { flex: 1 1 auto; min-width: 0; }
.ask-head p { margin: 4px 0 0; }

.ask-log {
  flex: 1 1 auto; min-height: 0; overflow-y: auto;
  padding: 14px 16px; display: flex; flex-direction: column; gap: 12px;
  overscroll-behavior: contain;
}
.ask-msg { font-size: 14px; line-height: 1.55; }
.ask-msg p { margin: 0 0 8px; }
.ask-msg p:last-of-type { margin-bottom: 0; }
.ask-msg.from-you {
  align-self: flex-end; max-width: 85%;
  background: var(--ink-navy); color: #fff;
  padding: 9px 13px; border-radius: 14px 14px 4px 14px;
}
.ask-msg.from-school {
  align-self: flex-start; max-width: 95%;
  background: #fff; border: 1px solid var(--line);
  padding: 12px 14px; border-radius: 14px 14px 14px 4px;
}
/* "I do not know" should look like an answer, not like a failure. */
.ask-msg.from-school.none { border-color: var(--gold-300); background: var(--gold-50, #fdf8ec); }

/* A caret while the sentence is still arriving, so a pause between two words
   reads as the answer still coming rather than as the answer having stopped
   short. It is on the paragraph's last line because it is an ::after on the
   paragraph itself, which is also what keeps it from needing a wrapper
   element the typing would have to write around. */
.ask-msg.typing p::after {
  content: ""; display: inline-block; vertical-align: -1px;
  width: 2px; height: 1em; margin-left: 2px;
  background: var(--gold-600);
  animation: ask-caret 1s steps(2, start) infinite;
}
@keyframes ask-caret { to { opacity: 0; } }

@media (prefers-reduced-motion: reduce) {
  /* Nothing is typed under reduced motion, so there is nothing to blink. */
  .ask-msg.typing p::after { display: none; }
}

.ask-more {
  display: inline-block; margin-top: 10px;
  font-size: 13px; font-weight: 700; color: var(--gold-600);
  text-decoration: none; border-bottom: 1px solid currentColor;
}
.ask-more:hover { color: var(--ink-navy); }
.ask-also { margin-top: 10px; display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }

.ask-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.ask-chip {
  appearance: none; cursor: pointer;
  background: #fff; border: 1px solid var(--line-strong); color: var(--ink-navy);
  font-family: var(--sans, Calibri, sans-serif); font-size: 12.5px;
  text-align: left; padding: 7px 11px; border-radius: 16px; min-height: 32px;
  transition: border-color .25s var(--e-quart), background-color .25s var(--e-quart);
}
.ask-chip:hover { border-color: var(--gold); background: var(--gold-50, #fdf8ec); }
.ask-chip:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }

.ask-form {
  display: flex; gap: 8px; padding: 10px 12px;
  background: #fff; border-top: 1px solid var(--line);
}
.ask-form .input { flex: 1 1 auto; min-width: 0; font-size: 15px; }
.ask-form .btn { flex: 0 0 auto; min-height: 42px; }
.ask-foot { padding: 0 14px 12px; background: #fff; margin: 0; }

@media (max-width: 480px) {
  /* On a phone the panel is the screen, so it takes the width and the
     launcher loses its label — the icon alone is unmistakable at that size
     and the words were pushing the button into the back-to-top. */
  .ask-panel { width: calc(100vw - 2 * clamp(14px, 3vw, 28px)); max-height: calc(100vh - 140px); }
  .ask-launch span { display: none; }
  .ask-launch { padding: 0; width: 52px; justify-content: center; border-radius: 50%; }
}

@media (prefers-reduced-motion: reduce) {
  .to-top, .ask-launch { transition: none; }
  .to-top { transform: none; }
}

@media print { .site-tools { display: none; } }

/* ==========================================================================
   The other public pages
   --------------------------------------------------------------------------
   The staff page, the family page and the door share the .site layer, so the
   scale, the curves and the micro-details come to them already. What they
   need of their own is a hero with the same weight as the school's, and the
   crest doing the same work behind it.
   ========================================================================== */
.staff-hero {
  position: relative;
  overflow: clip;
  padding: clamp(72px, 11vw, 150px) 0 clamp(64px, 9vw, 124px);
}
.staff-hero::before {
  content: ""; position: absolute;
  top: 50%; right: -8vw; width: min(62vh, 620px); aspect-ratio: 1;
  transform: translateY(-50%);
  background: url("../assets/logo-256.png") center / contain no-repeat;
  opacity: .07; pointer-events: none;
}
.staff-hero::after {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 2px;
  background: linear-gradient(to right, var(--gold) 0%, var(--gold-300) 38%, rgba(217,194,126,0) 100%);
}
.staff-hero .wrap { position: relative; }
.staff-hero h1 { font-size: var(--t-display); line-height: 0.96; letter-spacing: -0.032em; max-width: 15ch; }
.staff-hero p { font-size: var(--t-lead); max-width: 52ch; }

/* The door: one field, centred, and the crest behind it. */
.gate-band { position: relative; overflow: clip; }
.gate-band::before {
  content: ""; position: absolute; top: 50%; left: 50%;
  width: min(78vh, 780px); aspect-ratio: 1; transform: translate(-50%, -50%);
  background: url("../assets/logo-256.png") center / contain no-repeat;
  opacity: .05; pointer-events: none;
}
.gate-wrap { position: relative; }
.gate-card h1 { font-size: clamp(30px, 4.4vw, 52px); line-height: 1.0; letter-spacing: -0.03em; }
.gate-card { transition: transform .8s var(--e-expo), opacity .6s var(--e-quart); }

/* The two doors on the landing page, given the weight of a decision. */
#portals .pillar h3 { font-size: clamp(24px, 2.6vw, 34px); letter-spacing: -0.02em; }
#portals .card.pillar { padding-top: clamp(26px, 3vw, 40px); }

/* ==========================================================================
   THE FLOW: ask first, then answer
   --------------------------------------------------------------------------
   The page used to be a brochure you scrolled. Now it opens with a question,
   and everything below it answers for the child you named. The chooser is
   the first interactive thing on the page; the rail carries the answer with
   you; the answer section is the payoff.

   Nothing here is hidden behind the interaction. Choose nothing and every
   section shows all four years, which is also the page with script off.
   ========================================================================== */

/* --- the question -------------------------------------------------------- */
.chooser { margin-top: clamp(26px, 3vw, 40px); }
.chooser-q {
  font-size: clamp(15px, 1.3vw, 17px); color: #c3d0df; max-width: 46ch;
  margin-bottom: 18px;
}
.chooser-q strong { color: var(--gold-300); font-weight: 400; }
.chooser-row { display: flex; flex-wrap: wrap; gap: 10px; }

.year {
  display: grid; gap: 2px; text-align: left;
  padding: 14px 20px 15px;
  background: transparent; color: #fff;
  border: 1px solid rgba(255, 255, 255, .34);
  cursor: pointer; font: inherit;
  transition: transform .5s var(--e-expo), background-color .35s var(--e-quart),
              border-color .35s var(--e-quart), color .35s var(--e-quart);
}
.year .y-age {
  font-family: var(--sans, Calibri, sans-serif);
  font-size: 10.5px; letter-spacing: .2em; text-transform: uppercase; color: var(--gold-300);
}
.year .y-grade { font-size: 17px; letter-spacing: -.01em; }
.year:hover { background: rgba(255, 255, 255, .08); border-color: var(--gold-300); transform: translateY(-2px); }
.year.on { background: var(--gold); border-color: var(--gold); color: #16304f; }
.year.on .y-age { color: rgba(22, 48, 79, .72); }
.year.clear { border-style: dashed; border-color: rgba(255, 255, 255, .28); }
.year.clear .y-grade { font-size: 14px; color: #c3d0df; }

.chooser-go {
  display: inline-block; margin-top: 20px;
  font-family: var(--sans, Calibri, sans-serif);
  font-size: 12px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--gold-300); text-decoration: none;
  border-bottom: 1px solid rgba(217, 194, 126, .45); padding-bottom: 4px;
  transition: border-color .4s var(--e-quart), color .3s var(--e-quart);
}
.chooser-go:hover { color: #fff; border-color: #fff; }

/* --- the rail: the answer follows you down --------------------------------
   Sticky under the bar rather than fixed, so it never covers content and a
   phone keyboard cannot trap it. */
.answer-rail {
  /* It used to be sticky, riding under the bar all the way down the page. The
     effect was a second header that moved: the figures were useful but the
     "Book a visit" button inside it followed the reader around and read as
     something floating loose on the page. It sits where it is written now,
     once, under the bar — and the bar's own "Book a visit" is the one that
     stays within reach. */
  position: static;
  background: var(--paper-warm);
  border-bottom: 1px solid var(--line);
  box-shadow: 0 1px 0 var(--line);
}
.answer-rail .wrap {
  display: flex; align-items: center; gap: 16px;
  padding-top: 11px; padding-bottom: 11px;
}
.rail-cells {
  display: flex; align-items: center; gap: clamp(14px, 2.4vw, 34px);
  flex: 1 1 auto; min-width: 0;
  overflow-x: auto; scrollbar-width: none;
}
.rail-cells::-webkit-scrollbar { display: none; }
.rail-year, .rail-cell { display: grid; gap: 1px; white-space: nowrap; }
.rail-year { background: none; border: 0; padding: 0; font: inherit; text-align: left; cursor: pointer; }
.answer-rail .k {
  font-family: var(--sans, Calibri, sans-serif);
  font-size: 9.5px; letter-spacing: .2em; text-transform: uppercase; color: var(--muted);
}
.answer-rail .v { font-size: 16px; color: var(--ink-navy); letter-spacing: -.01em; }
.answer-rail .v.none { color: var(--red); }
.rail-year:hover .v { color: var(--gold-600); }
.rail-cta { flex: 0 0 auto; }

/* --- the answer ---------------------------------------------------------- */
.answer-band { background: var(--paper-true); }
.answer-grid {
  display: grid; gap: 1px; background: var(--line);
  border: 1px solid var(--line);
  grid-template-columns: repeat(3, 1fr);
}
.ans { background: var(--paper-true); padding: clamp(24px, 2.6vw, 38px); }
.ans-k {
  font-family: var(--sans, Calibri, sans-serif);
  font-size: 10.5px; letter-spacing: .22em; text-transform: uppercase; color: var(--gold-600);
}
/* A line-height under 1 makes the box shorter than the glyphs, so whatever
   follows sits inside them — which is what the three discount figures on the
   fees page were doing to their own captions. The bottom margin gives the
   overshoot somewhere to go; it collapses against .ans-sub's own top margin,
   so the answer cards are unchanged. */
.ans-fig {
  font-size: clamp(50px, 6vw, 88px); line-height: .95; letter-spacing: -.04em;
  color: var(--ink-navy); margin: 18px 0 16px;
}
.ans-full .ans-fig { color: var(--red); }
.ans-sub { font-size: 15px; color: var(--muted); margin-top: 10px; max-width: 30ch; line-height: 1.5; }
.ans-sub strong { color: var(--ink-navy); font-weight: 400; }
.ans-dl { display: grid; grid-template-columns: auto 1fr; gap: 6px 18px; margin-top: 22px; font-size: 14px; }
.ans-dl dt { color: var(--muted); }
.ans-dl dd { margin: 0; color: var(--ink-navy); }
.ans-table { width: 100%; font-size: 14px; border-collapse: collapse; }
.ans-table td { padding: 7px 0; border-bottom: 1px solid var(--line); color: var(--muted); }
.ans-table .right { text-align: right; color: var(--ink-navy); }
.ans-table .tot td { border-bottom: 0; border-top: 1px solid var(--line-strong); color: var(--ink-navy); padding-top: 10px; }

.answer-act { display: flex; flex-wrap: wrap; gap: 12px; }

/* --- all four years, when nothing is chosen ------------------------------ */
/* Flex, not a fixed four-column grid. The grey is the container showing
   through 1px gaps, which draws the hairlines between cards — but it also
   means an empty cell is a grey hole, and the school now has five year
   groups, so a four-column grid left exactly one. Flex items wrap and then
   grow to fill whatever row they land in, so there is never an empty cell
   to show through at any width. */
.year-grid {
  display: flex; flex-wrap: wrap;
  gap: 1px; background: var(--line); border: 1px solid var(--line);
}
.year-grid > .year-card { flex: 1 1 206px; min-width: 0; }
.year-card {
  display: grid; align-content: start; gap: 10px; text-align: left;
  background: var(--paper-true); border: 0; cursor: pointer; font: inherit;
  padding: clamp(22px, 2.4vw, 32px);
  transition: background-color .4s var(--e-quart);
}
.year-card:hover { background: var(--paper-warm); }
.yc-age { font-family: var(--sans, Calibri, sans-serif); font-size: 10.5px; letter-spacing: .2em; text-transform: uppercase; color: var(--gold-600); }
.yc-name { font-size: clamp(19px, 1.7vw, 23px); line-height: 1.18; letter-spacing: -.015em; color: var(--ink-navy); }
.yc-row { display: flex; justify-content: space-between; gap: 12px; font-size: 14px; color: var(--muted); border-top: 1px solid var(--line); padding-top: 9px; }
.yc-row b { color: var(--ink-navy); font-weight: 400; }
.yc-row b.none { color: var(--red); }
.yc-go {
  font-family: var(--sans, Calibri, sans-serif); font-size: 11px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--gold-600); margin-top: 6px;
  transition: transform .5s var(--e-expo);
}
.year-card:hover .yc-go { transform: translateX(5px); }

/* --- phone --------------------------------------------------------------- */
@media (max-width: 1000px) {
  .answer-grid { grid-template-columns: minmax(0, 1fr); }
  .year-grid > .year-card { flex-basis: 44%; }
}
@media (max-width: 620px) {
  .year-grid > .year-card { flex-basis: 100%; }
  .chooser-row { display: grid; grid-template-columns: 1fr 1fr; }
  .year { padding: 12px 14px 13px; }
  .year.clear { grid-column: 1 / -1; text-align: center; }
  .answer-rail .wrap { gap: 12px; }
  .rail-cells { gap: 18px; }
  .answer-act .btn { width: 100%; justify-content: center; }
}

@media (prefers-reduced-motion: reduce) {
  .year, .year-card, .yc-go, .chooser-go, .rail-cta { transition: none; }
  .year:hover { transform: none; }
}

/* ==========================================================================
   Copy: counter-objections where the friction is
   --------------------------------------------------------------------------
   Placed beside the send button rather than in an FAQ, because a concern
   answered after somebody has left is not answered.
   ========================================================================== */
.after-send { margin-top: clamp(28px, 3.4vw, 44px); padding-top: clamp(24px, 3vw, 34px); border-top: 1px solid var(--line); }
.after-steps { list-style: none; margin: 18px 0 0; padding: 0; display: grid; gap: 14px; }
.after-steps li { display: flex; gap: 14px; align-items: flex-start; font-size: 15px; line-height: 1.55; color: var(--muted); }
.after-steps .n {
  flex: 0 0 auto; width: 26px; height: 26px; display: grid; place-items: center;
  border: 1px solid var(--gold); color: var(--gold-600); font-family: Georgia, serif; font-size: 13px;
}
.after-steps strong { color: var(--ink-navy); font-weight: 400; }
.after-assure { list-style: none; margin: 22px 0 0; padding: 0; display: grid; gap: 9px; }
.after-assure li { display: flex; gap: 10px; align-items: flex-start; font-size: 14px; color: var(--muted); line-height: 1.5; }
.after-assure .ico { width: 15px; height: 15px; color: var(--green); flex: 0 0 auto; margin-top: 3px; }

/* An optional field should look optional. */
.site .field .opt {
  font-size: 9.5px; letter-spacing: .14em; color: var(--faint);
  text-transform: uppercase; margin-left: 8px;
}

/* The page's goal is enquiries, so the portal doors step back a little. */
.site-bar .btn.quiet { opacity: .82; }
.site-bar .btn.quiet:hover { opacity: 1; }

/* A proof line under a very large headline wants to read as one breath. */
.hero-proof { max-width: 52ch; }

/* ==========================================================================
   The enrichment curriculum, and the specialists
   --------------------------------------------------------------------------
   Set as a timetable rather than as a list of clubs: each subject carries
   when it happens, because when it happens is the whole argument.
   ========================================================================== */
.enrich-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1px; background: var(--line); border: 1px solid var(--line); }
.enrich { background: var(--paper-true); padding: clamp(24px, 2.6vw, 38px); }
.enrich-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 10px; }
.enrich-head h3 { letter-spacing: -0.015em; }
.enrich-when {
  font-family: var(--sans, Calibri, sans-serif);
  font-size: 10px; letter-spacing: .16em; text-transform: uppercase; color: var(--gold-600);
  text-align: right; max-width: 22ch; line-height: 1.5;
}
.enrich-line { font-style: italic; color: var(--gold-600); margin-top: 10px; font-size: 16px; }
.enrich p.small { margin-top: 12px; }
.enrich-who { color: var(--faint); margin-top: 14px; border-top: 1px solid var(--line); padding-top: 12px; }
.enrich-note {
  margin-top: clamp(28px, 3.4vw, 46px); font-size: var(--t-lead); line-height: 1.5;
  max-width: 44ch; color: var(--ink-navy);
  border-left: 2px solid var(--gold); padding-left: clamp(18px, 2vw, 28px);
}

.spec { border-top: 1px solid var(--line-strong); padding-top: 22px; }
.spec-head { display: flex; align-items: baseline; justify-content: space-between; gap: 14px; }
.spec-head h3 { letter-spacing: -0.015em; }

/* Inside the per-year answer: the same subjects, named for that year. */
.ans-plus { margin-top: 22px; padding-top: 18px; border-top: 1px solid var(--line); display: grid; gap: 10px; }
.ans-plus-k {
  font-family: var(--sans, Calibri, sans-serif);
  font-size: 10px; letter-spacing: .2em; text-transform: uppercase; color: var(--gold-600);
}

@media (max-width: 900px) {
  .enrich-grid { grid-template-columns: minmax(0, 1fr); }
  .enrich-head { flex-direction: column; gap: 4px; }
  .enrich-when { text-align: left; max-width: none; }
  .enrich-note { max-width: none; }
}

/* ==========================================================================
   Accessibility corrections — WCAG 2.1 AA
   --------------------------------------------------------------------------
   Measured against the live page rather than guessed at. The colour tokens
   above fix most of the 68 contrast failures at once; what is left here is
   the handful that needed a local value, plus target sizes and the skip link.
   ========================================================================== */

/* Pill text on its own tint. green 4.32 and amber 3.16 both failed; the
   tokens themselves are left alone because they are also fills and borders. */
.pill.green { color: #2b794b; }
.pill.amber { color: #8a5200; }

/* 2.5.5 — the menu button was 36x30 and is the only way into the navigation
   on a phone. */
/* 2.5.5 again, but scoped this time. The first version of this rule carried
   `display: grid`, unqualified and late in the file, which beat the
   `display: none` the button is supposed to have on a wide screen — so the
   hamburger appeared on desktop, wrapped onto a second row of the bar, and
   opened a drawer duplicating the navigation already visible beside it.
   The sizing applies everywhere; only the showing is conditional. */
.menu-btn { min-width: 44px; min-height: 44px; place-content: center; gap: 5px; }
@media (max-width: 980px) { .menu-btn { display: grid; } }



/* A target under 24px is hard to hit even with a mouse; the footer and in-page
   navigation links were 21px tall. */
.site-nav a, .foot-links a { display: inline-block; padding-block: 4px; }

@media (pointer: coarse) {
  .site .btn, .site-nav a, .foot-links a, .year, .chooser-go { min-height: 44px; }
  .site .btn { display: inline-flex; align-items: center; }
  .site .input, .site select.input { min-height: 44px; }
}

/* ==========================================================================
   A site, not a page
   --------------------------------------------------------------------------
   Everything below dresses the six public pages that used to be six sections
   of one scroll: the head each of them opens with, the call to action each of
   them closes with, and the furniture in between — fee tables, the questions
   families ask, the three doors on the front page.

   Nothing here introduces a colour or a typeface. The palette and the two
   families are exactly as they were; what changes is that a page now has a
   beginning and an end instead of being the middle of something longer.
   ========================================================================== */

/* --- the bar, carrying five links now ------------------------------------ */
.site-nav a { white-space: nowrap; }

/* The short names are the default, and the full ones are an upgrade the bar
   earns by measuring that they fit — see fitNav() in js/landing.js. Doing it
   this way round means the failure is a shorter word rather than two pieces
   of type on top of each other, which is what a guessed breakpoint gives you
   the moment somebody renames a link. */
.nav-long  { display: none; }
.nav-short { display: inline; }
.site.nav-wide .nav-long  { display: inline; }
.site.nav-wide .nav-short { display: none; }
.site-sign { display: inline-flex; align-items: center; gap: 14px; margin-left: 6px; }
.site-sign .quiet-link {
  font-family: var(--sans, Calibri, sans-serif);
  font-size: 11px; letter-spacing: .12em; text-transform: uppercase; font-weight: 700;
  color: #93a7bd; text-decoration: none; display: inline-flex; align-items: center; gap: 6px;
  padding-block: 4px; transition: color .2s ease;
}
.site-sign .quiet-link:hover { color: var(--gold-300); }
.site-sign .quiet-link svg { width: 14px; height: 14px; }

/* Tightened early, because the wordmark now holds the middle of the bar and
   everything else has to clear it rather than push it aside. */
@media (max-width: 1400px) {
  .site-nav { gap: 16px; }
  .site-sign { gap: 10px; margin-left: 2px; }
  .site-bar { padding-inline: 28px; }
}

.site-drawer a[aria-current="page"] { color: #fff; }

/* --- the head of an inside page ------------------------------------------
   Same ground as the hero, a third of the height: a parent who followed a
   link to the fees page did not come for another full-screen photograph. */
.page-head { background: var(--ink-navy); color: #fff; padding: clamp(44px, 6vw, 88px) 0 clamp(40px, 5vw, 72px); }
.page-head .wrap { max-width: var(--measure); padding: 0 40px; }
.page-head h1 { color: #fff; font-size: clamp(32px, 5vw, 62px); max-width: 17ch; margin-top: 18px; }
.page-lead { color: #b9c6d6; font-size: clamp(17px, 1.4vw, 20px); line-height: 1.6; max-width: 62ch; margin-top: 24px; }
.page-act { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 32px; }
.page-act .btn svg { width: 15px; height: 15px; }

/* --- the close of every page --------------------------------------------- */
.cta-band { background: var(--paper-warm); border-top: 1px solid var(--line); }
.cta-acts { display: flex; flex-wrap: wrap; gap: 12px; justify-content: center; }
.cta-assure {
  list-style: none; margin: 44px auto 0; padding: 26px 0 0; max-width: 62ch;
  border-top: 1px solid var(--line-strong); display: grid; gap: 14px;
}
.cta-assure li { display: flex; gap: 11px; align-items: flex-start; font-size: 15px; line-height: 1.6; color: var(--muted); }
.cta-assure li strong { color: var(--ink-navy); }
.cta-assure svg { width: 16px; height: 16px; flex: none; margin-top: 4px; color: var(--gold-600); }

/* --- the three doors on the front page ------------------------------------ */
.door-grid { gap: 0; border-top: 1px solid var(--line-strong); }
.door {
  display: flex; flex-direction: column; gap: 12px; padding: 34px 30px 30px;
  border-bottom: 1px solid var(--line-strong); border-right: 1px solid var(--line-strong);
  text-decoration: none; color: inherit; background: transparent;
  transition: background-color .35s var(--e-quart, ease), padding-left .35s var(--e-quart, ease);
}
.door:first-child { border-left: 1px solid var(--line-strong); }
.door:hover { background: var(--paper-warm); padding-left: 38px; }
.door-k { font-family: var(--sans, Calibri, sans-serif); font-size: 10.5px; letter-spacing: .22em; text-transform: uppercase; color: var(--gold-600); }
.door-h { font-family: Georgia, serif; font-size: 22px; line-height: 1.24; color: var(--ink-navy); }
.door-b { font-size: 15px; line-height: 1.6; color: var(--muted); flex: 1; }
.door-go { font-family: var(--sans, Calibri, sans-serif); font-size: 11.5px; letter-spacing: .14em; text-transform: uppercase; font-weight: 700; color: var(--ink-navy); margin-top: 6px; }

/* --- the questions families ask ------------------------------------------- */
.faq-group { margin-top: clamp(34px, 4vw, 52px); }
.faq-group-h {
  font-family: var(--sans, Calibri, sans-serif); font-size: 11px; letter-spacing: .22em;
  text-transform: uppercase; color: var(--gold-600); font-weight: 700;
  padding-bottom: 12px; border-bottom: 1px solid var(--line-strong); margin-bottom: 0;
}
.faq { border-bottom: 1px solid var(--line); }
.faq > summary {
  display: flex; justify-content: space-between; align-items: flex-start; gap: 20px;
  padding: 20px 0; cursor: pointer; list-style: none;
  font-family: Georgia, serif; font-size: 18px; line-height: 1.4; color: var(--ink-navy);
}
.faq > summary::-webkit-details-marker { display: none; }
.faq > summary:hover { color: var(--gold-600); }
.faq > summary i {
  flex: none; width: 13px; height: 13px; margin-top: 7px; position: relative;
}
.faq > summary i::before, .faq > summary i::after {
  content: ""; position: absolute; inset: 50% 0 auto; height: 1px; background: currentColor;
  transition: transform .3s var(--e-quart, ease);
}
.faq > summary i::after { transform: rotate(90deg); }
.faq[open] > summary i::after { transform: rotate(0deg); }
.faq[open] > summary { color: var(--gold-600); }
.faq-a { padding: 0 44px 24px 0; font-size: 16px; line-height: 1.68; color: var(--muted); max-width: 72ch; }
.faq-a strong { color: var(--ink-navy); }

/* --- the "tell us more" disclosure on the enquiry form -------------------- */
.more-fields { border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.more-fields > summary {
  display: flex; justify-content: space-between; align-items: center; gap: 16px;
  padding: 16px 0; cursor: pointer; list-style: none;
  font-family: var(--sans, Calibri, sans-serif); font-size: 13px; font-weight: 700;
  letter-spacing: .04em; color: var(--navy-600);
}
.more-fields > summary::-webkit-details-marker { display: none; }
.more-fields > summary i { flex: none; width: 11px; height: 11px; position: relative; }
.more-fields > summary i::before, .more-fields > summary i::after {
  content: ""; position: absolute; inset: 50% 0 auto; height: 1px; background: currentColor;
  transition: transform .3s var(--e-quart, ease);
}
.more-fields > summary i::after { transform: rotate(90deg); }
.more-fields[open] > summary i::after { transform: rotate(0deg); }
.more-body { padding-bottom: 20px; }

/* --- fees, side by side --------------------------------------------------- */
.fee-table th.right, .fee-table td.right { text-align: right; }
.fee-table tr.tot td { font-weight: 700; border-top: 2px solid var(--ink-navy); background: var(--paper-warm); }
.fee-table td.none, table td.none { color: var(--red, #b3261e); }
.day-table tr.break td { background: var(--paper-warm); color: var(--muted); }
.day-table tr.admin td { background: var(--gold-50); }

/* --- the open intake, stated once at the top of Joining ------------------- */
.tight-band { padding: clamp(28px, 3.5vw, 48px) 0; }
.intake-strip {
  display: flex; flex-wrap: wrap; align-items: center; gap: 28px;
  padding: 22px 26px; background: var(--paper-warm); border: 1px solid var(--line-strong);
}
.intake-strip > span { display: flex; flex-direction: column; gap: 3px; }
.intake-strip b { font-family: Georgia, serif; font-weight: 400; font-size: 19px; color: var(--ink-navy); }
.intake-strip i {
  font-style: normal; font-family: var(--sans, Calibri, sans-serif);
  font-size: 10.5px; letter-spacing: .18em; text-transform: uppercase; color: var(--gold-600);
}
.intake-strip .btn { margin-left: auto; }

/* --- book a visit --------------------------------------------------------- */
.visit-grid { grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); gap: 26px; align-items: start; }
.visit-side { display: grid; gap: 26px; min-width: 0; }
.visit-grid > * { min-width: 0; }
.contact-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; }
.contact-list li { display: flex; gap: 10px; align-items: center; font-size: 15px; color: var(--muted); }
.contact-list svg { width: 16px; height: 16px; flex: none; color: var(--gold-600); }

/* --- the two stages on the learning page ---------------------------------- */
.stage-plus { margin-top: 22px; padding-top: 18px; border-top: 1px solid var(--line); display: grid; gap: 10px; }

/* --- the hero's opening line of fact -------------------------------------- */
.hero-kicker {
  font-family: var(--sans, Calibri, sans-serif);
  font-size: 11px; letter-spacing: .22em; text-transform: uppercase;
  color: var(--gold-300); margin-bottom: 22px;
}
.hero-note a { color: inherit; text-decoration: none; border-bottom: 1px solid rgba(255,255,255,.28); }
.hero-note a:hover { color: var(--gold-300); border-bottom-color: var(--gold-300); }
.hero-note .dot { opacity: .5; }

/* --- the footer, now with four columns ------------------------------------ */
.foot-grid { display: grid; grid-template-columns: 1.4fr .7fr .7fr 1.2fr; gap: 36px; align-items: start; }
.site-foot a { color: #cbd5e1; }
.site-foot .foot-links { display: flex; flex-direction: column; gap: 2px; }

@media (max-width: 980px) {
  .door-grid { grid-template-columns: minmax(0, 1fr); }
  .door, .door:first-child { border-left: 1px solid var(--line-strong); border-right: 1px solid var(--line-strong); }
  .visit-grid { grid-template-columns: minmax(0, 1fr); }
  .foot-grid { grid-template-columns: 1fr 1fr; }
  .page-head .wrap { padding: 0 22px; }
  .intake-strip { gap: 18px; }
  .intake-strip .btn { margin-left: 0; width: 100%; justify-content: center; }
}
@media (max-width: 620px) {
  .foot-grid { grid-template-columns: minmax(0, 1fr); }
  .faq > summary { font-size: 16.5px; }
  .faq-a { padding-right: 0; }
  .cta-acts .btn { width: 100%; justify-content: center; }
}

/* The fee comparison is four year-groups wide and will not fold; let it
   scroll inside its card rather than push the page sideways. */
@media (max-width: 720px) {
  .fee-table { min-width: 520px; }
}

/* --- corrections the new pages needed ------------------------------------
   Measured on the built pages rather than reasoned about. Four of these are
   contrast, and three of the four exist only because a component that had
   been written for the navy hero is now being asked to stand on white. */

/* The inside pages' head is the same navy as the hero, so it needs the same
   two exceptions the hero already has: a pale gold eyebrow, and a ghost
   button that is not navy-on-navy. */
.page-head .eyebrow { color: var(--gold-300); }
.page-head .btn.ghost { color: #fff; border-color: rgba(255,255,255,.55); }
.page-head .btn.ghost:hover { background: #fff; color: var(--ink-navy); border-color: #fff; }

/* The year chooser was written to sit in the hero — white and gold on navy.
   On the fees page it stands on paper, where every one of those colours is
   invisible. Same control, inverted. */
.chooser-light .chooser-q { color: var(--muted); }
.chooser-light .chooser-q strong { color: var(--ink-navy); font-weight: 700; }
.chooser-light .year { color: var(--ink-navy); border-color: var(--line-strong); background: var(--paper); }
.chooser-light .year .y-age { color: var(--gold-600); }
.chooser-light .year:hover { background: var(--paper-warm); border-color: var(--gold-600); }
.chooser-light .year.on { background: var(--ink-navy); border-color: var(--ink-navy); color: #fff; }
.chooser-light .year.on .y-age { color: var(--gold-300); }
.chooser-light .year.clear { border-color: var(--line-strong); }
.chooser-light .year.clear .y-grade { color: var(--muted); }
.chooser-light .chooser-go { color: var(--gold-600); border-bottom-color: rgba(135,106,30,.45); }
.chooser-light .chooser-go:hover { color: var(--ink-navy); border-bottom-color: var(--ink-navy); }

/* Gold pill text on its own gold tint measured 4.37, and the success notice
   4.32. Both are the token doing double duty as a fill; only the text moves. */
.pill.gold { color: #7a5f15; }
.notice.ok, .notice.ok strong { color: #2a7047; }

/* The selected year button. Navy on gold measured 4.27, and the age above it
   4.27 as well — a failure the last audit missed because it only ever
   measured the chooser with nothing chosen. Both go a shade darker; the
   de-emphasis of the age line is carried by its size and letter-spacing,
   which is where it should have been carried anyway. */
.year.on { color: #0c1b2e; }
.year.on .y-age { color: #0c1b2e; }

/* The telephone and email links added to the hero and the footer were 15 and
   21 pixels tall — and on a phone the telephone link is the whole point of
   putting the number there. */
.site-foot p a, .hero-note a, .contact-list a { display: inline-block; padding-block: 5px; }
@media (pointer: coarse) {
  .site-foot p a, .hero-note a, .contact-list a, .faq > summary, .more-fields > summary { min-height: 44px; }
  .hero-note a, .site-foot p a { display: inline-flex; align-items: center; }
}

/* The rail on a phone. Four cells and a button will not sit on one 375px
   line, and the scroller was leaving "Places left" cut in half behind the
   button — the two figures a parent came for, half-legible. Below 620px the
   button takes its own row and the cells get the whole width, which fits
   without scrolling at all. */
@media (max-width: 620px) {
  .answer-rail .wrap { flex-wrap: wrap; gap: 10px; }
  .rail-cells { flex: 1 0 100%; justify-content: space-between; gap: 12px; overflow-x: visible; }
  .rail-cta { flex: 1 0 100%; justify-content: center; }
  .answer-rail .v { font-size: 15px; }
}

/* The FAQ and the "tell us more" disclosure are <summary> elements, which no
   existing focus rule reached — they are neither a link, a button nor an
   input, and a keyboard user tabbing down the questions had nothing to show
   where they were. */
.site summary:focus-visible {
  outline: 2px solid var(--gold); outline-offset: 3px; border-radius: 1px;
}

/* --- the bar was two rows tall on every wide screen -----------------------
   The wordmark is placed in column 2 and comes first in the markup, so grid's
   auto-placement cursor had already passed column 1 by the time it reached
   the navigation. The navigation therefore dropped to a second row and took
   the sign-in links down with it — a bar 102px deep carrying one line of
   type. Naming the row for all four children puts them back on it. */
.site-brand, .site-nav, .site-actions, .menu-btn { grid-row: 1; }
@media (max-width: 980px) { .menu-btn { grid-column: 3; justify-self: end; } }

/* The two portal pages have no hamburger — they are one page each, so there
   is no menu to put behind one. But the blanket rule that hides .site-actions
   on a phone was hiding the only two controls they have: "School website" and
   "Sign in". The door-code page already had an override for exactly this;
   these two needed the same one. */
@media (max-width: 980px) {
  .staff-site .site-actions { display: flex; }
  .staff-site .site-actions .btn { padding: 10px 13px; font-size: 10px; letter-spacing: .1em; }
  .staff-site .site-bar { gap: 10px; }
}
@media (max-width: 420px) {
  .staff-site .site-brand .t { display: none; }
}

/* On a narrow phone the portal pages' bar had the wordmark and "School
   website" printed over each other. The back link keeps its arrow and loses
   its words — it still carries an aria-label — and the wordmark is allowed
   to truncate rather than to overlap whatever is beside it. */
.staff-site .site-brand, .gate-site .site-brand { min-width: 0; }
@media (max-width: 560px) {
  .staff-site .btn-lbl, .gate-site .btn-lbl { display: none; }
  /* The bar hides button icons at this width, which with the label gone as
     well left an empty box. Here the arrow IS the button. */
  .staff-site .site-bar .btn svg, .gate-site .site-bar .btn svg { display: inline-block; }
  .staff-site .site-actions .btn, .gate-site .site-actions .btn { padding: 11px 12px; }
}

/* --- the door, now the size of the thing it guards ------------------------
   The code box used to be a whole page of its own. It is a card in the
   sign-in slot now, so it has to sit level with the card beside it — the one
   explaining how to be given a sign-in, which stays readable whether or not
   you have the code. */
.gate-card-slot .gate-mark { margin: 0 0 4px; }
.gate-card-slot .gate-form { margin-top: 20px; }
.gate-card-slot .field { text-align: left; }
.gate-card-slot .card-body.center { display: grid; place-items: center; min-height: 220px; }
.gate-card-slot .card-head .pill { display: inline-flex; align-items: center; gap: 5px; }
.gate-card-slot .card-head .pill svg { width: 12px; height: 12px; }

/* Two on the portal pages, both older than the change that found them.

   The family page's hero is .staff-hero, not .hero, so the rule that turns a
   ghost button white on a navy ground never reached it — the button read
   navy on navy, at a ratio of 1.

   And the numeral on the selected tour step was white on --gold: 3.13 at
   11px, where 4.5 is wanted. The badge takes the darker gold; the step's own
   highlight is unchanged. */
.staff-hero .btn.ghost { color: #fff; border-color: rgba(255,255,255,.55); }
.staff-hero .btn.ghost:hover { background: #fff; color: var(--ink-navy); border-color: #fff; }
.tour-step.on .n { background: var(--gold-600); }

/* --- Home, said out loud -------------------------------------------------
   The first link in the bar, marked when you are on it. Six links is one
   more than the row was carrying, so the short labels start a little
   earlier. */
.site-nav a[href="#/"][aria-current="page"] { color: #fff; }
/* --- the guide, now a page of the portal ---------------------------------
   The tour was built for the public page, where it stood in a full-width
   band under a sticky bar 76px deep. Inside the portal it sits in the
   content column under a different bar, so only the sticky offset and the
   outer spacing change. */
.tour.in-portal { grid-template-columns: 240px 1fr; }
.tour.in-portal .tour-list { top: 16px; }
.tour.in-portal .tour-stage { border-radius: 10px; }
@media (max-width: 900px) {
  .tour.in-portal { grid-template-columns: minmax(0, 1fr); }
  .tour.in-portal .tour-list { position: static; display: flex; gap: 6px; overflow-x: auto; padding-bottom: 6px; }
  .tour.in-portal .tour-list li { flex: none; }
  .tour.in-portal .tour-step { white-space: nowrap; }
}

/* The three discount cards set a display figure directly above a paragraph,
   and .site p carries no margin of its own. */
.card-body > .ans-fig + p { margin-top: 4px; }
.card-body > .eyebrow + .ans-fig { margin-top: 10px; }

/* --- the wordmark, actually in the middle ---------------------------------
   `1fr auto 1fr` centres the middle column only when the two side columns
   can both fit inside their equal share. They cannot: the navigation is six
   links and the sign-in group is three, so the navigation track grew past
   its half and pushed the crest sixty pixels to the right of centre. It was
   never centred on the bar — only on whatever was left over.

   So all three sit in the same cell instead, spanning the whole row, and
   align themselves within it: navigation to the start, sign-in group to the
   end, wordmark to the centre. The wordmark is then measured against the bar
   rather than against its neighbours, and stays put whatever is beside it.
   Everything remains in flow, so the row is still as tall as the tallest of
   them and --bar-h still measures what it always did. */
@media (min-width: 1200px) {
  .site-bar { grid-template-columns: minmax(0, 1fr); }
  .site-nav, .site-brand, .site-actions { grid-area: 1 / 1 / 2 / 2; }
  .site-nav     { justify-self: start; }
  .site-brand   { justify-self: center; }
  .site-actions { justify-self: end; }

  /* They share a cell now, so nothing stops them meeting in the middle. The
     centre is the wordmark's; the other two are told where it begins. */
  .site-nav     { padding-right: 24px; }
  .site-actions { padding-left: 24px; }
}

/* --- where the bar stops fitting across -----------------------------------
   The wordmark is centred on the bar, so the navigation has to clear half of
   it rather than simply sit beside it: the margin, the six short links and
   half the wordmark come to just under 1200px of window. Below that the three
   of them would meet in the middle, so the bar collapses to the crest and the
   menu button — the same arrangement a phone gets, which already works. The
   content breakpoints stay at 980 where they were; this one is the bar's. */
@media (max-width: 1199px) {
  .site-nav { display: none; }
  .site-actions { display: none; }
  .menu-btn { display: grid; grid-column: 3; justify-self: end; }
  .site-bar { grid-template-columns: auto 1fr auto; padding: 12px 22px; }
  /* stretch, not start. A grid item with justify-self:start is sized to its
     own content and simply overhangs a track too narrow for it — min-width:0
     does nothing, because nothing is asking it to be narrower. Stretched, it
     takes the track's width and the ellipsis inside it finally has an edge to
     work against. It still reads as left-aligned: the brand is a flex row and
     its contents start at the left either way. */
  .site-brand { grid-column: 2; justify-self: stretch; flex-direction: row; text-align: left; gap: 10px; }
  .site-brand .n { font-size: 13px; letter-spacing: .05em; }
  /* the two portal pages have no menu button, so they keep their two links */
  .staff-site .site-actions, .gate-site .site-actions { display: flex; }
}

/* The issuing forms' one checkbox carries a sentence of explanation, so it
   aligns to the first line rather than to the middle of a paragraph. */
.check { align-items: flex-start; }
.check input { margin-top: 3px; }
.check .tiny { display: block; margin-top: 3px; }

/* ==========================================================================
   Two things the portals were saying by hand
   --------------------------------------------------------------------------
   An audit of the two portals found the component vocabulary in good order —
   card, btn, input, field, pill, stat, notice, empty, table-wrap, used
   consistently across four files and thirty-six views — with one gap. Status
   was being applied as a colour rather than named as a state: sixty-eight
   `style="color:var(--red)"` and friends, some of them conditional
   expressions writing out a token twice.

   A colour is not a meaning. These are, and now the meaning is in the markup
   where somebody reading it can see it — and the day the school wants a
   different red, or a pattern for people who cannot see red, there is one
   place to change it rather than sixty-eight.
   ========================================================================== */
.t-good { color: var(--green); }
.t-bad  { color: var(--red); }
.t-warn { color: var(--gold-600); }

/* `.stat .value` sets its own colour at two-class specificity, so a state on
   a stat figure needs the same weight to be heard. The inline styles these
   replaced always won by definition; a class has to be told to. */
.stat .value.t-good, .card .value.t-good, td.t-good, .tiny.t-good { color: var(--green); }
.stat .value.t-bad,  .card .value.t-bad,  td.t-bad,  .tiny.t-bad  { color: var(--red); }
.stat .value.t-warn, .card .value.t-warn, td.t-warn, .tiny.t-warn { color: var(--gold-600); }

/* Destructive actions were each hand-coloured at the point of use. There are
   eight of them, and they are all the same thing. */
.btn.danger { color: var(--red); border-color: var(--red); }
.btn.danger:hover:not(:disabled) { background: var(--red); border-color: var(--red); color: #fff; }

/* The topbar's register action goes quiet once the day's registers are all
   taken: still there to press, no longer asking to be. */
.topbar-act.quiet-done { opacity: .72; }
.topbar-act.quiet-done:hover { opacity: 1; }
.topbar-act .tiny { opacity: .78; margin-left: 6px; font-size: 10.5px; letter-spacing: .04em; }

/* The stat figure at its smaller size, which several views were setting by
   hand alongside a colour. */
.card.stat .value.fig-sm { font-size: 22px; }

/* --- an exchange, read the way you read an email thread ------------------
   One row per exchange: subject once, the latest line showing, the whole of
   it when you open it. The gold edge marks the ones where the family spoke
   last and nobody has answered — the only rows on the page that are asking
   for something. */
.comm.thread { padding: 0; }
.thread-top { padding: 14px 16px; }
.thread-top.clickable { cursor: pointer; }
.thread-top.clickable:hover { background: var(--navy-50); }
.comm.thread.unanswered { border-left: 3px solid var(--gold); }
.thread-peek { margin: 0; color: var(--muted); overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.thread-body { border-top: 1px solid var(--line); background: var(--navy-50); }
.thread-msg { padding: 12px 16px; border-bottom: 1px solid var(--line); }
.thread-msg:last-child { border-bottom: 0; }
.thread-msg.in { background: var(--paper); box-shadow: inset 3px 0 0 var(--gold-300); }
.thread-act { padding: 10px 16px 14px; border-top: 1px solid var(--line); }

/* ==========================================================================
   Two things the heuristic audit asked for
   ========================================================================== */

/* --- Undo, in the toast that tells you what happened --------------------- */
.toast.with-undo { display: flex; align-items: center; gap: 16px; padding-right: 8px; }
.toast-undo {
  flex: none; background: none; border: 1px solid rgba(255,255,255,.45); color: #fff;
  font: inherit; font-weight: 700; font-size: 12px; letter-spacing: .08em; text-transform: uppercase;
  padding: 8px 14px; border-radius: 6px; cursor: pointer; min-height: 36px;
  transition: background-color .2s ease, border-color .2s ease;
}
.toast-undo:hover { background: rgba(255,255,255,.16); border-color: #fff; }
.toast-undo:focus-visible { outline: 2px solid var(--gold-300); outline-offset: 2px; }

/* --- Find: one box, top right, where everyone looks for it --------------- */
.find { position: relative; display: flex; align-items: center; }
.find > svg { position: absolute; left: 10px; width: 15px; height: 15px; color: var(--faint); pointer-events: none; }
.find .input { padding-left: 32px; padding-right: 30px; width: 236px; }
.find .input::-webkit-search-cancel-button { display: none; }
.find-clear {
  position: absolute; right: 6px; background: none; border: 0; cursor: pointer;
  color: var(--faint); display: grid; place-items: center; width: 24px; height: 24px; padding: 0;
}
.find-clear:hover { color: var(--navy); }
.find-clear svg { width: 13px; height: 13px; }

.find-menu {
  position: absolute; top: calc(100% + 6px); right: 0; width: min(380px, 84vw); z-index: 60;
  background: var(--paper); border: 1px solid var(--line-strong); border-radius: 10px;
  box-shadow: 0 18px 44px -18px rgba(12,27,46,.45); overflow: hidden; max-height: 60vh; overflow-y: auto;
}
.find-hit {
  display: grid; grid-template-columns: 74px 1fr; gap: 2px 10px; align-items: baseline;
  width: 100%; text-align: left; background: none; border: 0; cursor: pointer;
  padding: 11px 14px; border-bottom: 1px solid var(--line); font: inherit;
}
.find-hit:last-child { border-bottom: 0; }
.find-hit:hover, .find-hit:focus-visible { background: var(--navy-50); outline: none; }
.find-kind {
  grid-row: span 2; font-size: 9.5px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--gold-600); font-weight: 700; padding-top: 3px;
}
.find-name { font-weight: 700; font-size: 14px; color: var(--navy); }
.find-note { font-size: 12px; color: var(--muted); }
.find-empty { padding: 16px 14px; font-size: 13.5px; color: var(--muted); }

@media (max-width: 1100px) { .find .input { width: 170px; } }

/* Hiding it on a phone would remove it exactly where it earns its keep — a
   teacher at the classroom door with a parent in front of them. It shrinks
   to the icon instead, which reads as a button, and opens out when tapped. */
@media (max-width: 900px) {
  .find .input { width: 44px; padding-left: 30px; padding-right: 8px; transition: width .25s var(--e-quart, ease); }
  .find .input::placeholder { color: transparent; }
  .find:focus-within .input { width: min(62vw, 300px); }
  .find:focus-within .input::placeholder { color: var(--faint); }
  .find-menu { width: min(340px, 92vw); }
  .find-clear { display: none; }
}

/* --- a teacher's own registers, as the way in ----------------------------
   The class and the period together, because that pair is what a register
   is — and coloured by whether it is waiting, taken or missed, so the one
   that needs doing is the one that catches the eye. */
.mine-regs { display: flex; gap: 6px; flex-wrap: wrap; }
.mine-reg {
  display: grid; gap: 1px; text-align: left; cursor: pointer; font: inherit;
  padding: 7px 12px; background: var(--paper); border: 1px solid var(--line-strong);
  border-left-width: 3px; min-height: 44px;
}
.mine-reg .t { font-size: 10.5px; color: var(--muted); font-variant-numeric: tabular-nums; }
.mine-reg .c { font-size: 13px; font-weight: 700; color: var(--navy); line-height: 1.2; }
.mine-reg .s { font-size: 11px; color: var(--muted); }
.mine-reg:hover { background: var(--navy-50); }
.mine-reg.on { border-color: var(--navy); border-left-color: var(--navy); background: var(--navy-50); box-shadow: inset 0 0 0 1px var(--navy); }
.mine-reg.open { border-left-color: var(--gold); }
.mine-reg.done { border-left-color: var(--green); }
.mine-reg.missed { border-left-color: var(--red); }
.mine-reg.upcoming { border-left-color: var(--line-strong); }
