/* ==========================================================================
   Rosehill School - house style (remaster, September 2026)

   Primary: RAL 5020 Ocean Blue (#00414b). Supporting colours are sampled
   directly from the school crest. Typeface: Century Gothic.
   Loaded last: this layer re-themes styles.css / enhancements.css / revamp.css.

   The visual idea is the crest itself. Its shield is a landscape - sky, a
   river, green hills and the ground - so every public page opens on a teal
   banner whose lower edge is that landscape: layered waves in the crest's own
   colours, with the page flowing out from under them. The same banner, crest,
   title and waves exist on every public page, which is what lets the router
   morph one page into the next (see "View transitions" at the end).
   ========================================================================== */

:root {
  /* School colours */
  --ocean: #00414b;          /* RAL 5020 Ocean Blue */
  --ocean-deep: #002b33;
  --ocean-mid: #0b5b66;
  --ocean-tint: #e7f0f1;
  --ocean-wash: #f2f7f8;

  /* Sampled from the crest */
  --crest-teal: #156363;
  --crest-sky: #4d809b;
  --crest-green: #376f4c;
  --crest-grey: #686868;
  --crest-gold: #da9317;
  --gold-ink: #93620a;            /* gold for text on light: 5:1 on white */
  --gold-bright: #e8a32b;
  --gold-wash: #fdf4e3;

  /* Mapped onto the tokens the older stylesheets already use */
  --canvas: #f7f9f9;
  --paper: #f7f9f9;
  --surface-soft: var(--ocean-tint);
  --navy: var(--ocean);
  --navy-soft: var(--ocean-mid);
  --ink: #10282d;
  --teal: var(--ocean);
  --teal-hover: var(--ocean-deep);
  --teal-pale: var(--ocean-tint);
  --teal-deep: var(--ocean-deep);
  --aqua: #cfe2e5;
  --mint: var(--ocean-tint);
  --muted: #4a6167;
  --line: #d5e1e3;
  --line-strong: #a9c2c6;
  --gold: var(--crest-gold);
  --sun: var(--crest-gold);
  --coral: #b4566a;
  --white: #ffffff;
  --danger: #a42b1d;
  --success: #17623d;

  /* Shadows carry the ocean hue, and all fall from the same light above. */
  --shadow-sm: 0 1px 2px rgb(0 65 75 / 6%), 0 6px 18px rgb(0 65 75 / 6%);
  --shadow-md: 0 2px 4px rgb(0 65 75 / 4%), 0 20px 48px -12px rgb(0 65 75 / 16%);
  --shadow-lg: 0 4px 10px rgb(0 43 51 / 6%), 0 36px 80px -20px rgb(0 43 51 / 34%);
  --shadow: var(--shadow-md);

  /* Century Gothic, with geometric fallbacks for machines that lack it. */
  --font-school: "Century Gothic", Questrial, "URW Gothic", "Avant Garde",
                 Futura, "Avenir Next", Avenir, "Trebuchet MS",
                 ui-sans-serif, system-ui, sans-serif;
  --font-code: ui-monospace, "Cascadia Code", "SF Mono", Consolas, monospace;

  /* Layout. --inline-pad lines full-bleed bands up with the content column. */
  --content: 1200px;
  --gutter: 2.5rem;
  --inline-pad: max(var(--gutter), calc((100% - var(--content)) / 2));
  --header-h: 5.25rem;
  --tide-h: clamp(84px, 11vw, 168px);

  /* Motion. --press is re-pointed so the older layers move the same way. */
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
  --ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);
  --press: var(--ease-out);
  --page-morph: 640ms;

  /* Wave geometry. The three drifting bands tile seamlessly left to right. */
  --wave-sky: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1200 120' preserveAspectRatio='none'%3E%3Cpath d='M0 60C200 20 400 20 600 60S1000 100 1200 60V120H0Z'/%3E%3C/svg%3E");
  --wave-river: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1200 120' preserveAspectRatio='none'%3E%3Cpath d='M0 44C150 84 450 84 600 44S1050 4 1200 44V120H0Z'/%3E%3C/svg%3E");
  --wave-hill: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1200 120' preserveAspectRatio='none'%3E%3Cpath d='M0 70C300 40 900 100 1200 70V120H0Z'/%3E%3C/svg%3E");
  --wave-edge: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1200 120' preserveAspectRatio='none'%3E%3Cpath d='M0 78C180 50 380 44 600 66S980 104 1200 70V120H0Z'/%3E%3C/svg%3E");
  --wave-crown: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1200 60' preserveAspectRatio='none'%3E%3Cpath d='M0 0H1200V30C1000 58 780 10 560 32S160 56 0 22Z'/%3E%3C/svg%3E");
  /* Page-change wipes: the wave sits across the middle of a 2.2x-tall mask. */
  --tide-up: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 200' preserveAspectRatio='none'%3E%3Cpath d='M0 100C17 92 33 92 50 100S83 108 100 100V200H0Z'/%3E%3C/svg%3E");
  --tide-down: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 200' preserveAspectRatio='none'%3E%3Cpath d='M0 0H100V100C83 108 67 108 50 100S17 92 0 100Z'/%3E%3C/svg%3E");
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 .06 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E");
  --contour: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='44' viewBox='0 0 240 44'%3E%3Cpath d='M0 22C40 2 80 2 120 22S200 42 240 22' fill='none' stroke='%2300414b' stroke-opacity='.07' stroke-width='1.4'/%3E%3C/svg%3E");
  --chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5' fill='none' stroke='%2300414b' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  --tick: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4 8.4 6.8 11 12 5.2' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");

  /* The banner behind every page title. */
  --banner:
    var(--grain),
    radial-gradient(80% 90% at 100% 0%, rgb(11 91 102 / 95%) 0%, transparent 62%),
    radial-gradient(60% 80% at 0% 100%, rgb(21 99 99 / 45%) 0%, transparent 70%),
    linear-gradient(162deg, #00474f 0%, #00363f 52%, #002b33 100%);
}

/* --------------------------------------------------------------- typography */

html { scroll-behavior: smooth; }
html, body { background: var(--canvas); }
body {
  font-family: var(--font-school);
  color: var(--ink);
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  /* clip, not hidden: it stops a stray full-bleed layer from scrolling the
     page sideways without breaking the sticky header. */
  overflow-x: clip;
}
h1, h2, h3, h4, .brand, .button, button, input, select, textarea, label {
  font-family: var(--font-school);
}
/* Century Gothic runs wide and light: tighten display sizes, open up small caps. */
h1, h2, h3 { font-weight: 700; letter-spacing: -.02em; text-wrap: balance; }
p, li { text-wrap: pretty; }
.eyebrow { letter-spacing: .18em; font-weight: 700; color: var(--ocean-mid); }
a { color: var(--ocean); text-underline-offset: .22em; }
code, .reference-card code { font-variant-numeric: tabular-nums; }
::selection { background: rgb(218 147 23 / 28%); color: var(--ocean-deep); }
#app:focus { outline: none; }
.skip-link { z-index: 100; }

/* The older layers gave these their own entrances; motion now lives at the
   end of this file, in one place. */
.hero, .content-page, .how-steps, .form-panel, .tracking-panel, .outcomes, .workspace, .plt-main { animation: none; }

/* ------------------------------------------------------------------- banner */

.prototype-banner {
  background: var(--ocean-tint);
  color: var(--ocean);
  font-weight: 600;
  letter-spacing: .02em;
  border-bottom: 1px solid #cfe0e2;
  view-transition-name: rh-banner;
}

/* ------------------------------------------------------------------- header */

/* Full-bleed and sticky, with its content held to the page column. Frosted so
   the banner and pages read through it as they scroll underneath. */
.site-header {
  position: sticky;
  top: 0;
  z-index: 40;
  width: 100%;
  min-height: var(--header-h);
  margin: 0;
  padding-block: 0;
  padding-inline: var(--inline-pad);
  border-bottom: 0;
  background: rgb(247 249 249 / 84%);
  box-shadow: 0 1px 0 var(--line);
  -webkit-backdrop-filter: blur(16px) saturate(160%);
  backdrop-filter: blur(16px) saturate(160%);
  view-transition-name: rh-header;
}
.brand { gap: .85rem; color: var(--ocean); text-decoration: none; }
.brand::before { content: none; display: none; }   /* retires the old single-letter glyph */
.brand-crest {
  width: 3.25rem;
  height: 3.25rem;
  object-fit: contain;
  flex-shrink: 0;
}
/* Institutional lockup: school name above the name of the service. */
.brand .brand-lockup {
  display: grid;
  gap: .14rem;
  border-left: 0;
  padding-left: 0;
  margin-left: 0;
}
.brand .brand-lockup strong {
  color: var(--ocean);
  font-size: 1.12rem;
  font-weight: 700;
  letter-spacing: -.005em;
  line-height: 1.1;
}
.brand .brand-lockup > span {
  border-left: 0;
  padding-left: 0;
  margin-left: 0;
  color: var(--muted);
  font-size: .62rem;
  font-weight: 600;
  letter-spacing: .2em;
  line-height: 1.1;
  text-transform: uppercase;
}
.site-header nav { gap: .2rem; }
.site-header nav a {
  position: relative;
  color: var(--ink);
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  border-radius: .35rem;
  background: transparent;
}
.site-header nav a:hover { background: transparent; color: var(--ocean); transform: none; }
/* Hover rule draws out from the left and retracts to the right. */
.site-header nav a::after {
  content: "";
  position: absolute;
  right: .8rem;
  bottom: .55rem;
  left: .8rem;
  height: 1px;
  border-radius: 1px;
  background: var(--ocean);
  transform: scaleX(0);
  transform-origin: right center;
  transition: transform 260ms var(--ease-out);
}
.site-header nav a[aria-current="page"] { background: transparent; color: var(--ocean); box-shadow: none; border-radius: .35rem; }
.site-header nav a[aria-current="page"]::after,
.site-header nav a.nav-signin::after { content: none; }
@media (hover: hover) and (pointer: fine) {
  .site-header nav a:hover::after { transform: scaleX(1); transform-origin: left center; }
}
/* The current page's gold mark. It is a real element, so it can carry a
   view-transition-name and glide between links when the page changes. */
.nav-mark {
  position: absolute;
  right: .8rem;
  bottom: .4rem;
  left: .8rem;
  height: 2px;
  border-radius: 2px;
  background: var(--crest-gold);
  pointer-events: none;
  view-transition-name: rh-nav-mark;
}
.site-header nav a.nav-signin {
  margin-left: .5rem;
  border: 1px solid var(--ocean);
  border-radius: .45rem;
  color: var(--ocean);
}
.site-header nav a.nav-signin .nav-mark { right: 0; bottom: -.55rem; left: 0; }
.site-header nav a.nav-signin:hover { background: var(--ocean); color: #fff; box-shadow: none; }
.nav-signin > span[aria-hidden="true"] { display: inline-block; transition: transform 220ms var(--ease-out); }
@media (hover: hover) and (pointer: fine) {
  .nav-signin:hover > span[aria-hidden="true"] { transform: translate(2px, -2px); }
}

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

/* Institutional geometry: modest radii instead of full pills. */
.button, button {
  min-height: 48px;
  gap: .55rem;
  border-radius: .55rem;
  padding: .8rem 1.3rem;
  font-size: .86rem;
  font-weight: 700;
  letter-spacing: .01em;
}
.button span[aria-hidden="true"] { display: inline-block; margin-left: 0; font-size: 1.05em; transition: transform 220ms var(--ease-out); }
input, select, textarea { border-radius: .55rem; }
.button:not(.button-secondary):not(.button-danger),
button[type="submit"]:not(.button-secondary):not(.button-danger) {
  background: var(--ocean);
  border: 1px solid var(--ocean);
  color: #fff;
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 12%), 0 10px 22px -10px rgb(0 65 75 / 55%);
}
.button:not(.button-secondary):not(.button-danger):hover,
button[type="submit"]:not(.button-secondary):not(.button-danger):hover {
  background: var(--ocean-deep);
  border-color: var(--ocean-deep);
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 10%), 0 14px 26px -10px rgb(0 43 51 / 60%);
}
.button-secondary { color: var(--ocean); border: 1px solid var(--line-strong); background: #fff; box-shadow: none; }
.button-secondary:hover { border-color: var(--ocean); background: var(--ocean-tint); color: var(--ocean); }
:focus-visible { outline: 3px solid var(--crest-gold); outline-offset: 2px; }

/* A submit that is working stays fully visible and says so, instead of
   greying out as if it had been refused. */
button.is-busy:disabled,
button.is-busy:disabled:hover { opacity: 1; cursor: progress; }
button.is-busy::after {
  content: "";
  width: .95rem;
  height: .95rem;
  flex: 0 0 auto;
  border: 2px solid rgb(255 255 255 / 35%);
  border-top-color: #fff;
  border-radius: 50%;
}

/* -------------------------------------------------------- the teal banner */

/* Home hero and page banners share one construction. Both are full-bleed,
   with their content held to the page column by --inline-pad. */
main#main-content.pupil-home,
main#main-content.info-page,
main#main-content.revamped-auth {
  width: 100%;
  max-width: none;
  margin: 0;
  padding: 0;
  display: block;
}
.pupil-home .hero,
.page-hero {
  position: relative;
  isolation: isolate;
  overflow: clip;
  margin: 0;
  border: 0;
  border-radius: 0;
  background: var(--banner);
  background-size: 180px 180px, auto, auto, auto;
  color: #e3eff1;
  box-shadow: none;
  view-transition-name: rh-hero;
}
.pupil-home .hero {
  display: grid;
  grid-template-columns: minmax(0, 1.08fr) minmax(0, .82fr);
  align-items: center;
  gap: clamp(2rem, 5vw, 5rem);
  min-height: clamp(36rem, 80svh, 48rem);
  padding: clamp(3.5rem, 7vw, 6rem) var(--inline-pad) calc(var(--tide-h) + clamp(2.5rem, 5vw, 4rem));
}
.hero-copy, .crest-panel, .page-hero-copy, .page-hero-crest { position: relative; z-index: 1; }

.hero p.eyebrow, .page-hero p.eyebrow {
  margin: 0;
  color: #b7d3d8;
  font-size: .68rem;
  letter-spacing: .2em;
}
.hero p.eyebrow::after, .page-hero p.eyebrow::after {
  content: "";
  display: block;
  width: 2.5rem;
  height: 2px;
  margin-top: .85rem;
  background: var(--crest-gold);
  transform-origin: left center;
}
/* A measured display size: institutional rather than promotional. */
.hero h1 {
  max-width: 13ch;
  margin: 1.2rem 0 1.35rem;
  color: #fff;
  font-size: clamp(2.6rem, 5.2vw, 4.5rem);
  font-weight: 700;
  line-height: 1.05;
  letter-spacing: -.03em;
  view-transition-name: rh-title;
}
/* Each line rises out of its own slot on arrival. The padding keeps
   descenders inside the clip once the line has settled. */
.hero h1 .line { display: block; overflow: clip; padding-bottom: .1em; margin-bottom: -.1em; }
.hero h1 .line > * { display: inline-block; }
.hero h1 em, .page-hero h1 em {
  font-family: var(--font-school);
  font-style: normal;
  font-weight: 700;
  color: var(--gold-bright);
}
.hero .lead { max-width: 38ch; margin: 0 0 1.9rem; color: #c4dcdf; font-size: clamp(1rem, 1.3vw, 1.1rem); line-height: 1.7; }
.hero p.hero-caption { margin: 1.1rem 0 0; color: #93b6bd; font-size: .78rem; }

/* Gold on the banner. Specificity must beat the global primary-button rule. */
:is(.pupil-home .hero, .page-hero) .button:not(.button-secondary):not(.button-danger) {
  background: var(--crest-gold);
  color: var(--ocean-deep);
  border: 1px solid var(--crest-gold);
  box-shadow: 0 12px 26px -12px rgb(218 147 23 / 70%);
}
:is(.pupil-home .hero, .page-hero) .button:not(.button-secondary):not(.button-danger):hover {
  background: var(--gold-bright);
  border-color: var(--gold-bright);
}
:is(.pupil-home .hero, .page-hero) .button-secondary {
  background: rgb(255 255 255 / 4%);
  color: #eaf3f4;
  border: 1px solid rgb(234 243 244 / 38%);
}
:is(.pupil-home .hero, .page-hero) .button-secondary:hover { background: rgb(255 255 255 / 10%); border-color: #eaf3f4; color: #fff; }

/* Crest: it sits on white, the way it does on a blazer, in front of a low
   gold sun (the rose on the shield) inside a single drawn gold ring. */
.crest-panel { display: grid; justify-items: center; gap: .85rem; }
.crest-stage {
  position: relative;
  display: grid;
  place-items: center;
  width: clamp(13.5rem, 23vw, 18.5rem);
  aspect-ratio: 1;
  view-transition-name: rh-crest;
}
.crest-sun {
  position: absolute;
  inset: -24%;
  border-radius: 50%;
  background: radial-gradient(circle, rgb(232 163 43 / 32%) 0%, rgb(218 147 23 / 12%) 36%, transparent 66%);
  pointer-events: none;
}
.crest-ring { position: absolute; inset: -8%; width: 116%; height: 116%; overflow: visible; }
.crest-ring circle {
  fill: none;
  stroke: var(--crest-gold);
  stroke-width: .9;
  stroke-dasharray: 1;
  stroke-dashoffset: 0;
  opacity: .9;
}
.crest-medallion {
  position: relative;
  display: grid;
  place-items: center;
  width: 100%;
  aspect-ratio: 1;
  padding: 13%;
  border-radius: 50%;
  background: #fff;
  box-shadow:
    0 0 0 1px rgb(255 255 255 / 20%),
    0 0 0 .6rem rgb(255 255 255 / 6%),
    0 34px 64px -18px rgb(0 18 22 / 60%);
}
.crest-medallion img { width: 100%; height: 100%; object-fit: contain; }
.hero .crest-name {
  margin: .5rem 0 0;
  color: #fff;
  font-size: 1.15rem;
  font-weight: 700;
  letter-spacing: .02em;
}
.hero .crest-estd {
  margin: 0;
  color: #bcd8dd;
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .22em;
  text-transform: uppercase;
}

/* The tide: sky, river and hills from the crest, drifting at their own pace,
   then the page itself as a still wave that every banner flows out from. */
.tide {
  position: absolute;
  right: 0;
  bottom: -1px;
  left: 0;
  z-index: 0;
  height: var(--tide-h);
  pointer-events: none;
  transform-origin: 50% 100%;
  view-transition-name: rh-tide;
}
.tide > span { position: absolute; bottom: 0; left: 0; display: block; background: currentColor; }
.tide-wave { width: 200%; }
.tide-sky {
  height: 100%;
  color: rgb(77 128 155 / 32%);
  -webkit-mask: var(--wave-sky) 0 100% / 25% 100% repeat-x;
  mask: var(--wave-sky) 0 100% / 25% 100% repeat-x;
}
.tide-river {
  height: 74%;
  color: rgb(21 99 99 / 90%);
  -webkit-mask: var(--wave-river) 0 100% / 50% 100% repeat-x;
  mask: var(--wave-river) 0 100% / 50% 100% repeat-x;
}
.tide-hill {
  height: 46%;
  color: var(--crest-green);
  -webkit-mask: var(--wave-hill) 0 100% / 25% 100% repeat-x;
  mask: var(--wave-hill) 0 100% / 25% 100% repeat-x;
}
/* The crest outlines each band in white; the foam is that outline. */
.tide-foam, .tide-edge {
  width: 100%;
  height: 30%;
  -webkit-mask: var(--wave-edge) 0 100% / 100% 100% no-repeat;
  mask: var(--wave-edge) 0 100% / 100% 100% no-repeat;
}
.tide > .tide-foam { bottom: 7px; color: rgb(247 249 249 / 40%); }
.tide-edge { color: var(--canvas); }

/* Page banners: the same construction at a smaller scale. */
.page-hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 2rem clamp(2rem, 6vw, 5rem);
  padding: clamp(2.6rem, 5vw, 4rem) var(--inline-pad) calc(var(--tide-h) + clamp(1.6rem, 3vw, 2.4rem));
}
.page-hero h1 {
  max-width: 20ch;
  margin: 1rem 0 .9rem;
  color: #fff;
  font-size: clamp(2.2rem, 4.2vw, 3.4rem);
  line-height: 1.08;
  letter-spacing: -.028em;
  view-transition-name: rh-title;
}
.page-hero .lead { max-width: 48ch; margin: 0; color: #c4dcdf; font-size: clamp(.98rem, 1.3vw, 1.08rem); line-height: 1.7; }
.page-hero .hero-actions { margin-top: 1.8rem; }
.page-hero-crest .crest-stage { width: clamp(7.5rem, 12vw, 10.5rem); }
.page-hero-crest .crest-medallion { box-shadow: 0 0 0 1px rgb(255 255 255 / 20%), 0 0 0 .4rem rgb(255 255 255 / 6%), 0 24px 44px -16px rgb(0 18 22 / 60%); }

/* --------------------------------------------------------------- page body */

.pupil-home > .safety-strip,
.pupil-home > .how-steps,
.pupil-home > .panel,
.info-body,
.auth-layout {
  width: min(100% - 2 * var(--gutter), var(--content));
  margin-inline: auto;
}

/* The safety note floats over the banner's lower edge, so it is the first
   thing read after the headline. */
.pupil-home .safety-strip {
  position: relative;
  z-index: 2;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 1rem 1.6rem;
  margin-top: calc(var(--tide-h) * -.5);
  padding: 1.35rem 1.6rem;
  background: #fffdf8;
  border: 1px solid #f0dcb4;
  border-left: 4px solid var(--crest-gold);
  border-radius: .8rem;
  box-shadow: var(--shadow-md);
  view-transition-name: rh-safety;
}
.safety-icon { width: 1.9rem; height: 1.9rem; fill: none; stroke: #b97a0d; stroke-width: 1.7; stroke-linecap: round; }
.safety-strip .eyebrow { margin: 0 0 .3rem; color: #8a5b0b; }
.safety-strip p:not(.eyebrow) { margin: 0; color: #4f4a3f; font-size: .82rem; max-width: 92ch; }
.safety-strip > a { flex-shrink: 0; color: var(--ocean); font-size: .8rem; font-weight: 700; }

/* How it works: three stations on one line, drawn in as it scrolls into view. */
.how-steps {
  display: grid;
  grid-template-columns: minmax(0, .62fr) minmax(0, 2fr);
  align-items: start;
  gap: 2rem clamp(2rem, 5vw, 4.5rem);
  padding: clamp(3.5rem, 7vw, 5.5rem) 0 clamp(2.5rem, 5vw, 4rem);
  border-top: 0;
}
.how-intro .eyebrow { margin: .6rem 0 .5rem; }
.how-steps h2 { margin: 0; color: var(--ocean); font-size: clamp(1.6rem, 2.6vw, 2.1rem); letter-spacing: -.02em; }
.how-steps ol {
  position: relative;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.how-steps ol::before {
  content: "";
  position: absolute;
  top: 1.35rem;
  left: 1.4rem;
  right: calc((100% - 3rem) / 3 - 1.4rem);
  height: 2px;
  background: linear-gradient(90deg, var(--ocean), var(--crest-teal) 55%, var(--crest-gold));
  transform-origin: left center;
}
.how-steps li,
.how-steps li:first-child {
  position: relative;
  min-height: 0;
  display: grid;
  align-content: start;
  gap: .4rem;
  padding: 0;
  border: 0;
}
.how-steps .step-num {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 2.8rem;
  height: 2.8rem;
  margin-bottom: .7rem;
  border: 2px solid var(--ocean);
  border-radius: 50%;
  background: var(--canvas);
  color: var(--ocean);
  font-size: .76rem;
  font-weight: 700;
  letter-spacing: .06em;
  font-variant-numeric: tabular-nums;
}
.how-steps li:last-child .step-num { border-color: var(--crest-gold); background: var(--crest-gold); color: var(--ocean-deep); }
.how-steps strong { color: var(--ocean); font-size: 1.15rem; font-weight: 700; }
.how-steps strong::before { content: none; display: none; }
.how-steps li > span:last-child { color: var(--muted); font-size: .9rem; max-width: 28ch; }

/* Panels. Containers get the softer radius; the fields inside stay tighter. */
.panel { background: #fff; border: 1px solid var(--line); border-radius: 1.1rem; }
.pupil-home > .panel { margin-bottom: clamp(1.5rem, 3vw, 2rem); }
.pupil-home .form-panel {
  display: grid;
  grid-template-columns: minmax(0, .78fr) minmax(0, 1.22fr);
  gap: 0 clamp(2rem, 5vw, 4.5rem);
  padding: clamp(1.6rem, 4vw, 3.2rem);
  box-shadow: var(--shadow-md);
}
/* The brief stays beside the form while a pupil works down it. */
.form-panel .form-intro { position: sticky; top: calc(var(--header-h) + 2rem); align-self: start; }
.form-panel h2, .tracking-panel h2 { color: var(--ocean); font-size: clamp(1.9rem, 3.2vw, 2.6rem); letter-spacing: -.025em; }
.form-panel .writing-tip > span { color: var(--crest-gold); }
.form-intro .eyebrow, .tracking-panel .eyebrow, .outcomes .eyebrow, .poll-panel .eyebrow { color: var(--ocean-mid); }

label { color: var(--ink); font-size: .84rem; font-weight: 700; }
label small { color: var(--muted); font-weight: 500; }
input, select, textarea {
  min-height: 50px;
  padding: .8rem .95rem;
  background: #fff;
  border: 1px solid var(--line-strong);
  color: var(--ink);
  transition: border-color 160ms ease, box-shadow 220ms var(--ease-out), background-color 160ms ease;
}
input:hover, select:hover, textarea:hover { border-color: #7fa3a9; }
input:focus, select:focus, textarea:focus {
  border-color: var(--ocean);
  box-shadow: 0 0 0 4px rgb(0 65 75 / 12%);
  outline: none;
}
input:user-invalid, textarea:user-invalid, select:user-invalid { border-color: var(--danger); }
input:user-invalid:focus, textarea:user-invalid:focus { box-shadow: 0 0 0 4px rgb(164 43 29 / 12%); }
::placeholder { color: #6b8489; }
textarea { min-height: 9rem; line-height: 1.55; }
select {
  -webkit-appearance: none;
  appearance: none;
  padding-right: 2.6rem;
  background-image: var(--chevron);
  background-repeat: no-repeat;
  background-position: right 1rem center;
  background-size: .75rem;
  cursor: pointer;
}

/* The confirmation box: a real checkbox, drawn in the house style. */
.check {
  grid-template-columns: auto 1fr;
  gap: .8rem;
  padding: .95rem 1rem;
  background: var(--ocean-wash);
  border: 1px solid var(--line);
  border-radius: .7rem;
  font-size: .84rem;
  font-weight: 600;
  line-height: 1.55;
  cursor: pointer;
}
.check input {
  -webkit-appearance: none;
  appearance: none;
  display: grid;
  place-content: center;
  width: 1.3rem;
  height: 1.3rem;
  min-height: 1.3rem;
  margin: .1rem 0 0;
  padding: 0;
  border: 1.5px solid var(--ocean);
  border-radius: .35rem;
  background: #fff;
  cursor: pointer;
  transition: background-color 160ms ease, border-color 160ms ease;
}
.check input::before {
  content: "";
  width: .8rem;
  height: .8rem;
  background: var(--tick) center / contain no-repeat;
  transform: scale(0);
  transition: transform 200ms var(--ease-out);
}
.check input:checked { background: var(--ocean); border-color: var(--ocean); }
.check input:checked::before { transform: scale(1); }
.check input:focus { box-shadow: none; }
.check input:focus-visible { outline: 3px solid var(--crest-gold); outline-offset: 2px; }
.privacy-note { color: var(--muted); }

/* Honeypot: off-screen rather than display:none, so bots that check for
   visibility still fill it in. Never reachable by keyboard or screen reader. */
.hp-field {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}
.human-check-note {
  margin: 0 0 1rem;
  color: var(--muted);
  font-size: .73rem;
  line-height: 1.6;
}

/* Tracking: the private side of the service, on a quiet tint with the
   crest's river drawn faintly across it. */
.pupil-home .tracking-panel {
  padding: clamp(1.6rem, 4vw, 3rem);
  background: var(--contour) 0 0 / 240px 44px, var(--ocean-tint);
  border-color: #cfe0e2;
}
.tracking-panel > p:not(.eyebrow) { max-width: 60ch; }
.tracking-panel input { background: #fff; font-family: var(--font-code); letter-spacing: .03em; }
.tracking-panel form > .button { min-height: 50px; }

.track-card {
  margin-top: 1.4rem;
  padding: 1.4rem 1.5rem 1.3rem;
  background: #fff;
  border: 1px solid var(--line);
  border-left: 4px solid var(--ocean);
  border-radius: .8rem;
  box-shadow: var(--shadow-sm);
}
.track-card h3 { margin: .1rem 0 1.1rem; color: var(--ocean); font-size: 1.45rem; }
.track-card > p:not(.eyebrow) { margin: 1rem 0 .4rem; max-width: 62ch; }
.track-card small { color: var(--muted); }

/* Progress rail: four stations joined by a line that fills to the current one. */
.track-rail {
  position: relative;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  margin: 0;
  padding: 0;
  list-style: none;
}
.track-rail::before,
.track-rail::after {
  content: "";
  position: absolute;
  top: .5rem;
  left: .55rem;
  right: calc(25% - .55rem);
  height: 2px;
  background: var(--line);
}
.track-rail::after { background: var(--ocean); transform-origin: left center; transform: scaleX(0); }
.track-rail[data-step="1"]::after { transform: scaleX(.3334); }
.track-rail[data-step="2"]::after { transform: scaleX(.6667); }
.track-rail[data-step="3"]::after { transform: scaleX(1); }
.track-rail li { position: relative; display: grid; gap: .5rem; padding-right: .5rem; }
.track-rail li::before {
  content: "";
  position: relative;
  z-index: 1;
  width: 1.1rem;
  height: 1.1rem;
  border: 2px solid var(--line-strong);
  border-radius: 50%;
  background: #fff;
}
.track-rail li.is-done::before { border-color: var(--ocean); background: var(--ocean) var(--tick) center / 70% no-repeat; }
.track-rail li.is-current::before { border-color: var(--crest-gold); background: var(--crest-gold); }
.track-rail li.is-current::after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 1.1rem;
  height: 1.1rem;
  border-radius: 50%;
  border: 2px solid var(--crest-gold);
  opacity: 0;
}
.track-rail li span { color: var(--muted); font-size: .74rem; font-weight: 700; line-height: 1.3; }
.track-rail li.is-done span, .track-rail li.is-current span { color: var(--ink); }
.track-rail[data-step="closed"] li::before { border-color: var(--line-strong); background: var(--ocean-wash); }

/* ---------------------------------------------------------------- polls */

.poll-panel { border-left: 4px solid var(--crest-gold); }
.poll-panel h3 { margin: .2rem 0 .4rem; font-size: 1.35rem; color: var(--ocean); }
.poll-summary { color: var(--muted); font-size: .9rem; margin: 0 0 1.2rem; max-width: 60ch; }
.poll-options {
  display: flex;
  flex-wrap: wrap;
  gap: .6rem;
  margin: 1rem 0;
}
.poll-option {
  min-height: 48px;
  padding: .75rem 1.15rem;
  border: 1px solid var(--line-strong);
  border-radius: .55rem;
  background: #fff;
  color: var(--ink);
  font-size: .88rem;
  font-weight: 650;
  box-shadow: none;
  cursor: pointer;
}
.poll-option:hover:not(:disabled) { border-color: var(--ocean); background: var(--ocean-tint); color: var(--ocean); }
.poll-option:disabled { opacity: .55; cursor: default; }
.poll-option.is-chosen {
  border-color: var(--ocean);
  background: var(--ocean);
  color: #fff;
  opacity: 1;
}
.poll-option.is-chosen::before { content: "✓"; content: "✓" / ""; margin-right: .1rem; }
.poll-status { margin: .6rem 0 0; color: var(--muted); font-size: .8rem; }
.poll-result {
  margin-top: 1.4rem;
  padding-top: 1.2rem;
  border-top: 1px solid var(--line);
}
.poll-result p:not(.eyebrow) { margin: 0; color: var(--ink); font-size: .92rem; }

/* Administrator tally view */
.poll-admin-card {
  margin-top: 1.2rem;
  padding: 1.2rem;
  border: 1px solid var(--line);
  border-radius: .5rem;
  background: var(--ocean-wash);
}
.poll-admin-card h3 { margin: 0 0 .2rem; font-size: 1.05rem; color: var(--ocean); }
.poll-tally { list-style: none; margin: .9rem 0; padding: 0; display: grid; gap: .5rem; }
.poll-tally li {
  display: grid;
  grid-template-columns: minmax(6rem, 12rem) 1fr auto auto;
  align-items: center;
  gap: .75rem;
  font-size: .85rem;
}
.poll-tally-label { font-weight: 600; }
.poll-tally-bar { height: .5rem; border-radius: .25rem; background: var(--ocean-tint); overflow: hidden; }
.poll-tally-bar > span { display: block; height: 100%; background: var(--crest-gold); }
.poll-publish-form { margin-top: .9rem; }

/* ------------------------------------------------------------- outcomes */

.pupil-home .panel.outcomes {
  margin-top: clamp(2rem, 5vw, 3rem);
  padding: clamp(2.5rem, 5vw, 3.5rem) 0 0;
  background: transparent;
  border: 0;
  border-top: 1px solid var(--line);
  border-radius: 0;
  box-shadow: none;
}
.outcomes h2 { margin-top: 0; color: var(--ocean); font-size: clamp(1.9rem, 3.4vw, 2.6rem); letter-spacing: -.025em; }
#outcome-list { grid-template-columns: repeat(auto-fill, minmax(min(17rem, 100%), 1fr)); gap: 1rem; margin-top: 1.6rem; }
.outcome-card {
  margin: 0;
  padding: 1.4rem 1.4rem 1.25rem;
  background: #fff;
  border: 1px solid var(--line);
  border-top: 3px solid var(--crest-gold);
  border-radius: .9rem;
  box-shadow: var(--shadow-sm);
}
.outcome-card h3 { margin: 0 0 .5rem; color: var(--ocean); font-size: 1.15rem; }
.outcome-card p { margin: 0 0 .9rem; color: var(--ink); font-size: .92rem; }
.outcome-card small { color: var(--muted); font-size: .74rem; font-weight: 600; }
/* Empty, loading and error states share one composed block rather than a
   bare line of grey text. */
#outcome-list > p {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: 1rem;
  margin: 0;
  padding: 1.3rem 1.5rem;
  border: 1px dashed var(--line-strong);
  border-radius: .9rem;
  background: var(--ocean-wash);
  color: var(--muted);
  font-size: .9rem;
}
#outcome-list > p::before {
  content: "";
  flex: 0 0 auto;
  width: 2.4rem;
  height: 2.4rem;
  border-radius: 50%;
  background: radial-gradient(circle, var(--crest-gold) 0 28%, transparent 30%), var(--gold-wash);
  box-shadow: inset 0 0 0 1px #f0dcb4;
}

/* Success: the reference is the one thing a pupil must keep. */
/* It replaces the form inside the two-column panel, so it spans both columns
   and centres itself (the panel's first child was capped at 48rem, which
   pushed the card off-centre). */
.pupil-home .form-panel > .reference-card {
  grid-column: 1 / -1;
  justify-self: center;
  width: min(100%, 44rem);
  max-width: none;
}
.reference-card { text-align: center; padding: clamp(.5rem, 2vw, 1.5rem) 0; }
.reference-card h2 { color: var(--ocean); }
.reference-card > p:not(.eyebrow) { max-width: 52ch; margin-inline: auto; color: var(--muted); }
.reference-card code {
  position: relative;
  padding: 1.1rem 1.3rem;
  border-radius: .8rem;
  background: var(--ocean);
  color: #fff;
  font-family: var(--font-code);
  font-size: clamp(.85rem, 2.2vw, 1.05rem);
  font-weight: 700;
  letter-spacing: .06em;
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / 10%), 0 18px 40px -14px rgb(0 65 75 / 55%);
}
.reference-card code::after {
  content: "";
  position: absolute;
  inset: -6px;
  border: 2px solid var(--crest-gold);
  border-radius: 1rem;
  opacity: 0;
  pointer-events: none;
}

/* ------------------------------------------------------ information page */

main#main-content.info-page { padding-bottom: 1rem; }
.info-body {
  display: grid;
  grid-template-columns: minmax(0, .8fr) minmax(0, 1.2fr);
  align-items: start;
  gap: clamp(2rem, 6vw, 5.5rem);
  margin-top: clamp(1.5rem, 4vw, 3rem);
}
.info-summary {
  position: sticky;
  top: calc(var(--header-h) + 1.5rem);
  padding: clamp(1.4rem, 3vw, 2.2rem);
  background: var(--contour) 0 0 / 240px 44px, var(--ocean-tint);
  border: 1px solid #cfe0e2;
  border-radius: 1.1rem;
}
.info-summary h2 { margin: 0 0 1.1rem; color: var(--ocean); font-size: 1.35rem; line-height: 1.25; }
.info-summary ul { display: grid; gap: .9rem; margin: 0; padding: 0; list-style: none; }
.info-summary li { position: relative; padding-left: 2rem; font-size: .92rem; line-height: 1.6; }
.info-summary li::before {
  content: "";
  position: absolute;
  top: .2em;
  left: 0;
  width: 1.2rem;
  height: 1.2rem;
  border-radius: 50%;
  background: var(--ocean) var(--tick) center / 72% no-repeat;
}
.info-item {
  display: grid;
  grid-template-columns: 3.2rem minmax(0, 1fr);
  column-gap: 1rem;
  padding: 1.7rem 0;
  border-top: 1px solid var(--line);
}
.info-item:first-child { padding-top: .2rem; border-top: 0; }
.info-num {
  grid-row: span 2;
  padding-top: .45rem;
  color: var(--gold-ink);
  font-size: .8rem;
  font-weight: 700;
  letter-spacing: .14em;
  font-variant-numeric: tabular-nums;
}
.info-item h2 { margin: 0 0 .45rem; color: var(--ocean); font-size: 1.3rem; line-height: 1.25; letter-spacing: -.012em; }
.info-item p { margin: 0; max-width: 62ch; color: var(--muted); }
.info-cta { display: flex; flex-wrap: wrap; gap: .75rem; padding-top: 2rem; border-top: 1px solid var(--line); }
.not-found .page-hero { min-height: min(34rem, 62svh); }

/* ---------------------------------------------------------- sign-in page */

.revamped-auth .page-hero { padding-bottom: calc(var(--tide-h) + 6.5rem); }
.auth-back {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  min-height: 44px;
  margin: 0 0 .9rem;
  color: #cfe2e5;
  font-size: .8rem;
  font-weight: 600;
  text-decoration: none;
}
.auth-back:hover { color: #fff; text-decoration: underline; }
.auth-layout {
  display: grid;
  grid-template-columns: minmax(0, .85fr) minmax(0, 1.15fr);
  align-items: start;
  gap: clamp(2rem, 6vw, 5rem);
  max-width: 1100px;
}
.auth-purpose { display: flex; gap: 1rem; margin: 0; padding-top: 2.4rem; border-top: 0; }
.auth-purpose > span { color: var(--crest-gold); font-size: 2rem; line-height: 1; }
.auth-purpose p { margin: 0; color: var(--muted); font-size: .88rem; max-width: 34ch; }
.auth-purpose strong { color: var(--ink); }
/* The card rises out of the banner; it carries its own transition name so it
   is never hidden behind the banner while the page is changing. */
.auth-page .auth-card {
  position: relative;
  z-index: 2;
  margin: calc(-1 * (6.5rem + var(--tide-h) * .6)) 0 0;
  background: #fff;
  border: 1px solid var(--line);
  box-shadow: var(--shadow-lg);
  view-transition-name: rh-card;
}
.auth-card h2 { color: var(--ocean); }
.password-toggle { color: var(--ocean); }

/* Loading the workspace: a quiet indeterminate bar, not a spinner. */
.workspace-loading { position: relative; overflow: hidden; }
.loading-bar {
  position: absolute;
  top: 0;
  right: 0;
  left: 0;
  height: 3px;
  background: linear-gradient(90deg, transparent, var(--crest-gold), transparent);
  transform: translateX(-100%);
}

/* ------------------------------------------------------------------- footer */

/* The footer mirrors the banner: the page's wave now arches over it. */
.footer {
  position: relative;
  margin-top: clamp(4rem, 8vw, 6.5rem);
  padding: calc(clamp(40px, 5vw, 64px) + 2.4rem) 0 2.2rem;
  background: var(--banner);
  background-size: 180px 180px, auto, auto, auto;
  color: #cfe2e5;
  border-top: 0;
}
.footer::before {
  content: "";
  position: absolute;
  top: -1px;
  right: 0;
  left: 0;
  height: clamp(40px, 5vw, 64px);
  background: var(--canvas);
  -webkit-mask: var(--wave-crown) 0 0 / 100% 100% no-repeat;
  mask: var(--wave-crown) 0 0 / 100% 100% no-repeat;
}
.footer .shell {
  width: min(100% - 2 * var(--gutter), var(--content));
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: 1.2rem 3rem;
}
.footer .footer-identity { display: flex; align-items: center; gap: 1rem; }
.footer .footer-crest { width: 3.6rem; height: 3.6rem; object-fit: contain; flex-shrink: 0; }
.footer .footer-school {
  margin: 0;
  color: #fff;
  font-size: 1.08rem;
  font-weight: 700;
  letter-spacing: -.005em;
}
.footer .footer-service {
  margin: .2rem 0 0;
  color: #9fbfc5;
  font-size: .64rem;
  font-weight: 600;
  letter-spacing: .18em;
  text-transform: uppercase;
}
.footer .footer-links {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: .5rem 1.8rem;
}
.footer .footer-links a {
  color: #cfe2e5;
  font-size: .78rem;
  font-weight: 600;
  text-decoration: none;
}
.footer .footer-links a:hover { color: #fff; text-decoration: underline; text-underline-offset: .2em; }
.footer .footer-note {
  grid-column: 1 / -1;
  margin: .4rem 0 0;
  padding-top: 1.4rem;
  border-top: 1px solid rgb(207 226 229 / 16%);
  color: #8bb0b7;
  font-size: .73rem;
  font-weight: 500;
  line-height: 1.7;
  max-width: 92ch;
}

/* ------------------------------------------------- destructive admin actions */

.button-small {
  min-height: 38px;
  padding: .45rem .8rem;
  font-size: .76rem;
}
.code-list article .button-small { margin-top: .5rem; }
.idea-danger {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .6rem 1rem;
  margin-top: 1.2rem;
  padding-top: 1rem;
  border-top: 1px solid var(--line);
}
.idea-danger .small-print { color: var(--muted); }
/* The ballot card is a flex row; keep its actions in their own column so a
   second button does not fight the content for width. */
.ballot-actions {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: .5rem;
  flex-shrink: 0;
}
.member-access { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; justify-content: flex-end; }

/* ------------------------------------------------ roles, codes, view switch */

.code-role {
  display: inline-block;
  margin-top: .35rem;
  padding: .12rem .5rem;
  border-radius: .3rem;
  font-size: .62rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
}
.code-role[data-role="standard"] { background: var(--ocean-tint); color: var(--ocean); }
/* An administrator code grants access to every private submission: make it
   visually unmistakable in the list so it is never handed out by accident. */
.code-role[data-role="admin"] { background: #fbe4df; color: #8d2a22; }
.code-list article.code-admin { border-left: 3px solid #a42b1d; padding-left: .7rem; }

.nav-view-pupil { margin-left: auto; color: var(--ocean-mid) !important; }

.staff-preview-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: .4rem 1.2rem;
  padding: .5rem 1rem;
  background: var(--ocean-deep);
  color: #cfe2e5;
  font-size: .76rem;
  font-weight: 600;
}
.staff-preview-bar a { color: #fff; font-weight: 700; text-underline-offset: .2em; }

/* Every delete is confirmed by typing a phrase, so the dialog needs room. */
.confirmation-dialog label { display: block; margin: 1rem 0; }
.confirmation-dialog input[name="confirmation"] { width: 100%; }

/* --------------------------------------------------- auth + staff workspace */

/* Workspace headings were inheriting the public display scale: a tool-panel h2
   rendered at ~60px, nearly as large as the page title. Scope a calmer scale to
   the staff workspace only, so the public pages keep their larger headings. */
.workspace .workspace-head h1,
.plt-main .workspace-head h1,
.workspace > h1,
.plt-main > h1 {
  font-size: clamp(1.9rem, 3vw, 2.4rem);
  line-height: 1.16;
  letter-spacing: -.025em;
}
.workspace .panel h2,
.plt-main .panel h2 {
  font-size: 1.35rem;
  line-height: 1.25;
  letter-spacing: -.012em;
}
.workspace .panel h3,
.plt-main .panel h3 { font-size: 1.02rem; }
.workspace .workspace-head > div > p:not(.eyebrow) { color: var(--muted); font-size: .9rem; }
.auth-page > .panel h1 { max-width: 20ch; color: var(--ocean); font-size: clamp(1.9rem, 3.4vw, 2.6rem); }

/* Pupil-entered text is untrusted input and can be one unbroken string - a long
   word, a pasted URL, or keyboard mashing. Flex children default to
   min-width:auto, so such a string refused to shrink and pushed the whole staff
   workspace into horizontal scroll. Never let submitted text set layout width. */
.ballot-admin-card,
.poll-admin-card,
.idea-card,
.outcome-card,
.reference-card { min-width: 0; }
.ballot-admin-card > *,
.poll-admin-card > *,
.idea-card > * { min-width: 0; }
.ballot-admin-card h3, .ballot-admin-card p, .ballot-admin-card li,
.poll-admin-card h3, .poll-admin-card p, .poll-admin-card li,
.idea-card h3, .idea-card p, .idea-card li,
.outcome-card h3, .outcome-card p,
.poll-panel h3, .poll-summary, .poll-tally-label,
.reference-card code,
#track-result p,
#outcome-list p { overflow-wrap: anywhere; }

/* The workspace tab bar sticks too; it sits below the header, not under it. */
.admin-page-nav {
  top: calc(var(--header-h) + .75rem);
  background: rgb(247 249 249 / 94%);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border: 1px solid var(--line);
  border-radius: .55rem;
}

.plt-sidebar { background: var(--ocean); }
/* The sidebar brand was text-only while every other surface carries the crest. */
.plt-brand { display: flex; align-items: center; gap: .65rem; }
.plt-brand-crest { width: 2.5rem; height: 2.5rem; object-fit: contain; flex-shrink: 0; }
.plt-brand > span { display: grid; gap: .1rem; line-height: 1.15; }
.plt-brand small { font-size: .58rem; font-weight: 600; letter-spacing: .18em; text-transform: uppercase; opacity: .78; }
.plt-choice-grid a:hover { border-color: var(--ocean); }

.how-steps li, .plt-choice-grid a, .ballot-option, .plt-stats article { border-radius: .6rem; }

/* ----------------------------------------------------------------- utilities */

.visually-hidden {
  position: absolute !important;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
/* A button that reads as a link: for secondary actions inside running text. */
.link-button,
.link-button:hover {
  display: inline;
  min-height: 0;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  box-shadow: none;
  color: var(--ocean);
  font-size: inherit;
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: .2em;
  cursor: pointer;
  transform: none;
}
.empty-state {
  margin: 0;
  padding: 1.3rem 1.5rem;
  border: 1px dashed var(--line-strong);
  border-radius: .9rem;
  background: var(--ocean-wash);
  color: var(--muted);
  font-size: .9rem;
}

/* ------------------------------------------------------------ writing help */

.field-meta { display: flex; justify-content: space-between; gap: 1rem; }
.char-count { flex: 0 0 auto; color: var(--muted); font-variant-numeric: tabular-nums; }
.char-count[data-near="true"] { color: #8a5b0b; font-weight: 700; }
.draft-note {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .3rem .6rem;
  margin: 0;
  padding: .7rem .95rem;
  border: 1px solid #cfe0e2;
  border-radius: .6rem;
  background: var(--ocean-tint);
  color: var(--ocean);
  font-size: .82rem;
  font-weight: 600;
}
/* Advice, never an error: the pupil can still send. */
.privacy-guard {
  margin: -.3rem 0 0;
  padding: .85rem 1rem .85rem 2.6rem;
  border: 1px solid #f0dcb4;
  border-left: 4px solid var(--crest-gold);
  border-radius: .6rem;
  background: var(--gold-wash) no-repeat .95rem 1rem / 1.05rem
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23b97a0d' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpath d='M12 11v5.5M12 7.5v.01'/%3E%3C/svg%3E");
  color: #4f4a3f;
  font-size: .84rem;
  line-height: 1.6;
}
.privacy-guard[data-kind="safety"] {
  border-color: var(--ocean-deep);
  background-color: var(--ocean-deep);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23e8a32b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20.8 4.6a5.5 5.5 0 0 0-7.8 0L12 5.7l-1-1.1a5.5 5.5 0 0 0-7.8 7.8L12 21.2l8.8-8.8a5.5 5.5 0 0 0 0-7.8z'/%3E%3C/svg%3E");
  color: #eaf3f4;
  font-weight: 600;
}
.tracking-panel input[data-complete="true"] {
  border-color: var(--success);
  padding-right: 2.6rem;
  background: #fff no-repeat right .95rem center / 1.05rem
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%2317623d' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 8.4 6.6 11.3 12.5 4.8'/%3E%3C/svg%3E");
}

/* What happens after an idea is sent, under the reference. */
.next-steps {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: .8rem;
  margin: 1.6rem 0 1rem;
  padding: 0;
  list-style: none;
  counter-reset: next;
  text-align: left;
}
.next-steps li {
  display: grid;
  gap: .25rem;
  padding: 1rem 1.05rem;
  border: 1px solid var(--line);
  border-radius: .8rem;
  background: var(--ocean-wash);
  counter-increment: next;
}
.next-steps strong { color: var(--ocean); font-size: .9rem; }
.next-steps strong::before { content: counter(next) ". "; color: var(--crest-gold); }
.next-steps span { color: var(--muted); font-size: .8rem; line-height: 1.5; }
.reference-links { display: flex; flex-wrap: wrap; justify-content: center; gap: .4rem 1.6rem; margin: 0; font-weight: 700; }

/* --------------------------------------------------------- staff workspace */

main#main-content.workspace {
  width: 100%;
  max-width: none;
  margin: 0;
  padding: 0 0 5rem;
}
.workspace-body { width: min(100% - 2 * var(--gutter), var(--content)); margin: 0 auto; }
.workspace-body > .panel, .workspace-body > .tool-grid, .workspace-body > .admin-account-grid { margin-bottom: 1.2rem; }
/* The public banner, compact: staff read it dozens of times a day. Its tide
   height is set on the whole workspace so the tab bar can sit against it. */
.workspace { --tide-h: clamp(60px, 7vw, 96px); }
.workspace .page-hero {
  padding: clamp(1.8rem, 3.4vw, 2.5rem) var(--inline-pad) calc(var(--tide-h) + clamp(2rem, 3.4vw, 2.6rem));
}
.workspace .page-hero h1 { font-size: clamp(1.9rem, 3.2vw, 2.6rem); max-width: 24ch; margin: .8rem 0 .6rem; }
.workspace .page-hero .lead { max-width: 62ch; font-size: .95rem; }
.workspace .page-hero .hero-actions { margin-top: 1.2rem; }
.workspace .page-hero-crest .crest-stage { width: clamp(5.5rem, 8vw, 7.5rem); }

/* Tabs float over the banner's lower edge and stick below the header. They
   overlap only the still, page-coloured wave at the very bottom, so all three
   bands of the tide stay in sight above them, and they wrap onto a second row
   rather than slide out of view when the window is narrow. */
.workspace .admin-page-nav {
  position: sticky;
  top: calc(var(--header-h) + .6rem);
  z-index: 30;
  display: flex;
  flex-wrap: wrap;
  width: min(100% - 2 * var(--gutter), var(--content));
  max-width: none;
  gap: .15rem;
  margin: calc(-.2 * var(--tide-h)) auto 1.6rem;
  padding: .35rem;
  background: rgb(255 255 255 / 94%);
  border: 1px solid var(--line);
  border-radius: .85rem;
  box-shadow: var(--shadow-md);
  view-transition-name: rh-tabs;
}
.admin-page-nav a {
  position: relative;
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  min-height: 44px;
  padding: .55rem .95rem;
  border-radius: .55rem;
  background: transparent;
  color: var(--muted);
  font-size: .8rem;
  font-weight: 700;
  text-decoration: none;
  white-space: nowrap;
}
.admin-page-nav a:hover { background: var(--ocean-wash); color: var(--ocean); }
.admin-page-nav a[aria-current="page"] { background: transparent; color: var(--ocean); }
.admin-page-nav .nav-view-pupil { margin-left: auto; }
.tab-mark {
  position: absolute;
  right: .95rem;
  bottom: .22rem;
  left: .95rem;
  height: 3px;
  border-radius: 3px;
  background: var(--crest-gold);
  pointer-events: none;
  view-transition-name: rh-tab-mark;
}
.tab-count {
  display: inline-grid;
  place-items: center;
  min-width: 1.35rem;
  height: 1.35rem;
  padding: 0 .38rem;
  border-radius: 1rem;
  background: var(--crest-gold);
  color: var(--ocean-deep);
  font-size: .68rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}
.tab-count[hidden] { display: none; }

/* Submissions: stage chips that are both the counts and the filter. */
.review-overview { margin-bottom: 1.2rem; }
.review-stats {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: .6rem;
}
.review-stats-loading, .stat-note { grid-column: 1 / -1; margin: 0; color: var(--muted); font-size: .8rem; }
.stat-note strong { color: #8a5b0b; }
.stat-chip,
.stat-chip:hover {
  --chip: var(--ocean);
  display: grid;
  align-content: space-between;
  justify-content: stretch;
  justify-items: start;
  gap: .35rem;
  min-height: 5.2rem;
  padding: .8rem .95rem .85rem;
  border: 1px solid var(--line);
  border-top: 3px solid var(--chip);
  border-radius: .75rem;
  background: #fff;
  box-shadow: var(--shadow-sm);
  color: var(--ink);
  text-align: left;
}
.stat-chip:hover { background: var(--ocean-wash); }
.stat-chip strong { color: var(--ocean); font-size: 1.7rem; line-height: 1; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.stat-chip span { color: var(--muted); font-size: .74rem; font-weight: 700; }
.stat-chip[aria-pressed="true"] { border-color: var(--chip); box-shadow: 0 0 0 3px rgb(0 65 75 / 12%), var(--shadow-sm); background: var(--ocean-wash); }
[data-stage="safety"] { --chip: var(--crest-gold); }
[data-stage="plt"] { --chip: var(--crest-sky); }
[data-stage="progress"] { --chip: var(--crest-teal); }
[data-stage="done"] { --chip: var(--crest-green); }
[data-stage="closed"] { --chip: var(--crest-grey); }

.review-panel-head { display: flex; flex-wrap: wrap; align-items: end; justify-content: space-between; gap: .6rem 1.5rem; }
.review-panel-head h2 { margin: 0; }
.review-panel-head .small-print { margin: 0; }
.review-toolbar {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) auto;
  align-items: end;
  gap: .8rem 1rem;
  margin: 1.2rem 0 .8rem;
  padding: 1rem;
  border: 1px solid var(--line);
  border-radius: .8rem;
  background: var(--ocean-wash);
}
.review-search input {
  padding-left: 2.5rem;
  background: #fff no-repeat .9rem center / 1rem
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%234a6167' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='m20 20-3.5-3.5'/%3E%3C/svg%3E");
}
.review-toolbar .check { min-height: 50px; align-items: center; background: transparent; border-style: dashed; }
.review-count { margin: 0 0 .6rem; color: var(--muted); font-size: .84rem; }
.idea-card[data-stage] { border-left: 4px solid var(--chip); }
.idea-card[hidden] { display: none; }
.idea-tags { display: flex; flex-wrap: wrap; gap: .35rem; }
.stage-pill {
  width: fit-content;
  padding: .18rem .55rem;
  border-radius: 1rem;
  background: color-mix(in srgb, var(--chip) 16%, #fff);
  color: var(--ink);
  font-size: .66rem;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
}
.update-templates { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; margin-top: -.35rem; }
.update-templates .small-print { margin-right: .2rem; font-size: .76rem; }
.template-chip,
.template-chip:hover {
  min-height: 34px;
  padding: .3rem .75rem;
  border: 1px solid var(--line);
  border-radius: 1rem;
  background: #fff;
  box-shadow: none;
  color: var(--ocean);
  font-size: .74rem;
  font-weight: 700;
}
.template-chip:hover { border-color: var(--ocean); background: var(--ocean-tint); }

/* Ballots and polls side by side where there is room. */
.tool-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: start; gap: 1.2rem; }
.tool-grid > .panel { margin: 0; }

/* Segmented filter, used by the suggestion inbox. */
.segmented { display: inline-flex; flex-wrap: wrap; gap: .2rem; padding: .25rem; border: 1px solid var(--line); border-radius: .7rem; background: var(--ocean-wash); }
.segmented button,
.segmented button:hover {
  min-height: 38px;
  padding: .35rem .85rem;
  border: 0;
  border-radius: .5rem;
  background: transparent;
  box-shadow: none;
  color: var(--muted);
  font-size: .78rem;
}
.segmented button:hover { color: var(--ocean); background: #fff; }
.segmented button[aria-pressed="true"] { background: var(--ocean); color: #fff; }
.suggestion-list { display: grid; gap: .8rem; margin-top: 1.2rem; }
.suggestion-card {
  --chip: var(--crest-gold);
  min-width: 0;
  padding: 1.15rem 1.3rem;
  border: 1px solid var(--line);
  border-left: 4px solid var(--chip);
  border-radius: .8rem;
  background: #fff;
}
.suggestion-card[data-status="reviewed"] { --chip: var(--crest-sky); }
.suggestion-card[data-status="closed"] { --chip: var(--crest-grey); }
.suggestion-meta { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem .8rem; }
.suggestion-meta small { color: var(--muted); }
.suggestion-status {
  padding: .15rem .55rem;
  border-radius: 1rem;
  background: color-mix(in srgb, var(--chip) 18%, #fff);
  font-size: .66rem;
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
}
.suggestion-card h3 { margin: .6rem 0 .3rem; color: var(--ocean); font-size: 1.1rem; overflow-wrap: anywhere; }
.suggestion-card p { margin: 0; max-width: 72ch; white-space: pre-wrap; overflow-wrap: anywhere; }
.suggestion-actions { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: .9rem; }

/* Access history. */
.access-log { display: grid; margin: 1rem 0 0; padding: 0; list-style: none; }
.access-log li {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: .9rem;
  padding: .8rem 0;
  border-top: 1px solid var(--line);
}
.access-log li:first-child { border-top: 0; }
.access-log p { margin: 0; font-size: .88rem; overflow-wrap: anywhere; }
.access-log small { color: var(--muted); white-space: nowrap; }
.access-log-dot { width: .7rem; height: .7rem; border-radius: 50%; background: var(--success); box-shadow: 0 0 0 4px rgb(23 98 61 / 14%); }
.access-log li[data-event="revoked"] .access-log-dot { background: var(--danger); box-shadow: 0 0 0 4px rgb(164 43 29 / 12%); }
.access-log li[data-event="reset"] .access-log-dot { background: var(--crest-gold); box-shadow: 0 0 0 4px rgb(218 147 23 / 16%); }
/* Password resets: the account row's note when there is no inbox, and the
   sign-in page's answer, shown beside its form. */
/* Account rows: the controls wrap under the name rather than push the page
   sideways, and the no-inbox note takes a line of its own. */
.member-row { flex-wrap: wrap; }
.member-access { flex: 1 1 18rem; min-width: 0; flex-wrap: wrap; }
.member-access .reset-unavailable { flex-basis: 100%; text-align: right; }
#reset-status .notice { margin: .7rem 0 0; }

/* PLT member layout: the sidebar is the banner, standing on its own tide.
   The tide is the last thing in it, below Sign out rather than behind it, and
   when a short window or larger text leaves too little room the sidebar
   scrolls, so nothing is ever hidden behind the waves or cut off. */
.plt-sidebar {
  position: sticky;
  height: 100vh;
  height: 100dvh;
  overflow: hidden auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: rgb(207 226 229 / 35%) transparent;
  isolation: isolate;
  background: var(--banner);
  background-size: 180px 180px, auto, auto, auto;
  view-transition-name: rh-sidebar;
}
.plt-sidebar > :not(.tide) { position: relative; z-index: 1; }
.plt-sidebar .tide { --tide-h: 88px; position: relative; inset: auto; flex: none; margin: 1rem -1rem -1.5rem; }
.plt-sidebar .tide-foam, .plt-sidebar .tide-edge { display: none; }
.plt-brand { color: #fff; }
.plt-signed { border-color: rgb(207 226 229 / 22%); background: rgb(255 255 255 / 5%); }
.plt-sidebar nav a { position: relative; display: flex; align-items: center; color: #cfe2e5; font-weight: 600; }
.plt-sidebar nav a:hover { background: rgb(255 255 255 / 7%); color: #fff; }
.plt-sidebar nav a[aria-current="page"] { background: rgb(255 255 255 / 10%); color: #fff; }
.plt-sidebar .tab-mark { top: .6rem; right: auto; bottom: .6rem; left: 0; width: 3px; height: auto; }
.plt-signout { border-color: rgb(207 226 229 / 30%); }
/* Reading options, for members too: the workspace has no top bar to hold it. */
.plt-reading { display: flex; align-items: center; gap: .6rem; min-height: 44px; margin-top: auto; padding: .6rem .72rem; border: 0; border-radius: .58rem; background: transparent; color: #cfe2e5; font: inherit; font-size: .86rem; font-weight: 600; text-align: left; cursor: pointer; box-shadow: none; }
.plt-reading:hover { background: rgb(255 255 255 / 7%); color: #fff; }
.plt-reading-mark { display: grid; place-items: center; width: 1.7rem; height: 1.7rem; border: 1px solid rgb(207 226 229 / 35%); border-radius: 50%; font-size: .72rem; font-weight: 700; }
.plt-sidebar .plt-reading + .plt-signout { margin-top: .5rem; }
@media (max-width: 760px) { .plt-reading { margin-top: 1.25rem; justify-content: center; } }
.plt-main .plt-head { margin-bottom: 2rem; }
.plt-main .plt-head h1 {
  max-width: 18ch;
  margin: .5rem 0 .6rem;
  color: var(--ocean);
  font-size: clamp(2.2rem, 4vw, 3.2rem);
  line-height: 1.08;
  view-transition-name: rh-title;
}
.plt-main .plt-head .lead { max-width: 56ch; color: var(--muted); font-size: 1rem; }
.plt-stats article { border-top: 3px solid var(--crest-gold); }
.plt-stats strong { color: var(--ocean); }
.plt-choice-grid a { position: relative; padding-right: 2.6rem; }
.plt-choice-grid a::after { content: "↗"; position: absolute; top: 1rem; right: 1rem; color: var(--crest-gold); font-size: 1.1rem; }

@media (max-width: 1000px) {
  .review-stats { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .tool-grid { grid-template-columns: 1fr; }
}
@media (max-width: 760px) {
  .workspace .page-hero-crest { display: none; }
  /* On a phone the tabs are a two-column grid in the page, not a strip that
     cuts its last tabs off at the screen edge. */
  .workspace .admin-page-nav { position: static; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .workspace .admin-page-nav a { justify-content: center; padding-inline: .5rem; white-space: normal; text-align: center; }
  .workspace .admin-page-nav .nav-view-pupil { margin-left: 0; }
  .review-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .review-toolbar { grid-template-columns: 1fr; }
  .next-steps { grid-template-columns: 1fr; }
  .access-log li { grid-template-columns: auto minmax(0, 1fr); }
  .access-log small { grid-column: 2; }
  .plt-sidebar { position: static; height: auto; overflow: visible; }
  .plt-sidebar .tide { display: none; }
  .plt-sidebar .tab-mark { top: auto; right: .6rem; bottom: .25rem; left: .6rem; width: auto; height: 3px; }
}
@media (pointer: coarse) {
  .template-chip, .segmented button { min-height: 44px; }
}

/* ------------------------------------------------------------- public poll */

/* A live poll is announced in the banner and sits straight after the safety
   note, rather than waiting at the bottom of the page. */
.hero-poll {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: .35rem 1rem;
  width: fit-content;
  max-width: min(100%, 34rem);
  margin-top: 1.6rem;
  padding: .8rem .95rem .85rem 1rem;
  border: 1px solid rgb(232 163 43 / 45%);
  border-radius: .9rem;
  background: rgb(0 28 34 / 42%);
  color: #fff;
  text-decoration: none;
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  box-shadow: 0 14px 34px -16px rgb(0 0 0 / 60%);
}
.hero-poll[hidden] { display: none; }
.hero-poll:hover { border-color: var(--gold-bright); color: #fff; }
.hero-poll-label {
  grid-column: 1 / -1;
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  color: var(--gold-bright);
  font-size: .64rem;
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
}
.hero-poll strong { font-size: .98rem; line-height: 1.35; }
.hero-poll-cta {
  padding: .35rem .75rem;
  border-radius: 1rem;
  background: var(--crest-gold);
  color: var(--ocean-deep);
  font-size: .74rem;
  font-weight: 700;
  white-space: nowrap;
}
.hero-poll[data-state="voted"] .hero-poll-cta,
.hero-poll[data-state="closed"] .hero-poll-cta { background: rgb(255 255 255 / 14%); color: #fff; }
.live-dot {
  position: relative;
  flex: 0 0 auto;
  width: .55rem;
  height: .55rem;
  border-radius: 50%;
  background: var(--gold-bright);
}
.live-dot::after {
  content: "";
  position: absolute;
  inset: 0;
  border: 2px solid var(--gold-bright);
  border-radius: 50%;
  opacity: 0;
}
.hero-poll[data-state="closed"] .live-dot,
.poll-panel[data-state="closed"] .live-dot { background: var(--crest-grey); }

.pupil-home > .poll-panel { margin-top: clamp(1.4rem, 3vw, 2rem); }
.pupil-home .poll-panel {
  padding: clamp(1.5rem, 4vw, 2.6rem);
  border: 1px solid var(--line);
  border-top: 4px solid var(--crest-gold);
  background: var(--contour) 0 0 / 240px 44px, #fff;
  box-shadow: var(--shadow-md);
}
.poll-head { display: grid; gap: .2rem; margin-bottom: .6rem; }
.poll-badge { display: inline-flex; align-items: center; gap: .55rem; margin: 0; }
.poll-badge .live-dot { background: var(--crest-gold); }
.poll-badge .live-dot::after { border-color: var(--crest-gold); }
.poll-panel h2 { margin: .2rem 0 0; color: var(--ocean); font-size: clamp(1.4rem, 2.4vw, 1.8rem); }
.poll-lede { margin: 0; color: var(--muted); font-size: .88rem; }
.poll-panel .poll-question { margin: 1.2rem 0 .3rem; color: var(--ink); font-size: clamp(1.35rem, 2.8vw, 2rem); line-height: 1.2; letter-spacing: -.015em; }
.poll-panel .poll-options {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr));
  gap: .7rem;
  margin: 1.2rem 0 .8rem;
}
.poll-panel .poll-option,
.poll-panel .poll-option:hover:not(:disabled) {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: .9rem;
  width: 100%;
  min-height: 64px;
  padding: .75rem 1rem;
  border: 2px solid var(--line);
  border-radius: .85rem;
  background: #fff;
  color: var(--ink);
  font-size: 1rem;
  font-weight: 700;
  text-align: left;
}
.poll-panel .poll-option:hover:not(:disabled) { border-color: var(--ocean); background: var(--ocean-wash); }
.poll-option.is-chosen::before { content: none; }
.poll-letter {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 2.2rem;
  height: 2.2rem;
  border-radius: 50%;
  background: var(--ocean-tint);
  color: var(--ocean);
  font-size: .85rem;
  font-weight: 700;
}
.poll-panel .poll-option.is-chosen,
.poll-panel .poll-option.is-chosen:disabled { border-color: var(--ocean); background: var(--ocean); color: #fff; opacity: 1; }
.poll-option.is-chosen .poll-letter { background: var(--crest-gold); color: var(--ocean-deep); }
.poll-panel[data-state="voted"] .poll-option:not(.is-chosen) { opacity: .5; }
.poll-panel[data-state="voted"] .poll-status { color: var(--success); font-weight: 700; }
.poll-panel .poll-status { font-size: .84rem; }

/* ---------------------------------------------------------- reading options */

.prototype-banner {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  gap: .4rem 1rem;
  padding-block: .35rem;
}
.prototype-banner > span[role="status"] { grid-column: 2; }
.reading-toggle,
.reading-toggle:hover {
  grid-column: 3;
  justify-self: end;
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  min-height: 30px;
  margin-right: max(0rem, calc((100vw - var(--content)) / 2 - 1.25rem));
  padding: .2rem .75rem;
  border: 1px solid rgb(0 65 75 / 22%);
  border-radius: 1rem;
  background: #fff;
  box-shadow: none;
  color: var(--ocean);
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .02em;
  transform: none;
}
.reading-toggle:hover { border-color: var(--ocean); }
.reading-toggle-mark { font-size: .82rem; letter-spacing: -.02em; }

.reading-panel {
  position: fixed;
  inset: auto;
  top: 3rem;
  right: max(1rem, calc((100vw - var(--content)) / 2));
  width: min(23.5rem, calc(100vw - 2rem));
  max-height: calc(100dvh - 4rem);
  margin: 0;
  padding: 1.1rem 1.2rem 1rem;
  overflow: auto;
  border: 1px solid var(--line);
  border-radius: 1rem;
  background: #fff;
  color: var(--ink);
  box-shadow: var(--shadow-lg);
}
.reading-panel[hidden] { display: none; }
.reading-panel::backdrop { background: transparent; }
.reading-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
.reading-head h2 { margin: 0; color: var(--ocean); font-size: 1.15rem; line-height: 1.2; }
.reading-close,
.reading-close:hover {
  display: grid;
  place-items: center;
  width: 40px;
  min-height: 40px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--ocean-wash);
  box-shadow: none;
  color: var(--ocean);
  font-size: 1.35rem;
  line-height: 1;
}
.reading-form { display: grid; gap: .55rem; margin: .9rem 0 1rem; }
.reading-sizes { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: .45rem; margin: 0 0 .2rem; padding: 0; border: 0; }
.reading-sizes legend { margin-bottom: .45rem; padding: 0; color: var(--muted); font-size: .72rem; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; }
.reading-sizes label {
  position: relative;
  display: grid;
  justify-items: center;
  align-content: end;
  gap: .15rem;
  min-height: 4.2rem;
  padding: .5rem .3rem;
  border: 1px solid var(--line);
  border-radius: .65rem;
  font-size: .74rem;
  font-weight: 600;
  cursor: pointer;
}
.reading-sizes input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; pointer-events: none; }
.reading-sizes label:has(input:checked) { border-color: var(--ocean); background: var(--ocean-wash); box-shadow: inset 0 0 0 1px var(--ocean); }
.reading-sizes label:has(input:focus-visible) { outline: 3px solid var(--crest-gold); outline-offset: 2px; }
.size-sample { color: var(--ocean); font-size: 1rem; font-weight: 700; line-height: 1; }
.size-large { font-size: 1.3rem; }
.size-larger { font-size: 1.65rem; }
/* Typefaces are a list, not tiles: each name is shown in its own letters,
   and OpenDyslexic is too wide to sit three abreast on a phone. */
.reading-fonts { grid-template-columns: 1fr; }
.reading-fonts label {
  grid-template-columns: 2.6rem minmax(0, 1fr);
  justify-items: start;
  align-items: center;
  align-content: center;
  min-height: 44px;
  padding: .3rem .75rem;
  font-size: .8rem;
}
/* On a phone the text sizes become rows too, so a long label in a wide
   typeface or the largest text never spills into its neighbour. */
@media (max-width: 480px) {
  .reading-sizes { grid-template-columns: 1fr; }
  .reading-sizes label {
    grid-template-columns: 2.6rem minmax(0, 1fr);
    justify-items: start;
    align-items: center;
    align-content: center;
    min-height: 44px;
    padding: .3rem .75rem;
    font-size: .8rem;
  }
}
.font-sample { color: var(--ocean); font-family: "Century Gothic", Questrial, sans-serif; font-size: 1.2rem; font-weight: 700; line-height: 1.1; }
.font-sample.font-readable { font-family: Verdana, Tahoma, sans-serif; }
.font-sample.font-dyslexic { font-family: "OpenDyslexic", Verdana, sans-serif; font-size: 1.05rem; }
.reading-switch {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: .8rem;
  padding: .6rem .75rem;
  border: 1px solid var(--line);
  border-radius: .7rem;
  cursor: pointer;
}
.reading-switch > span { display: grid; gap: .05rem; }
.reading-switch strong { font-size: .86rem; }
.reading-switch small { color: var(--muted); font-size: .74rem; font-weight: 500; line-height: 1.4; }
.reading-switch input {
  -webkit-appearance: none;
  appearance: none;
  position: relative;
  order: 2;
  width: 2.7rem;
  height: 1.55rem;
  min-height: 1.55rem;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 1rem;
  background: var(--line-strong);
  cursor: pointer;
  transition: background-color 180ms ease;
}
.reading-switch input::before {
  content: "";
  position: absolute;
  top: .2rem;
  left: .2rem;
  width: 1.15rem;
  height: 1.15rem;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 3px rgb(0 0 0 / 25%);
  transition: transform 220ms var(--ease-out);
}
.reading-switch input:checked { background: var(--ocean); }
.reading-switch input:checked::before { transform: translateX(1.15rem); }
.reading-switch input:focus { box-shadow: none; }
.reading-switch input:focus-visible { outline: 3px solid var(--crest-gold); outline-offset: 2px; }
.reading-switch:has(input:checked) { border-color: var(--ocean); background: var(--ocean-wash); }
.reading-actions { display: flex; flex-wrap: wrap; gap: .5rem; }
.reading-actions .button { min-height: 44px; font-size: .8rem; }
.reading-panel > .small-print { margin: .7rem 0 0; font-size: .74rem; }
@media (forced-colors: active) {
  .reading-switch input { -webkit-appearance: auto; appearance: auto; width: auto; height: auto; }
  .reading-switch input::before { display: none; }
}

/* The preferences themselves, set on <html> by prefs.js and the panel. */
:root[data-text="large"] { font-size: 112.5%; }
:root[data-text="larger"] { font-size: 125%; }
:root[data-spacing="wide"] :is(p, li, label, small, dd, .lead) { line-height: 1.9; letter-spacing: .03em; word-spacing: .12em; }
:root[data-spacing="wide"] :is(p, li) { max-width: 64ch; }
:root[data-font="readable"] { --font-school: Verdana, Tahoma, "Segoe UI", Arial, sans-serif; }
:root:is([data-font="readable"], [data-font="dyslexic"]) :is(h1, h2, h3) { letter-spacing: 0; }
/* OpenDyslexic (SIL Open Font Licence, public/fonts) gives each letter a
   heavier base so it is harder to flip or mirror. The browser only downloads
   it for someone who chooses it, or who opens the panel and sees its sample.
   Its letters are wide and tall, so text is set a touch smaller and looser. */
@font-face {
  font-family: "OpenDyslexic";
  src: url("/fonts/opendyslexic-latin-400-normal.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "OpenDyslexic";
  src: url("/fonts/opendyslexic-latin-700-normal.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
:root[data-font="dyslexic"] { --font-school: "OpenDyslexic", Verdana, Tahoma, sans-serif; font-size: 93.75%; }
:root[data-font="dyslexic"][data-text="large"] { font-size: 105%; }
:root[data-font="dyslexic"][data-text="larger"] { font-size: 117.5%; }
:root[data-font="dyslexic"] :is(p, li, dd, .lead) { line-height: 1.8; }
:root[data-font="dyslexic"] em { font-style: normal; }
/* Wide letters or the largest text can make one long word wider than a
   phone. Headings hyphenate (the page is lang="en-GB") and break a word
   rather than push the page sideways. */
:root:is([data-font="dyslexic"], [data-text="larger"]) :is(h1, h2, h3) { -webkit-hyphens: auto; hyphens: auto; overflow-wrap: break-word; }
@media (max-width: 760px) {
  .plt-member-layout { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 480px) {
  :root[data-font="dyslexic"] :is(.hero, .page-hero) h1 { font-size: clamp(1.6rem, 8.4vw, 2.1rem); }
}
:root[data-contrast="high"] { --muted: #1f3338; --line: #87a1a6; --line-strong: #3a575d; --ocean-mid: #00343c; }
:root[data-contrast="high"] :is(.hero, .page-hero) :is(.lead, .hero-caption, p.eyebrow, .crest-estd, .auth-back) { color: #fff; }
:root[data-contrast="high"] :is(input, select, textarea, .panel, .safety-strip, .track-card, .outcome-card) { border-color: var(--ocean); }
:root[data-contrast="high"] .site-header { background: var(--canvas); -webkit-backdrop-filter: none; backdrop-filter: none; }
:root[data-contrast="high"] .footer :is(.footer-note, .footer-service, .footer-links a) { color: #fff; }
:root[data-contrast="high"] a { text-decoration-thickness: 2px; }
:root[data-contrast="high"] .tide-sky { opacity: .4; }
:root[data-motion="reduce"],
:root[data-motion="reduce"] *,
:root[data-motion="reduce"] *::before,
:root[data-motion="reduce"] *::after {
  animation: none !important;
  transition: none !important;
  scroll-behavior: auto !important;
}

/* ------------------------------------------------------ duplicate finder */

.ai-panel { background: linear-gradient(135deg, #fff 0%, var(--ocean-wash) 100%); border-color: #cfe0e2; }
.ai-head { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: 1rem 1.3rem; }
.ai-head h2 { margin: 0 0 .25rem; }
.ai-head .eyebrow { margin: 0 0 .2rem; }
.ai-head .small-print { margin: 0; max-width: 70ch; }
.ai-mark {
  width: 3rem;
  height: 3rem;
  border-radius: .9rem;
  background: var(--ocean) no-repeat center / 58%
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23e8a32b'%3E%3Cpath d='M12 2l1.9 5.6L19.5 9.5l-5.6 1.9L12 17l-1.9-5.6L4.5 9.5l5.6-1.9zM19 14l.9 2.6 2.6.9-2.6.9L19 21l-.9-2.6-2.6-.9 2.6-.9zM5 15l.7 1.8 1.8.7-1.8.7L5 20l-.7-1.8-1.8-.7 1.8-.7z'/%3E%3C/svg%3E");
  box-shadow: 0 10px 22px -12px rgb(0 65 75 / 70%);
}
.ai-progress { display: grid; gap: .4rem; margin-top: 1.1rem; }
.ai-progress[hidden] { display: none; }
.ai-progress-track { height: 6px; overflow: hidden; border-radius: 3px; background: var(--ocean-tint); }
#ai-progress-bar {
  display: block;
  height: 100%;
  background: linear-gradient(90deg, var(--ocean), var(--crest-gold));
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 200ms var(--ease-out);
}
.ai-progress small { color: var(--muted); font-size: .78rem; }
#ai-results { display: grid; gap: .8rem; }
#ai-results:not(:empty) { margin-top: 1.1rem; }
.ai-suggestion {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 1.1rem;
  padding: 1.15rem 1.25rem;
  border: 1px solid var(--line);
  border-left: 4px solid var(--crest-gold);
  border-radius: .85rem;
  background: #fff;
  animation: rise-in 420ms var(--ease-out) both;
}
.ai-score {
  display: grid;
  place-content: center;
  justify-items: center;
  width: 4.4rem;
  height: 4.4rem;
  border-radius: 50%;
  background: var(--ocean);
  color: #fff;
}
.ai-score strong { font-size: 1.15rem; line-height: 1; font-variant-numeric: tabular-nums; }
.ai-score span { color: #bcd8dd; font-size: .6rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; }
.ai-suggestion h3 { margin: 0 0 .15rem; color: var(--ocean); font-size: 1.05rem; }
.ai-suggestion .small-print { margin: 0; }
.ai-ideas { display: grid; gap: .4rem; margin: .7rem 0; padding: 0; list-style: none; }
.ai-ideas label {
  display: flex;
  align-items: flex-start;
  gap: .7rem;
  padding: .55rem .75rem;
  border: 1px solid var(--line);
  border-radius: .6rem;
  cursor: pointer;
}
.ai-ideas label:has(input:checked) { border-color: var(--ocean); background: var(--ocean-wash); }
.ai-ideas input { width: 1.1rem; height: 1.1rem; min-height: 1.1rem; margin: .2rem 0 0; padding: 0; accent-color: var(--ocean); flex: 0 0 auto; }
.ai-ideas span { display: grid; gap: .1rem; min-width: 0; }
.ai-ideas strong { overflow-wrap: anywhere; }
.ai-ideas small { color: var(--muted); font-size: .76rem; }
.ai-words { margin: 0 0 .8rem; color: var(--muted); font-size: .78rem; }
.ai-words span { display: inline-block; margin: .2rem .3rem 0 0; padding: .1rem .55rem; border-radius: 1rem; background: var(--gold-wash); color: #6b4a0c; font-weight: 700; }
.ai-related { padding: .2rem 0; }
.ai-related summary { display: flex; align-items: center; min-height: 44px; color: var(--ocean); font-weight: 700; cursor: pointer; }
.ai-related ul { display: grid; margin: .3rem 0 0; padding: 0; list-style: none; }
.ai-related li {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto minmax(0, 1fr) auto;
  align-items: center;
  gap: .6rem;
  padding: .6rem 0;
  border-top: 1px solid var(--line);
  font-size: .86rem;
}
.ai-related li > span { overflow-wrap: anywhere; }
.ai-related-score { color: var(--ocean); font-weight: 700; font-variant-numeric: tabular-nums; }

/* Merged requests in the submissions list. */
.merge-label {
  width: fit-content;
  padding: .2rem .55rem;
  border-radius: 999px;
  background: var(--ocean);
  color: #fff;
  font-size: .66rem;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
}
.duplicate-explainer.is-merged { border-left-color: var(--crest-gold); }
.duplicate-explainer .button { justify-self: start; margin-top: .5rem; }
.merged-list { margin-top: .6rem; padding-top: 1rem; border-top: 1px dashed var(--line-strong); }
.merged-list h4 { margin: 0 0 .6rem; color: var(--muted); font-size: .74rem; letter-spacing: .12em; text-transform: uppercase; }
.merged-row { margin-bottom: .5rem; border: 1px solid var(--line); border-radius: .65rem; background: var(--ocean-wash); }
.merged-row summary { display: flex; align-items: center; justify-content: space-between; gap: 1rem; min-height: 44px; padding: .6rem .9rem; font-weight: 700; cursor: pointer; }
.merged-title { overflow-wrap: anywhere; }
.merged-row summary small { flex: 0 0 auto; color: var(--muted); font-weight: 500; }
.merged-body { padding: 0 .9rem .9rem; }
.merged-body p { white-space: pre-wrap; overflow-wrap: anywhere; }

@media (max-width: 760px) {
  .prototype-banner { grid-template-columns: minmax(0, 1fr) auto; text-align: left; }
  .prototype-banner > span[role="status"] { grid-column: 1; }
  .reading-toggle, .reading-toggle:hover { grid-column: 2; margin-right: 0; }
  .reading-toggle-text { display: none; }
  .reading-panel { top: 3.4rem; right: 1rem; }
  .hero-poll { width: 100%; }
  .ai-head { grid-template-columns: auto minmax(0, 1fr); }
  .ai-head > .button { grid-column: 1 / -1; justify-self: start; }
  .ai-suggestion { grid-template-columns: 1fr; }
  .ai-score { width: auto; height: auto; padding: .4rem .8rem; border-radius: 1rem; display: inline-flex; gap: .4rem; justify-self: start; }
  .ai-related li { grid-template-columns: auto minmax(0, 1fr); }
  .ai-related li > span[aria-hidden] { display: none; }
  .ai-related li > .button { grid-column: 1 / -1; justify-self: start; }
}
@media (prefers-reduced-motion: no-preference) {
  .live-dot::after { animation: dot-ring 2.2s var(--ease-out) infinite; }
  .hero-poll:not([hidden]) { animation: rise-in 640ms var(--ease-out) both; }
}

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

   Calls to action carry the tide: a wave drifts along the foot of the button
   and rises to fill it on hover, focus or press. On the home banner the tide
   also comes in as the page scrolls down and goes out again on the way back.
   The wave is a masked ::before, so it survives a label change ("Sending…")
   and never moves the text.

   --tide (0 to 1) is how far the tide has come in by scrolling. It is a
   registered number so a scroll timeline can animate it; everywhere else it
   stays 0 and the wave rests at --wave-rest. */
@property --tide {
  syntax: "<number>";
  inherits: false;
  initial-value: 0;
}
.wave-button {
  --wave-colour: var(--ocean-deep);
  --wave-rest: 76%;
  position: relative;
  overflow: hidden;
  isolation: isolate;
}
.wave-button::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: -14% 0 -2%;
  background: var(--wave-colour);
  -webkit-mask:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 46 10' preserveAspectRatio='none'%3E%3Cpath d='M0 5Q11.5 0 23 5T46 5V10H0Z'/%3E%3C/svg%3E") 0 0 / 46px 10px repeat-x,
    linear-gradient(#000 0 0) 0 9px / 100% 100% no-repeat;
  mask:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 46 10' preserveAspectRatio='none'%3E%3Cpath d='M0 5Q11.5 0 23 5T46 5V10H0Z'/%3E%3C/svg%3E") 0 0 / 46px 10px repeat-x,
    linear-gradient(#000 0 0) 0 9px / 100% 100% no-repeat;
  translate: 0 calc(var(--wave-rest) - var(--tide, 0) * 42%);
  pointer-events: none;
  transition: translate 620ms var(--ease-out);
}
.wave-button:not(:disabled):is(:focus-visible, :active)::before { translate: 0 0; }
@media (hover: hover) and (pointer: fine) {
  .wave-button:not(:disabled):hover::before { translate: 0 0; }
}

/* Each surface gets a tide that keeps its label's contrast, and the flat
   hover colour steps aside so the wave is the hover state. */
.button-secondary.wave-button { --wave-colour: var(--ocean-tint); }
.button.wave-button:not(.button-secondary):not(.button-danger):hover { background: var(--ocean); border-color: var(--ocean); }
.button-secondary.wave-button:hover { background: #fff; }
:is(.pupil-home .hero, .page-hero) .wave-button { --wave-colour: #f5bd55; }
:is(.pupil-home .hero, .page-hero) .button-secondary.wave-button { --wave-colour: rgb(255 255 255 / 16%); }
:is(.pupil-home .hero, .page-hero) .button.wave-button:not(.button-secondary):not(.button-danger):hover { background: var(--crest-gold); border-color: var(--crest-gold); }
:is(.pupil-home .hero, .page-hero) .button-secondary.wave-button:hover { background: rgb(255 255 255 / 4%); }
/* Poll answers sit in a list, so their tide stays out of sight until one is
   pointed at: four drifting waves at once would be noise. */
.poll-option.wave-button { --wave-colour: var(--ocean-tint); --wave-rest: 100%; }
.poll-panel .poll-option.wave-button:hover:not(:disabled) { background: #fff; }
.poll-panel .poll-option.wave-button.is-chosen::before { content: none; }

@media (prefers-reduced-motion: no-preference) {
  @keyframes wave-drift {
    from { -webkit-mask-position: 0 0, 0 9px; mask-position: 0 0, 0 9px; }
    to   { -webkit-mask-position: 46px 0, 0 9px; mask-position: 46px 0, 0 9px; }
  }
  .wave-button::before { animation: wave-drift 2.6s linear infinite; }
  .button-secondary.wave-button::before { animation: wave-drift 3.4s linear infinite reverse; }

  /* The home banner's tide comes in with the scroll. It follows the buttons
     themselves rather than the page, so it rises as they travel from the
     middle of the screen up to the header on a phone and a desktop alike,
     ending three-quarters full with the crest still drifting across. */
  @supports (animation-timeline: view()) {
    @keyframes wave-tide-in { to { --tide: 1; } }
    .pupil-home .hero-actions { view-timeline: --hero-actions block; }
    .pupil-home .hero .wave-button::before {
      animation: wave-drift 2.6s linear infinite, wave-tide-in linear both;
      animation-timeline: auto, --hero-actions;
      animation-range: normal, cover 45% cover 85%;
    }
    .pupil-home .hero .button-secondary.wave-button::before {
      animation: wave-drift 3.4s linear infinite reverse, wave-tide-in linear both;
      animation-timeline: auto, --hero-actions;
      animation-range: normal, cover 45% cover 85%;
    }
  }
}
@media (forced-colors: active) { .wave-button::before { display: none; } }

/* Sentence starters under the idea box. */
.writing-starters { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; margin-top: -.45rem; color: var(--muted); font-size: .78rem; }
.starter-chip,
.starter-chip:hover {
  min-height: 34px;
  padding: .3rem .75rem;
  border: 1px dashed var(--line-strong);
  border-radius: 1rem;
  background: #fff;
  box-shadow: none;
  color: var(--ocean);
  font-size: .76rem;
  font-weight: 700;
}
.starter-chip:hover { border-style: solid; border-color: var(--ocean); background: var(--ocean-wash); }
@media (pointer: coarse) { .starter-chip { min-height: 44px; } }

/* ------------------------------------------------------------- PLT polls

   Members suggest a poll beside a live preview of how pupils will see it;
   administrators publish or decline it from the public poll panel. A poll
   that came from the PLT carries a small label on the pupil home page. */
.plt-choice-grid { grid-template-columns: repeat(auto-fit, minmax(min(13rem, 100%), 1fr)); }
.poll-source {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  margin: 1rem 0 0;
  padding: .2rem .65rem;
  border-radius: 1rem;
  background: var(--ocean-tint);
  color: var(--ocean);
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .03em;
}
.poll-source::before { content: ""; width: .45rem; height: .45rem; border-radius: 50%; background: var(--crest-gold); }
.poll-panel .poll-source + .poll-question { margin-top: .5rem; }
.poll-suggest-grid { display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr); gap: 1rem; align-items: start; }
.poll-suggest-grid > .panel { margin: 0; }
#poll-proposal-form, .proposal-form { display: grid; }
.live-poll-line { margin: 0 0 1rem; padding: .65rem .85rem; border-left: 3px solid var(--crest-gold); border-radius: .5rem; background: var(--ocean-wash); font-size: .85rem; overflow-wrap: anywhere; }
.poll-preview { position: sticky; top: calc(var(--header-h, 4.5rem) + 1rem); border-style: dashed; background: var(--ocean-wash); }
.poll-preview .poll-source { margin-top: .2rem; }
.poll-preview .poll-question { margin: .5rem 0 .3rem; color: var(--ink); font-size: 1.2rem; line-height: 1.25; overflow-wrap: anywhere; }
.poll-preview .poll-summary { margin: 0 0 .6rem; }
.poll-preview-options { display: grid; gap: .45rem; margin: .8rem 0 0; padding: 0; list-style: none; }
.poll-preview-options li {
  display: flex;
  align-items: center;
  gap: .7rem;
  min-height: 48px;
  padding: .45rem .75rem;
  border: 2px solid var(--line);
  border-radius: .75rem;
  background: #fff;
  font-weight: 700;
  overflow-wrap: anywhere;
}
.poll-preview-options .poll-letter { width: 1.9rem; height: 1.9rem; }
.suggestion-card[data-status="pending"] { --chip: var(--crest-gold); }
.suggestion-card .proposal-note { margin-top: .7rem; padding: .55rem .75rem; border-radius: .5rem; background: var(--ocean-wash); font-size: .88rem; }
.poll-proposals { display: grid; gap: .8rem; margin: 1rem 0 1.4rem; padding-bottom: 1.4rem; border-bottom: 1px solid var(--line); }
.poll-proposals > h3 { margin: 0; color: var(--ocean); font-size: 1.05rem; }
.poll-proposals > .small-print { margin: -.4rem 0 0; }
.proposal-card .moderation-flag, .proposal-card .moderation-clear { margin: .7rem 0 0; }
.proposal-form { margin-top: .8rem; }
@media (max-width: 900px) {
  .poll-suggest-grid { grid-template-columns: 1fr; }
  .poll-preview { position: static; }
}

/* --------------------------------------------------------------- responsive */

@media (min-width: 761px) {
  /* Anchors land below the sticky header rather than under it - and below the
     sticky tab bar as well on administrator pages. */
  html { scroll-padding-top: calc(var(--header-h) + 1rem); }
  html:has(.workspace-admin) { scroll-padding-top: calc(var(--header-h) + 5.5rem); }
}

@media (max-width: 1000px) {
  :root { --gutter: 1.5rem; }
  .pupil-home .hero { grid-template-columns: minmax(0, 1fr) minmax(0, .7fr); }
  .crest-stage { width: clamp(11rem, 26vw, 14rem); }
  .how-steps { grid-template-columns: 1fr; gap: 1.6rem; }
  .info-body { grid-template-columns: 1fr; }
  .info-summary { position: static; }
  .auth-layout { grid-template-columns: minmax(0, .7fr) minmax(0, 1.3fr); }
}

@media (max-width: 760px) {
  :root { --gutter: 1rem; --header-h: 0rem; --tide-h: clamp(64px, 18vw, 96px); }
  body { overflow-x: clip; }

  /* Phones: the header scrolls away with the page rather than taking a
     permanent tenth of a small screen. */
  .site-header {
    position: relative;
    display: grid;
    align-items: start;
    gap: .8rem;
    min-height: auto;
    padding-block: 1rem;
  }
  .brand-crest { width: 2.7rem; height: 2.7rem; }
  .brand .brand-lockup strong { font-size: .95rem; }
  .brand .brand-lockup > span { font-size: .55rem; letter-spacing: .16em; }
  /* Uppercase labels wrap mid-word at 375px; sentence case fits on one line. */
  .site-header nav { gap: 0; }
  .site-header nav a {
    font-size: .68rem;
    font-weight: 600;
    letter-spacing: .005em;
    text-transform: none;
    padding-inline: .3rem;
    white-space: nowrap;
  }
  .site-header nav a::after { display: none; }
  .nav-mark { right: .3rem; bottom: .3rem; left: .3rem; }
  .site-header nav a.nav-signin { padding-inline: .45rem; margin-left: .25rem; }
  .site-header nav a.nav-signin .nav-mark { bottom: -.4rem; }

  .pupil-home .hero {
    grid-template-columns: 1fr;
    gap: 1.4rem;
    min-height: 0;
    padding: 1.9rem var(--gutter) calc(var(--tide-h) + 2.2rem);
    text-align: left;
  }
  .hero h1 { font-size: clamp(2.2rem, 10vw, 2.9rem); max-width: 16ch; margin: 1rem 0 1.1rem; }
  /* The crest heads the banner, centred across it, with its name beneath. */
  .crest-panel { order: -1; justify-items: center; gap: .5rem; text-align: center; }
  .crest-panel .crest-stage { width: 7.5rem; }
  .crest-medallion { padding: 12%; }
  .hero .crest-name { font-size: 1rem; }
  .hero .crest-estd { letter-spacing: .16em; }

  .page-hero {
    grid-template-columns: minmax(0, 1fr);
    gap: 1.2rem;
    padding: 1.8rem var(--gutter) calc(var(--tide-h) + 1.6rem);
  }
  .page-hero-crest { order: -1; display: grid; justify-items: center; }
  .page-hero-crest .crest-stage { width: 5.5rem; }
  .page-hero h1 { font-size: clamp(2rem, 8.6vw, 2.6rem); }

  .pupil-home .safety-strip {
    grid-template-columns: auto minmax(0, 1fr);
    gap: .8rem 1rem;
    margin-top: calc(var(--tide-h) * -.4);
    padding: 1.15rem 1.1rem;
  }
  .safety-icon { width: 1.6rem; height: 1.6rem; align-self: start; }
  .safety-strip > a { grid-column: 1 / -1; }

  .how-steps { padding: 2.6rem 0 2rem; }
  .how-steps ol { grid-template-columns: 1fr; gap: 1.4rem; }
  .how-steps ol::before { top: 1.4rem; bottom: 1.4rem; left: 1.35rem; right: auto; width: 2px; height: auto; background: linear-gradient(180deg, var(--ocean), var(--crest-teal) 55%, var(--crest-gold)); transform-origin: center top; }
  .how-steps li, .how-steps li:first-child { grid-template-columns: 2.8rem minmax(0, 1fr); column-gap: 1rem; row-gap: .15rem; padding: 0; border: 0; }
  .how-steps .step-num { grid-row: span 2; margin: 0; }

  .pupil-home .form-panel { display: block; padding: 1.4rem; }
  .form-panel .form-intro { position: static; }
  .form-panel #idea-form { margin-top: 1.6rem; }
  .pupil-home .tracking-panel { padding: 1.4rem; }
  .track-card { padding: 1.2rem 1.1rem; }

  .info-body { margin-top: 1.5rem; gap: 2rem; }
  .info-item { grid-template-columns: 2.4rem minmax(0, 1fr); column-gap: .6rem; }

  .revamped-auth .page-hero { padding-bottom: calc(var(--tide-h) + 2.5rem); }
  .auth-layout { grid-template-columns: 1fr; gap: 0; }
  .auth-page .auth-card { margin-top: calc(-1 * (2.5rem + var(--tide-h) * .5)); padding: 1.4rem; }

  .footer { padding: calc(clamp(40px, 5vw, 64px) + 1.6rem) 0 1.6rem; }
  .footer .shell { grid-template-columns: 1fr; gap: 1.4rem; }
  .footer .footer-links { justify-content: flex-start; gap: .5rem 1.2rem; }
  .footer .footer-crest { width: 3rem; height: 3rem; }

  .nav-view-pupil { margin-left: 0; }
  .staff-preview-bar { font-size: .7rem; padding: .45rem .75rem; }
  .poll-options { flex-direction: column; }
  .poll-option { width: 100%; text-align: left; justify-content: flex-start; }
  .poll-tally li { grid-template-columns: 1fr auto auto; }
  .poll-tally-bar { grid-column: 1 / -1; order: 3; }

  /* iOS Safari zooms the whole page in when a focused field is under 16px. The
     tracking reference sat at 13.6px, so the one field a pupil types into to
     check their idea made the page jump and forced a pinch back out. */
  input, select, textarea,
  .tracking-panel input { font-size: 1rem; }

  /* Functional small text was reaching ~11px. These are instructions pupils
     actually need to read, not decoration, so they get a floor. */
  .field-hint,
  .small-print,
  label small,
  .human-check-note,
  .privacy-note,
  .poll-status { font-size: .8rem; line-height: 1.6; }
  .eyebrow { font-size: .72rem; }
  .hero p.eyebrow, .page-hero p.eyebrow, .hero .crest-estd { font-size: .7rem; }
  .track-rail li span { font-size: .7rem; }
  /* Letterspaced caps read smaller than their size suggests; 10px was too fine
     on a phone even for brand chrome. */
  .footer .footer-service { font-size: .7rem; letter-spacing: .12em; }
}

/* The smallest phones cannot fit four links on one row: the sign-in label
   spilled out of its border at 320px. Two rows of two keep every label whole. */
@media (max-width: 374px) {
  .site-header nav { grid-template-columns: repeat(2, minmax(0, 1fr)); row-gap: .25rem; }
  .site-header nav a { justify-content: center; }
  .site-header nav a.nav-signin { margin-left: 0; }
}

@media (prefers-contrast: more) {
  .panel, input, select, textarea { border-color: var(--ocean); }
  .hero .lead, .hero p.hero-caption, .page-hero .lead { color: #fff; }
}
@media (prefers-reduced-transparency: reduce) {
  .site-header { background: var(--canvas); -webkit-backdrop-filter: none; backdrop-filter: none; }
}
/* Windows high-contrast: hand the checkbox back to the system. */
@media (forced-colors: active) {
  .check input { -webkit-appearance: auto; appearance: auto; }
  .check input::before { display: none; }
  .tide, .crest-sun { display: none; }
}

/* ==========================================================================
   Touch targets

   Keyed to the pointer, not the viewport width. A tablet in portrait is 768px
   wide - past any phone breakpoint - but it is still a finger, and these links
   sat at 20px tall there. `pointer: coarse` is the honest signal for "this is
   being tapped, not clicked".
   ========================================================================== */
@media (pointer: coarse) {
  .safety-strip > a,
  .footer .footer-links a,
  .poll-result a,
  .idea-danger .button-small,
  .code-list .button-small,
  .auth-help a,
  .session-note a,
  .reference-card p > a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }
  .brand { min-height: 44px; }
  /* The checkbox is small, but its label is the real target - make the whole
     row comfortably tappable. */
  .check { min-height: 44px; display: flex; align-items: center; gap: .6rem; }
  /* Nav and workspace links are already 44px, but guard them against future
     font-size changes shrinking them below it. */
  .site-header nav a, .plt-sidebar nav a, .admin-page-nav a { min-height: 44px; }
}

/* ==========================================================================
   Motion

   Three rules govern everything below:
   1. A pupil who has asked their device to reduce motion gets a completely
      still interface - the override at the end is a hard stop, not a hint -
      and the router swaps pages instantly for them.
   2. Interface feedback is quick (under ~300ms) and moves a few pixels. The
      longer, richer movement is spent where it is rare: arriving at the site,
      changing page, and the moment an idea is received.
   3. Everything animates transform, opacity or a mask - never layout.
   ========================================================================== */

@media (prefers-reduced-motion: no-preference) {
  @keyframes rise-in {
    from { opacity: 0; transform: translateY(18px); }
    to   { opacity: 1; transform: none; }
  }
  @keyframes line-up {
    from { transform: translateY(108%); }
    to   { transform: none; }
  }
  @keyframes soft-in {
    from { opacity: 0; }
    to   { opacity: 1; }
  }
  @keyframes crest-in {
    from { opacity: 0; transform: scale(.9); }
    to   { opacity: 1; transform: none; }
  }
  @keyframes sun-rise {
    from { opacity: 0; transform: translateY(18%) scale(.8); }
    to   { opacity: 1; transform: none; }
  }
  @keyframes ring-draw {
    from { stroke-dashoffset: 1; }
    to   { stroke-dashoffset: 0; }
  }
  @keyframes rule-draw {
    from { transform: scaleX(0); }
    to   { transform: scaleX(1); }
  }
  @keyframes tide-rise {
    from { translate: 0 100%; }
    to   { translate: 0 0; }
  }
  @keyframes tide-drift {
    from { transform: translateX(0); }
    to   { transform: translateX(-50%); }
  }
  @keyframes crest-float {
    0%, 100% { translate: 0 0; }
    50%      { translate: 0 -7px; }
  }
  @keyframes bar-grow {
    from { transform: scaleX(0); }
    to   { transform: scaleX(1); }
  }
  @keyframes rail-fill {
    from { transform: scaleX(0); }
  }
  @keyframes dot-ring {
    0%   { opacity: .75; transform: scale(1); }
    100% { opacity: 0; transform: scale(2.2); }
  }
  @keyframes notice-in {
    from { opacity: 0; transform: translateY(-6px); }
    to   { opacity: 1; transform: none; }
  }
  @keyframes dialog-in {
    from { opacity: 0; transform: translateY(10px) scale(.985); }
    to   { opacity: 1; transform: none; }
  }
  @keyframes spin { to { transform: rotate(1turn); } }
  @keyframes sweep {
    from { transform: translateX(-100%); }
    to   { transform: translateX(100%); }
  }
  @keyframes stamp {
    from { opacity: 0; transform: scale(.94); }
    to   { opacity: 1; transform: none; }
  }
  @keyframes ring-out {
    0%   { opacity: .9; transform: scale(.97); }
    100% { opacity: 0; transform: scale(1.1); }
  }

  /* ------------------------------------------------------------- arrival

     The first page a visitor opens is choreographed: the words rise out of
     their lines, the sun comes up behind the crest, its ring draws itself and
     the tide rolls in. It plays once. html[data-navigated] is set by the
     router on the first click, so changing page never replays it - the view
     transition below carries the page instead. */
  :root:not([data-navigated]) :is(.hero, .page-hero) p.eyebrow { animation: rise-in 700ms var(--ease-out) 60ms both; }
  :root:not([data-navigated]) :is(.hero, .page-hero) p.eyebrow::after { animation: rule-draw 760ms var(--ease-out) 380ms both; }
  :root:not([data-navigated]) .hero h1 .line > * { animation: line-up 1000ms var(--ease-out) both; }
  :root:not([data-navigated]) .hero h1 .line:nth-child(1) > * { animation-delay: 120ms; }
  :root:not([data-navigated]) .hero h1 .line:nth-child(2) > * { animation-delay: 230ms; }
  :root:not([data-navigated]) .page-hero h1 { animation: rise-in 820ms var(--ease-out) 130ms both; }
  :root:not([data-navigated]) :is(.hero, .page-hero) .lead { animation: rise-in 760ms var(--ease-out) 330ms both; }
  :root:not([data-navigated]) :is(.hero, .page-hero) .hero-actions { animation: rise-in 760ms var(--ease-out) 420ms both; }
  :root:not([data-navigated]) .hero .hero-caption { animation: soft-in 800ms ease 560ms both; }
  :root:not([data-navigated]) .auth-back { animation: soft-in 600ms ease both; }
  :root:not([data-navigated]) .crest-sun { animation: sun-rise 1600ms var(--ease-out) 120ms both; }
  :root:not([data-navigated]) .crest-medallion { animation: crest-in 1000ms var(--ease-out) 220ms both; }
  :root:not([data-navigated]) .crest-ring circle { animation: ring-draw 1700ms var(--ease-in-out) 480ms both; }
  :root:not([data-navigated]) .hero .crest-name { animation: rise-in 700ms var(--ease-out) 620ms both; }
  :root:not([data-navigated]) .hero .crest-estd { animation: rise-in 700ms var(--ease-out) 700ms both; }
  :root:not([data-navigated]) .pupil-home .safety-strip { animation: rise-in 820ms var(--ease-out) 540ms both; }
  :root:not([data-navigated]) .auth-page .auth-card { animation: rise-in 820ms var(--ease-out) 300ms both; }
  :root:not([data-navigated]) .info-summary { animation: rise-in 820ms var(--ease-out) 360ms both; }
  :root:not([data-navigated]) .nav-mark { animation: rule-draw 700ms var(--ease-out) 420ms both; }

  /* The tide never stops moving, slowly and at three different speeds. Its
     arrival uses `translate`, which leaves `transform` free for the drift. */
  .tide-sky   { animation: tide-drift 56s linear infinite; }
  .tide-river { animation: tide-drift 40s linear infinite reverse; }
  .tide-hill  { animation: tide-drift 74s linear infinite; }
  :root:not([data-navigated]) .tide-sky   { animation: tide-drift 56s linear infinite, tide-rise 1300ms var(--ease-out) 60ms backwards; }
  :root:not([data-navigated]) .tide-river { animation: tide-drift 40s linear infinite reverse, tide-rise 1300ms var(--ease-out) 160ms backwards; }
  :root:not([data-navigated]) .tide-hill  { animation: tide-drift 74s linear infinite, tide-rise 1300ms var(--ease-out) 260ms backwards; }

  /* Once it has arrived, the home crest rests on the tide. */
  .pupil-home .crest-stage { animation: crest-float 8s ease-in-out 1.8s infinite; }

  /* ------------------------------------------------------- scroll-driven

     Where the browser supports scroll timelines, the home banner gains depth
     as it scrolls away - the words drift slower than the page and dim, the
     tide swells up over it - and later sections rise as they are reached.
     Anything that is not supported is simply shown, never left hidden. */
  @supports (animation-timeline: scroll()) {
    @keyframes header-progress { to { transform: scaleX(1); } }
    @keyframes header-lift { to { box-shadow: 0 1px 0 rgb(0 65 75 / 10%), 0 12px 30px -8px rgb(0 43 51 / 14%); } }
    @keyframes copy-drift { to { translate: 0 14vh; opacity: .12; } }
    @keyframes crest-drift-out { to { translate: 0 18vh; scale: .9; opacity: .15; } }
    @keyframes tide-swell { to { transform: scaleY(1.45); } }

    .site-header { animation: header-lift linear both; animation-timeline: scroll(root); animation-range: 0 140px; }
    /* A thin gold reading line along the foot of the header. */
    .site-header::after {
      content: "";
      position: absolute;
      right: 0;
      bottom: -1px;
      left: 0;
      height: 2px;
      background: linear-gradient(90deg, var(--crest-gold), var(--gold-bright));
      transform: scaleX(0);
      transform-origin: left center;
      animation: header-progress linear both;
      animation-timeline: scroll(root);
    }
    .pupil-home .hero-copy { animation: copy-drift linear both; animation-timeline: scroll(root); animation-range: 0 90vh; }
    .pupil-home .crest-panel { animation: crest-drift-out linear both; animation-timeline: scroll(root); animation-range: 0 90vh; }
    .pupil-home .tide { animation: tide-swell linear both; animation-timeline: scroll(root); animation-range: 0 80vh; }
    /* On a phone the banner is taller than the screen and its buttons are
       still being read as it scrolls: keep them solid and in place. */
    @media (max-width: 760px) {
      .pupil-home .hero-copy, .pupil-home .crest-panel { animation: none; }
    }
  }

  @supports (animation-timeline: view()) {
    @keyframes reveal {
      from { opacity: 0; translate: 0 36px; }
      to   { opacity: 1; translate: 0 0; }
    }
    @keyframes steps-line { from { transform: scaleX(0); } to { transform: scaleX(1); } }
    @keyframes steps-line-y { from { transform: scaleY(0); } to { transform: scaleY(1); } }
    @keyframes step-in {
      from { opacity: 0; translate: 0 22px; }
      to   { opacity: 1; translate: 0 0; }
    }

    .pupil-home .how-intro,
    .pupil-home .form-panel,
    .pupil-home .tracking-panel,
    .pupil-home .poll-panel,
    .pupil-home .outcomes > .eyebrow,
    .pupil-home .outcomes > h2,
    .outcome-card,
    .info-item,
    .info-cta {
      animation: reveal linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 240px;
    }

    .how-steps ol { view-timeline: --steps block; }
    .how-steps ol::before { animation: steps-line linear both; animation-timeline: --steps; animation-range: entry 60% cover 50%; }
    .how-steps li { animation: step-in linear both; animation-timeline: --steps; }
    .how-steps li:nth-child(1) { animation-range: entry 20% entry 90%; }
    .how-steps li:nth-child(2) { animation-range: entry 50% cover 35%; }
    .how-steps li:nth-child(3) { animation-range: entry 80% cover 45%; }
  }

  /* ---------------------------------------------------- moments of state */

  button.is-busy::after { animation: spin 700ms linear infinite; }
  .loading-bar { animation: sweep 1.3s var(--ease-in-out) infinite; }
  .track-card { animation: rise-in 520ms var(--ease-out) both; }
  .track-rail::after { animation: rail-fill 900ms var(--ease-out) 240ms both; }
  .track-rail li.is-current::after { animation: dot-ring 2.4s var(--ease-out) 1.1s infinite; }
  /* Receiving an idea is the rare moment that earns a flourish. */
  .reference-card > * { animation: rise-in 560ms var(--ease-out) both; }
  .reference-card > :nth-child(2) { animation-delay: 60ms; }
  .reference-card > :nth-child(3) { animation-delay: 110ms; }
  .reference-card > code { animation: stamp 700ms var(--ease-out) 180ms both; }
  .reference-card > code::after { animation: ring-out 1000ms var(--ease-out) 520ms both; }
  .reference-card > :nth-child(n + 5) { animation-delay: 300ms; }
  .poll-option.is-chosen { animation: vote-confirm 280ms var(--ease-out) both; }

  /* Tally bars draw in from the left so a result reads as it appears. */
  .poll-tally-bar > span { transform-origin: left center; animation: bar-grow 760ms var(--ease-out) both; }

  /* Notices and dialogs. */
  #notice > *, #workspace-notice > *, .notice { animation: notice-in 300ms var(--ease-out) both; }
  dialog[open] { animation: dialog-in 240ms var(--ease-out) both; }
  dialog::backdrop { animation: soft-in 240ms ease both; }

  /* Workspace entrances. Like the public pages, the page structure only
     animates on arrival: once html[data-navigated] is set, paint() moves each
     page as a whole, and replaying these inside that transition would double
     the motion. Cards that arrive later, when their data loads, always rise. */
  .auth-page > .panel { animation: rise-in 420ms var(--ease-out) both; }
  :root:not([data-navigated]) .workspace-body > * { animation: rise-in 460ms var(--ease-out) both; }
  :root:not([data-navigated]) .workspace-body > :nth-child(2) { animation-delay: 60ms; }
  :root:not([data-navigated]) .workspace-body > :nth-child(3) { animation-delay: 120ms; }
  :root:not([data-navigated]) .workspace-body > :nth-child(4) { animation-delay: 180ms; }
  :root:not([data-navigated]) .workspace .admin-page-nav { animation: soft-in 400ms ease 120ms both; }
  /* The PLT member dashboard is a different layout: a sidebar plus .plt-main,
     with no .panel elements at all, so it needs its own coverage. */
  :root:not([data-navigated]) .plt-member-layout .plt-sidebar { animation: soft-in 420ms ease both; }
  :root:not([data-navigated]) .plt-main > * { animation: rise-in 460ms var(--ease-out) both; }
  :root:not([data-navigated]) .plt-main > :nth-child(2) { animation-delay: 60ms; }
  :root:not([data-navigated]) .plt-main > :nth-child(3) { animation-delay: 120ms; }
  :root:not([data-navigated]) .plt-main > :nth-child(4) { animation-delay: 180ms; }
  .idea-card, .poll-admin-card, .ballot-admin-card, .suggestion-card, .stat-chip, .access-log li { animation: rise-in 420ms var(--ease-out) both; }

  /* ------------------------------------------------ workspace transitions

     Staff pages swap on a short fade: they are visited many times a session
     and wait on Firestore, so they get speed rather than spectacle. */
  @keyframes page-in {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: none; }
  }
  #app.page-exit {
    opacity: 0;
    transition: opacity 110ms ease;
  }
  #app.page-enter { animation: page-in 260ms var(--ease-out) both; }
  /* During a navigation the page moves as a whole, so per-element entrances
     are held back rather than replayed on every click. */
  #app.page-enter *,
  #app.page-enter *::before,
  #app.page-enter *::after { animation: none !important; }

  /* ---------------------------------------------------- view transitions

     Public pages change through document.startViewTransition (app.js). Named
     pieces morph from their old place to their new one; everything else - the
     body of the page - is carried in on the tide: the new page is revealed
     behind a wave-edged mask while the old one sinks away beneath it. Going
     deeper the tide rises; coming back it falls. */
  @keyframes vt-tide-in {
    from { -webkit-mask-position: 0 0%; mask-position: 0 0%; }
    to   { -webkit-mask-position: 0 100%; mask-position: 0 100%; }
  }
  @keyframes vt-tide-in-back {
    from { -webkit-mask-position: 0 100%; mask-position: 0 100%; }
    to   { -webkit-mask-position: 0 0%; mask-position: 0 0%; }
  }
  @keyframes vt-recede {
    to { opacity: .2; transform: translateY(-4%) scale(.98); }
  }
  @keyframes vt-recede-back {
    to { opacity: .2; transform: translateY(4%) scale(.98); }
  }
  @keyframes vt-fade-out { to { opacity: 0; } }
  @keyframes vt-fade-in { from { opacity: 0; } }
  @keyframes vt-lift-in { from { opacity: 0; transform: translateY(28px); } }
  @keyframes vt-mark-in { from { opacity: 0; transform: scaleX(0); } }

  ::view-transition-group(*) {
    animation-duration: var(--page-morph);
    animation-timing-function: var(--ease-in-out);
  }
  ::view-transition-old(root),
  ::view-transition-new(root) { mix-blend-mode: normal; }
  ::view-transition-old(root) { animation: vt-recede var(--page-morph) var(--ease-in-out) both; }
  ::view-transition-new(root) {
    animation: vt-tide-in 760ms var(--ease-in-out) both;
    -webkit-mask: var(--tide-up) 0 0 / 100% 220% no-repeat;
    mask: var(--tide-up) 0 0 / 100% 220% no-repeat;
  }
  :root[data-transition="back"]::view-transition-old(root) { animation-name: vt-recede-back; }
  :root[data-transition="back"]::view-transition-new(root) {
    animation-name: vt-tide-in-back;
    -webkit-mask-image: var(--tide-down);
    mask-image: var(--tide-down);
  }

  /* The banner changes height between pages; clip it so it reads as one panel
     folding, and show both snapshots at their natural size from the top. */
  ::view-transition-group(rh-hero) {
    overflow: clip;
    /* Painted behind both snapshots, so wherever the shorter one runs out the
       panel is still teal rather than a see-through gap. */
    background: linear-gradient(162deg, #00474f 0%, #00363f 52%, #002b33 100%);
  }
  ::view-transition-old(rh-hero),
  ::view-transition-new(rh-hero) {
    width: 100%;
    height: 100%;
    object-fit: none;
    object-position: 50% 0;
  }
  /* The old banner's contents clear out early; the new ones arrive once the
     panel is close to its new size. */
  ::view-transition-old(rh-hero) { animation: vt-fade-out 280ms var(--ease-out) both; }
  ::view-transition-new(rh-hero) { animation: vt-fade-in 440ms var(--ease-out) 180ms both; }

  /* Titles hand over rather than smear: the old one leaves quickly, the new
     one settles in once the move is under way. */
  ::view-transition-old(rh-title) { animation: vt-fade-out 240ms var(--ease-out) both; }
  ::view-transition-new(rh-title) { animation: vt-fade-in 440ms var(--ease-out) 200ms both; }

  /* Pieces that exist on only one side of the change. */
  ::view-transition-new(rh-nav-mark):only-child { animation: vt-mark-in 460ms var(--ease-out) 220ms both; }
  ::view-transition-old(rh-nav-mark):only-child,
  ::view-transition-old(rh-safety):only-child,
  ::view-transition-old(rh-card):only-child { animation: vt-fade-out 220ms var(--ease-out) both; }
  ::view-transition-new(rh-safety):only-child,
  ::view-transition-new(rh-card):only-child { animation: vt-lift-in 620ms var(--ease-out) 200ms both; }

  /* Workspace pages (paint() in app.js): the banner and tab bar hold still,
     the gold mark slides to the new tab and the page body settles in. Kept
     short, because staff move between these pages all day. */
  @keyframes vt-content-in { from { opacity: 0; transform: translateY(12px); } }
  :root[data-transition="workspace"]::view-transition-group(*) { animation-duration: 380ms; }
  :root[data-transition="workspace"]::view-transition-old(root) { animation: vt-fade-out 160ms var(--ease-out) both; }
  :root[data-transition="workspace"]::view-transition-new(root) {
    -webkit-mask: none;
    mask: none;
    animation: vt-content-in 360ms var(--ease-out) 80ms both;
  }
}

/* Interactive feedback. Transitions are safe to declare unconditionally: the
   reduced-motion override below collapses them to nothing. */
.button, button, .poll-option, .nav-signin, .site-header nav a,
.footer-links a, .outcome-card, .poll-admin-card, .plt-choice-grid a {
  transition:
    transform 160ms var(--ease-out),
    background-color 180ms ease,
    border-color 180ms ease,
    color 180ms ease,
    box-shadow 220ms ease;
}
@media (hover: hover) and (pointer: fine) {
  .button:hover, button:hover, .poll-option:hover:not(:disabled) { transform: translateY(-1px); }
  .button:hover > span[aria-hidden="true"] { transform: translate(2px, -2px); }
  .outcome-card:hover, .poll-admin-card:hover { box-shadow: var(--shadow-md); }
  .brand:hover .brand-crest { transform: rotate(-4deg) scale(1.05); }
}
.button:active, button:active, .poll-option:active:not(:disabled) { transform: scale(.97); }
button:disabled:active { transform: none; }
.poll-option.is-chosen { transform: none; }
.brand-crest { transition: transform 320ms var(--ease-out); }

/* ------------------------------------------------------------------ events

   The budget sits at the top, then each event is a card: its date, what it
   is, its running total and its shopping list. Every amount is set in
   tabular figures so the pounds line up down the list. The cards size their
   insides to their own width (a container), because the same card sits
   beside the member sidebar and across the full administrator page. */
.events-page { display: grid; gap: var(--gap-stack); }
.events-page .panel { margin: 0; }
.events-page form { display: grid; gap: var(--gap-field); margin: 0; }
.events-page form > p { margin: 0; }
.events-page textarea { min-height: 5.5rem; }

.events-page .budget-summary h2 {
  margin: .4rem 0 .35rem;
  color: var(--ocean);
  font-size: clamp(1.7rem, 3.4vw, 2.4rem);
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}
.events-page .budget-summary h2.is-over { color: var(--danger); }
.budget-summary .small-print { max-width: 62ch; margin: 0; }
.budget-meter {
  position: relative;
  display: flex;
  height: .75rem;
  margin-top: var(--space-m);
  overflow: hidden;
  border-radius: 999px;
  background: var(--ocean-wash);
  box-shadow: inset 0 0 0 1px var(--line);
}
.budget-spent { background: var(--ocean); }
.budget-planned { background: repeating-linear-gradient(135deg, var(--crest-gold) 0 5px, var(--gold-bright) 5px 10px); }
.budget-limit { position: absolute; top: 0; bottom: 0; width: 3px; margin-left: -1.5px; background: var(--danger); box-shadow: 0 0 0 1px #fff; }
.budget-figures { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--gap-list); margin: var(--space-s) 0 0; }
.budget-figures div { padding: var(--space-xs) var(--space-s); border-radius: .8rem; background: var(--ocean-wash); }
.budget-figures dt { display: flex; align-items: center; gap: .4rem; color: var(--muted); font-size: .76rem; font-weight: 700; }
.budget-figures dd { margin: .2rem 0 0; color: var(--ocean); font-size: 1.15rem; font-weight: 700; font-variant-numeric: tabular-nums; }
.budget-figures [data-figure="over"] dd { color: var(--danger); }
/* The key to the two colours in the meter. */
:is([data-figure="spent"], [data-figure="planned"]) dt::before { content: ""; width: .6rem; height: .6rem; border-radius: 2px; }
[data-figure="spent"] dt::before { background: var(--ocean); }
[data-figure="planned"] dt::before { background: var(--crest-gold); }
.budget-edit { margin-top: var(--space-m); padding-top: var(--space-s); border-top: 1px solid var(--line); }
.budget-edit > summary, .past-events > summary {
  display: flex;
  align-items: center;
  width: fit-content;
  min-height: 44px;
  color: var(--ocean);
  font-weight: 700;
  cursor: pointer;
}
.budget-edit form { grid-template-columns: repeat(auto-fit, minmax(min(12rem, 100%), 1fr)); align-items: end; margin-top: var(--space-2xs); }
.budget-edit form > .button { grid-column: 1 / -1; justify-self: start; }

.events-upcoming { display: grid; gap: var(--space-s); }
.events-bar { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-xs) var(--space-s); }
.events-bar h2 { margin: 0; color: var(--ink); font-size: clamp(1.35rem, 2vw, 1.6rem); line-height: 1.2; letter-spacing: -.015em; }
.event-list { display: grid; gap: var(--gap-stack); }
.past-events[open] > summary { margin-bottom: var(--space-s); }
.past-events .event-date { background: var(--muted); }

.event-card { container-type: inline-size; }
.event-card > * + * { margin-top: var(--space-m); }
.event-card > .event-status:empty { margin-top: 0; }
.event-head { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: var(--space-s); align-items: start; }
.event-date {
  display: grid;
  place-items: center;
  width: 3.6rem;
  margin: 0;
  padding: .5rem 0 .55rem;
  border-radius: .8rem;
  background: var(--ocean);
  color: #fff;
  line-height: 1;
}
.event-date span { color: var(--aqua); font-size: .66rem; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; }
.event-date strong { margin-top: .25rem; font-size: 1.55rem; font-variant-numeric: tabular-nums; }
.event-when { margin: 0; color: var(--muted); font-size: .8rem; font-weight: 700; }
.events-page .event-heading h3 { margin: .25rem 0 0; color: var(--ink); font-size: 1.2rem; line-height: 1.2; overflow-wrap: anywhere; }
.event-details { max-width: 62ch; margin: .4rem 0 0; color: var(--muted); font-size: .9rem; }
.event-sum { display: grid; justify-items: end; gap: .15rem; margin: 0; text-align: right; }
.event-sum strong { color: var(--ocean); font-size: 1.2rem; font-variant-numeric: tabular-nums; }
.event-sum small { color: var(--muted); font-size: .76rem; }

/* The list: fixed columns for the amounts so they line up row to row. */
.shopping-list { margin: 0; padding: 0; list-style: none; border-top: 1px solid var(--line); }
.shopping-item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 7.5rem 5.5rem 7rem;
  grid-template-areas: "check qty line actions";
  align-items: center;
  gap: 0 var(--space-s);
  padding: .15rem 0;
  border-bottom: 1px solid var(--line);
}
.shopping-item.is-editing { display: block; padding: var(--space-s) 0; }
.shopping-check { grid-area: check; display: flex; align-items: center; gap: .7rem; min-height: 44px; color: var(--ink); font-size: .95rem; font-weight: 600; cursor: pointer; }
.shopping-check input { flex: none; width: 1.2rem; height: 1.2rem; min-height: 0; margin: 0; padding: 0; accent-color: var(--ocean); cursor: pointer; }
.shopping-name { overflow-wrap: anywhere; }
.shopping-item[data-bought] .shopping-name { color: var(--muted); text-decoration: line-through; text-decoration-color: var(--line-strong); }
.shopping-qty { grid-area: qty; color: var(--muted); font-size: .84rem; text-align: right; font-variant-numeric: tabular-nums; }
.shopping-line { grid-area: line; color: var(--ink); text-align: right; font-variant-numeric: tabular-nums; }
.shopping-item[data-bought] .shopping-line { color: var(--muted); }
.shopping-actions { grid-area: actions; display: flex; justify-content: flex-end; gap: .9rem; font-size: .82rem; }
.shopping-actions .link-button { display: inline-flex; align-items: center; min-height: 44px; }

.item-form {
  grid-template-columns: minmax(0, 1fr) 6rem 8rem auto;
  grid-template-areas: "name qty price ." "link link link buttons";
  align-items: end;
}
.item-name { grid-area: name; }
.item-qty { grid-area: qty; }
.item-price { grid-area: price; }
.item-link { grid-area: link; }
.item-buttons { grid-area: buttons; }
.item-buttons { display: flex; gap: .5rem; }
.item-buttons .button-small { min-height: 44px; }
.event-status .notice { margin: 0; }
.event-actions { display: flex; flex-wrap: wrap; gap: .5rem; padding-top: var(--space-s); border-top: 1px solid var(--line); }
.event-delete { color: var(--danger); border-color: rgb(164 43 29 / 35%); }
.event-delete:hover { border-color: var(--danger); background: rgb(164 43 29 / 7%); color: var(--danger); }

/* The profit calculator: folded under each list, with its headline figure
   in the fold so the answer shows without opening it. Profit reads green and
   a loss red, in the numbers as well as the words. */
.roi { border: 1px solid var(--line); border-radius: .9rem; background: var(--canvas); }
.roi > summary {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: .2rem 1rem;
  min-height: 44px;
  padding: var(--space-xs) var(--space-s);
  cursor: pointer;
}
.roi[open] > summary { border-bottom: 1px solid var(--line); }
.roi-title { color: var(--ocean); font-weight: 700; }
.roi-headline { color: var(--muted); font-size: .85rem; font-weight: 600; font-variant-numeric: tabular-nums; }
.roi-headline[data-tone="gain"], .roi-figures [data-tone="gain"] dd { color: var(--success); }
.roi-headline[data-tone="loss"], .roi-figures [data-tone="loss"] dd { color: var(--danger); }
.events-page .roi-form { padding: var(--space-s); }
.roi-sales { display: grid; gap: var(--space-xs); min-width: 0; margin: 0; padding: 0; border: 0; }
.roi-sales legend { margin-bottom: var(--space-2xs); padding: 0; color: var(--ink); font-size: .84rem; font-weight: 700; }
.roi-lines { display: grid; gap: var(--space-xs); }
.roi-line { display: grid; grid-template-columns: minmax(0, 1fr) 6rem 7rem auto; gap: var(--space-xs); align-items: end; }
.roi-line .link-button, .roi-sales [data-add-sale] { display: inline-flex; align-items: center; min-height: 44px; }
.roi-sales [data-add-sale] { justify-self: start; }
.roi-sales [data-add-sale][hidden] { display: none; }
/* Two columns reading like the sum (money in, costs, then the profit across
   both), and one row of five once the card is wide enough. */
.roi-figures { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--gap-list); margin: 0; }
.roi-figures > [data-tone] { grid-column: 1 / -1; }
@container (min-width: 48rem) {
  .roi-figures { grid-template-columns: repeat(5, minmax(0, 1fr)); }
  .roi-figures > [data-tone] { grid-column: auto; }
}
.roi-figures div { padding: var(--space-xs) var(--space-s); border: 1px solid var(--line); border-radius: .8rem; background: #fff; }
.roi-figures dt { color: var(--muted); font-size: .76rem; font-weight: 700; }
.roi-figures dd { margin: .2rem 0 0; color: var(--ocean); font-size: 1.15rem; font-weight: 700; font-variant-numeric: tabular-nums; }
.roi-figures small { display: block; margin-top: .2rem; color: var(--muted); font-size: .74rem; line-height: 1.35; }
.roi-breakeven { margin: var(--space-s) 0 0; color: var(--ink); font-size: .9rem; }
@container (max-width: 36rem) {
  .roi-line { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .roi-line > label:first-child { grid-column: 1 / -1; }
  .roi-line .link-button { grid-column: 1 / -1; justify-self: start; min-height: 36px; }
}

@container (max-width: 36rem) {
  .event-head { grid-template-columns: auto minmax(0, 1fr); }
  .event-sum { grid-column: 1 / -1; display: flex; align-items: baseline; gap: .6rem; justify-content: flex-start; text-align: left; }
  .shopping-item { grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "check line" "qty actions"; padding: .3rem 0 .4rem; }
  .shopping-qty { padding-left: 1.9rem; text-align: left; }
  .item-form { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); grid-template-areas: "name name" "qty price" "link link" "buttons buttons"; }
}
@media (max-width: 560px) {
  .budget-figures { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ------------------------------------------------------------- new pieces

   Small labels, the "I'll get this" claim, what pupils see of an event, the
   pupil home page's "What's on", the impact report, the clear-out panel and
   the "new" dots on a member's menu. Surfaces use --surface so the dark
   colours can reach them. */
:root { --surface: #fff; }

.tag {
  display: inline-block;
  padding: .12rem .5rem;
  border-radius: 1rem;
  background: var(--ocean-tint);
  color: var(--ocean);
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  vertical-align: .1em;
}

/* A shopping row: the name, and beside it who is getting it. */
.shopping-main { grid-area: check; display: flex; flex-wrap: wrap; align-items: center; gap: 0 .8rem; min-width: 0; }
.shopping-check { grid-area: auto; }
.shopping-claim { color: var(--muted); font-size: .78rem; font-weight: 600; }
.shopping-claim[data-claim="mine"] { color: var(--success); }
button.shopping-claim, .shopping-claim .link-button { display: inline-flex; align-items: center; min-height: 32px; font-size: .78rem; }
/* Where to buy it: a quiet link beside the name, opening the shop in a new tab. */
.shopping-link { display: inline-flex; align-items: center; gap: .2rem; min-height: 32px; color: var(--ocean); font-size: .78rem; font-weight: 700; text-underline-offset: .2em; }
@media (pointer: coarse) { .shopping-link { min-height: 44px; } }
@media (pointer: coarse) { button.shopping-claim, .shopping-claim .link-button { min-height: 44px; } }

.events-tools { display: flex; flex-wrap: wrap; gap: .5rem; }
.event-public { padding-top: var(--space-s); border-top: 1px solid var(--line); }
.event-public-note { margin: 0; color: var(--muted); font-size: .85rem; }
.event-public .suggestion-actions { margin-top: var(--space-2xs); }
.event-public-form { margin-top: var(--space-s); }
.roi-budget { margin-top: var(--space-2xs); }
.roi-budget .small-print { margin: .4rem 0 0; }

/* What's on, on the pupil home page. */
.whats-on-lede { margin: .2rem 0 0; color: var(--muted); }
.whats-on-list { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr)); gap: var(--gap-list); margin: var(--space-m) 0 0; padding: 0; list-style: none; }
.whats-on-item { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--space-s); align-items: start; padding: var(--pad-card); border: 1px solid var(--line); border-radius: 1rem; background: var(--canvas); }
.whats-on-item h3 { margin: 0; color: var(--ink); font-size: 1.05rem; line-height: 1.25; overflow-wrap: anywhere; }
.whats-on-item p { margin: .3rem 0 0; font-size: .88rem; }
.whats-on-when { color: var(--muted); font-weight: 700; font-size: .78rem !important; }

/* The impact report: a document, on screen and on paper. */
.report-form { display: grid; grid-template-columns: repeat(2, minmax(0, 12rem)) 1fr; gap: var(--gap-field); align-items: end; }
.report-form input { min-width: 0; }
.report-buttons { display: flex; flex-wrap: wrap; gap: .5rem; justify-content: flex-end; }
.report-controls .small-print { margin: var(--space-2xs) 0 0; }
.report-controls .small-print:empty { display: none; }
.report-head { display: flex; align-items: center; gap: var(--space-s); padding-bottom: var(--space-m); border-bottom: 2px solid var(--ocean); }
.report-head img { flex: none; width: 3.5rem; height: 3.5rem; }
.report-head h2 { margin: .2rem 0; color: var(--ocean); font-size: clamp(1.6rem, 3vw, 2.1rem); }
.report-head p { margin: 0; }
.report-section { padding: var(--space-m) 0; border-bottom: 1px solid var(--line); break-inside: avoid; }
.report-section h3 { margin: 0 0 var(--space-xs); color: var(--ocean); font-size: 1.2rem; }
.report-section h4 { margin: 0 0 var(--space-2xs); color: var(--ink); font-size: .95rem; }
.report-section > p { max-width: 70ch; margin: 0 0 var(--space-s); }
.report-stats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--gap-list); margin: 0; }
.report-stats div { padding: var(--space-xs) var(--space-s); border-radius: .8rem; background: var(--ocean-wash); }
.report-stats dt { color: var(--muted); font-size: .76rem; font-weight: 700; }
.report-stats dd { margin: .2rem 0 0; color: var(--ocean); font-size: 1.5rem; font-weight: 700; font-variant-numeric: tabular-nums; }
.report-columns { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr)); gap: var(--space-m); }
.report-bars { display: grid; gap: .35rem; }
.report-bar { display: grid; grid-template-columns: minmax(6rem, 9rem) minmax(0, 1fr) 4.5rem; gap: .6rem; align-items: center; font-size: .82rem; }
.report-bar-label { overflow-wrap: anywhere; }
.report-bar-track { height: .6rem; overflow: hidden; border-radius: 999px; background: var(--ocean-wash); }
.report-bar-fill { display: block; width: 0; height: 100%; border-radius: inherit; background: var(--ocean); print-color-adjust: exact; -webkit-print-color-adjust: exact; }
.report-bar-value { font-weight: 700; font-variant-numeric: tabular-nums; text-align: right; }
.report-bar-value small { color: var(--muted); font-weight: 600; }
.report-poll + .report-poll { margin-top: var(--space-m); }
.report-poll .small-print { margin: 0 0 var(--space-2xs); }
.report-note { margin: var(--space-2xs) 0 0; font-size: .88rem; }
.report-outcomes { display: grid; gap: var(--gap-list); margin: 0; padding-left: 1.2rem; }
.report-outcomes p { margin: .2rem 0; }
.report-outcomes small { color: var(--muted); }
.report-table { width: 100%; border-collapse: collapse; font-size: .88rem; font-variant-numeric: tabular-nums; }
.report-table th, .report-table td { padding: .5rem .6rem; border-bottom: 1px solid var(--line); text-align: right; }
.report-table :is(th, td):first-child { text-align: left; }
.report-table thead th { color: var(--muted); font-size: .76rem; }
.report-table tfoot :is(th, td) { border-bottom: 0; font-weight: 700; }
.report-foot p { margin: var(--space-m) 0 0; color: var(--muted); font-size: .8rem; }
@media (max-width: 760px) {
  .report-form { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .report-buttons { grid-column: 1 / -1; justify-content: flex-start; }
  .report-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .report-table { display: block; overflow-x: auto; }
}

/* Clearing out old records. */
.cleanup-panel form { display: grid; gap: var(--gap-field); max-width: 30rem; margin-top: var(--space-s); }
.cleanup-result:not(:empty) { margin-top: var(--space-s); }
.cleanup-result p { margin: 0 0 var(--space-2xs); }
.cleanup-counts { margin: 0 0 var(--space-xs); padding-left: 1.2rem; }
.access-log li[data-event="deleted"] .access-log-dot { background: var(--danger); box-shadow: 0 0 0 4px rgb(164 43 29 / 12%); }
.access-log li[data-event="cleanup"] .access-log-dot { background: var(--muted); box-shadow: 0 0 0 4px rgb(74 97 103 / 14%); }

/* Something new in that part of the workspace since the member last looked. */
.nav-new { flex: none; width: .5rem; height: .5rem; margin-left: .5rem; border-radius: 50%; background: var(--crest-gold); box-shadow: 0 0 0 3px rgb(218 147 23 / 25%); }
.nav-new[hidden] { display: none; }

/* The colour choices, each shown as a little swatch of itself. */
.reading-themes { grid-template-columns: 1fr; }
.reading-themes label { grid-template-columns: 2.6rem minmax(0, 1fr); justify-items: start; align-items: center; align-content: center; min-height: 44px; padding: .3rem .75rem; font-size: .8rem; }
.theme-sample { width: 1.6rem; height: 1.6rem; border: 1px solid var(--line-strong); border-radius: 50%; }
.theme-light { background: #f7f9f9; }
.theme-dark { background: #10262a; }
.theme-auto { background: linear-gradient(135deg, #f7f9f9 50%, #10262a 50%); }

/* ---------------------------------------------------------- more pieces

   The idle warning, the pupil board, poll closing times and years, the month
   view, PLT actions, bulk moves on submissions and the noticeboard poster.
   Colours come from the tokens, so the dark scheme reaches all of them. */

/* "Still there?" before an idle workspace signs itself out. */
.idle-warning {
  position: fixed;
  z-index: 200;
  right: 1rem;
  bottom: 1rem;
  width: min(22rem, calc(100% - 2rem));
  padding: var(--space-s) var(--space-m);
  border: 1px solid var(--line);
  border-top: 3px solid var(--crest-gold);
  border-radius: 1rem;
  background: var(--surface);
  box-shadow: var(--shadow-lg);
}
.idle-warning p { margin: 0 0 var(--space-xs); }

/* The pupil board. */
.board-lede { margin: .2rem 0 0; color: var(--muted); }
.board-list { display: grid; gap: var(--gap-list); margin: var(--space-m) 0 0; padding: 0; list-style: none; }
.board-item { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--space-s); align-items: center; padding: var(--pad-card); border: 1px solid var(--line); border-radius: 1rem; background: var(--canvas); }
.board-copy h3 { margin: .35rem 0 0; color: var(--ink); font-size: 1.05rem; line-height: 1.3; overflow-wrap: anywhere; }
.board-copy p { margin: .3rem 0 0; color: var(--muted); font-size: .88rem; }
.board-back { display: grid; justify-items: end; gap: .35rem; text-align: right; }
.board-count { margin: 0; color: var(--muted); font-size: .8rem; }
.board-count strong { display: block; color: var(--ocean); font-size: 1.5rem; line-height: 1; font-variant-numeric: tabular-nums; }
.board-backed { margin: 0; color: var(--success); font-size: .82rem; font-weight: 700; }
.board-status:empty { display: none; }
.board-status { margin: var(--space-s) 0 0; font-size: .88rem; }
@media (max-width: 560px) {
  .board-item { grid-template-columns: minmax(0, 1fr); }
  .board-back { grid-template-columns: auto 1fr; justify-items: start; align-items: center; text-align: left; }
  .board-back .board-button, .board-back .board-backed { justify-self: end; }
}
.board-admin form { display: grid; gap: var(--gap-field); margin-top: var(--space-s); }
.board-admin-list { display: grid; gap: var(--gap-list); margin-top: var(--space-m); }
.idea-board { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem 1rem; margin-top: 1rem; }

/* Poll closing times and the year question. */
.poll-extras { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(14rem, 100%), 1fr)); gap: var(--gap-field); align-items: end; }
.poll-closes { margin: .2rem 0 var(--space-xs); color: var(--muted); font-size: .88rem; font-weight: 600; }
.poll-year { display: grid; gap: .35rem; max-width: 16rem; margin: 0 0 var(--space-s); }
.poll-years { width: 100%; margin: var(--space-s) 0; border-collapse: collapse; font-size: .82rem; font-variant-numeric: tabular-nums; }
.poll-years caption { margin-bottom: .3rem; color: var(--muted); font-weight: 700; text-align: left; }
.poll-years th, .poll-years td { padding: .35rem .5rem; border-bottom: 1px solid var(--line); text-align: right; }
.poll-years :is(th, td):first-child { text-align: left; }

/* The month view. */
.events-month { container-type: inline-size; }
.month-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-s); margin-bottom: var(--space-s); }
.month-head h3 { margin: 0; color: var(--ink); font-size: 1.15rem; }
.month-weekdays, .month-grid { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 4px; }
.month-weekdays { margin-bottom: 4px; color: var(--muted); font-size: .72rem; font-weight: 700; text-align: center; }
.month-grid { margin: 0; padding: 0; list-style: none; }
.month-day { min-height: 5.2rem; padding: .35rem .4rem; border: 1px solid var(--line); border-radius: .6rem; background: var(--surface); }
.month-day.is-blank { border-color: transparent; background: transparent; }
.month-day.is-today { border-color: var(--crest-gold); box-shadow: inset 0 0 0 1px var(--crest-gold); }
.month-day.has-events { background: var(--ocean-wash); }
.month-num { color: var(--muted); font-size: .75rem; font-weight: 700; }
.month-day ul { display: grid; gap: .2rem; margin: .25rem 0 0; padding: 0; list-style: none; }
.month-event { width: 100%; padding: .2rem .35rem; border: 0; border-radius: .4rem; background: var(--ocean); color: #fff; font: inherit; font-size: .72rem; font-weight: 600; line-height: 1.25; text-align: left; overflow-wrap: anywhere; cursor: pointer; }
.month-event:hover { background: var(--ocean-deep); }
.month-empty { margin: var(--space-s) 0 0; color: var(--muted); font-size: .88rem; }
@container (max-width: 40rem) {
  .month-weekdays, .month-day.is-blank, .month-day:not(.has-events) { display: none; }
  .month-grid { grid-template-columns: minmax(0, 1fr); gap: var(--space-2xs); }
  .month-day { display: grid; grid-template-columns: 7.5rem minmax(0, 1fr); align-items: start; min-height: 0; }
  .month-num .visually-hidden { position: static; width: auto; height: auto; margin: 0; overflow: visible; clip-path: none; white-space: normal; color: var(--ink); }
  .month-num [aria-hidden="true"] { display: none; }
  .month-day ul { margin: 0; }
}
.event-ics { display: inline-flex; align-items: center; min-height: 32px; margin-top: .35rem; font-size: .8rem; }
@media (pointer: coarse) { .event-ics { min-height: 44px; } }

/* PLT actions. */
.actions-page { display: grid; gap: var(--gap-stack); }
.actions-page .panel { margin: 0; }
.actions-page form { display: grid; gap: var(--gap-field); margin: 0; }
.actions-page textarea { min-height: 4.5rem; }
.action-due-field { max-width: 14rem; }
.actions-heading { margin: 0 0 var(--space-xs); color: var(--ink); font-size: clamp(1.2rem, 2vw, 1.4rem); }
.action-count { color: var(--muted); font-size: .9rem; font-weight: 600; }
.action-list { display: grid; gap: var(--gap-list); margin: 0; padding: 0; list-style: none; }
.action-card { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--space-s); align-items: start; padding: var(--pad-card); border: 1px solid var(--line); border-left: 4px solid var(--ocean); border-radius: 1rem; background: var(--surface); }
.action-card[data-done] { border-left-color: var(--success); opacity: .85; }
.action-card[data-done] h3 { text-decoration: line-through; text-decoration-color: var(--line-strong); }
.action-card:has(form) { display: block; }
.action-main h3 { margin: 0; color: var(--ink); font-size: 1.02rem; overflow-wrap: anywhere; }
.action-main p { margin: .3rem 0 0; }
.action-meta { display: flex; flex-wrap: wrap; gap: .2rem 1rem; color: var(--muted); font-size: .82rem; }
.action-due { font-weight: 700; }
.action-due.is-overdue { color: var(--danger); }
.action-buttons { display: flex; flex-wrap: wrap; justify-content: flex-end; align-items: center; gap: .4rem; }
.action-edit { display: flex; gap: .8rem; font-size: .82rem; }
.action-edit .link-button { display: inline-flex; align-items: center; min-height: 36px; }
.actions-done[open] > summary { margin-bottom: var(--space-s); }
@media (max-width: 640px) {
  .action-card { grid-template-columns: minmax(0, 1fr); }
  .action-buttons { justify-content: flex-start; }
}

/* Moving several submissions at once. */
.idea-row { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: .6rem; align-items: start; }
.idea-row[hidden] { display: none; }
.idea-select { display: grid; place-items: center; width: 44px; height: 44px; margin-top: .6rem; cursor: pointer; }
.idea-select input { width: 1.2rem; height: 1.2rem; min-height: 0; margin: 0; padding: 0; accent-color: var(--ocean); cursor: pointer; }
.bulk-bar {
  position: sticky;
  z-index: 20;
  bottom: .75rem;
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  gap: var(--space-xs) var(--space-s);
  margin: 0 0 var(--space-s);
  padding: var(--space-s);
  border: 1px solid var(--line-strong);
  border-radius: 1rem;
  background: var(--surface);
  box-shadow: var(--shadow-md);
}
.bulk-bar[hidden] { display: none; }
.bulk-count { align-self: center; margin: 0; font-size: .9rem; }
.bulk-bar label { display: grid; gap: .3rem; font-size: .8rem; }
.bulk-message { flex: 1 1 16rem; }
.bulk-bar .suggestion-actions { margin: 0; }

/* The noticeboard poster: an A4 sheet on screen, and alone on the paper. */
.poster {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-s);
  width: min(100%, 210mm);
  margin: 0 auto;
  padding: clamp(1.5rem, 5vw, 3.5rem);
  aspect-ratio: 210 / 297;
  border: 1px solid var(--line);
  border-radius: 1rem;
  background: #fff;
  color: #0b2a30;
  text-align: center;
  box-shadow: var(--shadow-md);
}
.poster-head { display: flex; align-items: center; gap: .9rem; }
.poster-head img { width: 4.5rem; height: 4.5rem; }
.poster-head p { margin: 0; color: #00414b; font-size: 1.2rem; font-weight: 700; text-align: left; line-height: 1.2; }
.poster-head span { display: block; color: #93620a; font-size: .8rem; letter-spacing: .2em; text-transform: uppercase; }
.poster-title { max-width: 16ch; margin: var(--space-s) 0 0; color: #00414b; font-size: clamp(2rem, 6vw, 3.4rem); line-height: 1.05; letter-spacing: -.02em; text-wrap: balance; }
.poster-lede { margin: 0; font-size: clamp(1.05rem, 2.6vw, 1.35rem); }
.poster-qr { width: min(60%, 9cm); height: auto; margin: var(--space-s) 0 0; }
.poster-scan { margin: 0; font-size: 1.15rem; font-weight: 700; }
.poster-address { margin: 0; }
.poster-foot { margin: auto 0 0; color: #3b5358; font-size: .9rem; }
@media print {
  @page { size: A4 portrait; margin: 12mm; }
  body:has(.poster) .poster-controls { display: none !important; }
  body:has(.poster) .workspace-body { width: 100%; }
  .poster { width: 100%; height: 270mm; aspect-ratio: auto; border: 0; border-radius: 0; box-shadow: none; }
  .idle-warning { display: none; }
}

/* ------------------------------------------------------------ spacing

   One scale for the whole site. Four stylesheets have set spacing over time,
   so the same kind of thing ended up 10, 13, 16, 19, 26 or 32px apart
   depending on which page it was on. These roles come last and win: a panel
   is padded the same on the pupil home page as in the workspace, panels sit
   the same distance apart everywhere, and every form has the same rhythm.
   Each role is fluid, so a phone gets the small end and a desktop the large.

     --space-*       the raw steps (4, 8, 12, 16, 24, 32, 48px)
     --pad-panel     inside a panel                      20 → 40px
     --pad-card      inside a card within a panel        16 → 20px
     --gap-stack     between panels, across or down      20 → 32px
     --gap-list      between cards in a list or row             12px
     --gap-field     between form fields                        16px
     --space-section above and below an open page section 40 → 72px   */
:root {
  --space-3xs: .25rem;
  --space-2xs: .5rem;
  --space-xs: .75rem;
  --space-s: 1rem;
  --space-m: 1.5rem;
  --space-l: 2rem;
  --space-xl: 3rem;
  --pad-panel: clamp(1.25rem, 3vw, 2.5rem);
  --pad-card: clamp(1rem, 2vw, 1.25rem);
  --gap-stack: clamp(1.25rem, 2.5vw, 2rem);
  --gap-list: var(--space-xs);
  --gap-field: var(--space-s);
  --space-section: clamp(2.5rem, 6vw, 4.5rem);
}

/* Panels: the same padding on every page. */
.panel,
.pupil-home :is(.form-panel, .tracking-panel, .poll-panel),
.auth-page .auth-card,
.info-summary,
.plt-choice-card { padding: var(--pad-panel); }

/* Panels stack and sit side by side the same distance apart. */
.panel,
.pupil-home > .panel { margin-bottom: var(--gap-stack); }
.pupil-home > .poll-panel { margin-top: var(--gap-stack); }
.workspace-body > :is(.panel, .tool-grid, .admin-account-grid, .review-overview) { margin-bottom: var(--gap-stack); }
.tool-grid, .admin-account-grid, .poll-suggest-grid { gap: var(--gap-stack); }
.tool-grid > .panel, .admin-account-grid > .panel, .poll-suggest-grid > .panel { margin: 0; }
.workspace .admin-page-nav { margin-bottom: var(--gap-stack); }
.plt-main .plt-head { margin-bottom: var(--gap-stack); }
.plt-stats { gap: var(--gap-list); margin: 0 0 var(--gap-stack); }

/* Open sections on the home page (no card around them) breathe evenly
   above and below their content; the divider line sits a panel-gap below
   whatever came before. */
.how-steps { padding-block: var(--space-section); }
.pupil-home .panel.outcomes { margin-top: 0; padding: var(--space-section) 0 0; }

/* Cards inside panels. */
.suggestion-card,
.ballot-admin-card,
.poll-admin-card,
.member-row,
.vote-card,
.plt-stats article,
.outcome-card,
.code-list article,
.code-list article.code-admin,
.ai-suggestion { padding: var(--pad-card); }
/* The choice cards keep room on the right for their arrow. */
.plt-choice-grid a { padding: var(--pad-card) calc(var(--pad-card) + 1.6rem) var(--pad-card) var(--pad-card); }
.plt-choice-grid { gap: var(--gap-list); }

/* Cards in a list. */
.suggestion-list, .member-list, .code-list, .poll-proposals,
#idea-list, #public-poll-list, #ballot-admin-list, #vote-topic-list { display: grid; gap: var(--gap-list); }
:is(#idea-list, #public-poll-list, #ballot-admin-list, #vote-topic-list) > * { margin-top: 0; margin-bottom: 0; }

/* Forms: fields 16px apart, a little more before the buttons, and a helper
   row (sentence starters, quick updates) held close to the field it serves. */
:is(.form-panel, .auth-page, .idea-card, .admin-tools, .plt-main, .code-dashboard, .events-page) form,
#poll-proposal-form, .proposal-form { gap: var(--gap-field); }
:is(.form-panel, .auth-page, .idea-card, .admin-tools, .plt-main, .code-dashboard, .events-page) form > p,
:is(#poll-proposal-form, .proposal-form) > p { margin: 0; }
:is(.form-panel, .auth-page, .idea-card, .admin-tools, .plt-main, .code-dashboard, .events-page) form > :is(button[type="submit"], .actions, .suggestion-actions),
:is(#poll-proposal-form, .proposal-form) > :is(button[type="submit"], .suggestion-actions) { margin-top: var(--space-2xs); }
.writing-starters, .update-templates { margin-top: calc(var(--gap-field) / -2); }
/* Two older rules name these forms by id, so the roles repeat them here. */
.form-panel #idea-form { gap: var(--gap-field); }
.auth-card #login-form > button { margin-top: var(--space-2xs); }

/* Printing. Paper has no use for the sticky header or the moving tide, and
   "Print" on the idea-received card prints that card alone. */
@media print {
  .site-header { position: static; -webkit-backdrop-filter: none; backdrop-filter: none; box-shadow: none; }
  .tide, .crest-sun, .skip-link { display: none !important; }
  :root.print-reference body * { visibility: hidden; }
  :root.print-reference .reference-card,
  :root.print-reference .reference-card * { visibility: visible; }
  :root.print-reference .reference-card { position: absolute; top: 0; right: 0; left: 0; }
  :root.print-reference .reference-card .hero-actions,
  :root.print-reference #copy-status,
  :root.print-reference .reference-links { display: none; }
  .reference-card code { border: 2px solid #000; background: none; color: #000; box-shadow: none; }
  .reference-card code::after { display: none; }
  /* Workspace pages print as their content: the impact report as a clean
     document, the events page as its shopping lists with their totals. */
  body:has(:is(.workspace, .plt-member-layout)) :is(.site-header, .prototype-banner, .staff-preview-bar, .footer),
  .workspace .page-hero, .admin-page-nav, .plt-sidebar, .report-controls, #workspace-notice,
  .events-tools, #event-form-panel, .item-form, .roi, .event-public, .event-actions, .event-status, .budget-edit, .shopping-actions, .shopping-claim, .past-events { display: none !important; }
  .plt-member-layout { display: block; }
  .plt-main { padding: 0; }
  .panel, .report { border: 0; box-shadow: none; }
  .event-card, .report-section { break-inside: avoid; }
}

/* Hard stop. Anything above is cancelled for anyone who asks for less motion. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-delay: 0ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}

/* ==========================================================================
   Rosehill Pupil Voice - dark colour theme
   Appended after school.css. Every rule below lives under
   :root[data-scheme="dark"] (set by prefs.js before first paint), so light
   mode is completely untouched and nothing here needs a media query.

   The approach: school.css already routes almost every colour through a
   small set of custom properties (--canvas, --ink, --ocean, --line...), so
   most of this file is those tokens re-pointed at dark values. That alone
   re-themes dozens of components for free (every --ocean-wash hover fill,
   every --line border, the tide's page-coloured edge, the budget and report
   washes). Two tokens are used BOTH as body text/links AND as a solid fill
   behind white text or a white tick icon (--ocean for buttons, --danger for
   the delete button): those are brightened for text as usual, then the
   handful of solid-fill spots are pinned back to a fixed dark tint so white
   text and icons on top stay readable. Everywhere else a colour is written
   as a literal hex (mostly '#fff' card backgrounds, and a few cream/rose
   "wash" badges), the same selector is overridden directly, grouped below by
   the part of the app it belongs to. The teal banners, the crest medallion
   and anything that is already dark in both modes (the sidebar, the staff
   preview bar, gold-on-banner text) are left alone on purpose - they already
   look right and changing them would break their identity.
   ========================================================================== */

:root[data-scheme="dark"] {
  color-scheme: dark;

  /* Surfaces, darkest to lightest: the page, a panel, a card raised on top
     of a panel, then the strongest tinted chip/badge fill. Every --ocean-wash
     and --ocean-tint background in school.css (hover fills, budget and
     report chips, poll tallies, the info page...) re-themes itself from
     these two alone. */
  --canvas: #10262a;
  --paper: #10262a;
  --surface: #15343a;
  --ocean-wash: #1b434a;
  --ocean-tint: #23545d;

  /* Text and hairlines. */
  --ink: #eaf3f2;
  --muted: #aec6c8;
  --line: #4f727a;
  --line-strong: #6a939a;

  /* Brand teal and its "mid" tone are body text, headings, links, icon
     strokes and focus/hover borders almost everywhere - brightened so they
     read on a dark page. --ocean-deep stays as it was: it is only ever used
     as dark text on a gold or white surface, in or out of the banner, and
     that is still correct in the dark. */
  --ocean: #9bd7dc;
  --ocean-mid: #7fc3ca;

  /* Profit/loss, success/danger text - brightened the same way. Gold is
     left as-is; it already reads well on the darker surfaces below. */
  --danger: #ff9a90;
  --success: #7be0a8;
  --gold-wash: #3a2a10;

  /* Depth reads through opacity, not a light source, once the page itself is
     dark: heavier, near-black shadows rather than tinted teal ones. */
  --shadow-sm: 0 1px 2px rgb(0 0 0 / 35%), 0 6px 18px rgb(0 0 0 / 30%);
  --shadow-md: 0 2px 4px rgb(0 0 0 / 30%), 0 20px 48px -12px rgb(0 0 0 / 45%);
  --shadow-lg: 0 4px 10px rgb(0 0 0 / 35%), 0 36px 80px -20px rgb(0 0 0 / 55%);

  /* Solid fills that carry white text or a white tick/icon (primary
     buttons, the reference code, selected poll answers...) cannot use the
     brightened --ocean above without losing their own contrast, so they are
     pinned to a fixed teal that still holds white text at AA and still
     reads as a distinct accent against the page. Same idea for the one
     danger fill (the delete button) and the four status-chip washes used by
     notices, codes, access and ballot choices. */
  --fill-ocean: #0e6572;
  --fill-danger: #c1493c;
  --wash-green: #16342a;
  --wash-red: #3a1f1c;
  --wash-amber: #3a2a10;
  --wash-grey: #26383c;
  --ink-amber: #e8c07a;
}

/* -------------------------------------------------------------- structure
   The header, the floating admin tab bar and the reading panel are frosted
   glass over whatever scrolls behind them: dark and translucent rather than
   opaque, so that stays true. The prototype banner and its "Reading
   options" pill are token-driven already; the pill just needs its own
   surface and a border that shows against it. */
:root[data-scheme="dark"] .site-header { background: rgb(16 38 42 / 82%); }
:root[data-scheme="dark"] .prototype-banner { border-bottom-color: var(--line); }
:root[data-scheme="dark"] :is(.admin-page-nav, .workspace .admin-page-nav) { background: rgb(21 52 58 / 90%); }
:root[data-scheme="dark"] .reading-toggle {
  background: var(--ocean-wash);
  border-color: var(--line);
}

/* ----------------------------------------------------------- surfaces (1)
   The main panels: the idea form, the reading panel, dialogs, the auth
   card, the poll-suggestion and choice cards. One step up from the page. */
:root[data-scheme="dark"] :is(
  .panel,
  .auth-page .auth-card,
  .reading-panel,
  .confirmation-dialog,
  .plt-choice-card,
  .vote-card
) { background: var(--surface); }
:root[data-scheme="dark"] .pupil-home .poll-panel { background-color: var(--surface); }
:root[data-scheme="dark"] .skip-link { background: var(--surface); color: var(--ink); }
:root[data-scheme="dark"] .confirmation-dialog::backdrop { background: rgb(8 16 18 / 62%); }
:root[data-scheme="dark"] dialog::backdrop { background: rgb(8 16 18 / 62%); }

/* ----------------------------------------------------------- surfaces (2)
   Cards raised a further step on top of those panels: submissions, codes,
   member rows, stat and filter chips, poll answers, AI suggestions, the
   profit calculator's figures. All were a flat white in light mode with
   only a shadow to lift them; here they get an actual lighter tone. */
:root[data-scheme="dark"] :is(
  .idea-card,
  .ballot-admin-card,
  .code-list article,
  .member-row,
  .stat-chip,
  .template-chip,
  .suggestion-card,
  .starter-chip,
  .poll-option,
  .poll-preview-options li,
  .roi-figures div,
  .ai-suggestion,
  .plt-stats article,
  .track-rail li::before,
  .button-secondary,
  .outcome-card
) { background: var(--ocean-wash); }
:root[data-scheme="dark"] :is(
  .segmented button:hover,
  .button-secondary.wave-button:hover,
  .poll-panel .poll-option.wave-button:hover:not(:disabled)
) { background: var(--ocean-wash); }

/* -------------------------------------------------------------- crest
   The medallion is meant to sit on white, like a blazer badge, in both
   modes - left alone on purpose. */

/* ------------------------------------------------------------- controls
   Inputs, selects and textareas as a class: background-colour only, so the
   select's chevron, the search field's icon and the tracking page's
   complete-tick keep their own images. Checkbox/radio fills and the two
   translucent focus halos get the brightened ocean and danger. */
:root[data-scheme="dark"] :is(input, select, textarea) { background-color: var(--surface); }
:root[data-scheme="dark"] ::placeholder { color: #7f9a9c; }
:root[data-scheme="dark"] input:focus, :root[data-scheme="dark"] select:focus, :root[data-scheme="dark"] textarea:focus {
  box-shadow: 0 0 0 4px rgb(155 215 220 / 18%);
}
:root[data-scheme="dark"] input:user-invalid:focus, :root[data-scheme="dark"] textarea:user-invalid:focus {
  box-shadow: 0 0 0 4px rgb(255 154 144 / 18%);
}
:root[data-scheme="dark"] .check input { background: var(--surface); }
:root[data-scheme="dark"] .stat-chip[aria-pressed="true"] { box-shadow: 0 0 0 3px rgb(155 215 220 / 18%), var(--shadow-sm); }

/* --------------------------------------------------------- solid fills
   Buttons, the reference code, selected poll answers, the event date badge
   and a handful of small filled icons: pinned to --fill-ocean so the white
   text/tick on top of them stays readable, rather than following the now
   much lighter --ocean text colour. */
:root[data-scheme="dark"] :is(
  .site-header nav a.nav-signin:hover,
  .button:not(.button-secondary):not(.button-danger),
  button[type="submit"]:not(.button-secondary):not(.button-danger),
  .check input:checked,
  .track-rail li.is-done::before,
  .poll-option.is-chosen,
  .reference-card code,
  .info-summary li::before,
  .segmented button[aria-pressed="true"],
  .poll-panel .poll-option.is-chosen,
  .poll-panel .poll-option.is-chosen:disabled,
  .reading-switch input:checked,
  .ai-mark,
  .ai-score,
  .merge-label,
  .button.wave-button:not(.button-secondary):not(.button-danger):hover,
  .event-date,
  .ballot-option.selected,
  .plt-signout:hover
) { background: var(--fill-ocean); }
:root[data-scheme="dark"] .button-danger { background: var(--fill-danger); }
/* The account avatar's teal-to-navy gradient runs through the same two
   brightened tokens, so it is pinned the same way. */
:root[data-scheme="dark"] .profile-avatar { background: linear-gradient(145deg, var(--fill-ocean), var(--ocean-deep)); }
/* The banner's own gold-on-teal buttons and the budget/report bar fills
   already carry enough contrast against the darker page and are left on
   the brightened --ocean: the budget meter and report bars read clearer
   for it, and the banner is untouched either way. The two rules above are
   written broadly enough to also match the hero's own gold buttons (same
   selector, higher up the cascade only by source order), so this puts
   those back on gold, where they belong in both modes. */
:root[data-scheme="dark"] :is(.pupil-home .hero, .page-hero) :is(
  .button:not(.button-secondary):not(.button-danger),
  button[type="submit"]:not(.button-secondary):not(.button-danger),
  .button.wave-button:not(.button-secondary):not(.button-danger):hover
) { background: var(--crest-gold); }

/* --------------------------------------------------------- status chips
   Notices, submission/access/code status, ballot choices and the two
   danger/admin badges: each is a small wash behind coloured text, hard-
   coded to a light tint in every stylesheet, so each is repointed here to
   its dark equivalent. */
:root[data-scheme="dark"] .notice.warning { border-color: #6b4f1c; background: var(--wash-amber); color: var(--ink-amber); }
:root[data-scheme="dark"] .notice.error { border-color: #6b332b; background: var(--wash-red); color: var(--danger); }
:root[data-scheme="dark"] .notice.success { border-color: #2f5c45; background: var(--wash-green); color: var(--success); }
:root[data-scheme="dark"] .code-status[data-status="active"],
:root[data-scheme="dark"] .access-status[data-status="active"] { background: var(--wash-green); color: var(--success); }
:root[data-scheme="dark"] .code-status[data-status="used"] { background: var(--wash-grey); color: var(--ink); }
:root[data-scheme="dark"] .code-status[data-status="expired"],
:root[data-scheme="dark"] .access-status[data-status="revoked"] { background: var(--wash-red); color: var(--danger); }
:root[data-scheme="dark"] .code-status[data-status="full"],
:root[data-scheme="dark"] .summary-review { background: var(--wash-amber); color: var(--ink-amber); }
:root[data-scheme="dark"] .code-role[data-role="admin"] { background: var(--wash-red); color: var(--danger); }
:root[data-scheme="dark"] .code-list article.code-admin { border-left-color: var(--danger); }
:root[data-scheme="dark"] .moderation-flag { border-color: #6b4f1c; background: var(--wash-amber); color: var(--ink-amber); }
:root[data-scheme="dark"] .moderation-flag small { color: #c9a86f; }
:root[data-scheme="dark"] .stage-pill { background: color-mix(in srgb, var(--chip) 24%, var(--surface)); color: var(--ink); }
:root[data-scheme="dark"] .suggestion-status { background: color-mix(in srgb, var(--chip) 26%, var(--surface)); }
:root[data-scheme="dark"] .ballot-option { background: var(--wash-grey); }
:root[data-scheme="dark"] .ballot-option[data-choice="FOR"] { background: var(--wash-green); }
:root[data-scheme="dark"] .ballot-option[data-choice="AGAINST"] { background: var(--wash-red); }
:root[data-scheme="dark"] .ballot-option[data-choice="ABSTAIN"] { background: var(--wash-amber); }
:root[data-scheme="dark"] .ballot-option:hover { background: var(--ocean-wash); }
:root[data-scheme="dark"] .ballot-icon { background: rgb(16 38 42 / 55%); }

/* ------------------------------------------------------------- warm notes
   The safety strip and the "this could identify you" guard: a warm, dark
   amber card rather than cream, its icon recoloured to match (both are
   plain <svg stroke>, not a baked-in image, so they take the colour
   directly). The near-duplicate small print elsewhere (char count, stat
   note) gets the same amber. */
:root[data-scheme="dark"] .pupil-home .safety-strip { background: #2a2013; border-color: #4a3a1c; }
:root[data-scheme="dark"] .safety-strip .eyebrow { color: var(--ink-amber); }
:root[data-scheme="dark"] .safety-strip p:not(.eyebrow) { color: #d8cdb8; }
:root[data-scheme="dark"] .safety-icon { stroke: var(--ink-amber); }
:root[data-scheme="dark"] .privacy-guard { background-color: var(--wash-amber); color: #d8cdb8; }
:root[data-scheme="dark"] .ai-words span { background: var(--wash-amber); color: var(--ink-amber); }
:root[data-scheme="dark"] .char-count[data-near="true"],
:root[data-scheme="dark"] .stat-note strong { color: var(--ink-amber); }

/* -------------------------------------------------------------- print
   Printing stays light regardless of what is showing on screen: reset the
   handful of tokens print actually uses, so a page printed from dark mode
   still comes out as ink on paper. */
@media print {
  :root[data-scheme="dark"] {
    color-scheme: light;
    --canvas: #f7f9f9;
    --paper: #f7f9f9;
    --surface: #ffffff;
    --ocean-wash: #f2f7f8;
    --ocean-tint: #e7f0f1;
    --ink: #10282d;
    --muted: #4a6167;
    --line: #d5e1e3;
    --line-strong: #a9c2c6;
    --ocean: #00414b;
    --ocean-mid: #0b5b66;
    --danger: #a42b1d;
    --success: #17623d;
    --gold-wash: #fdf4e3;
    --fill-ocean: #00414b;
    --fill-danger: #9c2e24;
    --wash-green: #dff5e8;
    --wash-red: #fff0ee;
    --wash-amber: #fff2d5;
    --wash-grey: #e7edf1;
    --ink-amber: #674700;
  }
  /* A few components were written as literal hex rather than tokens (the
     header's translucency, the safety note's cream card): put those back by
     hand so a page printed from dark mode looks the same as one printed
     from light. */
  :root[data-scheme="dark"] .site-header { background: rgb(247 249 249 / 84%); }
  :root[data-scheme="dark"] .pupil-home .safety-strip { background: #fffdf8; border-color: #f0dcb4; }
  :root[data-scheme="dark"] .safety-strip .eyebrow { color: #8a5b0b; }
  :root[data-scheme="dark"] .safety-strip p:not(.eyebrow) { color: #4f4a3f; }
  :root[data-scheme="dark"] .safety-icon { stroke: #b97a0d; }
  :root[data-scheme="dark"] .privacy-guard { color: #4f4a3f; }
  :root[data-scheme="dark"] .ai-words span { color: #6b4a0c; }
}
/* Gold text sits on light in the light scheme and needs the deeper shade; on
   the dark page the crest's own bright gold reads well. */
:root[data-scheme="dark"] { --gold-ink: var(--crest-gold); }
