/* ===========================================================================
   GRIPswich — group bookings
   The organiser's own pages: /groups/book/, /groups/<token>/ and the two ways
   of signing a waiver from them.

   WHY THIS FILE EXISTS AT ALL. group_booking_manage.html was written in the
   console's vocabulary — .stat-row, .table, .badge, .notice, .inline-form,
   .row, .mt2, .container--narrow — but it extends base.html, which loads
   style.css and never console.css. Roughly half of those classes are defined in
   console.css and the rest in no stylesheet in this repo, so the page a teacher
   opens from their confirmation email rendered as a bare browser-default table
   on a dark ground. Importing console.css into the public shell was not the fix:
   it is 2,700 lines of staff chrome (over 6,000 by 2026-09) that resolves its
   own tokens and would restyle every public form on the site.

   So: one self-contained sheet, .gb- prefixed, using style.css's :root tokens
   (it is always loaded first). Nothing here leaks onto another page.

   RESPONSIVE CONTRACT. The audience is a teacher on a school laptop, a parent
   on a phone at a bus stop, and a group leader with an iPad in a hall. Every
   layout here is single-column first and widens at four breakpoints:
     560px   large phone / phone landscape — two-up stats
     768px   iPad portrait — a roll row becomes two lines instead of four
     1024px  iPad landscape, small laptop — the four summary figures fit one row
     1200px  desktop — the summary rail moves alongside and sticks
   Nothing has a fixed pixel width, every control clears 44px wherever the
   pointer is coarse (the denser 40px small button is mouse-only),
   and the one wide thing on the page (the roll) never makes the BODY scroll
   sideways — it is a grid that reflows, not a table that overflows.
   =========================================================================== */

/* --------------------------------------------------------------------------
   Shell
   -------------------------------------------------------------------------- */

/* The reading column these pages sit in. `.container--narrow` was used by the
   manage template and defined nowhere, so the roll ran the full width of a
   27-inch monitor. */
.container--narrow {
  width: 100%;
  max-width: 74rem;
  margin-inline: auto;
  padding-inline: clamp(1rem, 4vw, 2rem);
}

.gb-page { padding-block: clamp(1.75rem, 5vw, 3.5rem); }

/* --------------------------------------------------------------------------
   Page head — what this booking is, and whether it is happening
   -------------------------------------------------------------------------- */
.gb-head { margin-bottom: clamp(1.25rem, 3vw, 2rem); }

.gb-head__eyebrow {
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--clr-teal-4);
  margin-bottom: 0.4rem;
}

.gb-head h1 {
  font-size: clamp(1.6rem, 4.5vw, 2.5rem);
  font-weight: 900;
  line-height: 1.15;
  overflow-wrap: anywhere; /* a school name with no spaces must not push the page wide */
}

.gb-head__when {
  margin-top: 0.5rem;
  color: var(--clr-muted-3);
  font-size: clamp(0.95rem, 2.2vw, 1.0625rem);
}

.gb-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 0.9rem;
}

/* --------------------------------------------------------------------------
   Chips and badges
   Their own, not console.css's .badge — same idea, public palette, and sized
   for a finger rather than for a dense staff table.
   -------------------------------------------------------------------------- */
.gb-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.3rem 0.7rem;
  border-radius: 999px;
  border: 1px solid var(--clr-border);
  background: rgba(255, 255, 255, 0.04);
  color: var(--clr-muted-3);
  font-size: 0.8125rem;
  font-weight: 700;
  line-height: 1.35;
  white-space: nowrap;
}
.gb-chip--ok {
  border-color: rgba(20, 184, 166, 0.5);
  background: rgba(20, 184, 166, 0.14);
  color: var(--clr-teal-4);
}
.gb-chip--warn {
  border-color: rgba(249, 115, 22, 0.5);
  background: rgba(249, 115, 22, 0.14);
  color: var(--clr-orange-4);
}
.gb-chip--bad {
  border-color: rgba(239, 68, 68, 0.5);
  background: rgba(239, 68, 68, 0.14);
  color: #fca5a5;
}

/* The dot is the redundant, non-colour half of the signal — the waiver badge is
   the one thing on this page a red/green colour-blind organiser has to be able
   to read at a glance (roughly 1 in 12 men). */
.gb-chip__dot {
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: currentColor;
  flex-shrink: 0;
}

/* --------------------------------------------------------------------------
   Notices
   -------------------------------------------------------------------------- */
.gb-notice {
  display: flex;
  gap: 0.75rem;
  padding: 0.95rem 1.1rem;
  border: 1px solid var(--clr-border);
  border-left-width: 4px;
  border-radius: var(--radius);
  background: rgba(255, 255, 255, 0.03);
  color: var(--clr-muted-3);
  font-size: 0.9375rem;
  margin-bottom: 1rem;
}
.gb-notice p { max-width: none; }
.gb-notice strong { color: var(--clr-text); }
.gb-notice--ok   { border-left-color: var(--clr-teal); }
.gb-notice--ok strong { color: var(--clr-teal-4); }
.gb-notice--warn { border-left-color: var(--clr-orange); }
.gb-notice--warn strong { color: var(--clr-orange-4); }
.gb-notice--info { border-left-color: #60a5fa; }
.gb-notice--info strong { color: #93c5fd; }

/* --------------------------------------------------------------------------
   Cards
   -------------------------------------------------------------------------- */
.gb-card {
  background: var(--clr-bg);
  border: 1px solid var(--clr-border);
  border-radius: 12px;
  padding: clamp(1.1rem, 3vw, 1.6rem);
  margin-bottom: 1.25rem;
}
.gb-card__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem 1rem;
  margin-bottom: 0.35rem;
}
.gb-card h2 {
  font-size: clamp(1.15rem, 2.6vw, 1.375rem);
  font-weight: 800;
  line-height: 1.25;
}
.gb-card__note {
  color: var(--clr-muted);
  font-size: 0.9rem;
  max-width: var(--measure);
  margin-bottom: 1rem;
}
.gb-card__note:last-child { margin-bottom: 0; }

/* --------------------------------------------------------------------------
   Progress — the number this page exists to move
   -------------------------------------------------------------------------- */
.gb-progress__row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.35rem 1rem;
  margin-bottom: 0.6rem;
}
.gb-progress__label { font-weight: 800; font-size: 1.0625rem; }
.gb-progress__count {
  font-variant-numeric: tabular-nums;
  color: var(--clr-muted);
  font-size: 0.9rem;
}
.gb-progress__track {
  height: 0.65rem;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.09);
  overflow: hidden;
}
.gb-progress__fill {
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--clr-teal), var(--clr-teal-4));
  /* No transition: this bar only ever changes across a page load, and an
     animation from 0 on every render reads as the number resetting. */
}
.gb-progress__fill--done {
  background: linear-gradient(90deg, var(--clr-teal), #4ade80);
}

/* --------------------------------------------------------------------------
   Stats
   One column on a small phone, two from 560px, four from 1024px. Never a fixed
   four-across: "12 adults · $20 ea" does not fit a quarter of a 360px screen.
   -------------------------------------------------------------------------- */
.gb-stats {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.75rem;
  margin-top: 1.25rem;
}
.gb-stat {
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--clr-border);
  border-radius: 10px;
  padding: 0.8rem 0.95rem;
}
.gb-stat__n {
  display: block;
  font-size: 1.6rem;
  font-weight: 900;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}
.gb-stat__l {
  display: block;
  margin-top: 0.15rem;
  font-size: 0.8125rem;
  color: var(--clr-muted);
}
.gb-stat--warn { border-color: rgba(249, 115, 22, 0.45); }
.gb-stat--warn .gb-stat__n { color: var(--clr-orange-4); }
.gb-stat--ok .gb-stat__n { color: var(--clr-teal-4); }

/* --------------------------------------------------------------------------
   The roll
   A grid of cards, NOT a table. A table with five columns and two inputs in it
   either overflows a phone or gets wrapped in a sideways scroller the organiser
   has to discover — and this is the list they work down. Each person is a card
   that lays itself out in a row once there is room.
   -------------------------------------------------------------------------- */
.gb-roll {
  display: grid;
  gap: 0.75rem;
  list-style: none;
}

.gb-person {
  display: grid;
  gap: 0.75rem;
  padding: 0.9rem 1rem;
  background: rgba(255, 255, 255, 0.025);
  border: 1px solid var(--clr-border);
  border-radius: 10px;
}
.gb-person--done { border-color: rgba(20, 184, 166, 0.35); }
.gb-person--todo { border-color: rgba(249, 115, 22, 0.35); }

.gb-person__id {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  min-width: 0;
}
.gb-person__name {
  font-weight: 800;
  font-size: 1.0625rem;
  overflow-wrap: anywhere;
}

/* The two editable details. Stacked on a phone, side by side from 768px. */
.gb-person__fields {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.6rem;
  align-items: end;
}
.gb-field { min-width: 0; }
.gb-field > label {
  display: block;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--clr-muted);
  margin-bottom: 0.25rem;
}
.gb-field input,
.gb-field select {
  width: 100%;
  min-height: 2.75rem; /* 44px — the smallest thing a finger should have to hit */
  padding: 0.55rem 0.7rem;
  background: var(--clr-bg-dark);
  border: 1px solid var(--clr-border);
  border-radius: 8px;
  color: var(--clr-text);
  font-family: inherit;
  font-size: 1rem; /* never below 1rem: iOS Safari zooms the page on focus if it is */
}
.gb-field input:focus,
.gb-field select:focus {
  outline: 2px solid var(--clr-teal);
  outline-offset: 1px;
  border-color: var(--clr-teal);
}

/* Actions. Wrap freely; each button keeps its own touch target. */
.gb-person__actions,
.gb-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}
.gb-person__actions form,
.gb-actions form { margin: 0; }

/* --------------------------------------------------------------------------
   Buttons
   .btn/.btn--orange/.btn--teal come from style.css. These are the two sizes and
   the quiet variant that sheet has no equivalent of.
   -------------------------------------------------------------------------- */
.gb-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  min-height: 2.75rem;
  padding: 0.55rem 1rem;
  border: 1px solid transparent;
  border-radius: 8px;
  font-family: inherit;
  font-size: 0.9375rem;
  font-weight: 700;
  line-height: 1.2;
  cursor: pointer;
  text-align: center;
  transition: background-color 0.15s, border-color 0.15s, color 0.15s;
}
.gb-btn:focus-visible { outline: 2px solid var(--clr-teal-4); outline-offset: 2px; }

/* Dark ink, not white — the same decision style.css records on .btn--orange:
   white on #f97316 is 2.80:1 and on #14b8a6 is 2.49:1, both well under the
   4.5:1 AA needs for 15px bold, while the page ground gives 6.3:1 and 7.1:1.
   These are every primary call to action on all three group pages, so getting
   it wrong here undoes that fix on the busiest buttons in the flow. */
.gb-btn--primary { background: var(--clr-orange); color: var(--clr-bg); }
.gb-btn--primary:hover { background: var(--clr-orange-h); color: var(--clr-bg); }

.gb-btn--teal { background: var(--clr-teal); color: var(--clr-bg); }
.gb-btn--teal:hover { background: var(--clr-teal-h); color: var(--clr-bg); }

.gb-btn--quiet {
  background: transparent;
  border-color: var(--clr-border);
  color: var(--clr-muted-3);
}
.gb-btn--quiet:hover { border-color: var(--clr-teal-4); color: var(--clr-teal-4); }

/* Removing somebody is destructive and reads as such only on approach — it is
   not painted red at rest, because a list of thirty red buttons is a list
   nobody reads. */
.gb-btn--danger { background: transparent; border-color: var(--clr-border); color: var(--clr-muted); }
.gb-btn--danger:hover { border-color: #ef4444; color: #fca5a5; }

/* Denser, because a roll of sixty rows carries three of these each — but only
   where a mouse is doing the pointing. On a touch screen they go back to the
   full 44px this file promises, which is the case that matters: these are the
   buttons a teacher taps over and over on a phone. */
.gb-btn--sm { min-height: 2.5rem; padding: 0.4rem 0.8rem; font-size: 0.875rem; }
@media (pointer: coarse) {
  .gb-btn--sm { min-height: 2.75rem; }
}
.gb-btn--block { width: 100%; }

/* --------------------------------------------------------------------------
   The two-choice picker on /groups/book/

   Two ANCHORS to ?type=public / ?type=private, not a radio group: the choice
   changes the prices, the bounds and half the copy, all of which are rendered
   by the server, so making it a link means one click and no JavaScript rather
   than a radio plus a Continue button. They are links to a screen reader too,
   headed by "What kind of booking?" and with aria-current on the live one; the
   circle beside each title is decoration, and the file no longer pretends
   otherwise.
   -------------------------------------------------------------------------- */
.gb-choice {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.85rem;
  margin-bottom: 1.5rem;
}

.gb-choice__opt {
  display: block;
  position: relative;
  padding: 1.1rem 1.2rem;
  background: rgba(255, 255, 255, 0.03);
  border: 2px solid var(--clr-border);
  border-radius: 12px;
  cursor: pointer;
  transition: border-color 0.15s, background-color 0.15s;
}
.gb-choice__opt:hover { border-color: var(--clr-teal-4); }

.gb-choice__opt:focus-visible {
  outline: 2px solid var(--clr-teal-4);
  outline-offset: 2px;
}
/* Which one the page is currently showing. Stamped by the server — there is no
   client state here to read. */
.gb-choice__opt.is-selected {
  border-color: var(--clr-orange);
  background: rgba(249, 115, 22, 0.1);
}

.gb-choice__title {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 1.125rem;
  font-weight: 800;
  margin-bottom: 0.35rem;
}
.gb-choice__opt.is-selected .gb-choice__title { color: var(--clr-orange-4); }

.gb-choice__title::before {
  content: "";
  width: 1.15rem;
  height: 1.15rem;
  border-radius: 50%;
  border: 2px solid var(--clr-muted);
  flex-shrink: 0;
  transition: border-color 0.15s, box-shadow 0.15s;
}
.gb-choice__opt.is-selected .gb-choice__title::before {
  border-color: var(--clr-orange);
  box-shadow: inset 0 0 0 4px var(--clr-orange);
}

.gb-choice__body {
  color: var(--clr-muted-3);
  font-size: 0.9375rem;
  line-height: 1.55;
}
.gb-choice__meta {
  display: block;
  margin-top: 0.5rem;
  font-size: 0.8125rem;
  font-weight: 700;
  color: var(--clr-teal-4);
}

/* --------------------------------------------------------------------------
   Pricing / "how it works" panels on the request page
   -------------------------------------------------------------------------- */
.gb-panel {
  background: var(--clr-bg);
  border: 1px solid var(--clr-border);
  border-radius: 12px;
  padding: clamp(1.1rem, 3vw, 1.5rem);
  margin-bottom: 1.25rem;
}
.gb-panel h3 {
  font-size: 1.0625rem;
  font-weight: 800;
  margin-bottom: 0.75rem;
}
.gb-panel p { color: var(--clr-muted-3); font-size: 0.9375rem; max-width: none; }

.gb-price {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.25rem 1rem;
  padding: 0.6rem 0;
  border-bottom: 1px solid var(--clr-border);
}
.gb-price:last-of-type { border-bottom: none; }
.gb-price__what { color: var(--clr-muted-3); }
.gb-price__amt { font-weight: 800; color: var(--clr-text); white-space: nowrap; }

.gb-steps {
  list-style: none;
  counter-reset: gbstep;
  display: grid;
  gap: 0.9rem;
}
/* Indent + an absolutely positioned marker, NOT a two-column grid.
   Each step reads "<strong>Tell us your date.</strong> Nothing's booked until
   we confirm it suits." — and under `display: grid` that trailing sentence
   becomes an ANONYMOUS grid item of its own, which lands in row 2 of the
   1.9rem number column and renders one word per line. Normal flow keeps the
   bold lead-in and its sentence as one paragraph, which is what they are. */
.gb-steps li {
  counter-increment: gbstep;
  position: relative;
  padding-left: 2.65rem;
  min-height: 1.9rem;
  color: var(--clr-muted-3);
  font-size: 0.9375rem;
  line-height: 1.55;
}
.gb-steps li::before {
  content: counter(gbstep);
  position: absolute;
  left: 0;
  top: 0;
  display: grid;
  place-items: center;
  width: 1.9rem;
  height: 1.9rem;
  border-radius: 50%;
  background: rgba(20, 184, 166, 0.15);
  border: 1px solid rgba(20, 184, 166, 0.45);
  color: var(--clr-teal-4);
  font-size: 0.875rem;
  font-weight: 800;
}
.gb-steps strong { color: var(--clr-text); }

/* --------------------------------------------------------------------------
   The guardian sign-for-many page
   -------------------------------------------------------------------------- */
.gb-pick {
  display: grid;
  gap: 0.5rem;
  margin-bottom: 0.5rem;
  /* .gb-roll and .gb-steps both reset this and this one did not — the global
     `* { padding: 0 }` zeroes the ul's inline start padding, so the default
     outside marker paints in .gb-card's padding: a disc beside every child's
     name, on a list that is already a column of checkboxes. */
  list-style: none;
}
/* One person: a tick with their name, and the date box that says whether they
   are a child at all. The card is the LI, not the label — the date input has to
   sit outside the label, because a tap on a date picker nested inside one
   toggles the checkbox as well. */
.gb-pick__item {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.5rem;
  padding: 0.7rem 0.85rem;
  background: rgba(255, 255, 255, 0.025);
  border: 1px solid var(--clr-border);
  border-radius: 10px;
}
.gb-pick__item:hover { border-color: var(--clr-teal-4); }
.gb-pick__item:has(input[type="checkbox"]:checked) {
  border-color: var(--clr-teal);
  background: rgba(20, 184, 166, 0.1);
}
.gb-pick__item:has(input[type="checkbox"]:focus-visible) {
  outline: 2px solid var(--clr-teal-4);
  outline-offset: 2px;
}

.gb-pick__row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  min-height: 2.75rem;
  cursor: pointer;
  min-width: 0;
}
/* Big enough to hit, and not shrunk by the flex row on a narrow screen. */
.gb-pick__row input[type="checkbox"] {
  width: 1.35rem;
  height: 1.35rem;
  flex-shrink: 0;
  accent-color: var(--clr-teal);
  cursor: pointer;
}
.gb-pick__name { font-weight: 700; overflow-wrap: anywhere; }

.gb-pick__dob { min-width: 0; }
.gb-pick__dob > label {
  display: block;
  /* Matched to .gb-field > label rather than being a size of its own. At 0.7rem
     this rendered at 11.2px — the only sub-12px text on any of these pages, and
     it is the caption on the date box that decides whether a child needs an
     adult to sign at all, on a form filled in by a parent on a phone. */
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--clr-muted);
  margin-bottom: 0.2rem;
}
.gb-pick__dob input {
  width: 100%;
  min-height: 2.75rem;
  padding: 0.45rem 0.6rem;
  background: var(--clr-bg-dark);
  border: 1px solid var(--clr-border);
  border-radius: 8px;
  color: var(--clr-text);
  font-family: inherit;
  font-size: 1rem;
}
.gb-pick__dob input:focus {
  outline: 2px solid var(--clr-teal);
  outline-offset: 1px;
  border-color: var(--clr-teal);
}

/* The document itself. Capped and scrollable so the "sign" button is never
   thousands of pixels below the error summary it bounces to. */
.gb-doc {
  max-height: 320px;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 1rem 1.15rem;
  background: var(--clr-bg-dark);
  border: 1px solid var(--clr-border);
  border-radius: 10px;
  color: var(--clr-muted-3);
  font-size: 0.9rem;
  line-height: 1.6;
}
.gb-doc p { max-width: none; margin-bottom: 0.85rem; }
.gb-doc p:last-child { margin-bottom: 0; }

/* The agreement tick: a big target with a paragraph-length label beside it. */
.gb-agree {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.75rem;
  align-items: start;
  padding: 0.95rem 1.1rem;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--clr-border);
  border-radius: 10px;
  margin-block: 1rem;
}
.gb-agree input[type="checkbox"] {
  width: 1.35rem;
  height: 1.35rem;
  margin-top: 0.15rem;
  accent-color: var(--clr-teal);
  cursor: pointer;
}
.gb-agree label { color: var(--clr-muted-3); font-size: 0.9375rem; line-height: 1.55; cursor: pointer; }
.gb-agree--error { border-color: #ef4444; background: rgba(239, 68, 68, 0.08); }
.gb-agree__error { grid-column: 1 / -1; color: #fca5a5; font-size: 0.875rem; }

/* --------------------------------------------------------------------------
   Empty state, fine print, the share-this-link box
   -------------------------------------------------------------------------- */
/* `.muted` is defined in console.css and nowhere else, so on a public page it
   rendered at full body colour — which made "(required if the climber is under
   18)" look exactly like the label it qualifies. Defined here rather than in
   style.css so the fix is scoped to the pages this sheet loads on. */
.muted { color: var(--clr-muted); }

/* Likewise `.form-group select`: style.css styles input and textarea and stops.
   An unstyled select is a light system widget on a dark form, and its UA font
   size is about 13px — under the 16px at which iOS zooms the page on focus. */
.form-group select,
.wform select {
  width: 100%;
  min-height: 2.75rem;
  padding: 0.7rem 0.75rem;
  background: var(--clr-bg-dark);
  border: 1px solid var(--clr-border);
  border-radius: 8px;
  color: var(--clr-text);
  font-family: inherit;
  font-size: 1rem;
}
.form-group select:focus,
.wform select:focus { border-color: var(--clr-teal); outline: 2px solid var(--clr-teal); outline-offset: 1px; }

/* The red outline on a refused box. `.wform__field--error > input` in style.css
   and `.gb-field input` here have identical specificity, and this sheet loads
   last — so the tint that style.css relies on for WCAG 1.4.1 (border AND fill
   AND message, not colour alone) was silently losing to the normal state. */
.gb-field.wform__field--error input,
.gb-field.wform__field--error select {
  border-color: #ef4444;
  background: rgba(239, 68, 68, 0.07);
}
.gb-field.wform__field--error > label { color: #fca5a5; }

.gb-empty {
  padding: 1.75rem 1.25rem;
  text-align: center;
  color: var(--clr-muted);
  border: 1px dashed var(--clr-border);
  border-radius: 10px;
}

.gb-fine {
  color: var(--clr-muted);
  font-size: 0.8125rem;
  line-height: 1.55;
  max-width: var(--measure);
}

/* The organiser's own link, shown so they can copy it off the screen. Wrapping
   is forced: a 43-character token in a nowrap box is a horizontal scrollbar on
   the whole page. */
.gb-link {
  display: block;
  padding: 0.7rem 0.85rem;
  background: var(--clr-bg-dark);
  border: 1px solid var(--clr-border);
  border-radius: 8px;
  font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  font-size: 0.8125rem;
  color: var(--clr-teal-4);
  overflow-wrap: anywhere;
  word-break: break-all;
}

/* --------------------------------------------------------------------------
   Breakpoints
   -------------------------------------------------------------------------- */

/* Large phone / phone landscape — stats pair up, and the pick list's date box
   moves alongside the name instead of under it. */
@media (min-width: 560px) {
  .gb-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .gb-pick__item {
    grid-template-columns: minmax(0, 1fr) minmax(8.5rem, 11rem);
    align-items: end;
    gap: 0.75rem;
  }
  .gb-pick__row { align-self: end; padding-bottom: 0.35rem; }
}

/* iPad portrait and up — a person card becomes two lines instead of four:
   name and buttons share the top line, the editable details fill the one below.

   NOT one flat row of five things. The three buttons come to roughly 320px of
   unshrinkable text, and on a desktop where the summary rail has already taken
   20rem, squeezing a name, a date picker and an email box into what is left
   gives every one of them about 80px — the fields stop being usable at exactly
   the width they were widened for. Two lines keeps every control full size at
   every width above this breakpoint. */
@media (min-width: 768px) {
  .gb-choice { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .gb-btn--block { width: auto; }

  .gb-person {
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    column-gap: 1rem;
  }
  .gb-person__id { grid-column: 1; grid-row: 1; }
  .gb-person__actions { grid-column: 2; grid-row: 1; justify-content: flex-end; }
  /* Full width on its own line: date | email | save. */
  .gb-person__fields {
    grid-column: 1 / -1;
    grid-template-columns: minmax(8rem, 12rem) minmax(0, 1fr) auto;
  }
  /* The Save button aligns with the boxes, not with their captions. */
  .gb-person__fields .gb-btn { min-width: 6rem; }
}

/* iPad landscape and up — the four summary figures fit one line. */
@media (min-width: 1024px) {
  .gb-stats { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* Desktop — the summary rail moves out beside the work and stays put while the
   organiser scrolls a roll of sixty names. */
@media (min-width: 1200px) {
  .gb-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 20rem;
    gap: 2rem;
    align-items: start;
  }
  /* Sticky, and never taller than the space it is sticking in — otherwise the
     bottom of the rail is unreachable on a short laptop screen.
     --visitbar-h as well as --nav-h: the pinned .site-chrome block holds BOTH,
     so clearing only the nav left the rail's first heading permanently behind
     46px of opaque strip, where its own overflow could not reach it. */
  .gb-rail {
    position: sticky;
    top: calc(var(--nav-h) + var(--visitbar-h, 0px) + 1rem);
    max-height: calc(100vh - var(--nav-h) - var(--visitbar-h, 0px) - 2rem);
    overflow-y: auto;
  }
  /* Back to two-up inside the rail: it is 20rem wide, and four columns there is
     80px each — not enough for "adults · $20 ea" to stay on one line. */
  .gb-rail .gb-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* A laptop screen short enough that a sticky rail would trap its own scroll.
   Same max-height: 560px axis the heroes and the nav already use. */
@media (max-height: 560px) {
  .gb-rail { position: static; max-height: none; overflow: visible; }
}

/* Somebody who asked not to be moved about. The only motion here is the
   progress fill and the button transitions, but the rule is cheap and the
   promise is site-wide. */
@media (prefers-reduced-motion: reduce) {
  .gb-btn,
  .gb-choice__opt,
  .gb-choice__title::before { transition: none; }
}

/* A pair of fields that really are a pair — two equal halves, top-aligned so a
   validation message under one does not shove the other's input down to line up
   with it. NOT .gb-person__fields, which is the roll's three-track
   date | email | Save row and leaves a dead third column here. */
.gb-pair { display: grid; grid-template-columns: 1fr; gap: 0.75rem; align-items: start; }
@media (min-width: 768px) {
  .gb-pair { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Print — a teacher printing the roll to carry on the bus wants the names, not
   the buttons or the input chrome. */
@media print {
  .gb-person__actions,
  .gb-actions,
  .gb-btn,
  .gb-progress__track { display: none !important; }
  .gb-card,
  .gb-person { border-color: #999; break-inside: avoid; }
}
