/* ============================================================
   Yetu Triathlon — main.css
   ------------------------------------------------------------
   Build contract: /Users/samvanooijen/yetutriathlon_site/BUILD_CONTRACT.md
   Tokens source:  /Users/samvanooijen/yetu_triathlon_build/03_design_system/04_consolidated_tokens.md
   Component recipes: /Users/samvanooijen/yetu_triathlon_build/08_hy_deep_review/03_visual_tokens.md

   Sections (in order):
     1.  Reset
     2.  Custom properties (:root)
     3.  Base typography
     4.  Layout primitives (.section, .container)
     5.  Buttons (.btn, .btn--primary, .btn--secondary, .btn--text)
     6.  Navigation (.nav)
     7.  Mobile drawer
     8.  Mobile pinned Register bar
     9.  Hero
     10. Stat band
     11. Pillar grid (3-color photo cards)
     12. Day accordion (5-day itinerary)
     13. Race toggle (Sprint / Long, WAI-ARIA Tabs)
     14. Calculator (€1,000 -> impact)
     15. Countdown
     16. FAQ accordion (native <details>/<summary>)
     17. Partner grid
     18. Footer
     19. Forms
     20. Utility / a11y
     21. Responsive breakpoints
     22. Print styles

   Conventions:
     - Mobile-first. Default styles target the smallest viewport.
     - @media (min-width: 768px)  -> tablet
     - @media (min-width: 1024px) -> desktop
     - No !important except .btn--primary override discipline.
     - WCAG AA: terracotta (#c34922) on cream (#efe5d7) = 3.92:1.
       Fails for body text. Use ONLY for headings >=18pt (24px)
       or as accent strokes (underlines, borders).
       Salmon (#ffafa8) on cream = 1.41:1 — never text. Use only
       as a tile background paired with ink (#171411) text.
   ============================================================ */


/* ============================================================
   1. RESET — modern, minimal
   ------------------------------------------------------------
   Not Normalize. Inline so we own every rule.
   Goals: predictable box model, kill default margin, sane media
   defaults, inherit line-height & color, prefers-reduced-motion
   honored.
   ============================================================ */

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

* {
  margin: 0;
  padding: 0;
}

html {
  -webkit-text-size-adjust: 100%;        /* iOS landscape autoscale fix */
  -moz-tab-size: 4;
  tab-size: 4;
  scroll-behavior: smooth;
  /* Patched 2026-06-02: clear the sticky nav when an in-page anchor is jumped to.
     The fixed nav is ~64–72px tall; 80px gives a small visual breathing margin. */
  scroll-padding-top: 80px;
}

@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;
    scroll-behavior: auto !important;
  }
}

body {
  min-height: 100vh;
  min-height: 100svh;                    /* mobile address-bar correct */
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

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

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

button {
  background: none;
  border: 0;
  cursor: pointer;
}

a {
  color: inherit;
  text-decoration: none;
}

ul,
ol {
  list-style: none;
}

p,
h1,
h2,
h3,
h4,
h5,
h6 {
  overflow-wrap: break-word;
}

/* Establish stacking + isolation contexts predictably */
#root,
#__next {
  isolation: isolate;
}


/* ============================================================
   2. CUSTOM PROPERTIES (:root)
   ------------------------------------------------------------
   Verbatim from BUILD_CONTRACT.md "Locked design tokens" block,
   extended with restricted tokens + type/motion scales from
   04_consolidated_tokens.md §9 (single copy-pasteable root).
   ============================================================ */

:root {
  /* === Color: 5 primary tokens (use freely) === */
  --brand-aubergine:    #580e41;
  --brand-terracotta:   #c34922;
  --brand-lilac:        #eaaaff;
  --surface-cream:      #efe5d7;
  --surface-ink:        #171411;

  /* === Color: 4 restricted tokens (component-locked) === */
  --accent-salmon:      #ffafa8;   /* tile bg only, paired w/ ink text */
  --accent-lavender:    #ac9fff;   /* quote tile / pillar card 3 only */
  --surface-white:      #ffffff;   /* micro-surfaces / cards / modals */
  --ink-muted:          #4a4541;   /* secondary text — 60% ink lightness */

  /* === Typography families === */
  --font-display: "Cosmic Buns", "Inter", sans-serif;
  --font-heading: "ZT Nature", "Inter", sans-serif;
  --font-body:    "ZT Nature", "Inter", sans-serif;

  /* === Type scale (mobile-first defaults — bumped up at 768/1024 below) === */
  /* Patched 2026-06-02: previous defaults were desktop sizes, which produced
     a 64px H1 on a 375px screen — Cosmic Buns would overflow the gutter. */
  --fs-h1: 40px;       --lh-h1: 1.05;   --ls-h1: -0.02em;
  --fs-h2: 28px;       --lh-h2: 1.15;   --ls-h2: -0.01em;
  --fs-h3: 20px;       --lh-h3: 1.30;
  --fs-eyebrow: 12px;  --lh-eyebrow: 1.20; --ls-eyebrow: 0.15em;
  --fs-body: 16px;     --lh-body: 1.60;
  --fs-small: 14px;    --lh-small: 1.50;

  /* === Spacing (8px base) === */
  --space-1:   4px;
  --space-2:   8px;
  --space-3:  16px;
  --space-4:  24px;
  --space-5:  32px;
  --space-6:  48px;
  --space-7:  64px;
  --space-8:  96px;
  --space-9: 128px;
  --section-pad-desktop: 96px;
  --section-pad-mobile:  64px;

  /* === Radii === */
  --radius-flat: 0;
  --radius-card: 4px;
  --radius-pill: 999px;

  /* === Motion === */
  --trans-fast:    150ms;
  --trans-default: 200ms;
  --trans-slow:    300ms;
  --easing-default: cubic-bezier(0.4, 0, 0.2, 1);

  /* === Layout containers === */
  --container-max:    1200px;
  --container-narrow: 720px;
  --container-pad:    24px;             /* horizontal gutter, default */

  /* === Canonical x-axis tokens (added 2026-06-02) =============
     Single source of truth for the page left-edge. Every wrapper
     that wraps "meaningful content" (heroes, section content,
     stat-bands, footers, closing CTAs, legal bodies) resolves to
     the SAME left-edge x-position by sharing these tokens. The
     left edge sits at:
        max( (viewport - --page-max) / 2 ,  --page-gutter )
     px from the viewport left.  Override per-breakpoint below. */
  --page-max:    var(--container-max);
  --page-gutter: var(--container-pad);

  /* === Z-index scale === */
  --z-base:      1;
  --z-nav:    8000;
  --z-mobile-bar: 9000;
  --z-drawer: 9500;
  --z-modal: 10000;
}


/* ============================================================
   3. BASE TYPOGRAPHY
   ------------------------------------------------------------
   Default body wires up to ZT Nature + cream canvas + ink text.
   Heading utility classes (.h1, .h2, .h3, .eyebrow, .body,
   .body--small) let any element adopt the role without changing
   semantics.
   ============================================================ */

html,
body {
  background: var(--surface-cream);
  color: var(--surface-ink);
  font-family: var(--font-body);
  font-weight: 400;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
}

/* H1 — Cosmic Buns 400, display weight, hero-only feel.
   64px desktop / 40px mobile (overridden in §21 breakpoints). */
.h1,
h1 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--fs-h1);
  line-height: var(--lh-h1);
  letter-spacing: var(--ls-h1);
}

/* H2 — ZT Nature 900, every section opener. */
.h2,
h2 {
  font-family: var(--font-heading);
  font-weight: 900;
  font-size: var(--fs-h2);
  line-height: var(--lh-h2);
  letter-spacing: var(--ls-h2);
}

/* H3 — ZT Nature 500, sub-headlines and card titles. */
.h3,
h3 {
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: var(--fs-h3);
  line-height: var(--lh-h3);
}

/* Eyebrow — small uppercase label, sits above H2. */
.eyebrow {
  display: inline-block;
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: var(--fs-eyebrow);
  line-height: var(--lh-eyebrow);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--brand-terracotta);    /* AA-safe at 12px? NO — see WCAG note.
                                        Mitigation: eyebrow always pairs with
                                        a larger H2 directly below, so it
                                        functions as decorative label, not
                                        load-bearing content. Acceptable for
                                        UI labels per WCAG 1.4.3 exception
                                        (incidental text). On dark sections,
                                        switch to --brand-lilac via .section--
                                        aubergine override (see §4). */
}

.body {
  font-family: var(--font-body);
  font-weight: 400;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
}

.body--small,
small {
  font-family: var(--font-body);
  font-weight: 400;
  font-size: var(--fs-small);
  line-height: var(--lh-small);
}

/* Inline emphasis */
strong,
b { font-weight: 900; }

em,
i { font-style: italic; }

/* Body paragraph rhythm */
p + p { margin-top: var(--space-3); }


/* ============================================================
   4. LAYOUT PRIMITIVES
   ------------------------------------------------------------
   .section is the full-bleed band. .container caps content
   width and centers it. Background variants flip color + text
   color in tandem.
   ============================================================ */

.section {
  padding-top: var(--section-pad-mobile);     /* mobile-first */
  padding-bottom: var(--section-pad-mobile);
  background: var(--surface-cream);
  color: var(--surface-ink);
}

.section--cream {
  background: var(--surface-cream);
  color: var(--surface-ink);
}

.section--aubergine {
  background: var(--brand-aubergine);
  color: var(--surface-white);
}
.section--aubergine .eyebrow { color: var(--brand-lilac); }

/* Patched 2026-06-02: inline links on aubergine sections must read on
   the dark purple background. Previously they inherited the body ink
   color from the global anchor reset and were near-invisible. */
.section--aubergine a:not(.btn):not(.nav__cta):not(.nav__menu-item):not(.nav__outbound):not(.footer__logo) {
  color: var(--brand-lilac);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.section--aubergine a:not(.btn):not(.nav__cta):not(.nav__menu-item):not(.nav__outbound):not(.footer__logo):hover,
.section--aubergine a:not(.btn):not(.nav__cta):not(.nav__menu-item):not(.nav__outbound):not(.footer__logo):focus-visible {
  color: var(--surface-white);
}
/* .btn--text on aubergine: invert from ink-on-cream to white-on-aubergine */
.section--aubergine .btn--text {
  color: var(--surface-white);
  border-bottom-color: var(--brand-lilac);
}
.section--aubergine .btn--text:hover,
.section--aubergine .btn--text:focus-visible {
  color: var(--brand-lilac);
}

.section--ink {
  background: var(--surface-ink);
  color: var(--surface-white);
}
.section--ink .eyebrow { color: var(--brand-lilac); }

/* --------------------------------------------------------------
   .container — the CANONICAL page wrapper. Every section wrapper
   eventually resolves here, share the same left-edge x-position.
   Patched 2026-06-02 (X-AXIS UNIFICATION):
     `.container--narrow` no longer overrides max-width on the
     wrapper itself — that would shift the LEFT EDGE of narrow
     pages 240px to the right of a regular container at viewport
     widths > 1200px (because flex-centering halves the difference
     into both gutters). Instead, the wrapper stays 1200px wide and
     the inner children are clamped to 720px via a child selector.
     This guarantees the left edge of `.container--narrow` ===
     left edge of `.container` on every viewport.
   ------------------------------------------------------------- */
.container,
.container--narrow {
  width: 100%;
  max-width: var(--page-max);
  margin-inline: auto;
  padding-inline: var(--page-gutter);
}

/* Inner children of .container--narrow cap at 720px but inherit the
   wrapper's left edge (margin-inline-start: 0 anchors them left). */
.container--narrow > * {
  max-width: var(--container-narrow);
  margin-inline-start: 0;
}


/* ============================================================
   5. BUTTONS
   ------------------------------------------------------------
   One pill spec everywhere. .btn--primary = aubergine fill.
   .btn--secondary = cream surface with terracotta border (the
   border is the AA-safe use of terracotta on cream — accent
   stroke, not body text).
   .btn--text  = inline text link, gets a trailing arrow ↗ for
   outbound contexts.
   ============================================================ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 14px 28px;
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: 16px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  text-decoration: none;
  border: 0;
  border-radius: var(--radius-pill);
  cursor: pointer;
  transition: background var(--trans-default) var(--easing-default),
              color var(--trans-default) var(--easing-default),
              border-color var(--trans-default) var(--easing-default);
  white-space: nowrap;
}

/* PRIMARY — terracotta (orange) fill / white text. Hover swaps to
   aubergine. Patched 2026-06-02 (Sam): site-wide CTAs all share the
   orange-pill treatment now. Was aubergine; now matches the original
   Donate / "Or donate" button site-wide. */
.btn--primary {
  background: var(--brand-terracotta) !important;
  color: var(--surface-white) !important;
}
.btn--primary:hover,
.btn--primary:focus-visible {
  background: var(--brand-aubergine) !important;
}
.btn--primary:disabled,
.btn--primary[aria-disabled="true"] {
  background: var(--ink-muted) !important;
  cursor: not-allowed;
}

/* SECONDARY — cream surface, ink text, terracotta border (1px). */
.btn--secondary {
  background: var(--surface-cream);
  color: var(--surface-ink);
  border: 1px solid var(--brand-terracotta);
}
.btn--secondary:hover,
.btn--secondary:focus-visible {
  background: var(--surface-white);
  border-color: var(--brand-aubergine);
}

/* TEXT button — inline text link. Outbound usage appends ↗ via
   the .btn--text__icon span (or ::after if author skips span). */
.btn--text {
  padding: 0;
  background: transparent;
  color: var(--surface-ink);
  text-transform: none;
  letter-spacing: 0;
  font-weight: 500;
  border-radius: 0;
  border-bottom: 1px solid var(--brand-terracotta);
  border-bottom-width: 1px;
  padding-bottom: 2px;
}
.btn--text:hover,
.btn--text:focus-visible {
  color: var(--brand-terracotta);
}
/* Outbound arrow only — patched 2026-06-02.
   Previously: every .btn--text got "↗". This produced doubled arrows where the
   HTML already includes a literal "↗" or "→". Now only outbound + new-tab
   variants append the arrow. */
.btn--text { /* default: no auto-arrow */ }
.btn--text[target="_blank"]::after,
.btn--text.btn--text--outbound::after,
.btn--text[rel*="external"]::after {
  content: " \2197";                 /* unicode ↗ — North East Arrow */
  display: inline;
  margin-left: 4px;
}


/* ============================================================
   6. NAVIGATION (.nav)
   ------------------------------------------------------------
   Sticky transparent on hero; opaque cream once scrolled (toggle
   the .nav--scrolled class from main.js via IntersectionObserver
   on the hero, or a scrollY threshold).
   8 menu items + Health Yetu outbound + Register CTA on the right.
   Mobile (<1024px): logo + hamburger; drawer covers the menu.
   ============================================================ */

.nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: var(--z-nav);
  background: transparent;
  transition: background var(--trans-default) var(--easing-default),
              box-shadow var(--trans-default) var(--easing-default),
              color var(--trans-default) var(--easing-default);
  color: var(--surface-white);       /* default — over dark hero photo */
}

.nav--scrolled {
  background: var(--surface-cream);
  color: var(--surface-ink);
  box-shadow: 0 2px 6px rgba(23, 20, 17, 0.08);
}

/* Patched 2026-06-01: nav is transparent on EVERY page until scrolled.
   Menu links and outbound are white over the hero (transparent state),
   ink once the nav fills with cream. The previous `body.subpage` cream-fill
   override has been removed in supplemental.css §1. */
.nav:not(.nav--scrolled) .nav__menu,
.nav:not(.nav--scrolled) .nav__menu a,
.nav:not(.nav--scrolled) .nav__menu-item {
  color: var(--surface-white);
}
.nav:not(.nav--scrolled) .nav__outbound {
  color: var(--surface-white);
  opacity: 0.85;
}
.nav--scrolled .nav__menu,
.nav--scrolled .nav__menu a,
.nav--scrolled .nav__menu-item {
  color: var(--surface-ink);
}

.nav__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  max-width: var(--page-max);
  margin-inline: auto;
  /* Patched 2026-06-02 (X-AXIS UNIFICATION): horizontal gutter uses
     `--page-gutter` token so the logo's left-edge aligns with every
     section heading and hero content on the page. */
  padding: var(--space-3) var(--page-gutter);
  gap: var(--space-4);
}

.nav__logo {
  display: inline-flex;
  align-items: center;
  flex: 0 0 auto;
  transition: opacity var(--trans-default) var(--easing-default);
}
.nav__logo:hover { opacity: 0.7; }
/* Patched 2026-06-01b: the previous selector list `.nav__logo img, .nav__logo svg,
   .nav__logo-img` had specificity 0,1,1 (class + element), which beat the
   `.nav__logo-img--white` / `--black` swap rules (specificity 0,1,0) in
   supplemental.css §21 — causing BOTH white and black <img> tags to render
   simultaneously. Sizing rules now live on the single-class selector only;
   the white/black swap is owned exclusively by supplemental.css §21. */
.nav__logo-img {
  max-height: 64px;
  height: auto;
  width: auto;
}
@media (max-width: 768px) {
  .nav__logo-img { max-height: 44px; }
}

/* Menu list — hidden on mobile; flex on desktop.
   Patched 2026-06-01: HTML emits `<nav class="nav__menu"><ul>…</ul></nav>`
   on every page. The previous rules flexed the outer <nav> but the inner
   <ul> retained block layout, so li items stacked vertically on desktop.
   Now both the wrapper AND the inner <ul> get flex-row treatment, and
   the menu items themselves are flexed for vertical alignment. */
.nav__menu {
  display: none;                     /* mobile: hidden, drawer takes over */
  align-items: center;
  gap: var(--space-4);
  flex: 1 1 auto;
  justify-content: center;
}
.nav__menu > ul {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: var(--space-4);
  list-style: none;
  margin: 0;
  padding: 0;
}

.nav__menu-item {
  display: flex;
  align-items: center;
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: 15px;
  text-decoration: none;
  color: inherit;
  padding-block: 4px;
  border-bottom: 2px solid transparent;
  white-space: nowrap;
  transition: color var(--trans-default) var(--easing-default),
              border-color var(--trans-default) var(--easing-default);
}
.nav__menu-item a { white-space: nowrap; }
/* Hover/focus terracotta — qualified with .nav so it wins specificity
   against the .nav:not(.nav--scrolled) .nav__menu-item rule above. */
.nav .nav__menu-item:hover,
.nav .nav__menu-item:focus-visible,
.nav .nav__menu-item:hover a,
.nav .nav__menu-item:focus-visible a,
.nav .nav__menu a:hover,
.nav .nav__menu a:focus-visible {
  color: var(--brand-terracotta);
}
/* aria-current="page" — underline in terracotta.
   Patched 2026-06-02: aria-current is on the inner <a> in some pages and on
   the .nav__menu-item wrapper in others; cover both forms. */
.nav__menu-item[aria-current="page"],
.nav__menu a[aria-current="page"],
.nav__menu-item a[aria-current="page"] {
  border-bottom-color: var(--brand-terracotta);
  border-bottom: 2px solid var(--brand-terracotta);
}

/* "Health Yetu ↗" outbound link — muted, sits between menu and CTA. */
.nav__outbound {
  display: none;                     /* mobile: hidden; desktop shows */
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: 14px;
  color: var(--ink-muted);
  text-decoration: none;
}
.nav__outbound::after {
  content: " \2197";
  margin-left: 2px;
}
.nav .nav__outbound:hover,
.nav .nav__outbound:focus-visible {
  color: var(--brand-terracotta);
  opacity: 1;
}
.nav--scrolled .nav__outbound { color: var(--ink-muted); opacity: 0.7; }

/* Right cluster: outbound + CTA. */
.nav__right {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex: 0 0 auto;
}

/* Primary CTA in nav — uses .btn .btn--primary but slightly tighter
   padding to fit the bar height. Set via additional class. */
.nav__cta {
  padding: 10px 22px;
  font-size: 14px;
}

/* Hamburger toggle — visible only below desktop breakpoint.
   Patched 2026-06-02: HTML uses either .nav__hamburger OR .nav__toggle
   depending on page agent. Both must render identically. */
.nav__toggle,
.nav__hamburger {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
  width: 44px;
  height: 44px;
  background: transparent;
  border: 0;
  color: inherit;
  cursor: pointer;
}
.nav__toggle-bar,
.nav__hamburger-bar {
  display: block;
  width: 24px;
  height: 2px;
  background: currentColor;
  position: relative;
}
/* Single-element form: synthesize 3 bars from one element via ::before/::after.
   .nav__hamburger uses 3 distinct <span class="nav__hamburger-bar"> children
   so it does NOT need the pseudo-element bars — only .nav__toggle-bar does. */
.nav__toggle .nav__toggle-bar::before,
.nav__toggle .nav__toggle-bar::after {
  content: "";
  position: absolute;
  left: 0;
  width: 24px;
  height: 2px;
  background: currentColor;
}
.nav__toggle .nav__toggle-bar::before { top: -7px; }
.nav__toggle .nav__toggle-bar::after  { top:  7px; }
/* When the toggle uses 3 child bars, the parent must NOT gap them with the
   ::before/::after trick — flex gap above handles it. */
.nav__hamburger .nav__hamburger-bar { display: block; }


/* ============================================================
   7. MOBILE DRAWER
   ------------------------------------------------------------
   Slides in from the right. JS toggles data-state="open|closed".
   When open, body should also get .body--drawer-open to lock
   scroll. Focus is moved to the close button by main.js (the
   focus trap markup uses [data-focus-trap-start] /
   [data-focus-trap-end] sentinels around the drawer contents —
   styled invisibly here, JS bounces focus on Tab/Shift-Tab).
   ============================================================ */

.mobile-drawer {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  width: min(360px, 88vw);
  background: var(--surface-cream);
  color: var(--surface-ink);
  z-index: var(--z-drawer);
  transform: translateX(100%);
  transition: transform var(--trans-slow) var(--easing-default);
  display: flex;
  flex-direction: column;
  padding: var(--space-5) var(--space-4);
  box-shadow: -2px 0 24px rgba(0, 0, 0, 0.12);
  overflow-y: auto;
}
.mobile-drawer[data-state="open"]   { transform: translateX(0); }
.mobile-drawer[data-state="closed"] { transform: translateX(100%); }

/* Backdrop. Sits below the panel; clicking it closes the drawer. */
.mobile-drawer__backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.4);
  z-index: calc(var(--z-drawer) - 1);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--trans-default) var(--easing-default);
}
.mobile-drawer[data-state="open"] + .mobile-drawer__backdrop,
.mobile-drawer__backdrop[data-state="open"] {
  opacity: 1;
  pointer-events: auto;
}

.mobile-drawer__close {
  align-self: flex-end;
  width: 44px;
  height: 44px;
  font-size: 24px;
  line-height: 1;
  background: transparent;
  border: 0;
  color: inherit;
  cursor: pointer;
}

.mobile-drawer__menu {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin-top: var(--space-4);
}

.mobile-drawer__menu-item {
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: 20px;
  color: var(--surface-ink);
  padding-block: var(--space-2);
  border-bottom: 1px solid rgba(23, 20, 17, 0.08);
}
.mobile-drawer__menu-item[aria-current="page"] {
  color: var(--brand-terracotta);
}

/* Focus-trap sentinels — invisible, JS-targeted. */
[data-focus-trap-start],
[data-focus-trap-end] {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

/* Body lock when drawer is open. */
body.body--drawer-open {
  overflow: hidden;
}


/* ============================================================
   8. MOBILE PINNED REGISTER BAR
   ------------------------------------------------------------
   Aubergine bar fixed to the bottom of the viewport on mobile.
   Always-visible REGISTER call to action. Hidden at desktop
   (>=1024px) where the nav already shows the CTA.
   ============================================================ */

.mobile-register-bar {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  height: 56px;
  background: var(--brand-aubergine);
  color: var(--surface-white);
  z-index: var(--z-mobile-bar);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: 15px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.15);
  text-decoration: none;
}
.mobile-register-bar:hover,
.mobile-register-bar:focus-visible {
  background: var(--brand-terracotta);
}

/* Offset body so the fixed bar never covers footer content. */
body { padding-bottom: 56px; }


/* ============================================================
   9. HERO
   ------------------------------------------------------------
   100svh full-bleed image with gradient overlay for legibility.
   Headline left-aligned, max-width 720px, lower-left position.
   One CTA only — per BUILD_CONTRACT discipline (no carousels).
   ============================================================ */

.hero {
  position: relative;
  width: 100%;
  min-height: 45svh;          /* default — overridden by .hero--home below */
  margin-top: 0;
  padding-top: 0;
  display: flex;
  align-items: flex-end;
  overflow: hidden;
  background: var(--surface-ink);    /* fallback before image loads */
  color: var(--surface-white);
}

/* Patched 2026-06-01: every hero variant starts at top: 0 so the
   fixed nav can overlay it. Content gets ~80px top padding so the
   headline isn't covered by the nav at scroll-top. */
.hero,
.hero--home,
.hero--short,
.hero--race,
.hero--impact,
.hero--register,
.hero--fundraise,
.hero--travel,
.hero--partners,
.hero--about-hy,
.hero--faq,
.hero--thanks,
.hero--404,
.hero--secondary,
.hero--cream {
  margin-top: 0;
  padding-top: 0;
}

.hero__image {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  z-index: 0;
}

.hero__overlay {
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    radial-gradient(ellipse at 30% 70%, rgba(0, 0, 0, 0.55) 0%, rgba(0, 0, 0, 0.15) 60%),
    linear-gradient(180deg, rgba(0, 0, 0, 0.1) 0%, rgba(0, 0, 0, 0.5) 100%);
  pointer-events: none;
}

.hero__content {
  position: relative;
  z-index: 2;
  width: 100%;
  max-width: var(--page-max);
  margin-inline: auto;
  /* Patched 2026-06-01: explicit padding-top:80px clears the fixed nav
     so the headline isn't covered when the page first lands.
     Patched 2026-06-02 (X-AXIS UNIFICATION): horizontal padding now uses
     `--page-gutter` token, so hero content shares the SAME left-edge x
     as every other `.container`-based wrapper on the page. */
  padding-block: var(--space-7);
  padding-inline: var(--page-gutter);
  padding-top: 80px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-4);
}

.hero__content > * {
  max-width: 720px;
}

.hero__h1 {
  color: var(--surface-white);
  text-wrap: balance;
}

.hero__sub {
  font-family: var(--font-body);
  font-weight: 400;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--surface-white);
  opacity: 0.92;
}

.hero__cta {
  margin-top: var(--space-2);
}

/* ------------------------------------------------------------
   Hero variants (patched 2026-06-02)
   ------------------------------------------------------------
   Page agents emit a mix of hero modifiers — codify them all here
   so heights are consistent and cream-section heroes don't get
   stuck with white-text overrides. */
/* Hero heights — Sam's canonical spec (LOCKED 2026-06-02):
   - Home hero (.hero--home): 100svh — cinematic full-screen landing.
   - EVERY other hero site-wide: 45svh, no responsive split.
   `!important` here defeats any leftover override (legacy supplemental
   rules, inline `<style>` blocks on travel-and-logistics, etc.). */
.hero--home {
  min-height: 100svh !important;
  max-height: none !important;
}
.hero--short,
.hero--race,
.hero--impact,
.hero--register,
.hero--fundraise,
.hero--travel,
.hero--partners,
.hero--about-hy,
.hero--faq,
.hero--thanks,
.hero--404,
.hero--secondary,
.hero--cream {
  min-height: 45svh !important;
  max-height: none !important;
}
/* Cream hero strip — for legal/utility pages without a photo hero.
   Background + alignment only; height matches the canonical above. */
.hero--cream {
  background: var(--surface-cream);
  color: var(--surface-ink);
  align-items: flex-end;
}
.hero--cream .hero__h1,
.hero--cream .hero__sub,
.hero--cream .eyebrow,
.hero--cream .hero__eyebrow {
  color: var(--surface-ink);
}
.hero--cream .hero__overlay { display: none; }

/* When the hero sits on cream (faq/thanks/404), flip text to ink
   so the white-on-white isn't invisible. Both .hero.section--cream
   and .hero--faq / .hero--thanks / .hero--404 trigger this. */
.section--cream .hero__h1,
.section--cream .hero__sub,
.hero.section--cream,
.hero.section--cream .hero__h1,
.hero.section--cream .hero__sub,
.hero--faq,
.hero--faq .hero__h1,
.hero--faq .hero__sub,
.hero--thanks,
.hero--thanks .hero__h1,
.hero--thanks .hero__sub,
.hero--404,
.hero--404 .hero__h1,
.hero--404 .hero__sub {
  color: var(--surface-ink);
  background: var(--surface-cream);
}
.hero--faq .hero__overlay,
.hero--thanks .hero__overlay,
.hero--404 .hero__overlay,
.hero.section--cream .hero__overlay {
  display: none;
}


/* ============================================================
   10. STAT BAND
   ------------------------------------------------------------
   4-column grid on desktop, 2x2 on mobile. Aubergine background
   white text. Big Cosmic Buns numbers, eyebrow labels.
   ============================================================ */

.stat-band {
  background: var(--brand-aubergine);
  color: var(--surface-white);
  /* Patched 2026-06-02 (SECTION PADDING UNIFICATION):
     Use the same vertical spacing token as .section so standalone
     stat-bands (impact.html, register.html) and stat-bands nested
     inside .section both render with the AT A GLANCE rhythm. */
  padding: var(--section-pad-mobile) 0;
}

/* Patched 2026-06-02 (NESTED STAT-BAND DE-DOUBLE):
   When `.stat-band` is nested INSIDE a `.section` wrapper (index.html
   PILOT and CUMULATIVE patterns: `<section class="section"> > .container
   > <div class="stat-band">`), the outer .section already provides the
   vertical rhythm. Zero the inner .stat-band's padding-block to avoid
   doubling — otherwise PILOT/CUMULATIVE render at 2× the AT A GLANCE
   reference. */
.section .stat-band {
  padding-block: 0;
}

/* Patched 2026-06-02: when a nested .stat-band sits inside a CREAM
   section (post-alternation), its own aubergine background +
   white text would visually punch a purple "block" inside the cream
   section — defeating the alternation rhythm. Make the nested stat-band
   transparent + ink-colored so the cream section reads as a single
   cream block end-to-end. */
.section--cream .stat-band,
.section--cream .stat-band__number,
.section--cream .stat-band__label,
.section--cream .stat-band__footnote {
  background: transparent;
  color: var(--surface-ink);
}

/* Patched 2026-06-01 (LEFT-ALIGN FLEX REWRITE, Sam's instruction):
   Two emission patterns coexist in the HTML:
     A) index.html, about-hy.html: `<div class="stat-band">` with direct
        `.stat-band__item` children (no inner grid wrapper).
     B) the-race.html: `<section class="stat-band"> > .container >
        .stat-band__grid > .stat-band__item`.
   Pattern A: the `.stat-band` element IS the grid container.
   Pattern B: the `.stat-band__grid` element is the container; the outer
              `.stat-band` is just a section wrapper.

   // Left-align flex pattern per Sam's instruction — no equal-width grids
   //   except where component design REQUIRES equal cells (pillar tiles,
   //   partner LOGO grid, accordion meta).
   First item aligns to container left edge (matches the section title's
   x-position because both sit inside the same .container with the same
   padding-inline). Items flow right with a FIXED gap. Each item is
   `flex: 0 0 auto` so it sizes to its natural content — long labels wrap
   INSIDE the item's max-width without disturbing neighbours. */
.stat-band:has(> .stat-band__item),
.stat-band__grid,
.stat-band__items,
.stat-band > ul:has(> .stat-band__item) {
  display: flex !important;
  flex-direction: row;
  flex-wrap: wrap;                            /* wrap if doesn't fit on one row */
  justify-content: flex-start;                /* first item at container left edge */
  align-items: flex-start;
  gap: 2rem;                                  /* fixed padding between items (mobile) */
  margin: 0;
  padding: 0;
  list-style: none;
}
/* Pattern A only: stat-band acts as the flex container; keep horizontal
   gutter via the canonical page-gutter (matches other full-bleed bands).
   Patched 2026-06-02 (X-AXIS UNIFICATION). */
.stat-band:has(> .stat-band__item) {
  width: 100%;
  max-width: var(--page-max);
  margin-inline: auto;
  padding-inline: var(--page-gutter);
}
/* Pattern B: inner flex wrapper. */
.stat-band__grid,
.stat-band__items {
  width: 100%;
  margin-inline: auto;
}

.stat-band__item {
  flex: 0 0 auto;                            /* natural width per content */
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  align-items: flex-start;
  min-width: 0;                              /* allow shrink only if absolutely needed */
  /* no max-width — block sizes to content (max of number_width, label_width).
     Patched 2026-06-01d (Sam): removed the 280px cap that was forcing labels
     like "SUMMITED POINT LENANA" and "FINISHED THE TRIATHLON" to wrap to a
     second line while "RAISED IN 2025" stayed single-line, producing uneven
     block heights with overlap. Labels now nowrap (see .stat-band__label). */
}

/* Patched 2026-06-01b: switched from clamp() responsive sizing to fixed
   per-breakpoint sizes so every cell renders at the SAME size regardless
   of content length. Short content ("5") no longer balloons and long
   content ("4,985 m") no longer forces a wrap. The unit ("m") stays
   attached via `white-space: nowrap`. Text-modifier cells (e.g.
   "Sirimon → Chogoria") opt back into wrapping with a smaller heading
   size. */
.stat-band__number {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 3.5rem;                          /* fixed desktop */
  line-height: 1;
  color: var(--surface-white);
  white-space: nowrap;                        /* keep "4,985 m" on one line */
  letter-spacing: -0.01em;
  max-width: 100%;
}
@media (max-width: 1024px) { .stat-band__number { font-size: 2.75rem; } }
@media (max-width: 768px)  { .stat-band__number { font-size: 2.25rem; } }
@media (max-width: 480px)  { .stat-band__number { font-size: 2rem; } }

/* Special-case modifier for text-content numbers (e.g., "Sirimon → Chogoria")
   — render at heading size, not display size, and allow wrapping. */
.stat-band__number--text {
  font-family: var(--font-heading);
  font-weight: 900;
  font-size: 1.75rem;                          /* desktop */
  line-height: 1.1;
  white-space: normal;                         /* override nowrap for text cells */
  letter-spacing: 0.01em;
}
@media (max-width: 768px) { .stat-band__number--text { font-size: 1.5rem; } }

.stat-band__label {
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: 0.8rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--brand-lilac);
  margin-top: 0.5rem;
  line-height: 1.3;
  white-space: nowrap;                         /* labels stay on one line — block width = max(number, label) */
}

.stat-band__footnote {
  margin-top: var(--space-4);
  font-family: var(--font-body);
  font-size: var(--fs-small);
  color: var(--brand-lilac);
  opacity: 0.85;
}


/* ============================================================
   11. PILLAR GRID (3-color photo cards)
   ------------------------------------------------------------
   Three cards: Cataract / Dental / HPV. Backgrounds rotate
   --brand-lilac / --accent-salmon / --accent-lavender. All
   three have ink text — none of them ever take terracotta or
   light text (WCAG: salmon on cream/white is 1.41:1, never
   text; but ink on salmon = 11.x:1 = safe).
   ============================================================ */

.pillar-grid {
  display: grid;
  grid-template-columns: 1fr;                /* mobile: stack */
  gap: var(--space-4);
  width: 100%;
  max-width: var(--page-max);
  margin-inline: auto;
  padding-inline: var(--page-gutter);        /* canonical page x-axis */
  align-items: stretch;                      /* equal heights at >=768 */
}

.pillar-card {
  background: var(--brand-lilac);
  color: var(--surface-ink);
  border-radius: var(--radius-card);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  min-height: 480px;                         /* visual rhythm anchor */
}
.pillar-card__body { flex: 1; }

/* Rotate background per nth-child — pillar cards always come in
   threes (eye / dental / HPV). */
.pillar-card:nth-child(3n + 1) { background: var(--brand-lilac); }
.pillar-card:nth-child(3n + 2) { background: var(--accent-salmon); }
.pillar-card:nth-child(3n + 3) { background: var(--accent-lavender); }

.pillar-card__image {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  display: block;
}

.pillar-card__body {
  padding: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  height: 100%;                       /* fill the card */
}

/* Patched 2026-06-02 (PILLAR-CARD ROW ALIGNMENT, Sam):
   Cards have variable content lengths (e.g. "Cervical Cancer Prevention"
   wraps to 2 lines, "Eye Care" fits on 1). Without explicit row sizing,
   the cost / body / "Learn more" rows drift to different Y positions
   across the three cards. Reserve 2 lines for the H3, let the body text
   absorb extra height via flex-grow, and pin the "Learn more" link to
   the card bottom so it lines up across all three cards. */
.pillar-card__body .h3,
.pillar-card__body h3 {
  min-height: calc(var(--fs-h3) * var(--lh-h3) * 2);
  margin: 0;
}
.pillar-card__body-text,
.pillar-card__body .pillar-card__list {
  flex: 1 1 auto;                    /* absorbs extra height — for both the
                                        program-pillar body text AND the
                                        sponsor-tier bullet list */
}
.pillar-card__body > .btn--text,
.pillar-card__body > .btn {
  margin-top: auto;
  align-self: flex-start;
}

.pillar-card__title {
  font-family: var(--font-heading);
  font-weight: 900;
  font-size: var(--fs-h3);
  line-height: var(--lh-h3);
  color: var(--surface-ink);
}

.pillar-card__cost {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 32px;
  line-height: 1;
  color: var(--surface-ink);
}

.pillar-card__quote {
  font-family: var(--font-body);
  font-style: italic;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--surface-ink);
}

.pillar-card__back-link {
  margin-top: var(--space-2);
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: 14px;
  color: var(--surface-ink);
  border-bottom: 1px solid var(--surface-ink);
  align-self: flex-start;
  padding-bottom: 2px;
  text-decoration: none;
}
.pillar-card__back-link::after {
  content: " \2197";
  margin-left: 2px;
}
.pillar-card__back-link:hover,
.pillar-card__back-link:focus-visible {
  color: var(--brand-aubergine);
  border-bottom-color: var(--brand-aubergine);
}


/* ============================================================
   12. DAY ACCORDION (5-day itinerary)
   ------------------------------------------------------------
   Vertical list of 5 expandable rows. Trigger is a button
   spanning full width. Content panel below. Day 1 default-open
   via [data-default-open] (and aria-expanded=true on trigger).
   Smooth height via grid-template-rows: 0fr -> 1fr trick.
   ============================================================ */

.day-accordion {
  width: 100%;
  max-width: var(--page-max);
  margin-inline: auto;
  padding-inline: var(--page-gutter);        /* canonical page x-axis */
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.day-accordion__item {
  background: var(--surface-white);
  border-radius: var(--radius-card);
  overflow: hidden;
  border: 1px solid rgba(23, 20, 17, 0.08);
}
/* Patched 2026-06-02: JS sets aria-expanded on BOTH trigger and item now,
   so aria-expanded is the single source of truth. `[data-default-open]`
   was previously in this union too, which permanently kept Day 1 styled
   aubergine even after the user collapsed it — removed. */
.day-accordion__item[aria-expanded="true"],
.day-accordion__item:has(.day-accordion__trigger[aria-expanded="true"]) {
  background: var(--brand-aubergine);
  color: var(--surface-white);
  border-color: transparent;
}

.day-accordion__trigger {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-4);
  background: transparent;
  color: inherit;
  text-align: left;
  cursor: pointer;
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: 18px;
}

.day-accordion__day-number {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 48px;
  line-height: 1;
  flex: 0 0 auto;
}

.day-accordion__title {
  flex: 1 1 auto;
  font-family: var(--font-heading);
  font-weight: 900;
  font-size: var(--fs-h3);
  line-height: var(--lh-h3);
}

.day-accordion__icon {
  flex: 0 0 auto;
  width: 24px;
  height: 24px;
  position: relative;
  transition: transform var(--trans-default) var(--easing-default);
}
.day-accordion__icon::before,
.day-accordion__icon::after {
  content: "";
  position: absolute;
  background: currentColor;
}
.day-accordion__icon::before {              /* horizontal bar */
  top: 50%;
  left: 0;
  width: 24px;
  height: 2px;
  transform: translateY(-50%);
}
.day-accordion__icon::after {               /* vertical bar -> "+" -> "-" via rotate */
  top: 0;
  left: 50%;
  width: 2px;
  height: 24px;
  transform: translateX(-50%);
  transition: transform var(--trans-default) var(--easing-default);
}
.day-accordion__item[aria-expanded="true"] .day-accordion__icon::after,
.day-accordion__trigger[aria-expanded="true"] .day-accordion__icon::after {
  transform: translateX(-50%) scaleY(0);
}

.day-accordion__panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--trans-slow) var(--easing-default);
}
/* Patched 2026-06-02: open-state is driven by aria-expanded ONLY.
   `data-default-open` was previously also in this selector, which permanently
   pinned Day 1 open (couldn't collapse). The JS reads data-default-open once
   at init and applies aria-expanded="true" from there on. */
.day-accordion__item[aria-expanded="true"] .day-accordion__panel,
.day-accordion__item:has(.day-accordion__trigger[aria-expanded="true"]) .day-accordion__panel,
.day-accordion__trigger[aria-expanded="true"] + .day-accordion__panel,
.day-accordion__trigger[aria-expanded="true"] ~ .day-accordion__panel {
  grid-template-rows: 1fr;
}
.day-accordion__panel-inner {
  overflow: hidden;
  min-height: 0;
}
/* Patched 2026-06-02: markup uses .day-accordion__content directly inside
   .day-accordion__item (no .day-accordion__panel wrapper), so the
   grid-template-rows: 0fr collapse mechanism above never matches. Hide the
   content explicitly when the item is closed. aria-expanded mirrored on
   the article AND/OR the trigger is the single source of truth — the JS
   sets aria-expanded="true" on Day 1 at init from [data-default-open], so
   we no longer reference that attribute here (was pinning Day 1 open). */
.day-accordion__item:not([aria-expanded="true"]):not(:has(.day-accordion__trigger[aria-expanded="true"])) .day-accordion__content {
  display: none;
}
.day-accordion__content {
  padding: 0 var(--space-4) var(--space-4) var(--space-4);
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-4);
}
.day-accordion__photo {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: var(--radius-card);
}


/* ============================================================
   13. RACE TOGGLE (Sprint vs Long — WAI-ARIA Tabs)
   ------------------------------------------------------------
   Two pill segments side-by-side. Each is role="tab".
   Panels are role="tabpanel" hidden via [hidden] attribute.
   Active tab has terracotta underline.
   ============================================================ */

.race-toggle {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  width: 100%;
  max-width: var(--container-narrow);
  /* Patched 2026-06-02 (X-AXIS UNIFICATION): anchor to container left
     edge instead of centering. The component still clamps to 720px for
     readability but its left edge now aligns with the section H2. */
  margin-inline-start: 0;
  margin-inline-end: auto;
}

.race-toggle__tablist {
  display: inline-flex;
  gap: 0;
  border-bottom: 1px solid rgba(23, 20, 17, 0.12);
  align-self: flex-start;
}

.race-toggle__tab {
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: 14px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  padding: var(--space-2) var(--space-4);
  background: transparent;
  color: var(--ink-muted);
  border: 0;
  border-bottom: 2px solid transparent;
  cursor: pointer;
  transition: color var(--trans-default) var(--easing-default),
              border-color var(--trans-default) var(--easing-default);
  margin-bottom: -1px;
}
.race-toggle__tab[aria-selected="true"] {
  color: var(--surface-ink);
  border-bottom-color: var(--brand-terracotta);
}
.race-toggle__tab:hover { color: var(--surface-ink); }

.race-toggle__panel {
  display: block;
}
.race-toggle__panel[hidden] {
  display: none;
}


/* ============================================================
   14. CALCULATOR (€1,000 -> impact)
   ------------------------------------------------------------
   Number input with EUR prefix on the left, three output rows
   for cataract / dental / HPV updated by JS.
   Aubergine section background recommended (see component
   recipe in 03_visual_tokens.md §3.4).
   ============================================================ */

.calculator {
  width: 100%;
  max-width: var(--container-narrow);
  /* Patched 2026-06-02 (X-AXIS UNIFICATION): anchor to container left
     edge instead of centering. The 720px clamp still constrains the
     input field, but the calculator no longer floats centered. */
  margin-inline-start: 0;
  margin-inline-end: auto;
  display: grid;
  gap: var(--space-5);
}

.calculator__input-wrap {
  position: relative;
  display: flex;
  align-items: center;
  background: var(--surface-white);
  border-radius: var(--radius-card);
  padding: var(--space-3) var(--space-4);
  gap: var(--space-2);
}
.calculator__input-prefix {
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: 24px;
  color: var(--ink-muted);
  flex: 0 0 auto;
}
.calculator__input {
  flex: 1 1 auto;
  border: 0;
  background: transparent;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 32px;
  color: var(--surface-ink);
  width: 100%;
  outline: none;
  /* hide native spinner */
  -moz-appearance: textfield;
}
.calculator__input::-webkit-outer-spin-button,
.calculator__input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.calculator__output {
  display: grid;
  gap: var(--space-3);
}
.calculator__row {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: baseline;
  gap: var(--space-3);
  padding-block: var(--space-2);
}

/* Patched 2026-06-02 (Sam): "or" separator between the 3 calculator
   results, in Cosmic Buns display font, italicized, centered, low-opacity. */
.calculator__or {
  display: block;
  text-align: center;
  font-family: var(--font-display);
  font-weight: 400;
  font-style: italic;
  font-size: 1.25rem;
  line-height: 1;
  margin: var(--space-1) 0;
  opacity: 0.55;
  text-transform: lowercase;
  letter-spacing: 0.02em;
}
.section--aubergine .calculator__or {
  color: var(--brand-lilac);
  opacity: 0.85;
}
.section--cream .calculator__or {
  color: var(--brand-aubergine);
  opacity: 0.7;
}

.calculator__row-label {
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: var(--fs-body);
  color: inherit;
}
.calculator__row-value {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 18px;
  line-height: 1;
  color: inherit;
}


/* ============================================================
   15. COUNTDOWN
   ------------------------------------------------------------
   4-cell display: days / hours / minutes / seconds.
   Numbers Cosmic Buns 24px (per spec); colons in lilac.
   Designed for use inside .section--aubergine.
   ============================================================ */

.countdown {
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  justify-content: center;
  flex-wrap: wrap;
}

.countdown__cell {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-1);
  min-width: 64px;
}

.countdown__number {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 24px;
  line-height: 1;
  color: inherit;
}

.countdown__label {
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: var(--fs-eyebrow);
  line-height: var(--lh-eyebrow);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--brand-lilac);
}

.countdown__sep {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 24px;
  color: var(--brand-lilac);
  align-self: flex-start;
}


/* ============================================================
   16. FAQ ACCORDION
   ------------------------------------------------------------
   Native <details>/<summary>. Remove the default disclosure
   triangle and add our own +/- glyph via ::before on the
   summary. Group headers separate categories.
   ============================================================ */

.faq-accordion {
  width: 100%;
  max-width: var(--container-narrow);
  /* Patched 2026-06-02 (X-AXIS UNIFICATION): anchor to container left
     edge instead of centering. The 720px clamp keeps the readable
     line-length but the questions now align with the section H2. */
  margin-inline-start: 0;
  margin-inline-end: auto;
}

.faq-accordion__group {
  display: block;
  font-family: var(--font-heading);
  font-weight: 900;
  font-size: var(--fs-h3);
  line-height: var(--lh-h3);
  margin-top: var(--space-6);
  margin-bottom: var(--space-3);
  color: var(--surface-ink);
}
.faq-accordion__group:first-child { margin-top: 0; }

.faq-accordion__item {
  border-top: 1px solid rgba(23, 20, 17, 0.12);
  padding-block: var(--space-3);
}
.faq-accordion__item:last-child {
  border-bottom: 1px solid rgba(23, 20, 17, 0.12);
}

/* Kill the native disclosure triangle (Chrome, Safari, Firefox). */
.faq-accordion__item summary {
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  cursor: pointer;
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: var(--fs-body);
  color: var(--surface-ink);
  padding-block: var(--space-2);
}
.faq-accordion__item summary::-webkit-details-marker { display: none; }
.faq-accordion__item summary::marker { display: none; content: ""; }

/* Custom +/- glyph on the right. */
.faq-accordion__item summary::after {
  content: "+";
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: 24px;
  line-height: 1;
  color: var(--brand-terracotta);
  flex: 0 0 auto;
  transition: transform var(--trans-default) var(--easing-default);
}
.faq-accordion__item[open] summary::after {
  content: "\2212";                  /* unicode minus sign */
}

.faq-accordion__answer {
  margin-top: var(--space-3);
  font-family: var(--font-body);
  font-weight: 400;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--ink-muted);
  padding-bottom: var(--space-2);
}


/* ============================================================
   17. PARTNER GRID
   ------------------------------------------------------------
   8 partners in a 4-col x 2-row grid on desktop, 2 cols on
   tablet, 1 col on mobile. Each card has a logo, a role, and
   a location line.
   ============================================================ */

.partner-grid {
  display: grid;
  grid-template-columns: 1fr;                /* mobile */
  gap: var(--space-4);
  width: 100%;
  max-width: var(--page-max);
  margin-inline: auto;
  padding-inline: var(--page-gutter);        /* canonical page x-axis */
}

.partner-card {
  background: var(--surface-white);
  border-radius: var(--radius-card);
  padding: var(--space-5) var(--space-4);
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--space-3);
  min-height: 200px;
  justify-content: center;
}

.partner-card__logo {
  max-width: 160px;
  max-height: 64px;
  width: auto;
  height: auto;
  object-fit: contain;
}

.partner-card__role {
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: var(--fs-small);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--brand-aubergine);
}

.partner-card__location {
  font-family: var(--font-body);
  font-weight: 400;
  font-size: var(--fs-small);
  color: var(--ink-muted);
}


/* ============================================================
   18. FOOTER
   ------------------------------------------------------------
   Aubergine background. 3-column grid (About / Navigate /
   Contact). Bottom strip: copyright + legal links.
   ============================================================ */

.footer {
  background: var(--brand-aubergine);
  color: var(--surface-white);
  padding-top: var(--section-pad-mobile);
  padding-bottom: var(--section-pad-mobile);
}

.footer__inner {
  width: 100%;
  max-width: var(--page-max);
  margin-inline: auto;
  /* Patched 2026-06-02 (X-AXIS UNIFICATION): canonical page-gutter
     so footer columns align with body/hero/nav left edges. */
  padding-inline: var(--page-gutter);
}

.footer__cols {
  display: grid;
  grid-template-columns: 1fr;                /* mobile: stacked */
  gap: var(--space-6);
}

.footer__col h4,
.footer__col-title {
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: var(--fs-eyebrow);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--brand-lilac);
  margin-bottom: var(--space-3);
}

.footer__col ul {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.footer__col a {
  color: var(--surface-white);
  text-decoration: none;
  font-family: var(--font-body);
  font-weight: 400;
  font-size: var(--fs-small);
  line-height: var(--lh-small);
}
.footer__col a:hover,
.footer__col a:focus-visible {
  color: var(--brand-lilac);
}

.footer__bottom {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin-top: var(--space-6);
  padding-top: var(--space-4);
  border-top: 1px solid rgba(255, 255, 255, 0.15);
  font-family: var(--font-body);
  font-size: var(--fs-small);
  color: rgba(255, 255, 255, 0.7);
}

.footer__bottom-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
}
.footer__bottom-links a {
  color: rgba(255, 255, 255, 0.7);
  text-decoration: none;
}
.footer__bottom-links a:hover,
.footer__bottom-links a:focus-visible {
  color: var(--brand-lilac);
}


/* ============================================================
   19. FORMS
   ------------------------------------------------------------
   Used on the registration interest form (and any Jotform
   chrome we override). Cream-input convention: cream background,
   ink text, terracotta accent on focus.
   ============================================================ */

.form-field {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
}

.form-label {
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: var(--fs-small);
  color: var(--surface-ink);
}

.form-input,
.form-textarea,
.form-select {
  width: 100%;
  padding: var(--space-3);
  font-family: var(--font-body);
  font-size: var(--fs-body);
  color: var(--surface-ink);
  background: var(--surface-white);
  border: 1px solid rgba(23, 20, 17, 0.18);
  border-radius: var(--radius-card);
  transition: border-color var(--trans-default) var(--easing-default),
              box-shadow var(--trans-default) var(--easing-default);
}
.form-input:focus,
.form-textarea:focus,
.form-select:focus {
  border-color: var(--brand-terracotta);
  outline: none;
  box-shadow: 0 0 0 3px rgba(195, 73, 34, 0.18);
}

.form-textarea { min-height: 120px; resize: vertical; }

.form-error {
  font-family: var(--font-body);
  font-size: var(--fs-small);
  color: var(--brand-terracotta);
  /* WCAG: terracotta on cream = 3.92:1, fails for body text (4.5:1).
     Mitigation: error messages are paired with a leading "⚠" icon
     and bold weight, and the input border also turns terracotta —
     so the error state isn't conveyed by color alone (1.4.1).
     If body text contrast becomes a hard requirement, swap to
     --surface-ink and rely on the icon + bold + border. */
  font-weight: 500;
}
.form-error::before {
  content: "\26A0\FE0F";              /* ⚠️ */
  margin-right: 4px;
}


/* ============================================================
   20. UTILITY / A11Y
   ------------------------------------------------------------
   .sr-only — visually hidden but reachable to screen readers.
   .skip-link — appears on focus; jumps to #main.
   :focus-visible — global outline ring in terracotta.
   ============================================================ */

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

.skip-link {
  position: absolute;
  top: -100px;
  left: var(--space-3);
  z-index: var(--z-modal);
  padding: var(--space-2) var(--space-4);
  background: var(--brand-aubergine);
  color: var(--surface-white);
  font-family: var(--font-heading);
  font-weight: 500;
  border-radius: var(--radius-card);
  text-decoration: none;
  transition: top var(--trans-default) var(--easing-default);
}
.skip-link:focus-visible {
  top: var(--space-3);
  outline: 2px solid var(--brand-terracotta);
  outline-offset: 2px;
}

/* Global focus ring. Per BUILD_CONTRACT line 200: 2px solid
   terracotta + 2px offset, applied to every interactive element. */
:focus-visible {
  outline: 2px solid var(--brand-terracotta);
  outline-offset: 2px;
  border-radius: 2px;
}


/* ============================================================
   21. RESPONSIVE BREAKPOINTS
   ------------------------------------------------------------
   Mobile-first. Two breakpoints:
     @media (min-width: 768px)  -> tablet
     @media (min-width: 1024px) -> desktop
   At desktop, mobile-only chrome (mobile-register-bar, hamburger,
   drawer) gets hidden; nav menu and outbound link become visible.
   ============================================================ */

/* ---- Tablet (>= 768px) ----------------------------------- */
@media (min-width: 768px) {

  :root {
    /* Bump type scale toward desktop (patched 2026-06-02). */
    --fs-h1: 56px;
    --fs-h2: 36px;
    --fs-h3: 22px;
    --fs-body: 17px;
  }

  .section,
  .stat-band,
  .footer {
    padding-top: var(--section-pad-desktop);
    padding-bottom: var(--section-pad-desktop);
  }

  /* De-double nested stat-band inside a section (see 1018 above). */
  .section .stat-band {
    padding-block: 0;
  }

  /* Stat band: left-align flex with wider fixed gap at tablet+. Items
     flow left-to-right and sit at their natural widths; the first item
     aligns to container left, matching the section title x-position.
     Covers both emission patterns: A) .stat-band as the flex container
     (direct .stat-band__item children); B) .stat-band__grid / __items
     inner wrappers. */
  .stat-band:has(> .stat-band__item),
  .stat-band__grid,
  .stat-band__items,
  .stat-band > ul:has(> .stat-band__item) {
    gap: 2.5rem;
  }

  /* Pillar grid: 3 across. */
  .pillar-grid {
    grid-template-columns: repeat(3, 1fr);
  }

  /* Partner grid: 2 across. */
  .partner-grid {
    grid-template-columns: repeat(2, 1fr);
  }

  /* Footer: 3 columns. */
  .footer__cols {
    grid-template-columns: repeat(3, 1fr);
  }
  .footer__bottom {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
  }

  /* Calculator output: numbers slightly larger on tablet+. */
  .calculator__row-value { font-size: 22px; }

  /* Day accordion: photo + text side-by-side in expanded panel. */
  .day-accordion__content {
    grid-template-columns: 1fr 1fr;
    gap: var(--space-5);
  }

  /* Countdown: bigger numbers. */
  .countdown__number,
  .countdown__sep { font-size: 32px; }
  .countdown__cell { min-width: 80px; }
}


/* ---- Desktop (>= 1024px) --------------------------------- */
@media (min-width: 1024px) {

  :root {
    /* Full desktop scale per locked tokens. */
    --fs-h1: 64px;
    --fs-h2: 40px;
    --fs-h3: 24px;
    --fs-body: 18px;
    --section-pad-desktop: 96px;
    --container-pad: 32px;
  }

  .section,
  .stat-band,
  .footer {
    padding-top: var(--section-pad-desktop);
    padding-bottom: var(--section-pad-desktop);
  }

  /* De-double nested stat-band inside a section (see 1018 above). */
  .section .stat-band {
    padding-block: 0;
  }

  /* Nav: show menu and outbound link, hide hamburger.
     Patched 2026-06-02: cover both .nav__toggle and .nav__hamburger. */
  .nav__menu      { display: flex; }
  .nav__outbound  { display: inline-flex; }
  .nav__toggle,
  .nav__hamburger { display: none; }

  /* Partner grid: 4 columns x 2 rows for 8 partners. */
  .partner-grid {
    grid-template-columns: repeat(4, 1fr);
  }

  /* Stat band: numbers handled by clamp() default; no override needed. */

  /* Hide mobile drawer entirely. */
  .mobile-drawer,
  .mobile-drawer__backdrop {
    display: none !important;       /* belt-and-suspenders: even if JS leaves
                                       state="open", desktop forces hidden. */
  }

  /* Hide mobile pinned Register bar on desktop. */
  .mobile-register-bar {
    display: none;
  }
  body { padding-bottom: 0; }       /* remove the 56px offset */

  /* Calculator output: desktop scale. */
  .calculator__row-value { font-size: 26px; }

  /* Countdown: bigger still. */
  .countdown__number,
  .countdown__sep { font-size: 40px; }
}


/* ---- Wide desktop (>= 1440px) — optional tightening ------ */
@media (min-width: 1440px) {
  :root {
    --container-pad: 48px;
  }
}


/* ---- Narrow mobile (<= 480px) — single-column collapses ---- */
@media (max-width: 480px) {
  .stat-band:has(> .stat-band__item),
  .stat-band__grid,
  .stat-band__items,
  .stat-band > ul:has(> .stat-band__item) {
    flex-direction: column !important;
    gap: 1.5rem;
  }
  .stat-band__item {
    max-width: 100% !important;
  }
}


/* ============================================================
   22. PRINT STYLES
   ------------------------------------------------------------
   Minimal: hide nav/footer/mobile-bar/drawer, force plain
   typography on cream-printable surfaces. Print is rare for a
   triathlon site but we don't want a broken layout when someone
   prints the FAQ or the registration confirmation.
   ============================================================ */

@media print {
  *,
  *::before,
  *::after {
    background: transparent !important;
    color: #000 !important;
    box-shadow: none !important;
    text-shadow: none !important;
  }

  html, body {
    background: #fff !important;
    font-size: 12pt;
    line-height: 1.4;
  }

  .nav,
  .mobile-drawer,
  .mobile-drawer__backdrop,
  .mobile-register-bar,
  .footer,
  .skip-link,
  .btn,
  .hero__overlay {
    display: none !important;
  }

  .hero {
    min-height: auto;
    padding: 0;
    color: #000 !important;
  }
  .hero__image { display: none !important; }
  .hero__content { padding: 0; }

  a {
    text-decoration: underline;
  }
  a[href^="http"]::after {
    content: " (" attr(href) ")";
    font-size: 10pt;
  }

  /* Prevent awkward page breaks inside cards / accordions. */
  .pillar-card,
  .day-accordion__item,
  .partner-card,
  .faq-accordion__item {
    break-inside: avoid;
    page-break-inside: avoid;
  }
}
