/* =============================================================================
   S.H.E. Hockey — design system
   -----------------------------------------------------------------------------
   Hand-written, no build step. Tokens first, then components.

   Palette is lifted from the live Wix site's own CSS custom properties
   (--color_0 … --color_35) so the brand colour is identical to what the
   organisation uses today, while nothing about the layout or type carries over.

   CONTRAST — this drives several choices below, so read before changing a colour.

   #F529B8 on white is 3.56:1. That clears WCAG AA for large text (3:1) and
   FAILS it for body copy (4.5:1). So the brand pink is used for:
     - large display type, rules, borders, fills
     - never small body text on white
   For pink-adjacent *text* on white use --pink-link (#A31B7B, 7.02:1, AAA).
   Black on the pink fill is 5.89:1, so pink buttons take black labels, not white.
   ========================================================================== */

/* -----------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */

:root {
  /* Brand pink — the live site's --wst-color-action and its shades. */
  --pink: #f529b8;
  --pink-bright: #f91593;
  --pink-deep: #a31b7b;
  --pink-dark: #520e3d;
  --pink-wash: #fcb6e7;
  --pink-pale: #fdeaf7;

  /* Neutrals. Not pure grey ramps — the ink is warmed very slightly so the pink
     reads as part of the same family rather than sitting on top of it. */
  --black: #000000;
  --ink: #141014;
  --ink-soft: #333333;
  --ink-muted: #6b6b6b;
  --rule: #e2dee2;
  --surface: #f7f5f6;
  --white: #ffffff;

  /* Semantic */
  --text: var(--ink);
  --text-muted: var(--ink-muted);
  --text-on-pink: var(--black);
  --link: var(--pink-deep);
  --link-hover: var(--pink-dark);
  --focus: var(--pink-deep);
  --border: var(--rule);
  --danger: #b91c1c;
  --danger-dark: #7f1515;
  --danger-pale: #fef2f2;
  --bg: var(--white);
  --bg-alt: var(--surface);
  /* A met password rule. Green on white reads as "done" without relying on the brand pink,
     which is reserved for actions and errors. */
  --positive: #1a7f37;
  /* The required-field asterisk. A true red reads as "required" at a glance; #c62828 clears
     4.5:1 on white, unlike the brand pink. */
  --required: #c62828;

  /* Type. No webfont request: a third-party font CDN would hand visitor IPs to
     that vendor on every page load, which is a poor fit for a site collecting
     children's data. Both stacks resolve on every desktop and mobile OS.
     The serif is what carries the editorial voice — the sans faces below are
     close to the Wix site's own Arial, so the serif does the differentiating. */
  --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, sans-serif;
  --font-serif: Georgia, "Times New Roman", Times, serif;
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  /* Type scale. Ratios are large on purpose — this is a display-led design.
     Steps below 1rem are body-and-smaller only. */
  --fs-display: clamp(3rem, 11vw, 8.5rem);
  --fs-h1: clamp(2.25rem, 6vw, 4.5rem);
  --fs-h2: clamp(1.75rem, 3.6vw, 2.75rem);
  --fs-h3: clamp(1.25rem, 2vw, 1.5rem);
  --fs-lead: clamp(1.125rem, 1.6vw, 1.375rem);
  --fs-body: 1.0625rem;
  --fs-small: 0.9375rem;
  --fs-micro: 0.8125rem;

  /* Space */
  --sp-1: 0.25rem;
  --sp-2: 0.5rem;
  --sp-3: 0.75rem;
  --sp-4: 1rem;
  --sp-5: 1.5rem;
  --sp-6: 2rem;
  --sp-7: 3rem;
  --sp-8: 4rem;
  --sp-9: 6rem;
  --sp-10: 8rem;

  /* Layout */
  --wrap: 76rem;
  --wrap-narrow: 46rem;
  --measure: 62ch;
  --rule-weight: 3px;

  --transition: 150ms cubic-bezier(0.4, 0, 0.2, 1);
}

/* -----------------------------------------------------------------------------
   2. Reset
   -------------------------------------------------------------------------- */

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

* {
  margin: 0;
}

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img,
picture,
svg {
  display: block;
  max-width: 100%;
  height: auto;
}

input,
button,
textarea,
select {
  font: inherit;
  color: inherit;
}

ul[class],
ol[class] {
  list-style: none;
  padding: 0;
}

/* -----------------------------------------------------------------------------
   3. Typography
   -------------------------------------------------------------------------- */

h1,
h2,
h3,
h4 {
  font-weight: 800;
  line-height: 1.02;
  letter-spacing: -0.03em;
  text-wrap: balance;
}

h1 {
  font-size: var(--fs-h1);
}
h2 {
  font-size: var(--fs-h2);
}
h3 {
  font-size: var(--fs-h3);
  letter-spacing: -0.015em;
  line-height: 1.2;
}

p {
  text-wrap: pretty;
}

/* Long unbroken strings — an email address in the footer, a long slug in a URL —
   must not force a horizontal scrollbar on a phone. The placeholder contact values are
   short enough to hide this, so it only shows up once the real ones land. */
body,
.site-footer__list,
.card__meta {
  overflow-wrap: break-word;
}

a {
  color: var(--link);
  text-decoration-thickness: 2px;
  text-underline-offset: 0.2em;
  transition: color var(--transition);
}

a:hover {
  color: var(--link-hover);
}

/* Visible focus everywhere. Never remove without a replacement. */
:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 3px;
  border-radius: 2px;
}

/* Editorial eyebrow: small, tracked-out, sits above a heading. */
.eyebrow {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--pink-deep);
  margin-bottom: var(--sp-3);
}

/* The pink bar. Used instead of borders where a hairline would be too quiet. */
.rule {
  height: var(--rule-weight);
  width: 4.5rem;
  background: var(--pink);
  border: 0;
  margin: var(--sp-5) 0;
}

.lead {
  font-size: var(--fs-lead);
  line-height: 1.45;
  max-width: var(--measure);
}

.prose {
  max-width: var(--measure);
}

.prose > * + * {
  margin-top: var(--sp-4);
}

/* Display headings need more air than body copy, and less air under them than over them.
   The uniform sibling gap above leaves an h2 sitting almost on top of the paragraph it
   introduces, which is what made /about/ read as cramped next to the landing page. */
.prose > * + h2,
.prose > * + h3 {
  margin-top: var(--sp-7);
}

.prose > h2 + *,
.prose > h3 + * {
   margin-top: var(--sp-2);
}

/* Bullets inside a prose block. The `> * + *` rule above spaces the list against its
   surroundings, but says nothing about the gap *within* it, which leaves the items
   touching — legal pages disclose open items as a list, so that gap is load-bearing. */
.prose li + li {
   margin-top: var(--sp-2);
}

.prose ul,
.prose ol {
   padding-left: var(--sp-5);
}

/* A paragraph-length prose block on the dark band. Two deliberate departures from the rest
   of the ink sections: body is a neutral near-white rather than pure white, which is harsh
   across four paragraphs, and rather than --pink-wash, which suits the two-sentence
   .cta__body but would tint a whole page if used at length. Headings stay full white, and
   the pink is left to accents. */
.section--ink .prose {
  color: var(--surface);
}

.section--ink .prose h2,
.section--ink .prose h3 {
  color: var(--white);
}

/* -----------------------------------------------------------------------------
   4. Layout primitives
   -------------------------------------------------------------------------- */

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--sp-5);
}

.wrap--narrow {
  max-width: var(--wrap-narrow);
}

.section {
  padding-block: var(--sp-9);
}

.section--tight {
  padding-block: var(--sp-7);
}

.section--alt {
  background: var(--bg-alt);
}

/* Photo background for the upcoming-events section on the home page. Cards and empty state
   stay white so they remain readable against the image. */
.section--events-photo {
  position: relative;
  overflow: hidden;
  background: transparent;
  color: var(--white);
}

.section--events-photo .eyebrow {
  color: var(--pink);
}

.section--events-photo h2 {
  text-shadow: 0 2px 16px rgba(20, 20, 20, 0.55);
}

.events-bg {
  position: absolute;
  inset: 0;
  z-index: -1;
  background-attachment: fixed;
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
}

.events-bg::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(20, 20, 20, 0.55);
}

@media (max-width: 47.99rem) {
  .events-bg {
    background-attachment: scroll;
  }
}

/* Dark band. Pink stays legible here because the text is white, not pink. */
.section--ink {
  background: var(--ink);
  color: var(--white);
}

.section--ink a {
  color: var(--pink-wash);
}

.section--ink .eyebrow {
  color: var(--pink);
}

/* Pink band. The one place a full-bleed saturated colour is allowed: it closes a page, and
   the alternation it makes against the white, black and grey bands is the whole point.

   Black text, not white — white on pink is 3.56:1 and fails AA for body copy. And the fill
   has to be the action colour rather than a deeper shade: of the pink ramp only --pink and
   --pink-bright can carry black text at all, --pink-deep manages 3.00:1. */
.section--pink {
  background: var(--pink);
  color: var(--text-on-pink);
}

.section--pink a {
  color: var(--black);
}

/* Hierarchy on this band comes from size and weight rather than colour. Black and --ink are
   the only two tones in the ramp that clear AA against pink as body text, and side by side
   they are indistinguishable. */
.section--pink .eyebrow,
.section--pink .cta__title,
.section--pink .cta__body {
  color: var(--black);
}

/* The default .btn is pink-on-pink, so it disappears. Invert it — and keep the hover off
   white text, which is what .btn--light:hover does at 3.56:1 here. */
.section--pink .btn {
  background: var(--black);
  border-color: var(--black);
  color: var(--pink);
}

.section--pink .btn:hover {
  background: var(--white);
  border-color: var(--black);
  color: var(--black);
}

/* The inert donate button on the home page lives on this band, and the global disabled
   hover turns a button pink. `.btn[aria-disabled]:hover` outranks `.section--pink .btn` on
   specificity, so without this it goes pink-on-pink and disappears into the background
   exactly when the user points at it. Keeps the resting treatment, which reads as
   disabled through opacity alone. */
.section--pink .btn[aria-disabled="true"],
.section--pink .btn[aria-disabled="true"]:hover {
  background: var(--black);
  border-color: var(--black);
  color: var(--pink);
}

/* White rather than black: this is the first thing painted over the page, and with a black
   header underneath a black skip link would be all but invisible when focused.
   `fixed`, not `absolute` -- it must sit at the top of the *viewport* when focused, which
   matters now that the header is sticky and the page can be scrolled. */
.skip-link {
  position: fixed;
  left: -9999px;
  top: 0;
  z-index: 100;
  background: var(--white);
  color: var(--black);
  padding: var(--sp-3) var(--sp-4);
  font-weight: 700;
  text-decoration: none;
}

.skip-link:focus {
  left: 0;
  color: var(--black);
  outline-color: var(--pink);
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* A sticky header covers the top of the viewport, so any in-page anchor target (#events on
   the landing page, section links on the rest) would otherwise be scrolled to underneath it
   and read as a blank strip. The header is about 62px tall; this leaves breathing room. */
[id] {
  scroll-margin-top: 5.5rem;
}

/* -----------------------------------------------------------------------------
   5. Buttons
   -------------------------------------------------------------------------- */

/* Black label on pink fill: 5.89:1. The reverse pairing fails. */
.btn {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 0.875rem 1.5rem;
  border: 2px solid var(--black);
  background: var(--pink);
  color: var(--text-on-pink);
  font-weight: 700;
  font-size: var(--fs-small);
  letter-spacing: 0.01em;
  text-decoration: none;
  cursor: pointer;
  transition:
    background var(--transition),
    color var(--transition),
    transform var(--transition);
}

.btn:hover {
  background: var(--black);
  border-color: var(--black);
  color: var(--pink);
}

.btn--ghost {
  background: transparent;
  color: var(--black);
}

.btn--ghost:hover {
  background: var(--black);
  color: var(--pink);
}

.btn--light {
  background: var(--white);
  border-color: var(--white);
  color: var(--black);
}

.btn--light:hover {
  background: transparent;
  color: var(--white);
}

.btn--danger {
  background: var(--danger);
  border-color: var(--danger);
  color: var(--white);
}

.btn--danger:hover {
  background: var(--danger-dark);
  border-color: var(--danger-dark);
}

/* Route not built yet. Deliberately visible so nobody mistakes it for a live
   link during review — see config/navigation.py. */
.btn[aria-disabled="true"],
.nav__link[aria-disabled="true"] {
  opacity: 0.45;
  cursor: not-allowed;
}

.btn[aria-disabled="true"]:hover {
  background: var(--pink);
  color: var(--text-on-pink);
  border-color: var(--black);
}

/* -----------------------------------------------------------------------------
   6. Header
   -------------------------------------------------------------------------- */

/* Sticky so the nav stays reachable while a long page scrolls. Requires that no ancestor
   clips or establishes a scroll container -- body and html set no overflow, which is the
   condition that silently breaks position:sticky when it is later added. */
.site-header {
  position: sticky;
  top: 0;
  /* Below the skip link (100) so the skip link still wins when focused. */
  z-index: 50;
  background: var(--black);
  /* Native `double` needs at least 3px to render two rules; 6px gives a visible gap. */
  border-bottom: 6px double var(--pink);
}

.site-header__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  padding-block: var(--sp-4);
}

.wordmark {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  font-weight: 800;
  font-size: 1.25rem;
  letter-spacing: -0.02em;
  color: var(--white);
  text-decoration: none;
}

.wordmark:hover {
  color: var(--white);
}

.wordmark__accent {
  color: var(--pink);
}

/* Pink underline marks the current page, not just the current section. */
.nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-5);
}

.nav__link {
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--white);
  padding-block: var(--sp-1);
  border-bottom: 3px solid transparent;
}

/* Hover is --pink, not --pink-deep: the deep plum is only 2.99:1 on black and fails AA. */
.nav__link:hover {
  color: var(--pink);
  border-bottom-color: var(--pink);
}

.nav__link[aria-current="page"] {
  border-bottom-color: var(--pink);
}

/* Pending routes. Given an explicit colour rather than opacity, because 45% white over
   black lands at 4.42:1 — a hair under AA, and it drifts with whatever sits behind it. */
.site-header .nav__link[aria-disabled="true"] {
  opacity: 1;
  color: #8a8a8a;
}

.site-header .nav__link[aria-disabled="true"]:hover {
  color: #8a8a8a;
  border-bottom-color: transparent;
}

/* --pink-deep focus rings reach only 2.99:1 on black. Pink clears 3:1 comfortably. */
.site-header :focus-visible {
  outline-color: var(--pink);
}

/* Session link sits at the far right of the header. It is deliberately separate from the
   public nav so the public nav can stay session-agnostic while the account entry point is
   always reachable. */
.session-nav {
  margin-left: auto;
}

.session-nav__link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-decoration: none;
  color: var(--white);
  width: 2.25rem;
  height: 2.25rem;
  border: 2px solid var(--pink);
  border-radius: 2px;
}

.session-nav__link:hover {
  color: var(--black);
  background: var(--pink);
}

.session-nav__link svg {
  display: block;
}

/* -----------------------------------------------------------------------------
   7. Hero
   -------------------------------------------------------------------------- */

.hero {
  position: relative;
  overflow: hidden;
  padding-block: var(--sp-9) var(--sp-8);
  border-bottom: var(--rule-weight) solid var(--pink);
  color: var(--white);
}

/* Parallax background image. `fixed` gives the scroll effect on desktop; it is removed on
   narrow viewports where fixed backgrounds stutter. A dark overlay sits on top of the image
   so the white hero text stays legible. */
.hero__bg {
  position: absolute;
  inset: 0;
  z-index: -1;
  background-attachment: fixed;
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
}

.hero__bg::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(20, 20, 20, 0.45);
}

.hero__title,
.hero__expanded,
.hero__tagline {
  text-shadow: 0 2px 16px rgba(20, 20, 20, 0.55);
}

.hero__title {
  font-size: var(--fs-display);
  line-height: 0.88;
  letter-spacing: -0.045em;
  text-transform: uppercase;
  margin-block: var(--sp-4);
}

/* One word of the headline carries the colour. Keeps it from looking themed. */
.hero__title em {
  font-style: normal;
  color: var(--pink);
}

/* The header wordmark is only ever "S.H.E." — this is the one place the acronym is spelled
   out. Pink on the S, H and E ties the line to the wordmark period and the rule below it. */
.hero__expanded {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.9);
  margin-block: 0 var(--sp-5);
}

.hero__expanded b {
  font-weight: 700;
  color: var(--pink);
}

.hero__tagline {
  font-size: var(--fs-lead);
  max-width: 34ch;
  line-height: 1.35;
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
  margin-top: var(--sp-6);
}

/* The ghost button is dark by default; against the photo it needs to be light. */
.hero .btn--ghost {
  border-color: var(--white);
  color: var(--white);
}

.hero .btn--ghost:hover {
  background: var(--white);
  border-color: var(--white);
  color: var(--black);
}

@media (max-width: 47.99rem) {
  .hero__bg {
    background-attachment: scroll;
  }
}

/* -----------------------------------------------------------------------------
   8. Pull quote
   -------------------------------------------------------------------------- */

.quote {
  font-family: var(--font-serif);
  font-size: clamp(1.5rem, 3.2vw, 2.5rem);
  font-style: italic;
  line-height: 1.25;
  letter-spacing: -0.015em;
  max-width: 24ch;
  text-indent: -0.45em;
}

.quote__mark {
  color: var(--pink);
}

.quote__attrib {
  font-family: var(--font-sans);
  font-style: normal;
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-top: var(--sp-5);
}

/* -----------------------------------------------------------------------------
   9. Event cards
   -------------------------------------------------------------------------- */

.cards {
  display: grid;
  gap: var(--sp-5);
  grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
}

/* Pink edge collapses to a top edge on narrow screens. */
.card {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  padding: var(--sp-5);
  background: var(--white);
  border: 1px solid var(--border);
  border-left: var(--rule-weight) solid var(--pink);
  text-decoration: none;
  color: inherit;
  transition:
    border-color var(--transition),
    transform var(--transition);
}

a.card:hover {
  border-color: var(--pink);
  color: inherit;
  transform: translateY(-2px);
}

/* The card is a link now that events:detail exists. A pseudo-element stretched over the
   card makes the whole box the hit target, which is what people expect from something
   drawn as a card — but the anchor itself stays in the <h3>, so screen readers and
   tab order announce one link with a title, not an unlabelled box. */
.card--linked {
  position: relative;
}

.card--linked:hover {
  border-color: var(--pink);
  transform: translateY(-2px);
}

.card__link {
  color: inherit;
  text-decoration: none;
}

.card__link::after {
  content: "";
  position: absolute;
  inset: 0;
}

.card--linked:hover .card__link,
.card__link:focus-visible {
  color: var(--pink-deep);
}

.card__date {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--pink-deep);
}

/* A personal marker: rendered only when the viewer's own account holds a place. The
   waitlist variant is deliberately neutral — a held spot is a commitment, a waitlist
   place is not, and the two must not look alike. */
.card__badge {
  align-self: flex-start;
  padding: var(--sp-1) var(--sp-3);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--white);
  background: var(--pink-deep);
}

.card__badge--waitlist {
  background: var(--ink-soft);
}

.card__title {
  font-size: 1.375rem;
  line-height: 1.15;
  letter-spacing: -0.02em;
}

.card__meta {
  font-size: var(--fs-small);
  color: var(--text-muted);
}

/* Fill state sits at the bottom of every card regardless of title length. */
.card__foot {
  margin-top: auto;
  padding-top: var(--sp-3);
  border-top: 1px solid var(--border);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.card__foot--open {
  color: var(--pink-deep);
}

.card__foot--full {
  color: var(--text-muted);
}

/* Empty state. Events are created by hand, so quiet months are normal and the
   page still has to look deliberate rather than broken. */
.empty {
  padding: var(--sp-6);
  border: 1px dashed var(--border);
  border-left: var(--rule-weight) solid var(--pink);
  background: var(--white);
  max-width: 40rem;
}

.empty__title {
  font-size: 1.25rem;
  margin-bottom: var(--sp-2);
}

.empty__body {
  color: var(--text-muted);
  font-size: var(--fs-small);
}

/* -----------------------------------------------------------------------------
   10. Call to action band
   -------------------------------------------------------------------------- */

.cta {
  display: grid;
  gap: var(--sp-5);
  align-items: center;
}

@media (min-width: 60rem) {
  .cta {
    grid-template-columns: 1.4fr 1fr;
    gap: var(--sp-8);
  }
}

.cta__title {
  font-size: var(--fs-h2);
  text-transform: uppercase;
  letter-spacing: -0.035em;
}

.cta__body {
  margin-top: var(--sp-4);
  color: var(--text-muted);
  max-width: var(--measure);
}

.section--ink .cta__body {
  color: var(--pink-wash);
}

/* -----------------------------------------------------------------------------
   11. Newsletter
   -------------------------------------------------------------------------- */

.newsletter__form {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
  margin-top: var(--sp-5);
  max-width: 34rem;
}

.field {
  flex: 1 1 14rem;
  min-width: 0;
  padding: 0.875rem 1rem;
  border: 2px solid var(--black);
  background: var(--white);
  color: var(--black);
}

.field::placeholder {
  color: var(--ink-muted);
}

.field:focus-visible {
  outline: 3px solid var(--pink);
  outline-offset: 2px;
}

.newsletter__note {
  margin-top: var(--sp-3);
  font-size: var(--fs-micro);
  color: var(--text-muted);
  max-width: 34rem;
}

/* -----------------------------------------------------------------------------
   12. Footer
   -------------------------------------------------------------------------- */

.site-footer {
  border-top: var(--rule-weight) solid var(--pink);
  padding-block: var(--sp-7) var(--sp-6);
  background: var(--white);
}

.site-footer__top {
  display: grid;
  gap: var(--sp-6);
}

@media (min-width: 48rem) {
  .site-footer__top {
    grid-template-columns: 1.5fr 1fr;
  }
}

/* Visit links get the full width to themselves, running horizontally. */
.site-footer__nav {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-2) var(--sp-6);
  margin-top: var(--sp-6);
  padding-top: var(--sp-5);
  border-top: 1px solid var(--border);
}

.site-footer__nav .site-footer__title {
  margin-bottom: 0;
  flex-shrink: 0;
}

.site-footer__links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-5);
  font-size: var(--fs-body);
  font-weight: 700;
  letter-spacing: -0.01em;
}

.site-footer__links a {
  color: var(--black);
  text-decoration: none;
}

.site-footer__links a:hover {
  color: var(--pink-deep);
  text-decoration: underline;
}

/* Pending routes are dimmed here too, so an unbuilt footer link is not mistaken for live. */
.site-footer__links span[aria-disabled="true"] {
  color: var(--text-muted);
  font-weight: 400;
}

.site-footer__venue {
  margin-top: var(--sp-3);
  color: var(--text-muted);
  font-size: var(--fs-small);
}

.site-footer__title {
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: var(--sp-3);
}

.site-footer__list {
  display: grid;
  gap: var(--sp-2);
  font-size: var(--fs-small);
}

.site-footer__legal {
  margin-top: var(--sp-5);
  padding-top: var(--sp-4);
  font-size: var(--fs-micro);
  color: var(--text-muted);
}

.site-footer__credit {
  margin-top: var(--sp-3);
  font-size: var(--fs-micro);
  color: var(--text-muted);
}

.site-footer__credit a {
  color: var(--text-muted);
  text-decoration: underline;
}

.site-footer__credit a:hover {
  color: var(--pink-deep);
}

/* -----------------------------------------------------------------------------
   13. Motion
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

@media print {
  .site-header,
  .site-footer,
  .hero__actions,
  .newsletter__form {
    display: none;
  }
}
/* -----------------------------------------------------------------------------
   14. Standing pages — /about/, /contact/, /events/
   -------------------------------------------------------------------------- */

/* Shared masthead for every page that is not the landing page. The landing page keeps its
   own hero; this is the quieter version of the same idea, and deliberately reuses the
   hero's tracking and leading rather than inventing its own -- a subpage title that set
   differently reads as a different site. */
.page-head {
  padding-block: var(--sp-8) var(--sp-7);
  border-bottom: var(--rule-weight) solid var(--pink);
}

/* Photo masthead used on the events directory. Taller than the default page-head to give
   the parallax image room to move, with white text and an overlay for readability. */
.page-head--photo {
  position: relative;
  overflow: hidden;
  padding-block: var(--sp-10) var(--sp-8);
  background: transparent;
  color: var(--white);
}

.page-head__bg {
  position: absolute;
  inset: 0;
  z-index: -1;
  background-attachment: fixed;
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
}

.page-head__bg::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(20, 20, 20, 0.45);
}

.page-head--photo .page-head__title,
.page-head--photo .lead,
.page-head--photo .eyebrow {
  text-shadow: 0 2px 16px rgba(20, 20, 20, 0.55);
}

.page-head__title {
  font-size: var(--fs-h1);
  line-height: 0.9;
  letter-spacing: -0.045em;
  text-transform: uppercase;
  margin-block: var(--sp-3) var(--sp-4);
}

/* Same job as .hero__tagline — the intro line under a display title — so it gets that
   measure and leading rather than .lead's 62ch. At lede size, 62ch is a much wider block
   than anything else on the site and reads as a different layout, not a different page. */
.page-head .lead {
  max-width: 34ch;
  line-height: 1.35;
}

@media (max-width: 47.99rem) {
  .page-head__bg {
    background-attachment: scroll;
  }
}

/* -----------------------------------------------------------------------------
   People — /about/
   -------------------------------------------------------------------------- */

.people {
  display: grid;
  gap: var(--sp-6);
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}

.people__list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.people__list li {
  padding-block: var(--sp-2);
  border-bottom: 1px solid var(--border);
}

.people__name {
  font-weight: 700;
}

/* Displayed as a run-in role rather than a nested line, so the list keeps a single rhythm
   whether or not an entry has one. */
.people__role {
  color: var(--text-muted);
  font-size: var(--fs-small);
}

.people__role::before {
  content: "— ";
}

.people__note {
  margin-top: var(--sp-6);
  max-width: var(--measure);
  color: var(--text-muted);
}

/* -----------------------------------------------------------------------------
   17b. People and pull quotes
   -------------------------------------------------------------------------- */

/* Biographies run longer than a name-and-role list can hold, so they get their own grid
   instead of stretching the existing two-column list. `minmax` is deliberately wider than
   the name list's 15rem: a biography at 15rem is four words per line. */
.coaches-photo {
  display: flex;
  justify-content: center;
  margin: 0 auto var(--sp-7);
  max-width: 18rem;
}

.coaches-photo img {
  border-radius: var(--radius);
  box-shadow: 0 4px 24px rgba(20, 20, 20, 0.1);
}

.people--bios {
  grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr));
  gap: var(--sp-7) var(--sp-6);
}

.person__name {
  font-size: var(--fs-h3);
  letter-spacing: -0.02em;
}

.person__role {
  margin-top: var(--sp-1);
  color: var(--pink-deep);
  font-size: var(--fs-small);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.person__bio {
  margin-top: var(--sp-3);
  color: var(--text-muted);
}

/* The founders' own words. Set as a blockquote rather than a pull quote spanning the page:
   it belongs to the "who we are" section, and a full-width treatment would fight the
   biographies below it. */
.pullquote {
  margin: 0 0 var(--sp-6);
  padding-left: var(--sp-4);
  border-left: 4px solid var(--pink);
}

.pullquote p {
  max-width: 32ch;
  font-size: var(--fs-h3);
  font-style: italic;
  line-height: 1.25;
  letter-spacing: -0.02em;
}

/* -----------------------------------------------------------------------------
   Contact — /contact/
   -------------------------------------------------------------------------- */

.contact {
  display: grid;
  gap: var(--sp-6);
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}

.contact__list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.contact__list li {
  padding-block: var(--sp-2);
}

/* <address> italicises by default, which reads as emphasis on a street address. */
.contact__address {
  font-style: normal;
  line-height: 1.5;
}

/* The gear/volunteer cards carry no link target of their own. */
.card--plain {
  border-left-color: var(--border);
}

/* -----------------------------------------------------------------------------
   Event directory — /events/
   -------------------------------------------------------------------------- */

.filters {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
}

/* Typographically an eyebrow, but it is a control, so it carries a border and padding.
   Tracking matches .eyebrow rather than inventing a looser value. */
.filters__item {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--ink-soft);
  padding: var(--sp-2) var(--sp-4);
  border: 1px solid var(--border);
  background: var(--white);
}

a.filters__item:hover {
  color: var(--pink-deep);
  border-color: var(--pink);
}

/* aria-current carries the meaning for assistive tech; the fill carries it visually. */
.filters__item--current {
  color: var(--white);
  background: var(--black);
  border-color: var(--black);
}

/* Admin-only shortcut on public pages. Kept visually quiet so it does not read as
   a participant action, but separated from filters so staff notice it. */
.admin-actions {
  margin-top: var(--sp-3);
  font-size: var(--fs-small);
}

.admin-actions a {
  color: var(--text-muted);
}

.admin-actions a:hover {
  color: var(--pink-deep);
}

/* -----------------------------------------------------------------------------
   Event detail — /events/<slug>/
   -------------------------------------------------------------------------- */

.event {
  padding-block: var(--sp-7) var(--sp-9);
}

.breadcrumb {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  margin-bottom: var(--sp-5);
}

.event__when {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--pink-deep);
}

.event__title {
  font-size: var(--fs-h1);
  line-height: 0.98;
  letter-spacing: -0.04em;
  text-transform: uppercase;
  margin-block: var(--sp-2) var(--sp-4);
}

/* Two states only. "Full" and "closed" both read as shut here on purpose — what differs is
   the reason, and that is in the label the model produces, not in the colour. */
.event__state {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid currentColor;
}

.event__state--open {
  color: var(--pink-deep);
}

.event__state--shut {
  color: var(--text-muted);
}

.facts {
  margin: var(--sp-7) 0 0;
  border-top: var(--rule-weight) solid var(--pink);
}

.facts__row {
  display: grid;
  gap: var(--sp-2) var(--sp-5);
  grid-template-columns: 8rem 1fr;
  padding-block: var(--sp-4);
  border-bottom: 1px solid var(--border);
}

.facts__key {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--pink-deep);
  padding-top: 0.2rem;
}

.facts__val {
  margin: 0;
  line-height: 1.5;
}

.facts__sub {
  color: var(--text-muted);
  font-size: var(--fs-small);
}

.event__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-4);
  margin-top: var(--sp-7);
}

.event__hint {
  font-size: var(--fs-small);
  color: var(--text-muted);
  max-width: 34ch;
}

/* One column on narrow screens: a two-column fact row at 320px leaves the value column too
   narrow for an address. */
@media (max-width: 34rem) {
  .facts__row {
    grid-template-columns: 1fr;
  }
}

/* -----------------------------------------------------------------------------
   17c. Document pages
   -------------------------------------------------------------------------- */

.doclist {
  list-style: none;
  margin: 0;
  padding: 0;
}

.doclist__item {
  border-bottom: 1px solid var(--border);
}

.doclist__item:first-child {
  border-top: 1px solid var(--border);
}

.doclist__link {
  display: block;
  padding-block: var(--sp-4);
  font-size: var(--fs-h3);
  font-weight: 700;
  letter-spacing: -0.02em;
  text-decoration: none;
}

.doclist__link:hover,
.doclist__link:focus-visible {
  color: var(--pink-deep);
}

/* No active version yet. Same muted treatment as a pending nav link, so a reader can tell
   this is not ready rather than assuming the link failed. */
.doclist__link--pending {
  color: var(--text-muted);
  cursor: not-allowed;
}

/* The "To be added." notice on the legal placeholders. Deliberately unmissable: a page that
   looks finished is a page someone ships without reading. */
.notice {
  padding: var(--sp-4);
  border-left: 4px solid var(--pink-deep);
  background: var(--surface);
  font-size: var(--fs-h4);
  font-weight: 700;
}

/* -----------------------------------------------------------------------------
   14. Forms — /accounts/ and /account/
   -----------------------------------------------------------------------------
   `.field` above was written for the newsletter: a bare input with a 14rem flex basis and
   no label. Real forms need the label, the help text, and the error to travel together,
   so the grid and label styles are added here and `.field` keeps its input treatment.

   Error text is --pink-deep rather than the brand pink. #F529B8 on white is 3.56:1, which
   fails WCAG AA for body copy, and an error message is body copy that matters a great deal.
   -------------------------------------------------------------------------- */

.form {
  max-width: 44rem;
}

.form__grid {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-5) var(--sp-4);
  margin-block: var(--sp-5);
}

.form__group {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  flex: 1 1 14rem;
  min-width: 0;
}

.form__group--wide {
  /* A textarea or a full-name row needs the whole measure, not a column. */
  flex-basis: 100%;
}

.form__group--no-grow {
  /* A date picker has its own intrinsic width; stretching it to fill the row reads as an
     empty, oversized control. */
  flex-grow: 0;
}

/* `[hidden]` has to beat `.form__group`'s `display: flex`. The player form hides the
   relationship field when the account holder says the player is them. */
.form__group[hidden] {
  display: none;
}

/* Checkbox groups are laid out as a single line of control plus its text, not as a
   stretched input, so they opt out of `.field`'s flex basis. */
.field--checkbox {
  flex: 0 0 auto;
  width: 1.25rem;
  height: 1.25rem;
  margin: 0;
  padding: 0;
  border: 2px solid var(--black);
  accent-color: var(--pink-deep);
}

.form__label {
  font-size: var(--fs-small);
  font-weight: 700;
  letter-spacing: 0.01em;
}

/* The asterisk marks a required field. It is decorative — the input already carries the
   `required` attribute, which assistive tech announces — so it is hidden from the
   accessibility tree in the template and exists only for sighted users. */
.form__required {
  margin-left: 0.15em;
  color: var(--required);
}

.form__help {
  font-size: var(--fs-micro);
  color: var(--text-muted);
  line-height: 1.4;
}

.form__error {
  font-size: var(--fs-small);
  font-weight: 700;
  color: var(--pink-deep);
}

/* Live password rules beside the signup password field. The glyph is decorative; the state is
   carried by the text a screen reader hears, which `password-strength.js` updates. */
.pw-reqs {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  margin-top: var(--sp-3);
  padding-left: 0;
  list-style: none;
  font-size: var(--fs-micro);
  color: var(--text-muted);
}

.pw-req::before {
  content: "○";
  margin-right: var(--sp-2);
  color: var(--text-muted);
}

.pw-req.is-met {
  color: var(--positive);
}

.pw-req.is-met::before {
  content: "✓";
  color: var(--positive);
}

.form fieldset {
  flex: 1 1 100%;
  border: 0;
  padding: 0;
  margin: 0;
}

.form legend {
  padding: 0;
  font-size: var(--fs-h4);
  font-weight: 700;
  margin-bottom: var(--sp-3);
  padding-top: var(--sp-2);
  border-top: var(--rule-weight) solid var(--pink);
  width: 100%;
}

/* A checkbox row reads as a sentence, so the label sits beside the box rather than above
   it, and the help text follows inside the same block. */
.form__check {
  display: flex;
  gap: var(--sp-3);
  align-items: flex-start;
  flex: 1 1 100%;
}

.form__check--danger {
  border-left: 4px solid var(--danger);
  background: var(--danger-pale);
  padding: var(--sp-4);
}

.form__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-4);
  margin-top: var(--sp-5);
}

/* Error summary at the top of a long form. `role="alert"` so it is announced when the
   page it sits on fails validation. */
.form__summary {
  border-left: 4px solid var(--pink-deep);
  background: var(--pink-pale);
  padding: var(--sp-4);
}

.form__summary-title {
  font-size: var(--fs-h4);
  font-weight: 700;
  margin-bottom: var(--sp-2);
}

/* Flash messages after a redirect. The success variant is used for confirmations ("your
   email is confirmed", "we sent a link"); the error variant for things like an invalid
   token that the user should retry. */
.messages {
  list-style: none;
  padding: 0;
  margin: var(--sp-4) 0 0;
}

.messages__item {
  border-left: 4px solid var(--ink-soft);
  background: var(--surface);
  padding: var(--sp-3) var(--sp-4);
  margin-bottom: var(--sp-3);
}

.messages__item--success {
  border-color: #2a6f2a;
  background: #e9f4e9;
}

.messages__item--error {
  border-color: var(--pink-deep);
  background: var(--pink-pale);
}

.messages__item--warning {
  border-color: #a36b1b;
  background: #fbf4e4;
}

.messages__item--info {
  border-color: var(--pink);
  background: var(--pink-pale);
}

/* -----------------------------------------------------------------------------
   15. Account area — /account/
   -------------------------------------------------------------------------- */

/* Session links. Always live in the page body rather than the site nav, because the nav is
   built once by a context processor that has no notion of a session. The base look is on the
   element rather than a `account-nav__link` class so that the current page can carry its own
   modifier without emitting two `class` attributes. */
.account-nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-5);
  padding-block: var(--sp-4);
  margin-bottom: var(--sp-6);
  border-bottom: var(--rule-weight) solid var(--pink);
  font-size: var(--fs-small);
}

.account-nav a {
  color: var(--link);
}

.account-nav__link--current {
  font-weight: 700;
  text-decoration: none;
  color: var(--black);
}

/* A privacy reminder on the pages that collect a minor's data. Present on every account
   form rather than only on sign-up, because a guardian may be updating a profile years
   later and should not have to remember the rule. */
.account-privacy {
  font-size: var(--fs-micro);
  color: var(--text-muted);
  max-width: 44rem;
  margin-top: var(--sp-5);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--border);
  line-height: 1.5;
}

.account-divider {
  border: 0;
  border-top: 1px solid var(--border);
  margin-block: var(--sp-7) var(--sp-5);
}

.account-subtitle {
  font-size: var(--fs-h4);
  font-weight: 700;
  margin-bottom: var(--sp-2);
}

/* Sign-out is a form, not a link: a GET route would let any third-party page sign the
   account holder out by loading an image. */
.account-signout {
  display: inline;
}

.account-signout .btn {
  padding: 0.5rem 1rem;
  font-size: var(--fs-micro);
}

/* Per-player status pills on the dashboard. */
.account-player {
  border-left: var(--rule-weight) solid var(--pink);
  padding: var(--sp-5) 0 var(--sp-5) var(--sp-4);
  margin-bottom: var(--sp-5);
}

.account-player__name {
  font-size: var(--fs-h3);
  margin-bottom: var(--sp-2);
}

.account-player__meta {
  font-size: var(--fs-small);
  color: var(--text-muted);
  margin-bottom: var(--sp-3);
}

.account-player__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
  align-items: center;
}

/* -----------------------------------------------------------------------------
   15. Registration flow step indicator
   -----------------------------------------------------------------------------
   A wrapping list of the five steps. The current step is the only one emphasised; the rest
   stay quiet so the page does not read as five things to click. The ordered list carries the
   sequence for assistive tech and `aria-current="step"` marks where the family is.
   -------------------------------------------------------------------------- */

.steps {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3) var(--sp-4);
  list-style: none;
  padding: 0;
  margin: 0 0 var(--sp-6);
}

.steps__item {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs-small);
  color: var(--text-muted);
}

.steps__num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  border: 2px solid currentColor;
  border-radius: 50%;
  font-size: var(--fs-micro);
  font-weight: 700;
}

.steps__item--current {
  color: var(--black);
  font-weight: 700;
}

