/* Quiz Night 2026 — Decades Gone By.
   Inherited verbatim from the Grassroots Classic sheet, whose structure, spacing,
   type scale and control shapes are calibrated against the GRC marketing site
   (dev.grassrootsclub.co.nz) so both events read as the same family. Palette is
   the same sub brand: Leaf accents on Moss and Coal, near black body text on
   paper.

   Everything below the "quiz night additions" heading at the foot is new for
   this page. The Classic rules above it are untouched on purpose — they are the
   design system here, not a starting point to rewrite. Some of them (the access
   gate, the countdown, the registration form, the waiver, the spot hold chip)
   have no markup on this two page site and are simply inert. */

/* ---------- fonts ---------- */
@font-face {
  font-family: "Founders Grotesk Condensed";
  src: url("./assets/fonts/founders-grotesk-condensed-regular.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Founders Grotesk Condensed";
  src: url("./assets/fonts/founders-grotesk-condensed-medium.woff2") format("woff2");
  font-weight: 500; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Founders Grotesk Condensed";
  src: url("./assets/fonts/founders-grotesk-condensed-semibold.woff2") format("woff2");
  font-weight: 600; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Founders Grotesk Condensed";
  src: url("./assets/fonts/founders-grotesk-condensed-bold.woff2") format("woff2");
  font-weight: 700; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Tiempos Text";
  src: url("./assets/fonts/tiempos-text-regular.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Tiempos Text";
  src: url("./assets/fonts/tiempos-text-semibold.woff2") format("woff2");
  font-weight: 600; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Tiempos Text";
  src: url("./assets/fonts/tiempos-text-regular-italic.woff2") format("woff2");
  font-weight: 400; font-style: italic; font-display: swap;
}

/* ---------- tokens (mirrors the marketing site) ---------- */
:root {
  --paper: #F2EDE3;
  --paper-2: #E9E2D2;
  --cream: #FFF9EE;
  --coal: #0B100D;
  --coal-2: #131A15;
  --ink: #131614;
  --ink-muted: #5C625B;
  --rule: rgba(19, 22, 20, 0.12);
  --coal-rule: rgba(255, 255, 255, 0.1);
  --moss: #1A4D2E;
  --moss-2: #246138;
  --leaf: #3CA673;
  --leaf-soft: #C5E0D2;
  /* The only leaf that clears 4.5:1 for small text on Moss or on the photo. */
  --leaf-hi: #5FC994;
  --alert: #A6301F;

  --display: "Founders Grotesk Condensed", "Impact", "Helvetica Neue Condensed",
    "Arial Narrow", sans-serif;
  --serif: "Tiempos Text", "Charter", "Georgia", serif;

  --t-section: clamp(36px, 5.4vw, 76px);
  --t-sub: clamp(26px, 3vw, 38px);
  --t-body-lg: clamp(17px, 1.3vw, 19px);
  --t-body: 17px;
  --t-utility: 13px;

  --space-xs: 8px;
  --space-sm: 16px;
  --space-md: 24px;
  --space-lg: 48px;
  --space-xl: 96px;

  --max: 1320px;
  --gutter: clamp(20px, 4vw, 48px);
  --section-pad: clamp(64px, 8vw, 112px);

  /* Radii come from Morgan's 2026-08-05 redesign: softer cards, softer panels,
     softer fields. The pill is unchanged. */
  --radius-pill: 999px;
  --radius-card: 14px;
  --radius-panel: 8px;
  --radius-input: 8px;
  /* Fields carry a slightly stronger hairline than section rules do. */
  --rule-field: rgba(19, 22, 20, 0.14);
}

/* ---------- base ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--serif);
  font-size: var(--t-body);
  line-height: 1.55;
  overflow-x: hidden;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { animation: none !important; transition: none !important; }
}
img, svg { max-width: 100%; display: block; }
/* [hidden] lives in the user agent sheet, so ANY author display rule beats it.
   .btn sets display:inline-flex, which is why the pre open hero CTA and the
   tapped waitlist button both stayed on screen after the JS set el.hidden. */
[hidden] { display: none !important; }
p { margin: 0 0 0.9em; max-width: 62ch; }
a { color: var(--moss); text-underline-offset: 3px; }
a:focus-visible, button:focus-visible, input:focus-visible,
select:focus-visible, [tabindex]:focus-visible {
  outline: 3px solid var(--moss-2);
  outline-offset: 2px;
}
.wrap { width: 100%; max-width: var(--max); margin: 0 auto; padding: 0 var(--gutter); }
.tnum { font-feature-settings: "tnum" 1; font-variant-numeric: tabular-nums; }

/* ---------- type ---------- */
h1, h2, h3, legend, .display {
  font-family: var(--display);
  text-transform: uppercase;
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.01em;
  margin: 0;
}
.section-h { font-size: var(--t-section); margin: 0 0 var(--space-sm); }
.sub-h { font-size: var(--t-sub); margin: 0 0 var(--space-sm); }
.eyebrow {
  font-family: var(--display);
  font-size: var(--t-utility); font-weight: 700; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--moss); margin: 0 0 var(--space-sm);
}
.lead { font-size: var(--t-body-lg); max-width: 56ch; }
section { padding: var(--section-pad) 0; }

/* ---------- brand bar ---------- */
.bar { background: var(--coal); color: #fff; }
.bar__inner {
  max-width: var(--max); margin: 0 auto;
  padding: 18px var(--gutter);
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  min-height: 68px;
}
.wordmark { display: inline-flex; line-height: 0; color: #fff; }
.wordmark svg { height: 30px; width: auto; }
.bar__back {
  font-family: var(--display); font-size: var(--t-utility); font-weight: 700;
  letter-spacing: 0.18em; text-transform: uppercase; color: var(--leaf-hi);
  text-decoration: none; display: inline-flex; align-items: center; min-height: 44px;
}
.bar__back:hover { text-decoration: underline; }
.bar--hero { background: transparent; position: relative; z-index: 3; }

/* ---------- hero countdown ---------- */
/* Mirrors the GRC wordmark across the same flex bar: wordmark left, clock
   right, both sitting on the heaviest part of the scrim (0.86 at the top),
   which is what makes plain white safe over a photo here.

   Stacked label over time rather than side by side, so the 375 case never has
   to compete with the wordmark for horizontal room. */
.countdown {
  display: flex; flex-direction: column; align-items: flex-end;
  gap: 3px; min-width: 0; text-align: right; color: #fff;
}
.countdown__label {
  font-family: var(--display); font-size: 11px; font-weight: 700;
  letter-spacing: 0.18em; text-transform: uppercase;
  white-space: nowrap; color: #fff;
}
/* tnum so the digits do not jitter the block sideways every second, the same
   treatment the spot counters get. */
.countdown__time {
  font-family: var(--display); font-weight: 700; line-height: 1;
  font-size: clamp(21px, 5.4vw, 30px);
  letter-spacing: 0.01em; white-space: nowrap; color: #fff;
  font-feature-settings: "tnum" 1; font-variant-numeric: tabular-nums;
}

/* ---------- early access gate ---------- */
/* ⚠ Wave management, not security. See gate.js.

   The blur is driven by a class the document head sets synchronously, so the
   real page never paints unblurred for a frame. Everything real lives inside
   the blurred elements; the card is a sibling of them, so it stays sharp. */
html.is-gated, html.is-gated body { overflow: hidden; }
html.is-gated .hero,
html.is-gated .page-head,
html.is-gated main,
html.is-gated footer {
  /* 8px, not more: Morgan wants the hero photo and the Classic lockup
     recognisable through it, so the visitor can see what they are being asked
     for a code to reach. Heavier reads as an error page. */
  filter: blur(8px);
  /* The blur fades to transparent at the element's edges, which would show a
     hard seam against the paper. A small scale-up pushes that fade off screen
     so the hero photo and the lockup read as one soft image behind the card. */
  transform: scale(1.04);
  pointer-events: none;
  user-select: none;
}
.access-gate { display: none; }
/* Dead centre of the VIEWPORT, always (Morgan): position fixed, never in flow,
   so scroll position, page height and however much blurred content sits behind
   it are all irrelevant.
 *
 * Centring is `margin: auto` on the card rather than align/justify-content on
 * purpose. They look identical when the card fits, but when it does NOT fit
 * (short landscape phone, or the on-screen keyboard eating half the screen)
 * centred flex items overflow EQUALLY in both directions and the top of the
 * card becomes unreachable, because you cannot scroll up past a flex
 * container's start edge. `margin: auto` centres when there is room and falls
 * back to normal top-aligned scrolling when there is not, so the heading and
 * the submit button are always reachable. */
html.is-gated .access-gate {
  display: flex; position: fixed; inset: 0; z-index: 100;
  padding: var(--gutter);
  overflow-y: auto;
  /* The page behind is already scroll locked; this stops a flick inside the
     overlay from chaining out to it on iOS. */
  overscroll-behavior: contain;
  background: rgba(9, 26, 17, 0.3);
}
.gate-card {
  margin: auto;
  width: 100%; max-width: 420px;
  background: var(--cream); color: var(--ink);
  border-radius: var(--radius-card);
  padding: clamp(24px, 6vw, 34px);
  box-shadow: 0 24px 60px rgba(9, 26, 17, 0.34);
}
.gate-card__h {
  font-family: var(--display); text-transform: uppercase; font-weight: 700;
  line-height: 1.05; letter-spacing: -0.01em;
  font-size: clamp(26px, 6.4vw, 34px);
  margin: 0 0 var(--space-md);
}
.gate-card .field { margin: 0 0 var(--space-md); text-align: left; }

/* A wrong code shakes the card once. Reduced motion turns it off; the inline
   error is what actually carries the message. */
@keyframes gate-shake {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-7px); }
  40% { transform: translateX(6px); }
  60% { transform: translateX(-4px); }
  80% { transform: translateX(2px); }
}
.access-gate.is-wrong .gate-card { animation: gate-shake 320ms ease-in-out; }
@media (prefers-reduced-motion: reduce) {
  .access-gate.is-wrong .gate-card { animation: none; }
}

/* Available to any component that needs a fact read aloud without painting it. */
.u-sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---------- hero ---------- */
/* Morgan's redesign makes the hero a full viewport panel. min-height, not
   height: a short landscape phone must be allowed to grow rather than clip the
   sign up button.

   The height unit is svh, NOT dvh. On iOS Safari the toolbars are always
   expanded at scroll position zero, so the small viewport IS the first paint
   view. dvh tracks the toolbars as they collapse and was resolving short on the
   first screen, which let the cream section underneath peek in at the bottom.
   svh is the floor that cannot do that. The 100vh line above it stays as the
   fallback for browsers that do not know the newer units. */
.hero {
  position: relative; padding: 0;
  background: var(--coal); isolation: isolate;
  min-height: 100vh;
  min-height: 100svh;
  display: flex; flex-direction: column;
}
.hero__media { position: absolute; inset: 0; z-index: 0; overflow: hidden; }
.hero__media img {
  width: 100%; height: 100%; object-fit: cover; object-position: 50% 42%;
  filter: grayscale(1) contrast(1.06) brightness(0.94);
}
/* Moss duotone: a moss plane multiplied into the greyscale photo. */
.hero__media::after {
  content: ""; position: absolute; inset: 0;
  background: var(--moss); mix-blend-mode: multiply; opacity: 0.42;
}
/* Scrim weighted to the top, where the photo's ceiling and banners are bright. */
.hero__scrim {
  position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(to bottom,
    rgba(9, 26, 17, 0.70) 0%,
    rgba(9, 26, 17, 0.32) 30%,
    rgba(9, 26, 17, 0.44) 58%,
    rgba(9, 26, 17, 0.88) 100%);
}
/* Everything inside the hero is measured in svh too, so the content composes
   against the same box the hero is sized by. Mixing vh in here would scale the
   rhythm off the toolbar-retracted height and push the button toward the fold.
   Each rule keeps its vh line first: an unknown unit inside clamp() invalidates
   the whole declaration, so the fallback has to be a separate declaration. */
.hero__inner {
  position: relative; z-index: 2;
  width: 100%; max-width: var(--max); margin: 0 auto;
  padding: clamp(12px, 3vh, 64px) var(--gutter) clamp(14px, 4vh, 52px);
  padding: clamp(12px, 3svh, 64px) var(--gutter) clamp(14px, 4svh, 52px);
  color: #fff;
  display: flex; flex-direction: column; justify-content: center;
  flex: 1; min-height: 0;
}
/* The h1. On the Classic this is a commissioned PNG; here it is the type
   lockup at the foot of this sheet, so the image sizing rules are gone and the
   spacing rule is all that is left. */
.hero__lockup { margin: 0 0 clamp(12px, 2.8vh, 28px); }
.hero__lockup { margin: 0 0 clamp(12px, 2.8svh, 28px); }
.hero__facts {
  list-style: none; padding: 0; margin: 0 0 clamp(14px, 3.5vh, 40px);
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: 4px;
  font-family: var(--display); text-transform: uppercase;
  font-size: clamp(15px, 2.2vw, 22px); font-weight: 500; letter-spacing: 0.08em;
  color: #fff;
}
.hero__facts { margin: 0 0 clamp(14px, 3.5svh, 40px); }
/* Pre open the CTA is hidden, so the gap that held it off the facts would sit
   there as dead space and pull the centred stack off centre. */
.hero__inner:has(.hero__cta[hidden]) .hero__facts { margin-bottom: 0; }
.hero__price { color: var(--leaf-hi); }
.hero__cta { align-self: center; min-height: clamp(48px, 7vh, 56px); }
.hero__cta { min-height: clamp(48px, 7svh, 56px); }

/* ---------- buttons (marketing site pill) ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 48px; padding: 15px 26px;
  font-family: var(--display); font-size: var(--t-utility); font-weight: 700;
  letter-spacing: 0.2em; text-transform: uppercase;
  border: 0; border-radius: var(--radius-pill); cursor: pointer;
  text-decoration: none; text-align: center;
  background: var(--leaf); color: var(--coal);
  transition: background 120ms linear;
}
.btn:hover { background: #4FBB86; }
.btn:disabled { background: #7FA893; color: #24312A; cursor: not-allowed; }
.btn--lg { min-height: 56px; padding: 18px 34px; font-size: 15px; }
.btn--ghost {
  background: transparent; color: var(--moss);
  box-shadow: inset 0 0 0 2px var(--moss);
}
.btn--ghost:hover { background: rgba(26, 77, 46, 0.08); }
.btn--block { width: 100%; }

/* ---------- the event section ---------- */
/* Was `.classic` on the Classic sheet; renamed only, rules unchanged. Morgan's
   redesign centres the whole section. Paragraphs keep their measure but sit
   centred in the column instead of ragging off the left gutter. */
.event { background: var(--paper); }
.event .wrap { text-align: center; }
.event p { margin-left: auto; margin-right: auto; }
.event__intro { margin-bottom: 72px; }
.block-h {
  font-family: var(--display); text-transform: uppercase; font-weight: 700;
  font-size: clamp(22px, 2.6vw, 30px); letter-spacing: -0.005em; line-height: 1;
  margin: 0 0 var(--space-md); padding-top: var(--space-md);
  border-top: 1px solid var(--rule);
}

/* ---------- schedule board ---------- */
.board { list-style: none; margin: 0 auto 72px; padding: 0; max-width: 520px; }
.board li {
  display: grid; grid-template-columns: 84px 1fr; gap: 14px;
  padding: 9px 0; border-bottom: 1px solid var(--rule); align-items: baseline;
}
@media (min-width: 560px) { .board li { grid-template-columns: 110px 1fr; gap: 18px; } }
.board time {
  font-family: var(--display); font-weight: 700; font-size: 17px;
  letter-spacing: 0.04em; color: var(--moss); text-transform: uppercase;
  text-align: right;
}
@media (min-width: 560px) { .board time { font-size: 19px; } }
.board-what {
  font-family: var(--display); font-size: 20px; font-weight: 500;
  text-transform: uppercase; letter-spacing: 0.01em; text-align: left;
}
@media (min-width: 560px) { .board-what { font-size: 22px; } }

/* ---------- divisions grid ---------- */
/* Morgan's redesign pairs the divisions into two sex columns at every width,
   headed once at the top, rather than six free standing cards. */
.grid {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px; margin: 0 0 72px; padding: 0; list-style: none;
}
.grid > li { display: flex; }
.grid .card { flex: 1 1 auto; min-width: 0; }
/* Overrides the flex display the grid puts on its cells. */
.grid > li.grid__head {
  display: block; padding: 0 0 4px;
  font-family: var(--display); font-size: var(--t-utility); font-weight: 700;
  letter-spacing: 0.2em; text-transform: uppercase; color: var(--ink-muted);
  text-align: center;
}

.card {
  position: relative; display: flex; flex-direction: column; align-items: center;
  min-height: 168px; padding: 18px 16px 16px;
  background: var(--cream); border: 1px solid var(--rule);
  border-radius: var(--radius-card);
  box-shadow: 0 1px 2px rgba(19, 22, 20, 0.04);
  text-align: center;
}
/* Two columns at 320 leaves about 100px of card interior, and INTERMEDIATE at
   18px does not fit it, so the clamp floor drops far enough to keep the longest
   division name on one line rather than breaking it mid word. */
.card__name {
  font-family: var(--display); text-transform: uppercase; font-weight: 700;
  font-size: clamp(15px, 4.7vw, 32px); line-height: 1; letter-spacing: -0.01em;
  margin: 0; overflow-wrap: anywhere;
}
/* Names the pair type under the division heading. Deliberately NOT uppercased:
   Morgan's casing is "Male pair" and "Female pair", and a text-transform would
   throw that away. */
.card__pair {
  font-family: var(--display); font-size: var(--t-utility); font-weight: 500;
  letter-spacing: 0.06em; color: var(--ink-muted);
  /* The auto bottom margin moved here from .card__name: it is what pushes the
     count and the button to the foot of the card, and it has to sit on the LAST
     line of the heading block or the subtitle floats away from its heading. */
  margin: 4px 0 auto;
}
.card__count {
  font-family: var(--display); font-size: 15px; font-weight: 700;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--moss);
  margin: var(--space-sm) 0 12px; min-height: 22px;
}
.card__count.is-low { color: var(--alert); }
.card__count.is-hidden { visibility: hidden; }
/* Morgan's card action is an auto width pill, not a full bleed bar. Held at 44px
   so it still clears the minimum tap target. */
.card .btn {
  width: auto; align-self: center;
  min-height: 44px; padding: 11px 20px; font-size: 12px; letter-spacing: 0.16em;
}
.card--full { background: var(--paper-2); }
.card .waitlist-slot { width: 100%; }

/* ---------- card expansion: the pairs already entered ---------- */
/* Native details. The Enter pill is the entry affordance, the summary is the
   expand affordance, so the two taps never fight over the same box. */
.card__teams { margin-top: 12px; width: 100%; }
.card__teams > summary {
  list-style: none; cursor: pointer;
  display: flex; align-items: center; justify-content: center; gap: 8px;
  padding-top: 12px; border-top: 1px solid var(--rule);
  font-family: var(--display); font-size: 12px; font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--moss);
  min-height: 44px;
}
.card__teams > summary::-webkit-details-marker { display: none; }
.card__teams > summary::marker { content: ""; }
.card__teams > summary:hover { color: var(--moss-2); }
.team-list {
  list-style: none; margin: 10px 0 0; padding: 0;
  display: flex; flex-direction: column; gap: 8px; text-align: center;
}
/* Two lines per pair: the team name, and the gym directly under it. Stacked with
   flex rather than by leaving the <span>s inline, so the gap between the name and
   its gym is smaller than the gap between one pair and the next — otherwise the
   list reads as one flat column of six things instead of three pairs of two. */
.team-list li {
  display: flex; flex-direction: column; gap: 2px;
  min-width: 0;
}
/* A 60 character team name with no spaces in it is a legal entry, and so is a
   long gym name, so both have to break rather than push the card wider than the
   column. `min-width: 0` on the flex item above is what lets that happen. */
.team-name {
  font-family: var(--serif); font-size: 15px; line-height: 1.35;
  overflow-wrap: anywhere;
}
/* Muted and one step down, reusing the existing utility size and muted ink —
   the gym is context for the team name, never a second heading. */
.team-gym {
  font-size: var(--t-utility); line-height: 1.3; color: var(--ink-muted);
  overflow-wrap: anywhere;
}
.team-empty { margin: 10px 0 0; font-size: 15px; color: var(--ink-muted); }

.skeleton {
  display: inline-block; height: 14px; width: 92px; border-radius: 2px;
  background: linear-gradient(90deg, var(--paper-2), var(--cream), var(--paper-2));
  background-size: 200% 100%; animation: shimmer 1.3s linear infinite;
}
.skeleton--row { display: block; width: 100%; height: 40px; margin-bottom: 8px; }
@keyframes shimmer { to { background-position: -200% 0; } }

.grid-note { margin: var(--space-md) 0 0; color: var(--ink-muted); }
.board-intro { margin: 0 0 var(--space-md); }
.waitlist-form { margin-top: 10px; display: grid; gap: 8px; }
.waitlist-form input {
  width: 100%; min-height: 46px; padding: 10px 12px;
  border: 1px solid var(--rule); border-radius: var(--radius-input);
  font-family: var(--serif); font-size: 16px; background: #fff; color: var(--ink);
}
.waitlist-form label {
  font-family: var(--display); font-size: 12px; font-weight: 700;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-muted);
}
.waitlist-done { font-size: 16px; color: var(--moss); font-weight: 600; margin: 10px 0 0; }

/* ---------- form ---------- */
/* Morgan's redesign centres the form column and its fields. */
.form-wrap > * { max-width: 620px; margin-left: auto; margin-right: auto; }
.form-wrap { text-align: center; }
.form-grid { display: grid; gap: var(--space-md); }
.field { display: grid; gap: 6px; min-width: 0; }
.field label {
  font-family: var(--display); font-size: var(--t-utility); font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--ink-muted);
}
.field .hint { font-size: 16px; color: var(--ink-muted); }
.field input, .field select {
  width: 100%; min-height: 48px; padding: 11px 14px; text-align: center;
  font-family: var(--serif); font-size: 17px; color: var(--ink);
  background: var(--cream); border: 1px solid var(--rule-field);
  border-radius: var(--radius-input); appearance: none;
}
.field select {
  text-align: center; text-align-last: center;
  background-image: linear-gradient(45deg, transparent 50%, var(--ink) 50%),
    linear-gradient(135deg, var(--ink) 50%, transparent 50%);
  background-position: calc(100% - 20px) 21px, calc(100% - 14px) 21px;
  background-size: 6px 6px, 6px 6px; background-repeat: no-repeat;
}
.field input[aria-invalid="true"], .field select[aria-invalid="true"] {
  border-color: var(--alert); border-width: 2px;
}
.field-error { font-size: 16px; color: var(--alert); font-weight: 600; }
.fieldset { border: 0; padding: 0; margin: 0; display: block; }
.fieldset > * + * { margin-top: var(--space-md); }
.fieldset > *:not(legend) { clear: both; }
/* A background line, not a border: a legend cuts a fieldset border in half.
   The float keeps the legend inside the box instead of straddling its top. */
.fieldset + .fieldset {
  padding-top: var(--space-lg);
  background-image: linear-gradient(var(--rule), var(--rule));
  background-size: 100% 1px; background-repeat: no-repeat; background-position: top left;
}
.fieldset legend {
  float: left; width: 100%;
  font-size: var(--t-sub); margin: 0 0 var(--space-md);
  text-align: center; color: var(--moss);
}
/* Two up from 320 in Morgan's redesign: division and pair are short enough. */
.two-up { display: grid; gap: 12px; grid-template-columns: 1fr 1fr; }
@media (min-width: 560px) { .two-up { gap: var(--space-md); } }

/* Ticks stay left aligned inside a centred column so the box and its sentence
   read as one line rather than drifting apart. */
.check {
  display: grid; grid-template-columns: 26px 1fr; gap: 12px;
  align-items: start; padding: 9px 0; min-height: 44px; cursor: pointer;
  width: 100%; max-width: 420px; margin: 0 auto; text-align: left;
}
.check input[type="checkbox"] {
  width: 26px; height: 26px; margin: 2px 0 0; accent-color: var(--moss);
}
.check span { font-size: 16px; line-height: 1.45; }

/* Morgan centred the whole agreement. Headings follow him, the body does not:
   nine paragraphs of legal prose ragged on both edges is the one place on these
   pages where the centred rhythm costs more than it buys. */
.waiver {
  max-height: 280px; overflow-y: auto; padding: 18px 20px;
  background: #fff; border: 1px solid var(--rule-field);
  border-radius: var(--radius-panel);
  font-size: 16px; line-height: 1.55; text-align: left;
}
.waiver h3, .waiver h4 { text-align: center; }
.waiver h3 { font-size: 20px; margin: 0 0 10px; }
.waiver h4 {
  font-family: var(--display); font-size: 14px; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--moss); margin: 20px 0 6px;
  font-weight: 700; line-height: 1.2;
}
.waiver p { max-width: none; }

/* Morgan folds both the collection statement and the policy recap into tinted
   disclosure panels, so the form reads short and the detail is one tap away.
   The wording inside each is unchanged. */
.panel {
  font-size: 16px; background: var(--paper-2); color: var(--ink-muted);
  border-left: 3px solid var(--moss); padding: 14px 18px;
  border-radius: var(--radius-panel); text-align: left;
}
.panel > summary {
  list-style: none; cursor: pointer;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  font-family: var(--display); font-size: var(--t-utility); font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--moss);
  min-height: 44px;
}
.panel > summary::-webkit-details-marker { display: none; }
.panel > summary::marker { content: ""; }
.panel > summary:hover { color: var(--moss-2); }
.panel .chev { font-family: var(--display); font-size: 15px; line-height: 1; }
.panel[open] .chev { transform: rotate(45deg); }
.panel__body { padding-top: 12px; }
.panel p { max-width: none; margin-left: 0; margin-right: 0; }
.panel__body p:last-child { margin-bottom: 0; }
.policy-recap dl { margin: 0; }
.policy-recap dt {
  font-family: var(--display); font-size: var(--t-utility); font-weight: 700;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--moss);
  margin-top: 14px;
}
.policy-recap dt:first-of-type { margin-top: 0; }
.policy-recap dd { margin: 4px 0 0; }

.banner {
  padding: 16px 18px; border-radius: var(--radius-panel); font-size: 16px;
  margin-bottom: var(--space-md); text-align: left;
  border-left: 3px solid var(--moss); background: var(--paper-2);
}
.banner p { margin-left: 0; margin-right: 0; }
.banner--warn { border-left-color: var(--alert); background: #FBEDEA; color: #6E1F13; }
.banner--good { border-left-color: var(--leaf); background: #E6F4EC; }
.banner strong { font-weight: 600; }
.banner p:last-child { margin-bottom: 0; }

/* ---------- the spot hold chip ---------- */
/* Sticky, because the form is longer than any phone screen and a countdown you
   have scrolled past is not a countdown. It rides at the top of the form column
   and stays there, so the answer to "how long have I got" is always one glance
   away rather than one scroll up.

   The chip is a pill inside a full width sticky strip: the strip is what sticks
   and centres, the pill is what is painted, so the moss never becomes a band
   across the page. Digits are tnum so the seconds do not jitter the pill wider
   and narrower once a second. */
.hold-chip {
  position: sticky; top: 0; z-index: 5;
  padding: var(--space-xs) 0; text-align: center;
}
.hold-chip__pill {
  display: inline-flex; align-items: center; gap: 10px; margin: 0;
  padding: 9px 18px; border-radius: var(--radius-pill);
  background: var(--moss); color: var(--cream);
  font-family: var(--display); font-size: var(--t-utility); font-weight: 700;
  letter-spacing: 0.12em; text-transform: uppercase;
  box-shadow: 0 2px 10px rgba(11, 16, 13, 0.14);
}
.hold-chip__dot {
  width: 8px; height: 8px; border-radius: 50%; background: var(--leaf-hi);
  flex: none;
}
/* Lapsed is a sentence, not a label, so it drops the pill's shouting: paper,
   ink, sentence case, serif. It is information, and nothing is wrong. */
.hold-chip--lapsed .hold-chip__pill {
  background: var(--paper-2); color: var(--ink-muted);
  font-family: var(--serif); font-size: 15px; font-weight: 400;
  letter-spacing: 0; text-transform: none; box-shadow: none;
  /* Long enough to wrap at 320px, so it needs to wrap like prose. */
  text-align: center; max-width: 100%;
}
/* The dot is the live signal. There is nothing live to signal any more, and
   beside two wrapped lines it sits in the vertical middle of nothing. */
.hold-chip--lapsed .hold-chip__dot { display: none; }

.spinner {
  width: 16px; height: 16px; margin-right: 10px; border-radius: 50%;
  border: 2px solid rgba(11, 16, 13, 0.35); border-top-color: var(--coal);
  animation: spin 700ms linear infinite; display: inline-block;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ---------- page head (register, partner and success) ---------- */
/* The moss band is GONE (Morgan, from a screenshot of the register head): the
   logo now sits in moss green straight on the paper, and the headline sits
   under it on the same plane. One less colour block between the athlete and
   the form.

   The band used to do two jobs at once, and losing it means doing them by hand:
   it held the page down from the top of the viewport, and its 56px of bottom
   padding kept the headline off the form. So the bar gets real top padding,
   and the head's bottom padding drops to var(--space-md) because the body
   sections already carry var(--space-lg) of their own. */
.page-head { background: transparent; color: var(--ink); padding: 0 0 var(--space-md); }
.page-head__bar {
  max-width: var(--max); margin: 0 auto;
  padding: 28px var(--gutter) 18px;
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  min-height: 68px;
}
.page-head__logo { display: inline-flex; line-height: 0; }
.page-head__logo img { height: 51px; width: auto; }
/* 8.39:1 on paper. Leaf would be 2.61:1 and is why the back link is moss and
   not the brand accent. */
.page-head__back {
  font-family: var(--display); font-size: 15px; font-weight: 700;
  letter-spacing: 0.18em; text-transform: uppercase; color: var(--moss);
  text-decoration: none; display: inline-flex; align-items: center; min-height: 44px;
}
.page-head__back:hover { color: var(--moss); text-decoration: underline; }
.page-head__title {
  width: 100%; max-width: var(--max); margin: 0 auto;
  padding: var(--space-md) var(--gutter) 0; text-align: center;
}
.page-head__title p {
  font-family: var(--serif); font-style: italic; font-size: 20px;
  color: var(--ink-muted); margin: 0 auto; max-width: 48ch;
}

.partner-head h1 { font-size: clamp(32px, 7.5vw, 56px); margin: 0 0 var(--space-xs); }
.partner-body { padding: var(--space-lg) 0 var(--space-xl); }
.state-msg { max-width: 46ch; margin: 0 auto; }

.register-head h1 { font-size: clamp(34px, 8vw, 64px); margin: 0 0 var(--space-xs); }
.register-body { padding: var(--space-lg) 0 var(--space-xl); }

/* ---------- success (the Stripe return) ---------- */
/* The whole page is one moment: paid, and the next thing is your inbox. It
   carries the logo block and nothing else, so there is no nav, no counts and no
   form to distract from that. The head loses its bottom padding because there
   is no headline sitting under the logo here. */
.success-head { padding-bottom: 0; }
/* No headline under the logo here, so the bar's own bottom padding is the whole
   gap and the body's var(--space-xl) does the rest. */
.success-head .page-head__bar { padding-bottom: 0; }
.success-body { padding: var(--space-xl) 0; text-align: center; }
.success-tick {
  width: clamp(88px, 22vw, 116px); height: auto;
  margin: 0 auto var(--space-md);
  color: var(--moss);
}
.success-h { font-size: clamp(38px, 9vw, 72px); margin: 0 0 var(--space-sm); }
/* max-width on p is 62ch site wide, which reads too wide for a single line at
   this size. Narrow it and re-centre, since p carries auto margins nowhere
   else. */
.success-line {
  font-size: var(--t-body-lg); max-width: 30ch;
  margin: 0 auto; color: var(--ink);
}

/* ==========================================================================
   QUIZ NIGHT ADDITIONS
   Everything above this line is the Classic sheet. Everything below is new for
   this page: the typographic lockup that stands in for a commissioned logo, the
   two entry option cards, the information list and the footer.
   ========================================================================== */

/* ---------- typographic event lockup ---------- */
/* The Classic hero hangs a commissioned PNG in the h1. Quiz Night has no logo,
   so the lockup is set in type: a tracked-caps kicker naming the night, the
   theme underneath in the display face. One component, two sizes — reversed
   white over the hero photo, moss on the light success page, which is the same
   colour pair the Classic gets from its white and moss logo files. */
/* text-align matters as well as align-items: the title shrink-wraps to its
   widest line, so a two line DECADES GONE BY would rag left inside a centred
   box without it. */
.lockup {
  display: flex; flex-direction: column; align-items: center;
  gap: 8px; margin: 0; max-width: 100%; text-align: center;
}
.lockup__kicker {
  font-family: var(--display); font-weight: 700; text-transform: uppercase;
  line-height: 1; letter-spacing: 0.22em;
  font-size: clamp(13px, 2.6vw, 20px);
  /* Tracking hangs a trailing space off the last letter, which drags the
     optical centre left. The indent puts it back. */
  text-indent: 0.22em;
}
/* Two stacked lines, broken in the markup rather than left to wrap. A logo does
   not reflow, and at 375 the phrase set on one line is within 8px of both
   gutters before it decides to break by itself — deterministic beats a clamp
   tuned to a hairline. Sizing therefore only ever has to clear the widest WORD,
   which is DECADES at about 3.45em. */
.lockup__title {
  font-family: var(--display); font-weight: 700; text-transform: uppercase;
  line-height: 0.9; letter-spacing: -0.01em;
  max-width: 100%; overflow-wrap: break-word;
}
.lockup__line { display: block; }
.lockup--hero { color: #fff; }
/* svh, not vh, for the same reason the hero itself uses it: on iOS the toolbars
   are expanded at scroll zero, so the small viewport IS the first paint view,
   and the lockup has to compose against the same box the hero is sized by. It
   caps the block at about 29svh, which is where the Classic pins its logo.
   The plain clamp above it is the fallback — an unknown unit inside clamp()
   invalidates the whole declaration, so it has to be a separate one. */
.lockup--hero .lockup__title { font-size: clamp(52px, 13vw, 168px); }
.lockup--hero .lockup__title { font-size: clamp(52px, min(13vw, 16svh), 168px); }
.lockup--sm { gap: 4px; color: var(--moss); }
.lockup--sm .lockup__kicker { font-size: 11px; letter-spacing: 0.2em; text-indent: 0.2em; }
.lockup--sm .lockup__title { font-size: clamp(24px, 5.4vw, 32px); }
/* .page-head__logo zeroes line-height for an image child. Type needs it back. */
.page-head__logo--type { line-height: normal; text-decoration: none; }

/* ---------- entry options ---------- */
/* The Classic packs six one word division names into two fixed columns. These
   two options carry sentence length names and a note, so the grid is auto-fit
   instead: one column on a phone, two once there is room for them. The
   min(260px, 100%) inside minmax is the overflow guard — at 320px the track
   collapses to the container width rather than holding a 260px floor and
   pushing the page sideways. */
.grid--entry {
  grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
  gap: var(--space-md);
}
.card--entry { min-height: 0; padding: 28px 20px 24px; }
.card--entry .card__name {
  font-size: clamp(22px, 4.6vw, 30px); line-height: 1.05;
  overflow-wrap: break-word;
}
/* $25 is the whole pitch, so it is set at display scale rather than tucked into
   the button. Moss, not leaf: leaf is 2.91:1 on cream and fails (visual system
   3.3). */
.card__price {
  font-family: var(--display); font-weight: 700; text-transform: uppercase;
  font-size: clamp(34px, 7vw, 46px); line-height: 1; letter-spacing: -0.01em;
  color: var(--moss); margin: 12px 0 var(--space-md);
}
.card__note {
  font-size: 16px; line-height: 1.45; color: var(--ink-muted);
  max-width: 34ch; margin: 14px 0 var(--space-md);
}
/* Auto top margin drops the pill to the foot of the card, so the two buttons
   line up across the row even though only one card carries the partner note.
   The preceding margin-bottom survives it, which is what guarantees a gap when
   the cards are tall enough that there is no free space to absorb. */
.card--entry .btn {
  margin-top: auto; max-width: 100%;
  min-height: 48px; padding: 14px 22px; font-size: 13px; letter-spacing: 0.16em;
}

/* ---------- important information ---------- */
/* Same dt/dd rhythm as the Classic's policy recap, but out in the open instead
   of folded into a disclosure: three facts, and every one of them is something
   you want to know before you pay rather than after. */
.info { margin: 0 auto 72px; max-width: 560px; }
.info dt {
  font-family: var(--display); font-size: var(--t-utility); font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--moss);
  margin-top: var(--space-md); padding-top: var(--space-md);
  border-top: 1px solid var(--rule);
}
.info dt:first-of-type { margin-top: 0; padding-top: 0; border-top: 0; }
.info dd { margin: 8px auto 0; max-width: 46ch; }

/* ---------- footer ---------- */
/* The Classic's index has no footer. This page needs one: it is the only place
   the night is attributed, and the committee owns it, never a person. */
.site-foot {
  background: var(--coal); color: #fff;
  padding: var(--space-lg) 0; text-align: center;
}
.site-foot__who {
  font-family: var(--display); font-size: var(--t-utility); font-weight: 700;
  letter-spacing: 0.18em; text-transform: uppercase; color: #fff;
  margin: var(--space-md) auto 0;
}
.site-foot__tag {
  font-family: var(--serif); font-style: italic; font-size: 17px;
  color: var(--leaf-hi); margin: var(--space-xs) auto 0; max-width: 34ch;
}

/* ---------- register pages: honeypot ---------- */
/* Both register pages POST to /api/register, so they are worth spamming. The
   `website` field is bait: a person never sees it, so anything in it came from
   a bot and the submission is dropped server side.
   Off-screen, NOT display:none or [hidden] — the bots worth catching read the
   CSS and skip anything switched off, and a screen reader is already told to
   ignore the wrapper by aria-hidden. The input is out of the tab order too, so
   nobody can land in it by keyboard. It is absolutely positioned, which takes
   it out of the form's flow: it contributes no gap and no height. */
.hp {
  position: absolute; left: -9999px;
  width: 1px; height: 1px; overflow: hidden;
}
/* Morgan asked for no subtitle under the register heading, so the 8px that used
   to space the h1 off its paragraph has nothing left to space. */
.register-head .page-head__title h1:only-child { margin: 0; }
/* "Register and pay — $50" at 13px with 0.2em of tracking sits within a few px
   of the interior at 320. Trimming the side padding lets it stay on one line
   there; it is free to wrap rather than push the page sideways if it does not. */
.register-body .btn--block { padding-left: 16px; padding-right: 16px; }

/* Photo strip: three shots in a row, flush and full-bleed, between the hero
   and the Quiz Night section. Kept in colour — no duotone, nothing overlaid. */
.photo-strip {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
.photo-strip img {
  display: block;
  width: 100%;
  height: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  object-position: 50% 35%;
}
