/* ============================================================================
   SOUTH WEST BOXING CLUB — site.css
   Built on the Pinovio base system (Stack A), aligned to the client's
   inspiration mockup: full-bleed photo hero, outlined-gold CTAs, green
   offer band w/ dashed Mindbody slot, cream story section, black footer.
   Brand book: green 60% / cream 20% / black 10% / gold 8% / pink = logo only.
   Fonts: Graduate (collegiate slab display) + Poppins (body) + IBM Plex Mono.
   ========================================================================== */


/* ============================================================================
   1. BRAND LAYER — SWBC
   ========================================================================== */
:root {
  --font-display: 'Graduate', 'Arial Black', system-ui, sans-serif;
  --font-body:    'Poppins', system-ui, -apple-system, Segoe UI, sans-serif;
  --font-mono:    'IBM Plex Mono', ui-monospace, monospace;

  /* Accent — Heritage Gold ramp (brand #C7A63A) */
  --accent-050: #faf6e6;
  --accent-100: #f1e6c2;
  --accent-300: #ddc270;
  --accent-500: #C7A63A;
  --accent-600: #a8892c;
  --accent-700: #836a20;
  /* One step darker than accent-700, for small gold text on cream: 700 lands at
     4.30:1 there, which misses AA for anything under 18px. */
  --accent-800: #77601d;
  --accent-soft: color-mix(in srgb, var(--accent-500) 14%, transparent);
  --accent-ring: color-mix(in srgb, var(--accent-500) 38%, transparent);

  /* Dark side — forest green (dominant brand surface) */
  --d-bg:       #13351D;
  --d-surface:  #1a4126;
  --d-surface-2:#215030;
  --d-text:     #EDEADD;
  --d-muted:    #a9b8a0;
  --d-line:     color-mix(in srgb, #EDEADD 18%, transparent);

  /* Light side — brand cream */
  --l-bg:       #EDEADD;
  --l-surface:  #f4f1e6;
  --l-surface-2:#e2ddc8;
  --l-text:     #16281b;
  --l-muted:    #52604f;
  --l-line:     #d5cfb6;

  /* Brand black (footer, hero shadows) — brand book #0D0D0D, never pure #000 */
  --ink: #0D0D0D;
  --ink-surface: #181816;
}

/* ============================================================================
   1.5 VIBE LAYER — heavy / SHARP / warm-dark / minimal + industrial microlabels
   ========================================================================== */
:root {
  --display-weight: 400;            /* Graduate ships one blocky weight */
  --btn-radius: 2px;                /* sharp — industrial, no pills */
  --tracking-display: 0.01em;
}

/* ============================================================================
   2. SYSTEM LAYER (base system, radii re-cut sharp for this brand)
   ========================================================================== */
:root {
  --step--2: 0.694rem;
  --step--1: 0.833rem;
  --step-0:  1.0625rem;
  --step-1:  1.25rem;
  --step-2:  1.5rem;
  --step-3:  clamp(1.6rem, 2.4vw, 2rem);
  --step-4:  clamp(2.1rem, 4vw, 2.8rem);
  --step-5:  clamp(2.5rem, 5.5vw, 3.9rem);
  --step-6:  clamp(2.9rem, 6.8vw, 4.9rem);

  --leading-solid:  1.06;
  --leading-tight:  1.12;
  --leading-snug:   1.2;
  --leading-normal: 1.65;
  --tracking-tight: 0;
  --tracking-wide:  0.09em;

  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-7: 3rem;
  --space-8: 4rem;
  --space-9: 6rem;
  --space-10: 8rem;

  /* Sharp radius scale — hairline industrial */
  --radius-xs:   2px;
  --radius-sm:   2px;
  --radius-md:   3px;
  --radius-lg:   4px;
  --radius-xl:   6px;
  --radius-pill: 999px;

  --shadow-xs: 0 1px 2px rgba(10,16,10,0.06);
  --shadow-sm: 0 1px 2px rgba(10,16,10,0.07), 0 2px 6px rgba(10,16,10,0.06);
  --shadow-md: 0 4px 12px rgba(10,16,10,0.09), 0 12px 28px rgba(10,16,10,0.07);
  --shadow-lg: 0 8px 24px rgba(10,16,10,0.11), 0 24px 48px rgba(10,16,10,0.09);

  --dur-fast: 150ms;
  --dur:      220ms;
  --dur-slow: 420ms;
  --ease-out:    cubic-bezier(0.22, 1, 0.36, 1);
  --ease-spring: cubic-bezier(0.34, 1.46, 0.64, 1);
  --ease-in:     cubic-bezier(0.4, 0, 1, 1);

  --container: 1200px;
  --gutter: clamp(1rem, 4vw, 2rem);
  --measure: 62ch;

  --nav-h: 116px;
}

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

/* scroll-padding keeps #anchor targets clear of the sticky nav */
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; scroll-padding-top: calc(var(--nav-h) + var(--space-4)); }

body {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--step-0);
  line-height: var(--leading-normal);
  color: var(--l-text);
  background: var(--l-bg);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4 {
  font-family: var(--font-display);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
  font-weight: var(--display-weight);
  margin: 0 0 var(--space-4);
  text-wrap: balance;
  text-transform: uppercase;
}
h1 {
  font-size: var(--step-5);
  line-height: var(--leading-solid);
  letter-spacing: var(--tracking-display);
}
h2 { font-size: var(--step-4); }
h3 { font-size: var(--step-3); }
h4 { font-size: var(--step-2); }

p  { margin: 0 0 var(--space-4); max-width: var(--measure); }
a  { color: var(--accent-600); text-decoration: none; }
a:hover { text-decoration: underline; }
img { max-width: 100%; }

.eyebrow {
  font-family: var(--font-mono);
  font-size: var(--step--1);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  font-weight: 500;
  color: var(--accent-600);
  margin: 0 0 var(--space-3);
}

/* Short gold rule under headings (mockup device) */
.rule-gold {
  width: 56px;
  height: 3px;
  background: var(--accent-500);
  border: 0;
  margin: var(--space-5) 0;
}

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section        { padding-block: var(--space-9); }
.section--tight { padding-block: var(--space-7); }
.section--tall  { padding-block: var(--space-10); }

.section--dark  { background: var(--d-bg); color: var(--d-text); }
.section--dark .eyebrow { color: var(--accent-300); }
.section--dark a { color: var(--accent-300); }
.section--dark p { color: color-mix(in srgb, var(--d-text) 88%, var(--d-bg)); }

/* Available to screen readers, invisible on screen. Used for the section
   headings that the .annot-line device stands in for visually — without them
   the pages jump straight from h1 to h3. */
.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Skip link */
.skip-link {
  position: absolute;
  left: var(--space-4); top: calc(-1 * var(--space-10));
  z-index: 200;
  padding: var(--space-3) var(--space-4);
  background: var(--accent-500);
  color: var(--ink);
  font-weight: 600;
  border-radius: var(--radius-sm);
  transition: top var(--dur) var(--ease-out);
}
.skip-link:focus { top: var(--space-4); }

/* ---------------------------------------------------------------------------
   Buttons — outlined-gold is the house CTA (per client mockup)
   ------------------------------------------------------------------------- */
.btn {
  --btn-py: 0.85rem;
  --btn-px: 1.6rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--btn-py) var(--btn-px);
  /* 44px floor so .btn--sm still clears the minimum touch target on phones */
  min-height: 44px;
  font-family: var(--font-mono);
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  line-height: 1;
  border-radius: var(--btn-radius);
  border: 1px solid transparent;
  cursor: pointer;
  user-select: none;
  transition: transform var(--dur-fast) var(--ease-out),
              background-color var(--dur) var(--ease-out),
              border-color var(--dur) var(--ease-out),
              box-shadow var(--dur) var(--ease-out),
              color var(--dur) var(--ease-out);
}
.btn:hover { text-decoration: none; }
.btn:active { transform: scale(0.97); }

.btn:focus-visible,
a:focus-visible,
button:focus-visible,
.input:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--accent-ring);
}

.btn:disabled,
.btn[aria-disabled="true"] { opacity: 0.5; cursor: not-allowed; transform: none; }

.btn--sm { --btn-py: 0.6rem; --btn-px: 1.1rem; font-size: var(--step--2); }
.btn--lg { --btn-py: 1.05rem; --btn-px: 2rem; font-size: var(--step-0); }
.btn--block { width: 100%; }

/* Outline — the mockup's CTA. On dark: gold border + cream text → gold fill. */
.btn--outline {
  background: transparent;
  color: var(--d-text);
  border-color: var(--accent-500);
}
.btn--outline:hover {
  background: var(--accent-500);
  color: var(--ink);
  transform: translateY(-1px);
  box-shadow: var(--shadow-sm);
}
/* On light sections the same outline reads green-on-cream. */
.on-light .btn--outline,
.section--light .btn--outline {
  color: var(--l-text);
  border-color: var(--accent-600);
}
.on-light .btn--outline:hover,
.section--light .btn--outline:hover { background: var(--accent-500); color: var(--ink); }

/* Filled gold — reserved for the single loudest action on a page. */
.btn--primary {
  background: var(--accent-500);
  color: var(--ink);
  box-shadow: var(--shadow-sm);
}
.btn--primary:hover {
  background: var(--accent-300);
  transform: translateY(-1px);
  box-shadow: var(--shadow-md);
}

/* Nav Book Now — raised green chip w/ gold hairline (mockup top-right) */
.btn--nav {
  background: var(--d-surface);
  color: var(--d-text);
  border-color: color-mix(in srgb, var(--accent-500) 55%, transparent);
}
.btn--nav:hover {
  border-color: var(--accent-500);
  color: var(--accent-300);
  background: var(--d-surface-2);
}

.btn--ghost {
  background: transparent;
  color: var(--l-text);
  border-color: color-mix(in srgb, var(--l-text) 28%, transparent);
}
.btn--ghost:hover {
  background: var(--l-surface-2);
  border-color: color-mix(in srgb, var(--l-text) 45%, transparent);
}
.section--dark .btn--ghost { color: var(--d-text); border-color: color-mix(in srgb, #EDEADD 38%, transparent); }
.section--dark .btn--ghost:hover { background: color-mix(in srgb, #EDEADD 10%, transparent); }

.btn__circle {
  display: inline-grid;
  place-items: center;
  width: 1.5em;
  height: 1.5em;
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, currentColor 14%, transparent);
  font-size: 0.85em;
  transition: transform var(--dur) var(--ease-out);
}
.btn:hover .btn__circle { transform: translateX(3px); }

/* Arrow text link — READ OUR STORY → (mockup device for light sections) */
.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-mono);
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--l-text);
  text-decoration: underline;
  text-underline-offset: 5px;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--accent-600);
}
.link-arrow .link-arrow__glyph {
  transition: transform var(--dur) var(--ease-out);
}
.link-arrow:hover { color: var(--accent-700); }
.link-arrow:hover .link-arrow__glyph { transform: translateX(4px); }
.section--dark .link-arrow { color: var(--d-text); }
.section--dark .link-arrow:hover { color: var(--accent-300); }

/* ---------------------------------------------------------------------------
   Cards
   ------------------------------------------------------------------------- */
.card {
  background: var(--l-surface);
  border: 1px solid var(--l-line);
  border-radius: var(--radius-md);
  padding: var(--space-6);
  box-shadow: var(--shadow-xs);
  transition: transform var(--dur) var(--ease-out),
              box-shadow var(--dur) var(--ease-out),
              border-color var(--dur) var(--ease-out);
}
.card:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-md);
  border-color: color-mix(in srgb, var(--accent-500) 34%, transparent);
}
.section--dark .card {
  background: var(--d-surface);
  border-color: var(--d-line);
  box-shadow: none;
}
.section--dark .card:hover { background: var(--d-surface-2); }

/* ---------------------------------------------------------------------------
   Forms (future use)
   ------------------------------------------------------------------------- */
.field { display: grid; gap: var(--space-2); margin-bottom: var(--space-4); }
.field > label { font-size: var(--step--1); font-weight: 600; color: var(--l-muted); }
.input {
  width: 100%;
  padding: 0.7rem 0.9rem;
  font: inherit;
  color: var(--l-text);
  background: var(--l-surface);
  border: 1px solid var(--l-line);
  border-radius: var(--radius-xs);
  transition: border-color var(--dur) var(--ease-out), box-shadow var(--dur) var(--ease-out);
}
.input:focus { outline: none; border-color: var(--accent-500); }

/* ---------------------------------------------------------------------------
   Media frames — sharp corners per mockup
   ------------------------------------------------------------------------- */
.media-frame {
  --media-radius: var(--radius-sm);
  position: relative;
  overflow: hidden;
  border-radius: var(--media-radius);
  border: 1px solid var(--l-line);
  background: var(--l-surface-2);
}
.section--dark .media-frame { border-color: var(--d-line); background: var(--d-surface); }
.media-frame > img,
.media-frame > video { display: block; width: 100%; height: 100%; object-fit: cover; }

/* Dark-photo treatment for real/placeholder photography: desaturated, moody,
   green-black shadow cast. Real shoot photos inherit the same wrapper later. */
.tone { background: #10240f; }
.tone > img {
  filter: saturate(0.42) contrast(1.06) brightness(0.94);
}
/* Keep native color (e.g. the pink-house silos shot — already B&W + pink) */
.tone--keep > img { filter: contrast(1.03) brightness(0.97); }
.tone::before {
  content: '';
  position: absolute; inset: 0;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(180deg,
              color-mix(in srgb, #13351D 22%, transparent),
              transparent 45%,
              color-mix(in srgb, #0D0D0D 38%, transparent));
}

/* ---------------------------------------------------------------------------
   Annotation kit
   ------------------------------------------------------------------------- */
.index {
  font-family: var(--font-mono);
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: var(--tracking-wide);
  color: var(--accent-600);
}
.section--dark .index { color: var(--accent-300); }

.annot-line {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--l-muted);
  margin-bottom: var(--space-7);
}
.annot-line > span { flex: none; }
.annot-line::after {
  content: '';
  flex: 1;
  order: 1;
  border-top: 1px dotted color-mix(in srgb, currentColor 45%, transparent);
}
.annot-line > span:last-child { order: 2; }
.section--dark .annot-line { color: var(--d-muted); }
/* The trailing label is decorative. On phones two labels plus the rule overrun
   the row — longer French strings push it past the container — so drop it. */
@media (max-width: 640px) {
  .annot-line > span:last-child { display: none; }
}

.hud-corner {
  position: absolute;
  z-index: 2;
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  line-height: 1.5;
  color: color-mix(in srgb, #EDEADD 75%, transparent);
  margin: var(--space-4);
}
.hud-corner--tl { top: 0; left: 0; }
.hud-corner--tr { top: 0; right: 0; text-align: right; }
.hud-corner--bl { bottom: 0; left: 0; }
.hud-corner--br { bottom: 0; right: 0; text-align: right; }

.txt-link {
  font-family: var(--font-mono);
  font-size: var(--step--1);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  text-decoration: none;
}
.txt-link::before { content: '('; }
.txt-link::after  { content: ')'; }
.txt-link:hover { text-decoration: underline; text-underline-offset: 3px; }

/* ---------------------------------------------------------------------------
   Grain
   ------------------------------------------------------------------------- */
.grain { position: relative; }
.grain::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  opacity: 0.055;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
.grain > .container { position: relative; z-index: 2; }

/* ---------------------------------------------------------------------------
   Motion — scroll reveals (CSS scroll-driven, zero JS, reduced-motion safe)
   ------------------------------------------------------------------------- */
.reveal { opacity: 1; }

@supports (animation-timeline: view()) {
  .reveal {
    opacity: 0;
    transform: translateY(20px);
    animation: reveal-in linear both;
    animation-timeline: view();
    animation-range: entry 5% cover 30%;
  }
  .reveal--left  { transform: translateX(-24px); }
  .reveal--right { transform: translateX(24px); }
  .reveal--scale { transform: scale(0.965); }
  .reveal[data-delay="1"] { animation-range: entry 10% cover 35%; }
  .reveal[data-delay="2"] { animation-range: entry 15% cover 40%; }
  .reveal[data-delay="3"] { animation-range: entry 20% cover 45%; }
}
@keyframes reveal-in { to { opacity: 1; transform: none; } }

.lift { transition: transform var(--dur) var(--ease-out); }
.lift:hover { transform: translateY(-2px); }

/* ============================================================================
   3. SWBC COMPONENTS
   ========================================================================== */

/* ---------------------------------------------------------------------------
   Nav — dark green bar, emblem left, links center, Book Now right (mockup)
   ------------------------------------------------------------------------- */
.nav {
  position: sticky;
  top: 0;
  z-index: 100;
  background: color-mix(in srgb, var(--d-bg) 97%, transparent);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--d-line);
  color: var(--d-text);
}
.nav__in {
  display: flex;
  align-items: center;
  gap: var(--space-6);
  min-height: var(--nav-h);
}
.nav__brand {
  display: inline-flex;
  align-items: center;
  color: var(--d-text);
  text-decoration: none;
  margin-right: auto;
}
.nav__brand:hover { text-decoration: none; }
/* Logo art is now edge-to-edge (transparent padding cropped), so this height is
   all mark — 88px here reads far larger than the old 120px padded file. */
.nav__brand img { height: 88px; width: auto; display: block; }
.nav__links {
  display: flex;
  align-items: center;
  gap: var(--space-6);
}
.nav__links a {
  /* Two-word labels (Private Training / Entraînement privé) wrapped onto two
     lines inside the anchor once the nav grew to six items, which knocked the
     row out of alignment. The nav row itself is nowrap; the labels have to be
     too. */
  white-space: nowrap;
  font-family: var(--font-mono);
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: color-mix(in srgb, var(--d-text) 84%, var(--d-bg));
  padding-block: var(--space-2);
  border-bottom: 2px solid transparent;
  transition: color var(--dur) var(--ease-out), border-color var(--dur) var(--ease-out);
}
.nav__links a:hover { color: var(--d-text); text-decoration: none; }
.nav__links a[aria-current="page"] {
  color: var(--d-text);
  border-bottom-color: var(--accent-500);
}
.nav__cta { display: flex; align-items: center; gap: var(--space-4); }
.nav__lang {
  color: var(--d-muted);
  font-family: var(--font-mono);
  font-size: var(--step--1);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
}
.nav__lang:hover { color: var(--accent-300); text-decoration: none; }

.nav__burger {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 44px;
  height: 44px;
  padding: 10px;
  background: transparent;
  border: 1px solid var(--d-line);
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.nav__burger span {
  display: block;
  height: 2px;
  width: 100%;
  background: var(--d-text);
  transition: transform var(--dur) var(--ease-out), opacity var(--dur) var(--ease-out);
}

/* Six nav items (Private Training joined the list) need ~1000px at a 2rem
   gap, but the burger doesn't take over until 980px — so the links wrapped to
   a second row in the narrow band just above the cutoff, in both languages.
   Tighten the gap across that band instead of moving the breakpoint, so
   tablets and small laptops keep the full nav. */
@media (min-width: 981px) and (max-width: 1140px) {
  .nav__in { gap: var(--space-4); }
  .nav__links { gap: var(--space-4); }
}

@media (max-width: 980px) {
  .nav__links {
    position: absolute;
    top: 100%;
    left: 0; right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    background: var(--d-bg);
    border-bottom: 1px solid var(--d-line);
    padding: var(--space-4) var(--gutter) var(--space-6);
    display: none;
  }
  .nav__links a { padding: var(--space-4) 0; border-bottom: 1px solid var(--d-line); }
  .nav__links a[aria-current="page"] { border-bottom-color: var(--accent-500); }
  .nav--open .nav__links { display: flex; }
  .nav__burger { display: flex; }
  .nav--open .nav__burger span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
  .nav--open .nav__burger span:nth-child(2) { opacity: 0; }
  .nav--open .nav__burger span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
  /* Keep the sticky bar from eating the viewport on phones while still enlarging the mark */
  :root { --nav-h: 92px; }
  .nav__brand img { height: 62px; }
}
@media (max-width: 560px) {
  .nav__lang { display: none; }
}

/* ---------------------------------------------------------------------------
   Hero — full-bleed photo, text left over green-black gradient (mockup)
   ------------------------------------------------------------------------- */
.hero {
  position: relative;
  background: var(--d-bg);
  color: var(--d-text);
  overflow: hidden;
  display: grid;
  align-items: end;             /* headline bottom-left, mural upper-right */
  min-height: min(88vh, 820px);
}
.hero__bg {
  position: absolute;
  inset: 0;
  z-index: 0;
}
.hero__bg img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Tuned for the club's own ring photo (hero-ring.jpg), which is portrait:
     on a landscape hero `cover` keeps only a middle band, and dead-centre
     cut the two overhead lamps that give the shot its atmosphere. 42%
     lifts the band just enough to hold the lamp glow AND the sparring
     pair. Re-tune this if the hero image is ever replaced. */
  object-position: 30% 42%;
  filter: saturate(0.55) contrast(1.05) brightness(0.92);
}
/* Legibility cast: black-green wash bottom-left where the headline sits */
.hero__bg::after {
  content: '';
  position: absolute;
  inset: 0;
  background:
    linear-gradient(76deg,
      color-mix(in srgb, var(--ink) 82%, transparent) 0%,
      color-mix(in srgb, #13351D 58%, transparent) 32%,
      color-mix(in srgb, #13351D 16%, transparent) 55%,
      transparent 72%),
    linear-gradient(0deg,
      color-mix(in srgb, var(--ink) 78%, transparent) 0%,
      color-mix(in srgb, var(--ink) 38%, transparent) 34%,
      transparent 62%),
    linear-gradient(180deg,
      color-mix(in srgb, var(--ink) 28%, transparent),
      transparent 26%);
}
.hero__content {
  position: relative;
  z-index: 2;
  padding-block: var(--space-9) var(--space-9);
}
.hero__title {
  font-size: var(--step-6);
  margin-bottom: 0;
  max-width: 13ch;
}
.hero__lead {
  font-size: var(--step-1);
  line-height: 1.55;
  color: color-mix(in srgb, var(--d-text) 92%, transparent);
  max-width: 34ch;
  margin-bottom: var(--space-6);
}
.hero .eyebrow { color: var(--accent-300); }
.hero__cta { display: flex; flex-wrap: wrap; gap: var(--space-4); }

/* Load-in: distinct from scroll reveals — rise + settle, staggered */
@keyframes hero-rise {
  from { opacity: 0; transform: translateY(26px); }
  to   { opacity: 1; transform: none; }
}
.hero [data-hero] { animation: hero-rise 640ms var(--ease-out) both; }
.hero [data-hero="1"] { animation-delay: 60ms; }
.hero [data-hero="2"] { animation-delay: 160ms; }
.hero [data-hero="3"] { animation-delay: 260ms; }
.hero [data-hero="4"] { animation-delay: 380ms; }

@media (max-width: 700px) {
  .hero { min-height: 78vh; }
  .hero__bg img { object-position: 72% center; }
  .hero__bg::after {
    background:
      linear-gradient(180deg,
        color-mix(in srgb, var(--ink) 62%, transparent),
        color-mix(in srgb, #13351D 48%, transparent) 45%,
        color-mix(in srgb, var(--ink) 72%, transparent) 100%);
  }
}

/* ---------------------------------------------------------------------------
   Page hero (inner pages)
   ------------------------------------------------------------------------- */
.page-hero {
  background: var(--d-bg);
  color: var(--d-text);
  padding-block: var(--space-8) var(--space-7);
}
.page-hero .eyebrow { color: var(--accent-300); }
.page-hero h1 { max-width: 20ch; margin-bottom: 0; }
.page-hero__lead {
  font-size: var(--step-1);
  color: color-mix(in srgb, var(--d-text) 85%, var(--d-bg));
  max-width: 52ch;
  margin: 0;
}
.page-hero .rule-gold { margin-block: var(--space-5); }
.page-hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  margin-top: var(--space-6);
}

/* --- 404 ----------------------------------------------------------------
   Vercel serves the single root /404.html for every miss, including misses
   under the French mirror at /fr — a static deploy has no per-directory 404.
   So both languages ship in the markup and js/notfound.js sets <html lang>
   from the path that failed. Matched on the language prefix, since the
   documents use regional tags (en-CA / fr-CA). Scoped to .notfound so it can
   never touch another page's markup. Defaults to English with no JS. */
html[lang^="en"] .notfound [data-lang="fr"],
html[lang^="fr"] .notfound [data-lang="en"] { display: none; }

/* Without this the cream page background shows as a band under the footer on
   a page this short — reading as exactly the broken site a branded 404 is
   meant to prevent. svh so mobile browser chrome can't push the footer off. */
.page-hero--fill {
  display: flex;
  align-items: center;
  min-height: calc(100svh - 4rem);
}

/* ---------------------------------------------------------------------------
   Offer band — green, text left + dashed Mindbody slot right (mockup)
   ------------------------------------------------------------------------- */
.offer-band {
  display: grid;
  grid-template-columns: minmax(16rem, 0.85fr) 1.15fr;
  gap: var(--space-8);
  align-items: center;
}
@media (max-width: 860px) { .offer-band { grid-template-columns: 1fr; gap: var(--space-6); } }
.offer-band h2 { margin-bottom: 0; }
.offer-band .rule-gold { margin: var(--space-4) 0 var(--space-5); }
.offer-band__copy p { font-size: var(--step-1); line-height: 1.55; margin: 0; max-width: 30ch; }

/* The dashed .mb-slot placeholder is gone — every Mindbody slot now holds real
   content (the live Schedules widget, or the client's prices as native markup).
   .mb-slot__note survives because the <noscript> fallbacks still use it. */
.mb-slot__note {
  font-size: var(--step--1);
  color: var(--l-muted);
  max-width: 44ch;
  margin: 0;
}
.section--dark .mb-slot__note,
.offer-band .mb-slot__note { color: var(--d-muted); }

/* Live Mindbody embed wrapper — reserves space to limit layout shift while widget.js loads */
.mb-embed { width: 100%; min-height: 300px; }

/* ---------------------------------------------------------------------------
   Story split — cream section, text + photo (mockup "The South West")
   ------------------------------------------------------------------------- */
.split {
  display: grid;
  grid-template-columns: 1fr 1.05fr;
  gap: var(--space-8);
  align-items: center;
}
.split--rev > :first-child { order: 2; }
@media (max-width: 860px) {
  .split { grid-template-columns: 1fr; gap: var(--space-6); }
  .split--rev > :first-child { order: 0; }
}
.split__media { aspect-ratio: 5 / 4; }
.split__media--tall { aspect-ratio: 4 / 5; }
/* Near-native ratio for real 3:2 camera photos, so a landscape shot isn't
   cropped into by the portrait frame the placeholder stills were built for. */
.split__media--wide { aspect-ratio: 3 / 2; }
.split h2 { color: var(--d-bg); }
.section--dark .split h2 { color: var(--d-text); }

/* Wordmark panel — exact brand green behind the on-green logo PNG */
.wordmark-panel {
  background: var(--d-bg);
  border: 1px solid var(--l-line);
  border-radius: var(--radius-sm);
  padding: var(--space-7);
  display: grid;
  place-items: center;
  position: relative;
  overflow: hidden;
}
.wordmark-panel img { max-width: 320px; width: 100%; height: auto; position: relative; z-index: 2; }

/* ---------------------------------------------------------------------------
   Values — typographic rows (kept: brand book core values, on-voice)
   ------------------------------------------------------------------------- */
.value-row {
  display: grid;
  grid-template-columns: 4rem minmax(11rem, 17rem) 1fr;
  gap: var(--space-5);
  align-items: baseline;
  padding-block: var(--space-5);
  border-bottom: 1px solid var(--d-line);
  transition: background-color var(--dur) var(--ease-out), padding-left var(--dur) var(--ease-out);
}
.value-row:first-child { border-top: 1px solid var(--d-line); }
.value-row:hover { background: color-mix(in srgb, #EDEADD 4%, transparent); padding-left: var(--space-3); }
.value-row h3 { margin: 0; font-size: var(--step-3); }
.value-row p { margin: 0; color: var(--d-muted); font-size: var(--step-0); }
@media (max-width: 700px) {
  .value-row { grid-template-columns: 3rem 1fr; }
  .value-row p { grid-column: 2; }
}

/* ---------------------------------------------------------------------------
   Explore cards (schedule / team)
   ------------------------------------------------------------------------- */
.explore-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-6);
}
@media (max-width: 860px) { .explore-grid { grid-template-columns: 1fr; } }

.explore-card { display: block; color: var(--l-text); text-decoration: none; }
.explore-card:hover { text-decoration: none; }
.explore-card .media-frame { aspect-ratio: 16 / 10; }
.explore-card .media-frame img { transition: transform var(--dur-slow) var(--ease-out); }
.explore-card:hover .media-frame img { transform: scale(1.035); }
.explore-card__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding-block: var(--space-4);
  border-bottom: 1px solid var(--l-line);
}
.explore-card__bar h3 { margin: 0; font-size: var(--step-2); color: var(--d-bg); }
.explore-card__bar .btn__circle {
  background: var(--accent-soft);
  color: var(--accent-700);
  width: 2.2em; height: 2.2em;
}
.explore-card:hover .btn__circle { transform: translateX(3px); background: var(--accent-500); color: var(--ink); }
.explore-card p { color: var(--l-muted); margin: var(--space-3) 0 0; font-size: var(--step--1); }

/* ---------------------------------------------------------------------------
   Long-form article (About)
   ------------------------------------------------------------------------- */
.about-wide { aspect-ratio: 21 / 9; }
@media (max-width: 700px) { .about-wide { aspect-ratio: 16 / 10; } }
.article { max-width: 70ch; }
.article p { max-width: none; }
.pull-quote {
  font-family: var(--font-display);
  font-size: var(--step-3);
  text-transform: uppercase;
  line-height: var(--leading-snug);
  color: var(--d-bg);
  border-left: 3px solid var(--accent-500);
  padding: var(--space-2) 0 var(--space-2) var(--space-6);
  margin: var(--space-8) 0;
  max-width: 24ch;
}

/* One documentary photo inside the About article. Deliberately INSET rather
   than full-column: it is a candid phone shot of the room mid-gut, and the
   smaller left-flush frame reads archival instead of asking a hand-held
   photo to carry a hero's weight. tone--keep because the shot is already
   black and white — the full .tone filter would only crush it further. */
.article-figure {
  margin: var(--space-9) 0;
  max-width: 34rem;
}
.article-figure .media-frame { aspect-ratio: 4 / 5; }
.article-figure figcaption {
  margin-top: var(--space-3);
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--l-muted);
}

/* ---------------------------------------------------------------------------
   Contact band (bottom of Home, per client brief)
   ------------------------------------------------------------------------- */
.contact-band { text-align: left; }
.contact-band__links {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: var(--space-7);
}
.contact-band__mail {
  font-family: var(--font-display);
  font-size: var(--step-3);
  text-transform: lowercase;
  color: var(--accent-500);
  word-break: break-all;
  display: inline-block;
  margin-bottom: var(--space-4);
  border-bottom: 3px solid color-mix(in srgb, var(--accent-500) 40%, transparent);
  padding-bottom: var(--space-2);
  transition: border-color var(--dur) var(--ease-out), color var(--dur) var(--ease-out);
}
.contact-band__mail:hover {
  text-decoration: none;
  color: var(--accent-300);
  border-bottom-color: var(--accent-500);
}

/* ---------------------------------------------------------------------------
   Footer — brand black, PAGES / CONNECT columns + CTA (mockup)
   ------------------------------------------------------------------------- */
.site-foot {
  background: var(--ink);
  color: #c9c5b4;
  padding-block: var(--space-8) var(--space-5);
  font-size: var(--step--1);
}
.site-foot a { color: #c9c5b4; }
.site-foot a:hover { color: var(--accent-300); }
.site-foot__grid {
  display: grid;
  grid-template-columns: 1.2fr 0.8fr 1.2fr auto;
  gap: var(--space-8);
  align-items: start;
  padding-bottom: var(--space-7);
  border-bottom: 1px solid color-mix(in srgb, #EDEADD 14%, transparent);
  margin-bottom: var(--space-5);
}
@media (max-width: 900px) { .site-foot__grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 560px) { .site-foot__grid { grid-template-columns: 1fr; gap: var(--space-6); } }
.site-foot__brand img { height: 180px; width: auto; max-width: 100%; object-fit: contain; }
.site-foot__col { display: grid; gap: var(--space-3); justify-items: start; }
.site-foot__col a { font-size: var(--step--1); }
.site-foot__head {
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--accent-500);
  margin-bottom: var(--space-2);
}
.site-foot__item {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
}
.site-foot__item svg {
  width: 18px; height: 18px;
  flex: none;
  color: var(--accent-500);
  margin-top: 3px;
}
.site-foot__sub {
  display: block;
  margin-top: var(--space-1);
  color: var(--d-muted);
  font-size: var(--step--2);
}
.site-foot__legal {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  justify-content: space-between;
  align-items: center;
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: 0.04em;
  color: #7d796a;
}
.site-foot__lang {
  display: inline-flex;
  gap: var(--space-3);
  font-family: var(--font-mono);
  text-transform: uppercase;
}
.site-foot__lang a[aria-current="true"] {
  color: var(--d-text);
  text-decoration: underline;
  text-underline-offset: 4px;
  text-decoration-color: var(--accent-500);
}

/* ---------------------------------------------------------------------------
   Plan ledger — memberships read as a weigh-in sheet, not three SaaS pricing
   cards. Deliberately the same numbered-row language as .value-row on Home.
   ------------------------------------------------------------------------- */
.plan-list { border-top: 1px solid var(--l-line); }
/* Amateur Team page stacks a class list and a single plan row */
.class-list + .plan-list { margin-top: var(--space-7); }

.plan-row {
  display: grid;
  grid-template-columns: 3.5rem minmax(0, 1fr) auto minmax(8rem, auto);
  gap: var(--space-5);
  align-items: center;
  padding-block: var(--space-6);
  border-bottom: 1px solid var(--l-line);
  transition: background-color var(--dur) var(--ease-out),
              padding-left var(--dur) var(--ease-out);
}
.plan-row:hover {
  background: color-mix(in srgb, var(--accent-500) 7%, transparent);
  padding-left: var(--space-3);
}
/* Coach-gated plan (Amateur Team): no price, no join link. Collapse the price
   and action tracks, otherwise the empty minmax(8rem,…) column leaves a gap on
   the right and squeezes the name. Declared before the 900px block on purpose,
   so the mobile two-column rule still overrides it. */
.plan-row--coach-gated { grid-template-columns: 3.5rem minmax(0, 1fr) auto; }
/* No description follows the name in a coach-gated row, so the name's
   bottom margin would hang as dead space under it. */
.plan-row--coach-gated .plan-row__name { margin-bottom: 0; }
/* The 14ch measure is sized for "Sign up at the gym"; this line is longer
   and breaks into three cramped lines at that width. */
.plan-row--coach-gated .plan-row__instore { max-width: 24ch; }
.plan-row__name { margin: 0 0 var(--space-2); font-size: var(--step-2); color: var(--d-bg); }
.plan-row__desc { margin: 0; font-size: var(--step--1); color: var(--l-muted); max-width: 54ch; }

/* Price lockup — display face for the number, mono for the unit beneath it */
.price {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--step-3);
  line-height: 1;
  color: var(--d-bg);
  white-space: nowrap;
}
.price__unit {
  display: block;
  margin-top: var(--space-2);
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--l-muted);
}
.plan-row__action { justify-self: end; }

/* Plans Mindbody can't sell online — say where to get them, don't fake a CTA */
.plan-row__instore {
  margin: 0;
  justify-self: end;
  max-width: 14ch;
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  line-height: 1.6;
  text-align: right;
  color: var(--l-muted);
}

@media (max-width: 900px) {
  .plan-row {
    grid-template-columns: 2.5rem minmax(0, 1fr);
    gap: var(--space-4);
    align-items: start;
  }
  .plan-row > .index { grid-column: 1; grid-row: 1; }
  .plan-row__body { grid-column: 2; grid-row: 1; }
  .plan-row .price,
  .plan-row__action,
  .plan-row__instore { grid-column: 2; justify-self: start; text-align: left; max-width: none; }
  .plan-row .price { display: flex; align-items: baseline; gap: var(--space-3); }
  .plan-row .price__unit { margin-top: 0; }
}

/* Tax / fine-print line under a price block. max-width:none because the
   global p measure (62ch) is far too narrow for uppercase mono. */
.fine-print {
  max-width: none;
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--l-muted);
  margin-top: var(--space-6);
}
.section--dark .fine-print { color: var(--d-muted); }

/* ---------------------------------------------------------------------------
   Packages & drop-ins — card grid on green, pace contrast against the ledger
   ------------------------------------------------------------------------- */
.pack-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  gap: var(--space-5);
}
/* Column, not auto-rows: every card leads with tag + price so the numbers line
   up across the row however the names wrap, and margin-top:auto pins the CTAs
   to a common baseline. */
.pack {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-6);
  background: var(--d-surface);
  border: 1px solid var(--d-line);
  border-radius: var(--radius-md);
  transition: transform var(--dur) var(--ease-out),
              background-color var(--dur) var(--ease-out),
              border-color var(--dur) var(--ease-out);
}
.pack:hover {
  transform: translateY(-3px);
  background: var(--d-surface-2);
  border-color: color-mix(in srgb, var(--accent-500) 50%, transparent);
}
.pack--feature { border-color: var(--accent-500); }
.pack__tag {
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--accent-300);
}
.pack__name { margin: 0; font-size: var(--step-2); color: var(--d-text); }
.pack__price {
  margin: 0;
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  font-family: var(--font-display);
  font-size: var(--step-4);
  line-height: 1;
  color: var(--accent-300);
}
.pack__price span {
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--d-muted);
}
.pack__desc { margin: 0; font-size: var(--step--1); color: var(--d-muted); }
.pack .btn { margin-top: auto; }

/* ---------------------------------------------------------------------------
   Class list — spec-sheet rows: what the class is, left; when it runs, right
   ------------------------------------------------------------------------- */
.class-list { border-top: 1px solid var(--l-line); }

/* Stands in for the per-class times that used to sit in each row (removed
   2026-08-31). Sits between the annot line and the list, so the annot line's
   own bottom margin tightens when it's present. */
.class-list-note {
  margin: 0 0 var(--space-5);
  max-width: 62ch;
  font-size: var(--step--1);
  line-height: 1.6;
  color: var(--l-text);
}
.annot-line:has(+ .class-list-note) { margin-bottom: var(--space-5); }
/* Times used to sit in a right-hand rail. The client changes the weekly
   schedule often, so the times came out (2026-08-31) and the live Mindbody
   widget is now the only place they live. The name moved into the left rail
   so the row keeps its two-column rhythm instead of reading as a gutted
   one-column list. */
.class-item {
  display: grid;
  grid-template-columns: minmax(0, 17rem) minmax(0, 1fr);
  gap: var(--space-4) var(--space-7);
  align-items: start;
  padding-block: var(--space-6);
  border-bottom: 1px solid var(--l-line);
}
.class-item__name { margin: 0; font-size: var(--step-2); line-height: 1.15; color: var(--d-bg); }
.class-item__desc { margin: 0; color: var(--l-muted); font-size: var(--step--1); max-width: 62ch; }
@media (max-width: 800px) {
  .class-item { grid-template-columns: 1fr; gap: var(--space-3); }
}

/* ---------------------------------------------------------------------------
   Offer card — the real intro offer, replaces the dashed Mindbody slot on Home
   ------------------------------------------------------------------------- */
.offer-card {
  border: 1px solid color-mix(in srgb, var(--accent-500) 55%, transparent);
  border-radius: var(--radius-md);
  background: color-mix(in srgb, var(--accent-500) 8%, transparent);
  padding: var(--space-7) var(--space-6);
  display: grid;
  gap: var(--space-4);
  justify-items: start;
}
.offer-card__price {
  font-family: var(--font-display);
  font-size: var(--step-5);
  line-height: 1;
  color: var(--accent-300);
}
.offer-card__price span {
  font-family: var(--font-mono);
  font-size: var(--step--1);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--d-muted);
  margin-left: var(--space-3);
}
.offer-card__name {
  font-family: var(--font-mono);
  font-size: var(--step--1);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--d-text);
  margin: 0;
}
.offer-card__desc { margin: 0; color: var(--d-muted); font-size: var(--step--1); max-width: 40ch; }
.offer-card__note { margin: var(--space-2) 0 0; color: var(--d-muted); font-size: var(--step--2); max-width: 40ch; opacity: .8; }

/* ---------------------------------------------------------------------------
   Legal / policy prose — utility pages (privacy)
   Deliberately quieter than the marketing pages. Graduate at --step-4 across a
   dozen section headings shouts and destroys scannability, and a policy gets
   scanned for one answer, never read start to finish. So headings drop to
   Poppins and take a mono index from the annotation layer instead — still the
   industrial-microlabel voice, without the collegiate slab.
   Body copy carries NO .reveal on purpose: nobody should have to scroll-trigger
   their way through a privacy policy, and it keeps the page readable if the
   scroll-timeline animation ever misfires.
   ------------------------------------------------------------------------- */
.legal { max-width: 74ch; counter-reset: legal-section; }
.legal p, .legal li { max-width: none; line-height: var(--leading-normal); }

.legal__meta {
  font-family: var(--font-mono);
  font-size: var(--step--1);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--l-muted);
  border-bottom: 1px solid var(--l-line);
  padding-bottom: var(--space-4);
  margin-bottom: var(--space-7);
}

/* Jump list — a policy is a lookup document, so give it an index. */
.legal__toc {
  border-left: 3px solid var(--accent-500);
  padding: var(--space-2) 0 var(--space-2) var(--space-5);
  margin: 0 0 var(--space-8);
}
.legal__toc ol {
  list-style: none;
  margin: 0;
  padding: 0;
  columns: 2;
  column-gap: var(--space-6);
}
.legal__toc li { margin: 0 0 var(--space-2); break-inside: avoid; }
.legal__toc a {
  font-size: var(--step--1);
  color: var(--l-text);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: border-color 160ms ease, color 160ms ease;
}
.legal__toc a:hover { color: var(--accent-800); border-bottom-color: var(--accent-500); }

.legal section { margin: 0 0 var(--space-8); scroll-margin-top: calc(var(--nav-h) + var(--space-4)); }

.legal h2 {
  counter-increment: legal-section;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: var(--step-2);
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-tight);
  text-transform: none;
  margin: 0 0 var(--space-4);
}
.legal h2::before {
  content: counter(legal-section, decimal-leading-zero);
  display: block;
  font-family: var(--font-mono);
  font-size: var(--step--2);
  font-weight: 400;
  letter-spacing: var(--tracking-wide);
  color: var(--accent-800);
  margin-bottom: var(--space-2);
}
.legal h3 {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: var(--step-0);
  text-transform: none;
  letter-spacing: var(--tracking-tight);
  margin: var(--space-6) 0 var(--space-3);
}

/* Underlined, not colour-only — colour alone is not an accessible link cue
   inside a wall of body text. accent-800 because 700 misses AA on cream
   below 18px (see the ramp comment up top). */
.legal a:not(.btn) {
  color: var(--accent-800);
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-thickness: 1px;
}
.legal a:not(.btn):hover { text-decoration-thickness: 2px; }

.legal ul { list-style: none; margin: 0 0 var(--space-4); padding: 0; }
.legal ul li { position: relative; padding-left: var(--space-5); margin-bottom: var(--space-3); }
.legal ul li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.7em;
  width: 8px;
  height: 1px;
  background: var(--accent-600);
}

/* Contact/rights callout — the one block people actually come here to find. */
.legal__callout {
  background: var(--l-surface);
  border: 1px solid var(--l-line);
  border-left: 3px solid var(--accent-500);
  border-radius: var(--radius-sm);
  padding: var(--space-5) var(--space-6);
  margin: var(--space-6) 0;
}
.legal__callout > :last-child { margin-bottom: 0; }

@media (max-width: 640px) {
  .legal__toc ol { columns: 1; }
}

/* ---------------------------------------------------------------------------
   Coach deck — /private-training.html
   A scroll-snap track, NOT a JS carousel. The track works with zero JS (swipe
   or scroll), so the page degrades to a readable, fully-navigable list; the
   arrows and dots are progressive enhancement and stay [hidden] until main.js
   removes the attribute. Cards are plain <li> in a <ul> that carries no ARIA
   role, so a screen reader announces "list, 4 items" rather than a bespoke
   widget — adding role="group" here silently costs that item count.
   ------------------------------------------------------------------------- */
.deck-wrap { position: relative; }

.deck {
  display: flex;
  gap: var(--space-5);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  /* Side padding lets the first and last card sit centred like the middle ones,
     which is what makes neighbours "peek" at both ends of the track. */
  padding-inline: max(var(--gutter), calc((100% - 60rem) / 2));
  /* Vertical padding has to clear the scaled-up active card, or the depth
     effect clips against the scrollport edge. */
  padding-block: var(--space-6) var(--space-7);
  margin: 0;
  list-style: none;
  scrollbar-width: none;
}
.deck::-webkit-scrollbar { display: none; }
.deck:focus-visible { outline: 2px solid var(--accent-500); outline-offset: 4px; }

/* .coach is the SNAP TARGET and must never be transformed.
   A scroll-snap area is the element's *transformed* border box, so animating
   the snap target's own transform feeds back into snapping: scroll moves the
   card → the card scales → its snap area moves → the browser snaps somewhere
   else. That is exactly what happened here — the snap point for card 2 landed
   at 374 instead of 439 and the error compounded per card. So the depth
   transform lives on .coach-inner, and .coach only ever changes z-index
   (which has no effect on layout or snap geometry).

   No negative margin either, for the same family of reason: overlapping the
   layout boxes desynced snapping from the centring maths in main.js. */
.coach {
  scroll-snap-align: center;
  flex: 0 0 min(60rem, 84vw);
  display: flex;
  /* Without this, min-width:auto lets the grid's min-content push individual
     cards past their flex-basis and they come out different widths. */
  min-width: 0;
  position: relative;
  z-index: 1;
  /* Perspective sits here, not on .deck, so it applies to this card's own
     direct child. Origin is then each card's centre, so a receding card sinks
     straight back instead of skewing toward the scrollport centre. */
  perspective: 2200px;
}
.coach-inner {
  flex: 1;
  display: grid;
  grid-template-columns: minmax(13rem, 20rem) 1fr;
  background: var(--l-bg);
  border: 1px solid var(--l-line);
  border-radius: var(--radius-md);
  overflow: hidden;
  box-shadow: var(--shadow-lg);
}

/* Monogram plate — deliberate stand-in, not filler. No headshots exist yet and
   we don't fabricate faces for real, named people. Same aspect box a real
   portrait will occupy, so the swap is 1:1: drop an <img> in, delete .coach-plate. */
.coach-plate {
  position: relative;
  background: #10240f;
  border-right: 1px solid var(--l-line);
  min-height: 100%;
  display: grid;
  place-items: center;
  padding: var(--space-6);
  overflow: hidden;
}
.coach-plate img {
  position: absolute;
  width: 82%;
  max-width: 260px;
  opacity: 0.16;
  filter: grayscale(1) brightness(1.7);
}
.coach-plate__initial {
  position: relative;
  font-family: var(--font-display);
  font-size: clamp(6rem, 15vw, 10rem);
  line-height: var(--leading-solid);
  color: color-mix(in srgb, var(--d-text) 82%, transparent);
  letter-spacing: var(--tracking-display);
}
.coach-plate__pending {
  position: absolute;
  bottom: var(--space-4);
  left: 0; right: 0;
  text-align: center;
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: color-mix(in srgb, var(--accent-300) 74%, transparent);
}

.coach-body { padding: var(--space-7) var(--space-6); }
.coach-role {
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--accent-800);
  margin: 0 0 var(--space-2);
}
.coach-name {
  font-size: var(--step-4);
  line-height: var(--leading-solid);
  margin: 0 0 var(--space-4);
}
.coach-body p { font-size: var(--step--1); color: var(--l-muted); margin-bottom: var(--space-4); }
.coach-body p:last-of-type { margin-bottom: var(--space-5); }

/* Facts, in the site's own microlabel language rather than a new icon set —
   the site has no icon vocabulary and adding one would break its minimal chrome. */
.coach-facts {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-3);
  margin: 0 0 var(--space-6);
  padding: 0;
  list-style: none;
}
.coach-facts li {
  border: 1px solid var(--l-line);
  border-left: 2px solid var(--accent-600);
  border-radius: var(--radius-xs);
  padding: var(--space-3) var(--space-4);
  background: var(--l-surface);
}
.coach-facts b {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--step--1);
  font-weight: 500;
  color: var(--l-text);
}
.coach-facts span {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--l-muted);
  margin-top: 2px;
}
.coach-cta { display: flex; flex-wrap: wrap; gap: var(--space-3); }

/* Light island inside .section--dark.
   The dark-section descendant rules (inherited heading colour, `a`,
   `.link-arrow`, `.btn--outline`) all target elements inside this cream card
   and render them cream-on-cream — the name and the "View schedule" link both
   measured 1.00:1 before this block, i.e. literally invisible, and the CTA
   1.45:1. Specificity here has to beat `.section--dark <x>` (0,2,0), hence the
   three-class selectors. The cards also carry `.on-light` in the markup, which
   is the site's existing marker for this situation and fixes .btn--outline. */
.coach-name { color: var(--l-text); }
.section--dark .coach .coach-role { color: var(--accent-800); }
.section--dark .coach .coach-facts b { color: var(--l-text); }
.section--dark .coach .coach-facts span { color: var(--l-muted); }
.section--dark .coach .link-arrow { color: var(--l-text); }
.section--dark .coach .link-arrow:hover { color: var(--accent-700); }
/* The plate stays dark, so its own text keeps the cream/gold treatment. */
.section--dark .coach .coach-plate__initial { color: color-mix(in srgb, var(--d-text) 82%, transparent); }
.section--dark .coach .coach-plate__pending { color: color-mix(in srgb, var(--accent-300) 74%, transparent); }

/* Controls — square and hairline, matching the sharp radius personality.
   [hidden] until JS removes it, so no-JS users never see dead buttons. */
.deck-controls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-4);
  margin-top: var(--space-2);
}
.deck-controls[hidden] { display: none; }
.deck-arrow {
  flex: none;
  width: 44px; height: 44px;
  display: grid;
  place-items: center;
  background: transparent;
  color: var(--d-text);
  border: 1px solid var(--accent-ring);
  border-radius: var(--radius-xs);
  cursor: pointer;
  transition: background-color var(--dur) var(--ease-out), border-color var(--dur) var(--ease-out);
}
.deck-arrow:hover:not(:disabled) { background: var(--accent-soft); border-color: var(--accent-500); }
.deck-arrow:disabled { opacity: 0.32; cursor: default; }
.deck-arrow svg { width: 18px; height: 18px; }
.deck-dots { display: flex; gap: var(--space-2); }
.deck-dot {
  width: 22px; height: 4px;
  padding: 0;
  border: 0;
  border-radius: 1px;
  background: color-mix(in srgb, var(--d-text) 26%, transparent);
  cursor: pointer;
  transition: background-color var(--dur) var(--ease-out), width var(--dur) var(--ease-out);
}
.deck-dot[aria-current="true"] { background: var(--accent-500); width: 40px; }
/* The 4px bar is the visual; this pad restores a 44px touch target around it. */
.deck-dot { position: relative; }
.deck-dot::after { content: ''; position: absolute; inset: -20px -4px; }

/* The teaser control. Hidden by default and switched on only inside the phone
   breakpoint, where the clamp it operates actually exists. */
.bio-more {
  display: none;
  margin: 0 0 var(--space-4);
  padding: var(--space-2) 0;
  background: none;
  border: 0;
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--accent-800);
  text-decoration: underline;
  text-decoration-color: var(--accent-600);
  text-underline-offset: 4px;
  cursor: pointer;
}
.bio-more:hover { color: var(--accent-700); }

/* 860px — the card collapses to one column. This is the rule that was broken:
   it used to target `.coach`, which is a flex CONTAINER, so
   `grid-template-columns` did nothing there and `.coach-inner` kept its
   `minmax(13rem, 20rem) 1fr` all the way down, leaving the bio a 104px column
   that clipped mid-word at 375px. The grid lives on `.coach-inner`.

   The TRACK stays a track. That only works because the card is also cut down to
   fit one screen here — plate at 2:1, tighter padding, facts two-up, and the
   bio showing a three-line teaser behind `.bio-more`. Measured at 375x812 that
   is ~670px against 719px of usable height below the sticky nav. If a future
   edit lets the card grow past the viewport again, the carousel breaks in a
   specific way worth knowing: horizontal and vertical scroll are independent,
   so tapping the arrow from the bottom of one card lands you at the bottom of
   the next, with that coach's portrait and name off-screen above. Keep it
   inside a screen. */
@media (max-width: 860px) {
  .deck {
    padding-inline: var(--gutter);
    padding-block: var(--space-5) var(--space-6);
  }
  .coach { flex-basis: 86vw; }
  .coach-inner { grid-template-columns: 1fr; }
  .coach-plate {
    /* 2:1 rather than the 3:2 a portrait wants, because height is the scarce
       thing here. When the real headshots land this is the one value to revisit
       — with the teaser collapsed there is room to go back toward 3:2. */
    aspect-ratio: 2 / 1;
    min-height: 0;
    border-right: 0;
    border-bottom: 1px solid var(--l-line);
  }
  /* Tracks the plate, which is now as wide as the card. The desktop size is
     tuned to a 20rem column and reads as a small mark adrift in this box. */
  .coach-plate__initial { font-size: clamp(3.5rem, 20vw, 9rem); }
  .coach-body { padding: var(--space-5); }
  .coach-facts {
    grid-template-columns: 1fr 1fr;
    gap: var(--space-2);
    margin-bottom: var(--space-5);
  }
  .coach-facts li { padding: var(--space-2) var(--space-3); }
  /* The secondary link goes, not the button: "See this week's schedule" is
     already the CTA of the section immediately below the deck, so on a phone it
     is the same link twice within one screen. */
  .coach-cta .link-arrow { display: none; }
  .bio-more { display: inline-block; }

  /* Clamped only under .deck--clamp, which main.js adds. Without JS there is no
     control to expand with, so the full bio renders and the card is simply
     taller — the same "works with zero JS" bargain the arrows and dots make. */
  .deck--clamp .coach-bio > p { margin-bottom: 0; }
  .deck--clamp .coach-bio > p ~ p { display: none; }
  .deck--clamp .coach-bio > p:first-child {
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }
  .deck--clamp .coach.is-open .coach-bio > p {
    display: block;
    margin-bottom: var(--space-4);
  }
  .deck--clamp .coach.is-open .coach-bio > p:first-child { -webkit-line-clamp: none; }
  /* Cards are stretched to a common height so nothing jumps as you swipe. That
     has to give the moment one is expanded, or every card in the track inherits
     the open one's height and the controls get pushed a screen away. */
  .deck--open { align-items: start; }
}

/* The deck effect from the client's mockup: the centred card comes forward and
   the neighbours fall back behind it. Driven by the card's own position in the
   scrollport (`view(x)`) — the same scroll-driven technique .reveal already
   uses, on the inline axis — so it tracks a swipe or a drag continuously
   rather than only settling on snap.

   Only transform, opacity and z-index animate. The first two are
   compositor-friendly; z-index interpolates discretely, which is what lifts
   the active card's stacking above the two it overlaps.

   Guarded to no-preference: under reduced motion the global block collapses
   animation-duration, which can strand a card mid-recede. Without the guard
   the fallback is every card flat, full-size and legible — which is correct.

   Runs at every width, phones included, because the track stays horizontal at
   every width. The one thing it depends on is a real horizontal scrollport for
   `view(x)` to read; if the deck is ever turned into a vertical stack again,
   this block has to be scoped away from that width, or a card can strand at
   translateZ(-460px)/opacity .3 and be unreadable. */
@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view(x)) {
    /* The timeline is NAMED on .coach and consumed by its child. Declaring it
       here (rather than `animation-timeline: view(x)` on .coach-inner) keeps
       the measured subject the untransformed snap target, so the timeline
       can't be perturbed by the very transform it drives. */
    /* Range is left at the default (`cover`), deliberately. An
       `entry …% exit …%` range assumes the subject is small relative to the
       scrollport; these cards are ~84% of it, which squeezes the entry/exit
       phases and skews the mapping — progress read 207% while a card was
       merely one step off-centre. Over `cover`, 50% is exactly the moment the
       card's centre meets the scrollport centre, which is the state we want. */
    .coach {
      view-timeline: --coach-card x;
      animation: coach-stack linear both;
      animation-timeline: --coach-card;
    }
    .coach-inner {
      animation: coach-focus linear both;
      animation-timeline: --coach-card;
      transform-origin: 50% 50%;
      will-change: transform, opacity;
    }
    /* z-index only — no layout or snap-geometry effect. Lifts the centred
       card above the two receding ones where their projections cross. */
    @keyframes coach-stack {
      0%, 100% { z-index: 1; }
      40%, 60% { z-index: 3; }
    }
    @keyframes coach-focus {
      0% {
        opacity: 0.3;
        transform: translateZ(-460px);
      }
      40%, 60% {
        opacity: 1;
        transform: translateZ(0);
      }
      100% {
        opacity: 0.3;
        transform: translateZ(-460px);
      }
    }
  }
}

/* ---------------------------------------------------------------------------
   Reduced motion — kills everything cleanly
   ------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  .reveal, .hero [data-hero] { opacity: 1 !important; transform: none !important; }
}
