/* ==========================================================================
   Flawless Gymnastics — flawlessrhythmic.com
   Plain CSS, no build step. Uses 2026-Baseline features: cascade layers,
   native nesting, oklch(), container queries, :has(), and scroll-driven
   animations behind @supports (Firefox has not shipped those — the site is
   complete and readable without them).

   Palette sampled from the client's real logo files 2026-08-24.
   CONTRAST RULE: --pink fails WCAG on cream (2.35:1) and white fails on
   --pink (2.59:1). --pink is for fills, rules and decorative art only.
   All text and buttons use --pink-deep (5.66:1 on white, 5.14:1 on cream).
   ========================================================================== */

@layer reset, tokens, base, layout, components, utilities;

@layer reset {
  *, *::before, *::after { box-sizing: border-box; }
  * { margin: 0; }
  html { -webkit-text-size-adjust: 100%; }
  body { -webkit-font-smoothing: antialiased; }
  img, picture, svg { display: block; max-width: 100%; }
  /* Let width/aspect-ratio drive sizing. Without this, the HTML height
     attribute is a used value and aspect-ratio is silently ignored.
     Applies to <video> for exactly the same reason — a 1024-tall attribute
     stretched the 9:16 players into 9:30 letterboxes. */
  img, video { height: auto; }
  button, input, select, textarea { font: inherit; color: inherit; }
  h1, h2, h3, h4 { text-wrap: balance; }
  p, li { text-wrap: pretty; }
}

@layer tokens {
  :root {
    /* Brand — verified from assets/logo-*.jpg */
    --cream: #F5F4F0;
    --pink: #FF70A6;
    --pink-deep: #C41E63;
    --ink: #2B2422;

    --cream-warm: color-mix(in oklab, var(--cream) 92%, var(--pink) 8%);
    --cream-deep: color-mix(in oklab, var(--cream) 84%, var(--pink) 16%);
    --ink-soft: color-mix(in oklab, var(--ink) 72%, var(--cream) 28%);
    --rule: color-mix(in oklab, var(--pink) 28%, var(--cream) 72%);
    /* A stronger rule for borders that need to read as an edge, not a hint.
       This was USED in two places before it was ever DEFINED, so both
       borders silently computed to `0px none`: an undefined var() makes the
       whole declaration invalid at computed-value time. */
    --rule-strong: color-mix(in oklab, var(--pink) 45%, var(--cream) 55%);
    /* SRG Academy's own mark is gold. MEASURED: #C6B299 is 1.87:1 on cream —
       it FAILS as text there, exactly like --pink. Gold is decorative, or
       text on --ink only (7.42:1). */
    --gold: #C6B299;

    /* Program accents, taken from the client's own schedule graphics */
    --a-little-stars: #E8407C;
    --a-recreational: #7B3FA0;
    --a-preteam:      #2C74C4;
    --a-l3:           #3E9B4F;
    --a-l4:           #C8912E;
    --a-l5:           #D2662A;
    --a-l67:          #7B4FA8;

    --serif: "Playfair Display", "Didot", "Bodoni MT", Georgia, serif;
    --sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;

    /* Fluid type — 320px to 1280px viewport */
    --step--1: clamp(0.83rem, 0.79rem + 0.2vw, 0.94rem);
    --step-0:  clamp(1rem, 0.95rem + 0.25vw, 1.13rem);
    --step-1:  clamp(1.2rem, 1.11rem + 0.44vw, 1.5rem);
    --step-2:  clamp(1.44rem, 1.28rem + 0.8vw, 2rem);
    --step-3:  clamp(1.73rem, 1.45rem + 1.4vw, 2.66rem);
    --step-4:  clamp(2.07rem, 1.6rem + 2.36vw, 3.55rem);
    --step-5:  clamp(2.49rem, 1.71rem + 3.9vw, 4.74rem);

    --gutter: clamp(1.25rem, 4vw, 2.5rem);
    --measure: 62ch;
    --wrap: 1180px;
    --radius: 1.25rem;

    --shadow-sm: 0 1px 2px oklch(0 0 0 / .04), 0 4px 12px oklch(0 0 0 / .05);
    --shadow-md: 0 2px 4px oklch(0 0 0 / .05), 0 12px 32px oklch(0 0 0 / .08);

    --ease: cubic-bezier(.22, .61, .36, 1);
  }
}

@layer base {
  html { scroll-behavior: smooth; }

  body {
    background: var(--cream);
    color: var(--ink);
    font-family: var(--sans);
    font-size: var(--step-0);
    line-height: 1.65;
  }

  h1, h2, h3 {
    font-family: var(--serif);
    font-weight: 500;
    line-height: 1.08;
    letter-spacing: -0.015em;
  }

  a { color: var(--pink-deep); text-underline-offset: 0.2em; }
  a:hover { text-decoration-thickness: 2px; }

  :focus-visible {
    outline: 3px solid var(--pink-deep);
    outline-offset: 3px;
    border-radius: 4px;
  }

  ::selection { background: var(--pink); color: #fff; }

  .skip {
    position: absolute;
    inset-inline-start: -9999px;
    top: 0;
    z-index: 100;
    background: var(--pink-deep);
    color: #fff;
    padding: 0.75rem 1.25rem;
    border-radius: 0 0 8px 0;

    &:focus { inset-inline-start: 0; }
  }

  @media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    *, *::before, *::after {
      animation-duration: .01ms !important;
      animation-iteration-count: 1 !important;
      transition-duration: .01ms !important;
    }
  }
}

@layer layout {
  .wrap {
    width: min(100% - (var(--gutter) * 2), var(--wrap));
    margin-inline: auto;
  }

  .section {
    padding-block: clamp(3.5rem, 9vw, 7rem);
    position: relative;
  }

  .section-head {
    text-align: center;
    margin-bottom: clamp(2rem, 5vw, 3.5rem);

    & .eyebrow { margin-bottom: 0.75rem; }
    & > p {
      max-width: 52ch;
      margin-inline: auto;
      margin-top: 1rem;
      color: var(--ink-soft);
    }
  }

}

@layer components {

  /* ---------- Buttons ---------- */
  .btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    padding: 0.9rem 1.6rem;
    border-radius: 999px;
    border: 2px solid transparent;
    font-weight: 600;
    font-size: var(--step-0);
    text-decoration: none;
    cursor: pointer;
    transition: transform .2s var(--ease), background-color .2s var(--ease),
                box-shadow .2s var(--ease);

    &:hover { transform: translateY(-2px); }
    &:active { transform: translateY(0); }
  }

  .btn--primary {
    background: var(--pink-deep);
    color: #fff;
    box-shadow: var(--shadow-sm);

    &:hover {
      background: color-mix(in oklab, var(--pink-deep) 88%, #000 12%);
      box-shadow: var(--shadow-md);
    }
  }

  .btn--ghost {
    border-color: var(--pink-deep);
    color: var(--pink-deep);
    background: transparent;

    &:hover { background: color-mix(in oklab, var(--pink) 12%, transparent); }
  }

  .btn--sm { padding: 0.6rem 1.15rem; font-size: var(--step--1); }

  /* ---------- Header ---------- */
  .site-header {
    position: sticky;
    top: 0;
    z-index: 50;
    background: color-mix(in oklab, var(--cream) 88%, transparent);
    backdrop-filter: blur(12px) saturate(1.4);
    border-bottom: 1px solid transparent;
    transition: border-color .3s var(--ease);

    /* Draws a hairline only once the page has scrolled */
    @supports (animation-timeline: scroll()) {
      animation: header-line steps(1) both;
      animation-timeline: scroll(root block);
      animation-range: 20px 21px;
    }
  }

  @keyframes header-line {
    to { border-bottom-color: var(--rule); }
  }

  .site-header > .wrap {
    display: flex;
    align-items: center;
    gap: 1rem;
    min-height: 4.5rem;

    /* The header carries nine items and the wordmark; the 1180px content
       measure is 44px too narrow for that row, and no viewport width helps
       because .wrap is capped. The header alone gets a wider measure. */
    --wrap: 78rem;
  }

  .brand {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    min-height: 44px;
    min-width: 0;

    @media (width >= 79rem) { flex: none; }
    text-decoration: none;
    color: var(--ink);
    margin-inline-end: auto;

    & img { width: 42px; height: 42px; border-radius: 50%; }

    & b {
      font-family: var(--serif);
      font-size: clamp(1.05rem, 0.9rem + 0.5vw, 1.3rem);
      font-weight: 600;
      line-height: 1.05;
      letter-spacing: 0.01em;

      /* Only the desktop row needs a single line; on a phone it may wrap. */
      @media (width >= 79rem) { white-space: nowrap; }
    }
    & span {
      display: block;
      font-size: 0.63rem;
      letter-spacing: 0.18em;
      text-transform: uppercase;
      color: var(--ink-soft);
      margin-top: 2px;
    }
  }

  .nav {
    display: flex;
    align-items: center;
    gap: clamp(0.6rem, 1.1vw, 1.05rem);

    & a {
      text-decoration: none;
      color: var(--ink);
      font-size: 0.82rem;
      font-weight: 500;
      letter-spacing: 0.005em;
      display: inline-flex;
      align-items: center;
      min-height: 44px;
      /* Eight items in one row will squeeze until labels break across two
         lines ("Program and / Schedule"), which reads as clutter. In the
         vertical popover the opposite is true — labels must be free to wrap. */
      @media (width >= 79rem) {
        white-space: nowrap;
        flex: none;
      }

      &:hover { color: var(--pink-deep); }
      &[aria-current="page"] {
        color: var(--pink-deep);
        text-decoration: underline;
        text-decoration-thickness: 2px;
        text-underline-offset: 0.35em;
      }
    }
  }

  .nav-toggle { display: none; }

  /* Mobile nav uses the native popover API — zero JavaScript.
     Threshold is 79rem, not 78: at a viewport of exactly 78rem the header
     .wrap loses its gutters out of that same 78rem, so the row spilled 14px
     past the content column. With nine items the row needs ~1175px, so anything
     narrower squeezes labels or overflows. Below this everything lives in the
     popover, which holds any number of items comfortably. */
  @media (width < 79rem) {
    .nav-toggle {
      display: inline-flex;
      align-items: center;
      gap: 0.5rem;
      background: transparent;
      border: 1px solid var(--rule);
      border-radius: 999px;
      padding: 0.5rem 0.95rem;
      min-height: 44px;
      font-size: var(--step--1);
      font-weight: 600;
      color: var(--ink);
      cursor: pointer;
    }

    .nav[popover]:not(:popover-open) { display: none; }

    .nav[popover] {
      position: fixed;
      inset: auto 0 0 0;
      width: 100%;
      max-width: none;
      margin: 0;
      border: 0;
      border-radius: var(--radius) var(--radius) 0 0;
      background: var(--cream);
      box-shadow: 0 -8px 40px oklch(0 0 0 / .16);
      padding: 1.5rem var(--gutter) 2rem;
      flex-direction: column;
      align-items: stretch;
      gap: 0;

      &::backdrop { background: oklch(0 0 0 / .3); backdrop-filter: blur(2px); }

      /* :not(.btn) so the CTA keeps the sans button styling */
      & a:not(.btn) {
        font-size: var(--step-1);
        font-family: var(--serif);
        padding-block: 0.85rem;
        border-bottom: 1px solid var(--rule);
      }
      & .nav__portal { margin-top: 1rem; justify-content: center; }
    }
  }

  /* Above the mobile breakpoint the nav is a plain flex row again. The
     `popover` attribute stays on the element, so the UA styles it as a
     fixed, bordered, centred dialog — every one of those has to be undone
     explicitly or the desktop header collapses into a floating box. */
  @media (width >= 79rem) {
    .nav[popover] {
      position: static;
      inset: auto;
      display: flex;
      inline-size: auto;
      block-size: auto;
      max-inline-size: none;
      max-block-size: none;
      margin: 0;
      padding: 0;
      border: 0;
      background: none;
      box-shadow: none;
      overflow: visible;
      color: inherit;
    }
    .nav[popover]::backdrop { display: none; }
  }

  /* ---------- Hero ---------- */
  .hero {
    position: relative;
    overflow: clip;
    padding-block: clamp(3rem, 8vw, 6rem) clamp(3.5rem, 9vw, 6.5rem);
    text-align: center;
    isolation: isolate;
  }

  .hero__wash {
    position: absolute;
    inset: 0;
    z-index: -1;
    object-fit: cover;
    width: 100%;
    height: 100%;
    opacity: 0.34;
    mask-image: radial-gradient(ellipse 92% 70% at 50% 30%, #000 18%, transparent 72%);
  }

  .hero__badge {
    width: clamp(112px, 22vw, 168px);
    aspect-ratio: 1;
    object-fit: cover;
    border-radius: 50%;
    margin-inline: auto;
    margin-bottom: clamp(1.25rem, 3vw, 2rem);
    filter: drop-shadow(0 8px 24px oklch(0 0 0 / .1));
  }

  .hero h1 {
    font-size: var(--step-5);
    max-width: 18ch;
    margin-inline: auto;

    & em {
      font-style: italic;
      color: var(--pink-deep);
    }
  }

  .hero__sub {
    font-size: var(--step-1);
    color: var(--ink-soft);
    max-width: 46ch;
    margin: 1.4rem auto 0;
  }

  .hero__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.85rem;
    justify-content: center;
    margin-top: clamp(1.75rem, 4vw, 2.5rem);
  }

  .hero__note {
    margin-top: 1.25rem;
    font-size: var(--step--1);
    color: var(--ink-soft);
  }

  /* ---------- The ribbon: the site's signature device ----------
     One continuous path threading the page, drawn on scroll.
     pathLength="1" lets us dash it without measuring in JS.        */
  .ribbon {
    position: absolute;
    inset-block: 0;
    inset-inline-start: 50%;
    translate: -50% 0;
    width: min(120%, 1400px);
    height: 100%;
    z-index: -1;
    pointer-events: none;
    overflow: visible;
  }

  .ribbon path {
    fill: none;
    stroke: var(--pink);
    stroke-width: 2.5;
    stroke-linecap: round;
    opacity: 0.38;   /* it crosses body copy, so it stays a whisper */
  }

  @supports (animation-timeline: view()) {
    .ribbon path {
      stroke-dasharray: 1;
      stroke-dashoffset: 1;
      animation: ribbon-draw linear both;
      animation-timeline: view();
      animation-range: entry 0% cover 62%;
    }
  }

  @keyframes ribbon-draw {
    to { stroke-dashoffset: 0; }
  }

  /* ---------- Pathway / program tiers ---------- */
  .tier {
    & + .tier { margin-top: clamp(2.5rem, 6vw, 4rem); }
  }

  /* The tier heading doubles as a link to the SRG page — give it a real
     target height rather than relying on the heading's line box. */
  .tier__head h3 a {
    display: inline-block;
    padding-block: 0.45rem;
    text-decoration: none;

    &:hover { text-decoration: underline; text-underline-offset: 0.15em; }
  }

  .tier__head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.5rem 1rem;
    padding-bottom: 0.9rem;
    margin-bottom: 1.75rem;
    border-bottom: 2px solid var(--rule);

    & h3 { font-size: var(--step-3); }
    & p {
      color: var(--ink-soft);
      font-size: var(--step--1);
      margin-inline-start: auto;
    }
  }

  .cards {
    display: grid;
    gap: 1.1rem;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
  }

  /* The five competitive levels never tile evenly: auto-fit gives four
     columns past 1280px, stranding one card alone in a four-wide row.
     Capping at three yields a balanced 3 + 2. */
  .cards--levels {
    @media (width >= 64rem) { grid-template-columns: repeat(3, 1fr); }

    /* Exactly four cards read 3 + 1 in three columns, stranding one, which
       looks broken in a way a ragged photo row does not. 2 x 2 instead. */
    &:has(> .card:nth-child(4):last-child) {
      @media (width >= 48rem) { grid-template-columns: repeat(2, 1fr); }
    }
  }

  /* Three cards in the auto-fit grid wrap 2 + 1 between 48rem and 64rem,
     because a third 17rem track does not fit until ~53rem. Force three. */
  .cards:has(> .card:nth-child(3):last-child) {
    @media (width >= 48rem) { grid-template-columns: repeat(3, 1fr); }
  }

  /* Exactly four items: 1 / 2 / 4 never strands one on its own row. */
  .cards--four {
    @media (width >= 40rem) { grid-template-columns: repeat(2, 1fr); }
  }

  .card {
    --accent: var(--pink-deep);
    container-type: inline-size;
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    background: #fff;
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    padding: 1.5rem 1.4rem 1.4rem;
    box-shadow: var(--shadow-sm);
    overflow: hidden;
    transition: transform .25s var(--ease), box-shadow .25s var(--ease);

    /* the program's color rail */
    &::before {
      content: "";
      position: absolute;
      inset-block: 0;
      inset-inline-start: 0;
      width: 5px;
      background: var(--accent);
    }

    &:hover {
      transform: translateY(-4px);
      box-shadow: var(--shadow-md);
    }

    /* Whole card is clickable via the stretched link on the title */
    &:has(a:focus-visible) {
      outline: 3px solid var(--pink-deep);
      outline-offset: 3px;
    }

    & h4 {
      font-family: var(--serif);
      font-size: var(--step-2);
      font-weight: 500;
      line-height: 1.1;
    }

    & .card__who {
      font-size: var(--step--1);
      font-weight: 600;
      letter-spacing: 0.08em;
      text-transform: uppercase;
      color: var(--accent);
    }

    & dl {
      display: grid;
      grid-template-columns: auto 1fr;
      gap: 0.3rem 0.9rem;
      font-size: var(--step--1);
      margin-top: 0.35rem;
      padding-top: 0.85rem;
      border-top: 1px solid var(--rule);
    }
    & dt { font-weight: 600; color: var(--ink-soft); }
    & dd { margin: 0; }

    /* A sub-heading inside the definition list: spans both columns and
       separates the schedule block from the dates above it. */
    & .times-head {
      grid-column: 1 / -1;
      margin-top: 0.5rem;
      padding-top: 0.6rem;
      border-top: 1px solid var(--rule);
      color: var(--accent);
      font-size: 0.72rem;
      letter-spacing: 0.08em;
      text-transform: uppercase;
    }
    & .times-head + dd { display: none; }
    & .times-head ~ dd { white-space: nowrap; }

    & .card__link {
      margin-top: auto;
      padding-top: 1rem;
      font-weight: 600;
      font-size: var(--step--1);
      text-decoration: none;

      &::after { content: " →"; }
      &:hover { text-decoration: underline; }
    }
  }

  /* ---------- Why / value props ---------- */
  .why {
    background: var(--cream-warm);
    border-block: 1px solid var(--rule);
  }

  .why__list {
    list-style: none;
    padding: 0;
    display: grid;
    gap: 1rem;
    /* 20rem caps this at three columns on the widest layout. At 15rem a
       1180px row fitted four, which shrank every photo and made a
       five-photo group end 4 + 1. */
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));

    /* Five points: cap at three so it reads 3 + 2, not 4 + 1. */
    @media (width >= 64rem) { grid-template-columns: repeat(3, 1fr); }
  }

  /* No counter. These are five parallel qualities, not steps, and 01-05
     invited a parent to look for a sequence that does not exist. */
  .why__list li {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    padding: 1.5rem 1.35rem;
    background: color-mix(in oklab, #fff 72%, transparent);
    border-radius: var(--radius);
    border: 1px solid color-mix(in oklab, var(--rule) 60%, transparent);

    & b { font-size: var(--step-1); font-family: var(--serif); font-weight: 500; }
  }

  /* ---------- Coach strip ---------- */
  .coach {
    display: grid;
    gap: clamp(1.5rem, 4vw, 3rem);
    align-items: center;
    grid-template-columns: 1fr;

    @media (width >= 48rem) {
      grid-template-columns: minmax(0, 22rem) minmax(0, 1fr);
    }
  }

  /* Holds a real photograph now. The old placeholder styling (grid
     centring, 2rem padding, a gradient ground and a max-height cap)
     shrank the photo to a thumbnail floating in a coloured box. */
  .coach__portrait {
    aspect-ratio: 4 / 5;
    border-radius: var(--radius);
    overflow: hidden;
    box-shadow: var(--shadow-md);
  }

  .coach__body {
    & h3 { font-size: var(--step-3); }
    & .coach__role {
      color: var(--pink-deep);
      font-weight: 600;
      font-size: var(--step-0);
      margin-top: 0.5rem;
      max-width: 34ch;
    }
    & p { margin-top: 1rem; max-width: var(--measure); color: var(--ink-soft); }
    & .btn { margin-top: 1.5rem; }
  }

  /* ---------- Visit ---------- */
  .visit {
    display: grid;
    gap: clamp(1.5rem, 4vw, 3rem);
    grid-template-columns: 1fr;

    @media (width >= 48rem) { grid-template-columns: 1fr 1fr; }
  }

  .visit address {
    font-style: normal;
    font-size: var(--step-1);
    line-height: 1.5;
  }

  .visit__meta {
    margin-top: 1.5rem;
    display: grid;
    gap: 0.75rem;
    font-size: var(--step--1);

    & > div { display: flex; gap: 0.75rem; align-items: center; }
    & dt { font-weight: 600; min-width: 6.5rem; }
    & a { display: inline-flex; align-items: center; min-height: 44px; }
  }

  .map-frame {
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--cream-warm);
    min-height: 18rem;

    & iframe { display: block; width: 100%; height: 100%; min-height: 18rem; border: 0; }
  }

  /* ---------- Final CTA ---------- */
  .cta-band {
    background: var(--ink);
    color: var(--cream);
    text-align: center;

    & h2 {
      font-size: var(--step-4);
      max-width: 20ch;
      margin-inline: auto;
      /* --pink is legible at display size on the dark ink ground */
      & em { font-style: italic; color: var(--pink); }
    }
    & p {
      margin: 1.25rem auto 0;
      max-width: 48ch;
      color: color-mix(in oklab, var(--cream) 78%, var(--ink) 22%);
    }
    & .btn--primary {
      margin-top: 2rem;
      background: var(--pink);
      color: var(--ink); /* dark on pink = 5.89:1, passes AA */
      &:hover { background: color-mix(in oklab, var(--pink) 85%, #fff 15%); }
    }
  }

  /* ---------- Footer ---------- */
  .site-footer {
    background: var(--cream-warm);
    border-top: 1px solid var(--rule);
    padding-block: clamp(2.5rem, 6vw, 4rem) 2rem;
    font-size: var(--step--1);

    & .cols {
      display: grid;
      gap: 2rem;
      grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr));
    }

    & h4 {
      font-size: var(--step--1);
      letter-spacing: 0.14em;
      text-transform: uppercase;
      color: var(--ink-soft);
      margin-bottom: 0.85rem;
    }

    & ul { list-style: none; padding: 0; display: grid; }
    & li { display: flex; }
    & a {
      color: var(--ink);
      text-decoration: none;
      padding-block: 0.6rem;
      min-height: 44px;
      display: inline-flex;
      align-items: center;

      &:hover { color: var(--pink-deep); text-decoration: underline; }
    }

    & .colophon {
      margin-top: 2.5rem;
      padding-top: 1.5rem;
      border-top: 1px solid var(--rule);
      display: flex;
      flex-wrap: wrap;
      gap: 0.5rem 1.5rem;
      color: var(--ink-soft);
    }
  }

  /* ---------- Interior page hero ---------- */
  .page-hero {
    padding-block: clamp(2.5rem, 6vw, 4.5rem) clamp(2rem, 5vw, 3.5rem);
    background: var(--cream-warm);
    border-bottom: 1px solid var(--rule);
    text-align: center;

    & h1 { font-size: var(--step-4); max-width: 20ch; margin-inline: auto; }
    & > .wrap > p {
      max-width: 54ch;
      margin: 1.1rem auto 0;
      color: var(--ink-soft);
      font-size: var(--step-1);
    }
  }

  /* ---------- Season schedule table ----------
     8 columns will never fit a phone, so the table scrolls inside its own
     container and the program column stays pinned. */
  .table-scroll {
    overflow-x: auto;
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    background: #fff;
    -webkit-overflow-scrolling: touch;
  }

  .schedule {
    border-collapse: collapse;
    width: 100%;
    /* 46rem suits the 7-column season table. A 3-column events table forced to
       the same width scrolls sideways for no reason, so pages override it. */
    min-width: var(--table-min, 46rem);
    font-size: var(--step--1);
    font-variant-numeric: tabular-nums;

    & th, & td {
      padding: 0.85rem 0.9rem;
      text-align: left;
      vertical-align: top;
      border-bottom: 1px solid var(--rule);

      /* Tighter gutters on a phone: a 3-column table missed fitting by 7px. */
      @media (width < 40rem) { padding-inline: 0.6rem; }
    }

    /* Stacking order matters here. Without it, cells scrolled under the
       pinned first column paint straight over it — stray digits appeared
       beside the row labels — and the "Program" heading slid away while the
       labels it describes stayed put. */
    & thead th {
      background: var(--pink-deep);
      color: #fff;
      font-weight: 600;
      letter-spacing: 0.06em;
      text-transform: uppercase;
      font-size: 0.72rem;
      /* Sticky for the horizontal pin only. `overflow-x: auto` makes
         .table-scroll a scroll container on BOTH axes, so a `top` offset
         resolves against a box that never scrolls vertically and does nothing
         — it only parked the headings under the site header. */
      position: sticky;
      z-index: 3;
    }

    /* The corner cell is pinned on both axes, so it must sit above both. */
    & thead th:first-child {
      inset-inline-start: 0;
      z-index: 4;
      /* A sub-pixel gap between the container's padding edge and the pinned
         cell let fragments of scrolled text show through. The shadow paints
         over that strip and is clipped by the scroll container. */
      box-shadow: -6px 0 0 0 var(--pink-deep);
    }

    & tbody th {
      font-weight: 600;
      font-size: var(--step-0);
      font-family: var(--serif);
      position: sticky;
      inset-inline-start: 0;
      z-index: 2;
      background: #fff;
      /* The rail is an INSET shadow, not a border. With
         `border-collapse: collapse` the browser paints collapsed borders in
         the table's own layer, so a sticky cell leaves its border behind when
         it pins — the rail vanished and text showed through the gap. An inset
         shadow belongs to the cell and travels with it. The outer white
         shadow covers the sub-pixel seam at the container edge. */
      box-shadow: inset 4px 0 0 0 var(--accent, var(--pink)), -8px 0 0 0 #fff;
      padding-inline-start: 1.05rem;
      min-width: 9.5rem;
    }

    /* Every program name links to its own description. The link lives inside the
       sticky <th>, so it inherits the cell colour and only underlines on
       hover/focus — ten permanently underlined row headers read as noise. */
    & tbody th a {
      color: inherit;
      text-decoration: none;
      text-underline-offset: 3px;

      /* An inline link here is only ~21px tall, under the 24px WCAG 2.5.8
         floor. Negative block margins let it absorb the cell's own vertical
         padding, so the target grows to the full row height without making
         the row any taller. */
      display: flex;
      align-items: center;
      min-height: 44px;
      margin-block: -0.85rem;
      padding-block: 0.85rem;

      &:hover, &:focus-visible {
        color: var(--pink-deep);
        text-decoration: underline;
        text-decoration-thickness: 2px;
      }
    }

    & tbody tr:last-child :is(th, td) { border-bottom: 0; }
    & .none { color: color-mix(in oklab, var(--ink) 35%, var(--cream) 65%); }
    & .ballet { color: var(--pink-deep); font-weight: 600; }
  }

  .table-hint {
    font-size: var(--step--1);
    color: var(--ink-soft);
    margin-top: 0.75rem;

    @media (width >= 52rem) { display: none; }
  }

  /* ---------- Per-program detail ---------- */
  .program {
    --accent: var(--pink-deep);
    scroll-margin-top: 6rem;
    padding-block: clamp(2rem, 5vw, 3rem);
    border-top: 1px solid var(--rule);
    display: grid;
    gap: clamp(1rem, 3vw, 2.5rem);
    grid-template-columns: 1fr;

    @media (width >= 46rem) { grid-template-columns: minmax(0, 15rem) minmax(0, 1fr); }

    & h3 {
      font-size: var(--step-3);
      &::after {
        content: "";
        display: block;
        width: 2.5rem;
        height: 4px;
        background: var(--accent);
        border-radius: 2px;
        margin-top: 0.75rem;
      }
    }

    & .program__who {
      font-size: var(--step--1);
      font-weight: 600;
      letter-spacing: 0.08em;
      text-transform: uppercase;
      color: var(--accent);
      margin-bottom: 0.5rem;
    }

    & p { color: var(--ink-soft); max-width: var(--measure); }
    & .btn { margin-top: 1.25rem; }
  }

  .times {
    list-style: none;
    padding: 0;
    margin: 1rem 0 0;
    display: grid;
    gap: 0.4rem;
    font-size: var(--step--1);

    & li {
      display: flex;
      gap: 0.85rem;
      padding-block: 0.4rem;
      border-bottom: 1px solid color-mix(in oklab, var(--rule) 55%, transparent);
    }
    & b { min-width: 5.5rem; font-weight: 600; }
  }

  /* ---------- Prose (About / bio) ---------- */
  .prose {
    max-width: var(--measure);
    margin-inline: auto;

    & p + p { margin-top: 1.1rem; }
    & p { color: var(--ink-soft); }
    & p.lead {
      font-size: var(--step-1);
      color: var(--ink);
      font-family: var(--serif);
      line-height: 1.4;
    }
  }

  .notes {
    display: grid;
    gap: 1rem;
    /* 20rem caps this at three columns on the widest layout. At 15rem a
       1180px row fitted four, which shrank every photo and made a
       five-photo group end 4 + 1. */
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
    list-style: none;
    padding: 0;
    margin-top: 2rem;

    & li {
      background: color-mix(in oklab, #fff 70%, transparent);
      border: 1px solid var(--rule);
      border-radius: var(--radius);
      padding: 1.25rem;
      font-size: var(--step--1);
    }
    & b { display: block; font-family: var(--serif); font-size: var(--step-1); font-weight: 500; margin-bottom: 0.3rem; }
  }

  /* Exactly five apparatus — auto-fit would break them 4+1, which reads as an
     accident. One row of five states the fact. */
  .notes--five {
    @media (width >= 72rem) { grid-template-columns: repeat(5, 1fr); }
  }

  /* Parent Portal is an outbound link to a separate system, so it gets a
     distinct treatment from the in-site nav items at every width. */
  .nav .nav__portal {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    font-weight: 600;
    color: var(--pink-deep);
    border: 1px solid color-mix(in oklab, var(--pink-deep) 45%, transparent);
    border-radius: 999px;
    padding-inline: 0.75rem;
    min-height: 40px;
    font-size: 0.8rem;

    & svg { flex: none; }

    &:hover {
      background: color-mix(in oklab, var(--pink) 12%, transparent);
      border-color: var(--pink-deep);
    }
  }

  /* ---------- Forms ---------- */
  .form {
    display: grid;
    gap: 1.1rem;
    max-width: 34rem;
  }
  .field {
    display: grid;
    gap: 0.4rem;

    & label {
      font-size: var(--step--1);
      font-weight: 600;
    }
    & .hint { font-size: 0.78rem; color: var(--ink-soft); font-weight: 400; }

    & input, & select, & textarea {
      width: 100%;
      padding: 0.75rem 0.9rem;
      border: 1px solid var(--line, var(--rule));
      border-radius: 10px;
      background: #fff;
      color: var(--ink);
      font-size: var(--step-0);
      min-height: 48px;

      &:focus-visible {
        outline: 3px solid var(--pink-deep);
        outline-offset: 2px;
        border-color: var(--pink-deep);
      }
      &:user-invalid {
        border-color: #B42318;
        background: #FEF3F2;
      }
    }
    & textarea { min-height: 8rem; resize: vertical; }

    /* Native validation message, shown only once the field has been touched */
    & input:user-invalid + .err,
    & textarea:user-invalid + .err { display: block; }
    & .err { display: none; color: #B42318; font-size: 0.78rem; }
  }

  .form__note {
    font-size: var(--step--1);
    color: var(--ink-soft);
    max-width: 44ch;
  }

  /* ---- Introductory offer -------------------------------------------------
     Deliberately restrained: the club asked for the offer on the site without
     it being plastered everywhere, so this appears on exactly two pages, the
     homepage and the contact page. Do not add a third without asking. */
  .offer {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem clamp(1rem, 3vw, 2rem);
    padding: clamp(1rem, 3vw, 1.4rem) clamp(1.1rem, 3vw, 1.75rem);
    background: var(--cream-warm);
    border: 1px solid var(--rule);
    border-inline-start: 3px solid var(--pink-deep);
    border-radius: 6px;
    /* The copy only fills about half of a 1180px row, so cap the band rather
       than letting it stretch with empty space trailing off to the right. */
    max-width: 46rem;
    margin-inline: auto;
  }
  .offer__price {
    font-family: var(--serif);
    font-size: var(--step-4);
    line-height: 1;
    color: var(--pink-deep);
    font-variant-numeric: tabular-nums;
    /* Stacked bands read as a set, so the body copy must start at the same x
       whether the slot says "$99" or the wider "Free". */
    min-width: 4ch;
    text-align: center;
  }
  .offer__body { flex: 1 1 18ch; }
  .offer__body strong { display: block; }
  .offer__body span {
    color: var(--ink-soft);
    font-size: 0.94rem;
  }

  /* In the hero the band must not push the CTAs below the fold on a small
     phone, so it runs tighter and the price drops a step. Measured: the
     standalone band was 168px tall at 375px, which put the offer 222px below
     the fold on an iPhone SE. */
  .offer--hero {
    margin-block: 1.25rem 0;
    padding: 0.7rem 0.9rem;
    gap: 0.15rem 0.85rem;
    text-align: start;
    /* Must stay on one row even at 320px: wrapping the body under the price
       took the band to 162px and pushed the hero CTA off a 667px screen. */
    flex-wrap: nowrap;

    & .offer__price { font-size: var(--step-3); }
    & .offer__body { flex: 1 1 auto; }
    & .offer__body strong { font-size: 0.95rem; }
    & .offer__body span { font-size: 0.85rem; }
    & s { color: var(--ink-soft); text-decoration-thickness: 1px; }
  }

  /* ---- Class packages -----------------------------------------------------
     The club's price cards. Two sets exist and they are NOT the same numbers:
     recreational (programs.html) and adult (adults.html). Keep them apart. */
  .packages {
    display: grid;
    gap: 1rem;
    grid-template-columns: 1fr;
    margin-top: 2rem;

    @media (width >= 40rem) { grid-template-columns: repeat(3, 1fr); }
  }
  .package {
    position: relative;
    display: grid;
    gap: 0.35rem;
    align-content: start;
    padding: clamp(1.25rem, 3vw, 1.75rem);
    background: var(--cream);
    border: 1px solid var(--rule);
    border-radius: 8px;
    text-align: center;
  }
  .package--flag { border-color: var(--pink-deep); }
  .package__count {
    font-family: var(--serif);
    font-size: var(--step-1);
  }
  .package__price {
    font-family: var(--serif);
    font-size: var(--step-4);
    line-height: 1;
    color: var(--pink-deep);
    font-variant-numeric: tabular-nums;
  }
  .package__each {
    color: var(--ink-soft);
    font-size: 0.9rem;
    font-variant-numeric: tabular-nums;
  }
  .package__flag {
    position: absolute;
    inset-block-start: 0;
    inset-inline-start: 50%;
    translate: -50% -50%;
    padding: 0.2rem 0.7rem;
    border-radius: 999px;
    background: var(--pink-deep);
    color: #fff;                 /* 5.66:1 on --pink-deep, measured */
    font-size: 0.68rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    white-space: nowrap;
  }

  .pkg-note {
    margin-top: 1.25rem;
    text-align: center;
    color: var(--ink-soft);
    font-size: 0.94rem;

    & strong { color: var(--ink); }
  }

  /* The uniform that comes with the three-month prepay offer. Sits beside the
     offer bands on desktop and drops under them on a phone. */
  .offer-with-photo {
    display: grid;
    gap: clamp(1rem, 3vw, 2rem);
    align-items: center;
    grid-template-columns: 1fr;

    @media (width >= 48rem) { grid-template-columns: 1fr 15rem; }
  }
  .offer-photo {
    margin: 0;
    justify-self: center;

    & img {
      display: block;
      width: 100%;
      max-width: 15rem;
      border-radius: var(--radius);
      background: var(--cream-deep);
    }
    & figcaption {
      margin-top: 0.5rem;
      text-align: center;
      font-size: var(--step--1);
      color: var(--ink-soft);
    }
  }

  /* Three short policy cards under the competitive picker. .notes is the base
     grid; this modifier follows it so the column count wins. */
  .notes--placement {
    @media (width >= 48rem) { grid-template-columns: repeat(3, 1fr); }
  }

  /* Key facts at the top of an event entry: time, place, fee, deadline. */
  .event-facts {
    display: grid;
    gap: 0.5rem 1.5rem;
    margin: 0 0 1.1rem;
    padding-bottom: 1rem;
    border-bottom: 1px solid var(--rule);
    grid-template-columns: 1fr;

    @media (width >= 34rem) { grid-template-columns: repeat(2, 1fr); }

    & > div { display: flex; gap: 0.5rem; align-items: baseline; }
    & dt {
      font-size: var(--step--1);
      text-transform: uppercase;
      letter-spacing: 0.07em;
      color: var(--ink-soft);
      /* min-width alone is not enough: flex items may shrink below their
         content, which clipped "Eligibility" by 18px at 320px. */
      flex: 0 0 auto;
      min-width: 7ch;
    }
    & dd { margin: 0; font-weight: 500; }
  }

  /* Per-level entry fees inside a competition disclosure. */
  .fee-head {
    margin-bottom: 0.4rem;
    font-size: var(--step--1);
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--ink-soft);
  }
  .fees {
    margin: 0 0 1rem;
    padding: 0;
    list-style: none;
    display: grid;
    gap: 0.3rem 1.5rem;
    grid-template-columns: 1fr;

    @media (width >= 40rem) { grid-template-columns: repeat(2, 1fr); }

    & li { display: flex; gap: 0.5rem; }
    & b { font-weight: 600; min-width: 11ch; }
  }

  /* The hero offer doubles as the way in to the pricing page. Placed after
     .offer--hero so it wins on source order. */
  .offer--link {
    text-decoration: none;
    color: inherit;
    transition: border-color .2s var(--ease), background .2s var(--ease);

    & .offer__body b {
      color: var(--pink-deep);
      white-space: nowrap;

      &::after { content: " \2192"; }
    }
    &:hover, &:focus-visible {
      background: var(--cream);
      border-color: var(--pink-deep);

      & .offer__body b { text-decoration: underline; }
    }
  }

  /* Jump nav for the questions page. 19 answers run five screens on a phone,
     so the problem is finding your question, not the length itself. */
  .faq-jump {
    position: sticky;
    inset-block-start: 73px;          /* clears the site header */
    z-index: 5;
    background: var(--cream);
    border-block-end: 1px solid var(--rule);

    & .wrap {
      display: flex;
      gap: 0.4rem;
      overflow-x: auto;
      scrollbar-width: none;
      padding-block: 0.6rem;

      &::-webkit-scrollbar { display: none; }
    }
    & a {
      flex: none;
      display: inline-flex;
      align-items: center;
      min-height: 40px;
      padding: 0 0.9rem;
      border: 1px solid var(--rule-strong);
      border-radius: 999px;
      font-size: 0.86rem;
      text-decoration: none;
      color: var(--ink);
      white-space: nowrap;

      &:hover, &:focus-visible {
        border-color: var(--pink-deep);
        color: var(--pink-deep);
      }
    }
  }

  /* How a gymnast moves to the next program. Visible rather than a collapsible:
     it was nested inside the description and read as buried. */
  .progress-note {
    margin-top: 1.25rem;
    padding: 0.9rem 1.1rem;
    background: var(--cream-warm);
    border-inline-start: 3px solid var(--accent, var(--pink-deep));
    border-radius: 0 6px 6px 0;

    /* Nesting the label rule inside keeps both at (0,2,0), so source order
       settles it — no !important. `.progress-note p` beating a flat
       `.progress-note__label` is the recurring cascade bug in this file. */
    & p { margin: 0; font-size: 0.94rem; }

    & .progress-note__label {
      margin-bottom: 0.3rem;
      font-size: var(--step--1);
      text-transform: uppercase;
      letter-spacing: 0.07em;
      font-weight: 600;
      color: var(--ink-soft);
    }
  }

  /* The .disclose chevron out of flow.
     `.faqs, .disclose summary::after` is a flex item with
     `margin-inline-start: auto`. In .disclose the summary wraps (name, date,
     sometimes a label), so on a wrapped line the chevron shares the row with
     .d-when and stole 24px from it: five event dates stopped short of the
     content edge while one, whose chevron happened to wrap further, sat flush.
     Positioning it is the same treatment .gal-group already uses.
     Placed after the base rule so source order settles it. */
  .disclose summary {
    position: relative;
    padding-inline-end: 2.5rem;

    &::after {
      position: absolute;
      inset-inline-end: 1.15rem;
      inset-block-start: 50%;
      margin-inline-start: 0;
      translate: 0 -65%;
    }
  }
  .disclose details[open] > summary::after { translate: 0 -25%; }

  /* Coach Sofia's year-by-year coaching record. */
  .record {
    display: grid;
    gap: 0.85rem;
    margin: 0.85rem 0 0;

    & > div {
      display: grid;
      gap: 0.15rem 1.25rem;
      grid-template-columns: 1fr;
      padding-bottom: 0.85rem;
      border-bottom: 1px solid var(--rule);

      @media (width >= 34rem) { grid-template-columns: 5ch 1fr; }
      &:last-child { border-bottom: 0; padding-bottom: 0; }
    }
    & dt {
      font-family: var(--serif);
      font-size: var(--step-1);
      color: var(--pink-deep);
      font-variant-numeric: tabular-nums;
    }
    & dd { margin: 0; }
  }

  /* Sub-headings inside a disclosure body had no top margin, so they sat flush
     against the paragraph above. */
  .disclose details > div h3 {
    margin-top: 1.75rem;
    font-family: var(--serif);
    font-weight: 500;
    font-size: var(--step-1);

    &:first-child { margin-top: 0; }
  }

  .free-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    background: var(--pink-deep);
    color: #fff;
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    padding: 0.3em 0.75em;
    border-radius: 999px;
  }

  /* ---------- SRG: levels & criteria ---------- */
  .level {
    --accent: var(--pink-deep);
    scroll-margin-top: 7rem;
    background: #fff;
    border: 1px solid var(--rule);
    border-inline-start: 5px solid var(--accent);
    border-radius: var(--radius);
    padding: 1.5rem 1.5rem 1.4rem;
    margin-bottom: 1rem;

    & header {
      display: flex;
      flex-wrap: wrap;
      align-items: baseline;
      gap: 0.4rem 1rem;
      margin-bottom: 0.9rem;
    }
    & h3 { font-size: var(--step-2); }
    & .level__load {
      font-size: var(--step--1);
      font-weight: 600;
      color: var(--accent);
      margin-inline-start: auto;
    }
    & p { color: var(--ink-soft); max-width: var(--measure); }
  }

  .criteria {
    list-style: none;
    padding: 0;
    margin: 1rem 0 0;
    display: grid;
    gap: 0.5rem;
    font-size: var(--step--1);

    & li {
      display: flex;
      gap: 0.6rem;
      align-items: flex-start;
    }
    & li::before {
      content: "";
      flex: none;
      width: 6px; height: 6px;
      margin-top: 0.55em;
      border-radius: 50%;
      background: var(--accent);
    }
  }

  /* ---------- Conduct ---------- */
  .conduct {
    counter-reset: rule;
    list-style: none;
    padding: 0;
    display: grid;
    gap: 0.75rem;

    & li {
      counter-increment: rule;
      display: grid;
      /* Two cells only. All text lives in one child div — three loose
         children would wrap the third into the 2rem number column. */
      grid-template-columns: 2rem minmax(0, 1fr);
      gap: 0.9rem;
      align-items: start;
      background: color-mix(in oklab, #fff 70%, transparent);
      border: 1px solid var(--rule);
      border-radius: var(--radius);
      padding: 1.1rem 1.25rem;
    }
    & li::before {
      content: counter(rule, decimal-leading-zero);
      font-family: var(--serif);
      font-size: var(--step-1);
      color: var(--pink);
      line-height: 1.1;
    }
    & b {
      display: flex;
      flex-wrap: wrap;
      align-items: center;
      gap: 0.5rem;
      font-size: var(--step-0);
      margin-bottom: 0.2rem;
    }
    & span { display: block; font-size: var(--step--1); color: var(--ink-soft); }
  }

  /* ---------- Empty-state panel for data we don't have yet ---------- */
  .awaiting {
    border: 2px dashed var(--rule);
    border-radius: var(--radius);
    padding: clamp(1.75rem, 5vw, 2.75rem);
    text-align: center;
    background: color-mix(in oklab, #fff 55%, transparent);

    & svg { width: 34px; margin: 0 auto 0.9rem; color: var(--pink); opacity: .7; }
    & b { display: block; font-family: var(--serif); font-size: var(--step-2); font-weight: 500; }
    & p { color: var(--ink-soft); max-width: 46ch; margin: 0.5rem auto 0; font-size: var(--step--1); }
    & .todo { margin-top: 1rem; }
  }

  /* ---------- FAQ (native <details>, no JavaScript) ---------- */
  .faq-group {
    /* A link target now, so it must clear the sticky header — same 6rem the
       other anchored components use. */
    scroll-margin-top: 9rem;
    font-size: var(--step-2);
    padding-bottom: 0.6rem;
    margin-bottom: 1.25rem;
    border-bottom: 2px solid var(--rule);
  }

  .faqs, .disclose {
    display: grid;
    gap: 0.6rem;

    & details {
      background: #fff;
      border: 1px solid var(--rule);
      border-radius: var(--radius);
      overflow: hidden;

      &[open] { border-color: color-mix(in oklab, var(--pink) 45%, var(--cream)); }
    }

    & summary {
      display: flex;
      align-items: center;
      gap: 0.9rem;
      padding: 0.8rem 1.15rem;
      min-height: 44px;
      cursor: pointer;
      font-weight: 600;
      font-size: var(--step-0);
      list-style: none;

      &::-webkit-details-marker { display: none; }

      /* chevron */
      &::after {
        content: "";
        flex: none;
        margin-inline-start: auto;
        width: 9px; height: 9px;
        border-right: 2px solid var(--pink-deep);
        border-bottom: 2px solid var(--pink-deep);
        rotate: 45deg;
        transition: rotate .2s var(--ease);
      }
      &:hover { color: var(--pink-deep); }
    }

    & details[open] > summary::after { rotate: -135deg; }

    & details > div {
      padding: 0 1.25rem 1.25rem;
      border-top: 1px solid var(--rule);
      padding-top: 1rem;
    }
    & details p {
      color: var(--ink-soft);
      max-width: var(--measure);
      font-size: var(--step--1);
      & + p { margin-top: 0.75rem; }
    }

    /* A paragraph following the list needs the same separation. */
    & .plain-list + p { margin-top: 0.9rem; }

    /* Terms that read better as a list than as a run-on sentence. */
    & .plain-list {
      margin: 0.75rem 0 0;
      padding-inline-start: 1.15rem;
      display: grid;
      gap: 0.35rem;
      color: var(--ink-soft);
      font-size: var(--step--1);
      max-width: var(--measure);

      & li::marker { color: var(--pink-deep); }
    }
  }

  /* ---------- Disclosure rows for long detail blocks ----------
     Same accordion mechanics as the FAQ, but the summary carries scannable
     metadata (name, who, when) so a parent can find the right row without
     opening anything. */
  .disclose {
    & details {
      border-inline-start: 5px solid var(--accent, var(--pink-deep));
      scroll-margin-top: 6rem;
    }

    & summary {
      flex-wrap: wrap;
      gap: 0.15rem 0.9rem;
      padding-block: 0.95rem;
    }

    & .d-name {
      font-family: var(--serif);
      font-size: var(--step-1);
      font-weight: 500;
      line-height: 1.15;
      /* Absorb the free space. Without this both .d-when and the chevron carry
         `margin-inline-start: auto`, the row splits the slack between them, and
         the date lands wherever the title happens to end. */
      flex: 1;
    }
    & .d-who {
      flex-basis: 100%;
      font-size: 0.7rem;
      font-weight: 700;
      letter-spacing: 0.09em;
      text-transform: uppercase;
      color: var(--accent, var(--pink-deep));
    }
    & .d-when {
      font-size: var(--step--1);
      font-weight: 400;
      color: var(--ink-soft);
      margin-inline-start: auto;
      padding-inline-end: 0.5rem;
    }

    & details > div { padding-top: 1.1rem; }
    & .times { margin-top: 0; }
    & .criteria { margin-top: 0; }
  }

  /* ---------- Program picker: chip rail + one open panel ----------
     Zero JavaScript. Hidden radios drive it, so it is keyboard and screen
     reader operable as a normal radio group. Every option's name and age
     stays visible while one panel is open — the point is comparing, not
     just reading. */
  .picker {
    display: grid;
  }

  .picker > input {
    position: absolute;
    opacity: 0;
    pointer-events: none;
  }

  .picker__rail {
    display: flex;
    gap: 0.6rem;
    overflow-x: auto;
    padding-block: 0.25rem 1rem;
    scrollbar-width: thin;
    scroll-snap-type: x proximity;

    & label {
      --on: 0;
      flex: none;
      scroll-snap-align: start;
      cursor: pointer;
      min-width: 8.5rem;
      padding: 0.7rem 1rem;
      border-radius: var(--radius);
      border: 1px solid var(--rule);
      background: #fff;
      display: grid;
      gap: 0.1rem;
      transition: border-color .18s var(--ease), background-color .18s var(--ease);

      /* the accent rail doubles as the selected state */
      border-inline-start: 4px solid
        color-mix(in oklab, var(--accent, var(--pink-deep)) calc(var(--on) * 100%),
                  var(--rule));
      background: color-mix(in oklab, var(--accent, var(--pink))
                  calc(var(--on) * 8%), #fff);

      & b {
        font-family: var(--serif);
        font-size: var(--step-0);
        font-weight: 500;
        line-height: 1.15;
        white-space: nowrap;
      }
      & span {
        font-size: 0.75rem;
        font-weight: 600;
        letter-spacing: 0.05em;
        text-transform: uppercase;
        color: color-mix(in oklab, var(--accent, var(--pink-deep))
                calc(40% + var(--on) * 60%), var(--ink-soft));
        white-space: nowrap;
      }

      &:hover { border-color: var(--pink-deep); }
    }
  }

  .picker > input:focus-visible ~ .picker__rail {
    outline: 3px solid var(--pink-deep);
    outline-offset: 4px;
    border-radius: var(--radius);
  }

  .picker__panel {
    display: none;
    scroll-margin-top: 6rem;
    background: #fff;
    border: 1px solid var(--rule);
    border-inline-start: 5px solid var(--accent, var(--pink-deep));
    border-radius: var(--radius);
    padding: clamp(1.25rem, 3vw, 1.75rem);

    & h3 { font-size: var(--step-2); }
    & .program__who {
      font-size: 0.72rem; font-weight: 700; letter-spacing: 0.09em;
      text-transform: uppercase; color: var(--accent, var(--pink-deep));
      margin-bottom: 0.3rem;
    }
    & p { color: var(--ink-soft); max-width: var(--measure); margin-top: 0.6rem; }
    & .times { margin-top: 1rem; }
  }

  .picker > input:nth-of-type(1):checked ~ .picker__panels > .picker__panel:nth-child(1) { display: block; }
  .picker > input:nth-of-type(2):checked ~ .picker__panels > .picker__panel:nth-child(2) { display: block; }
  .picker > input:nth-of-type(3):checked ~ .picker__panels > .picker__panel:nth-child(3) { display: block; }
  .picker > input:nth-of-type(4):checked ~ .picker__panels > .picker__panel:nth-child(4) { display: block; }
  .picker > input:nth-of-type(5):checked ~ .picker__panels > .picker__panel:nth-child(5) { display: block; }
  .picker > input:nth-of-type(6):checked ~ .picker__panels > .picker__panel:nth-child(6) { display: block; }
  .picker > input:nth-of-type(7):checked ~ .picker__panels > .picker__panel:nth-child(7) { display: block; }
  .picker > input:nth-of-type(8):checked ~ .picker__panels > .picker__panel:nth-child(8) { display: block; }

  .picker > input:nth-of-type(1):checked ~ .picker__rail > label:nth-child(1) { --on: 1; }
  .picker > input:nth-of-type(2):checked ~ .picker__rail > label:nth-child(2) { --on: 1; }
  .picker > input:nth-of-type(3):checked ~ .picker__rail > label:nth-child(3) { --on: 1; }
  .picker > input:nth-of-type(4):checked ~ .picker__rail > label:nth-child(4) { --on: 1; }
  .picker > input:nth-of-type(5):checked ~ .picker__rail > label:nth-child(5) { --on: 1; }
  .picker > input:nth-of-type(6):checked ~ .picker__rail > label:nth-child(6) { --on: 1; }
  .picker > input:nth-of-type(7):checked ~ .picker__rail > label:nth-child(7) { --on: 1; }
  .picker > input:nth-of-type(8):checked ~ .picker__rail > label:nth-child(8) { --on: 1; }


  /* ---------- Photography ---------- */
  /* Collapsible gallery groups. Same chevron language as the FAQ accordion,
     but the summary reads as a section heading rather than a boxed row, so the
     groups still scan as page structure when they are all closed. */
  /* Collapsible gallery groups. The summary is styled as a section heading —
     centred serif, same weight as an <h2> elsewhere — so a closed group still
     reads as page structure rather than as a form control. The chevron is
     positioned rather than flowed, so it cannot pull the title off centre. */
  /* Collapsible gallery groups, styled as the site's standard section head:
     eyebrow, serif title, then a short line of description. The description
     lives inside the <summary> on purpose, so it stays visible when the group
     is collapsed. The chevron is positioned rather than flowed, so it cannot
     pull the centred text off axis. */
  .gal-group {
    border-top: 1px solid var(--rule-strong);
    /* A link to #competitions must not park the eyebrow under the sticky header. */
    scroll-margin-top: 6rem;

    & > summary {
      position: relative;
      display: block;
      text-align: center;
      padding: clamp(2rem, 5vw, 3rem) 2.75rem clamp(1.5rem, 4vw, 2.25rem);
      cursor: pointer;
      list-style: none;

      &::-webkit-details-marker { display: none; }

      &::after {
        content: "";
        position: absolute;
        inset-inline-end: 0.6rem;
        inset-block-start: 50%;
        width: 11px; height: 11px;
        border-right: 2px solid var(--pink-deep);
        border-bottom: 2px solid var(--pink-deep);
        rotate: 45deg;
        translate: 0 -65%;
        transition: rotate .2s var(--ease);
      }
      &:hover .gal-title { color: var(--pink-deep); }
    }

    &[open] > summary::after { rotate: -135deg; translate: 0 -25%; }

    & .eyebrow { display: block; margin-bottom: 0.75rem; }

    & .gal-title {
      display: block;
      font-family: var(--serif);
      font-weight: 500;
      font-size: var(--step-3);
      line-height: 1.15;
      transition: color .2s var(--ease);
    }

    & .gal-desc {
      display: block;
      max-width: 52ch;
      margin: 1rem auto 0;
      color: var(--ink-soft);
      font-size: var(--step--1);
    }

    & .gallery { padding-bottom: clamp(2rem, 5vw, 3rem); }
  }

  /* A photo inside an accordion answer. The crop is 2:1, so the slot is too —
     object-fit would otherwise crop it a second time. */
  .event-photo {
    aspect-ratio: 2 / 1;
    margin-top: 1rem;
  }
  .event-photo figcaption { padding-bottom: 0; }

  /* Summer Show gallery. The slots match the crops exactly, 2:1 for the wide
     frames and 9:16 for the tall ones, so object-fit never crops a second time.
     Six tracks divide cleanly into 6 / 3 / 2, which is why the band, the pair
     and the trio all fill their rows. */
  .showgrid {
    display: grid;
    gap: 0.9rem;
    grid-template-columns: 1fr;

    & .sg-band, & .sg-wide { aspect-ratio: 2 / 1; }
    & .sg-tall { aspect-ratio: 9 / 16; }

    @media (width >= 48rem) {
      grid-template-columns: repeat(6, 1fr);

      & .sg-band { grid-column: 1 / -1; }
      & .sg-wide { grid-column: span 3; }
      & .sg-tall { grid-column: span 2; }
    }
  }

  .photo {
    margin: 0;
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--cream-deep);

    /* <picture> sits between the figure and the img. It has no height of its
       own, so `height: 100%` on the img resolves against nothing and the image
       letterboxes whenever its crop ratio differs from the slot's. */
    & > picture {
      display: block;
      width: 100%;
      height: 100%;
    }

    & img {
      width: 100%;
      height: 100%;
      object-fit: cover;
      display: block;
    }
    & figcaption {
      font-size: var(--step--1);
      color: var(--ink-soft);
      padding: 0.6rem 0.15rem 0;
    }
  }

  /* Masonry-ish gallery that never leaves a stranded final row */
  .gallery {
    display: grid;
    gap: 0.9rem;
    /* 20rem caps this at three columns on the widest layout. At 15rem a
       1180px row fitted four, which shrank every photo and made a
       five-photo group end 4 + 1. */
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
    /* Wide items span two tracks, which otherwise strands half-empty rows.
       `dense` lets a later single-track photo backfill the hole. */
    grid-auto-flow: dense;

    & .photo {
      aspect-ratio: 4 / 5;
      box-shadow: var(--shadow-sm);
      transition: transform .25s var(--ease), box-shadow .25s var(--ease);

      &:hover { transform: translateY(-3px); box-shadow: var(--shadow-md); }
    }
    & .photo--wide { aspect-ratio: 3 / 2; grid-column: span 1; }

    @media (width >= 48rem) {
      & .photo--wide { grid-column: span 2; }

      /* A wide photo in the final position leaves the rest of its row empty.
         Letting it run the full width turns that hole into a closing band. */
      & .photo--wide:last-child {
        grid-column: 1 / -1;
        aspect-ratio: 2 / 1;
      }
    }

    /* Exactly two photos: a spanning wide plus one single leaves half a row
       empty. Two equal columns fills it. */
    &:has(> .photo:nth-child(2):last-child) {
      @media (width >= 48rem) {
        grid-template-columns: repeat(2, 1fr);

        & .photo--wide { grid-column: auto; aspect-ratio: 4 / 5; }
      }
    }

    /* Exactly three photos: a wide + two singles wraps to 2 + 1 and strands
       one. Three equal columns fills the row instead. */
    &:has(> .photo:nth-child(3):last-child) {
      @media (width >= 60rem) {
        grid-template-columns: repeat(3, 1fr);

        & .photo--wide { grid-column: auto; aspect-ratio: 4 / 5; }
      }
    }

    /* Exactly four photos: with three tracks, a wide in third position spans
       two and leaves the third column empty, and `dense` cannot backfill it
       because the fourth photo is the closing full-width band. Measured on
       srg-academy: a 398px hole. Two columns give a clean 2 x 2. */
    &:has(> .photo:nth-child(4):last-child) {
      @media (width >= 48rem) {
        grid-template-columns: repeat(2, 1fr);

        & .photo--wide,
        & .photo--wide:last-child { grid-column: auto; aspect-ratio: 4 / 5; }
      }
    }
  }

  /* Photo beside prose */
  .feature {
    display: grid;
    gap: clamp(1.25rem, 4vw, 3rem);
    align-items: center;
    grid-template-columns: 1fr;

    @media (width >= 48rem) {
      grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
      &.feature--flip > .photo { order: 2; }
    }

    & > .photo { aspect-ratio: 4 / 5; box-shadow: var(--shadow-md); }
    & h2, & h3 { margin-bottom: 0.75rem; }
    & p { color: var(--ink-soft); max-width: var(--measure); }
    & p + p { margin-top: 0.9rem; }
  }

  /* ---------- Results: the numbers, stated plainly ---------- */
  .results {
    display: grid;
    gap: 0.6rem;
    grid-template-columns: repeat(3, 1fr);

    @media (width >= 40rem) { gap: 1rem; }
  }

  /* Four stat cards. 3-across would strand one on its own row, and 4-across on a
     phone leaves ~75px per card — so it reads 2x2 on mobile, 4-up from 40rem. */
  .results--four {
    grid-template-columns: repeat(2, 1fr);

    @media (width >= 40rem) { grid-template-columns: repeat(4, 1fr); }
  }

  .result-card {
    background: #fff;
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    padding: 1rem 0.6rem;
    text-align: center;

    @media (width >= 40rem) { padding: 1.5rem 1.35rem; }

    & b {
      display: block;
      font-family: var(--serif);
      font-size: clamp(1.9rem, 7vw, 3.4rem);
      line-height: 1;
      color: var(--pink-deep);
      font-weight: 500;
      font-variant-numeric: tabular-nums;
    }
    & span {
      display: block;
      margin-top: 0.4rem;
      font-size: 0.72rem;
      line-height: 1.35;
      color: var(--ink-soft);
      text-wrap: pretty;

      @media (width >= 40rem) { font-size: var(--step--1); margin-top: 0.5rem; }
    }
  }

  .placings {
    list-style: none;
    padding: 0;
    margin: 1.5rem 0 0;
    display: grid;
    gap: 0.6rem;

    & li {
      display: flex;
      flex-wrap: wrap;
      align-items: baseline;
      gap: 0.4rem 0.9rem;
      background: color-mix(in oklab, #fff 70%, transparent);
      border: 1px solid var(--rule);
      border-radius: var(--radius);
      padding: 0.9rem 1.15rem;
      font-size: var(--step--1);
    }
    & .place {
      font-family: var(--serif);
      font-size: var(--step-1);
      color: var(--pink-deep);
      min-width: 2.6rem;
      font-variant-numeric: tabular-nums;
    }
    & .who { font-weight: 600; }
    & .what { color: var(--ink-soft); margin-inline-start: auto; }
  }

  /* ---------- SRG Academy mark ---------- */
  .srg-mark {
    width: clamp(120px, 24vw, 180px);
    height: auto;
    margin-inline: auto;
    margin-bottom: clamp(1rem, 3vw, 1.5rem);
  }

  /* ---------- Vertical video beside text ----------
     The source is 9:16 (shot for Reels). Letterboxing it into a 16:9 band left
     71% of the row empty and read as a failed image. Pairing it with a column
     of copy uses the width for something, and the portrait shape becomes an
     asset rather than a problem. */
  .vsplit {
    display: grid;
    gap: clamp(1.5rem, 4vw, 3rem);
    align-items: center;
    grid-template-columns: 1fr;

    @media (width >= 52rem) {
      grid-template-columns: minmax(0, 22rem) minmax(0, 1fr);
    }


    & > figure {
      margin: 0;
      border-radius: var(--radius);
      overflow: hidden;
      box-shadow: var(--shadow-md);
      background: var(--ink);
      max-width: 22rem;
      margin-inline: auto;
      width: 100%;
    }

    & > figure video {
      display: block;
      width: 100%;
      aspect-ratio: 9 / 16;
      object-fit: cover;
    }

    & h2 { margin-bottom: 0.75rem; }
    & p { color: var(--ink-soft); max-width: var(--measure); }
    & p + p { margin-top: 0.9rem; }
    & .btn { margin-top: 1.5rem; }
  }

  /* ---------- Map skeleton ----------
     The OSM iframe is lazy, so the frame sits empty for a moment. A quiet
     shimmer reads as loading rather than broken. */
  .map-frame {
    position: relative;

    &::before {
      content: "";
      position: absolute;
      inset: 0;
      background: linear-gradient(100deg,
        var(--cream-warm) 30%, var(--cream-deep) 50%, var(--cream-warm) 70%)
        0 0 / 300% 100%;
      animation: shimmer 1.6s linear infinite;
    }
    & iframe { position: relative; z-index: 1; }
  }

  @keyframes shimmer { to { background-position: -300% 0; } }

  @media (prefers-reduced-motion: reduce) {
    .map-frame::before { animation: none; }
  }

  /* ---------- Proof band ---------- */
  .proof {
    background: var(--ink);
    color: var(--cream);
    text-align: center;

    & .results { margin-top: clamp(1.5rem, 4vw, 2.25rem); }

    & .result-card {
      background: color-mix(in oklab, var(--cream) 8%, transparent);
      border-color: color-mix(in oklab, var(--cream) 18%, transparent);

      & b { color: var(--pink); }
      & span { color: color-mix(in oklab, var(--cream) 76%, var(--ink) 24%); }
    }
  }

  /* ---------- TODO-CLIENT flag (preview only, strip before launch) ---------- */
  .todo {
    display: inline-block;
    background: repeating-linear-gradient(45deg, #FFF3C4, #FFF3C4 8px, #FFE79A 8px, #FFE79A 16px);
    border: 1px dashed #A9862B;
    color: #6B540F;
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    padding: 0.15em 0.5em;
    border-radius: 4px;
  }
}

@layer utilities {
  /* A deep link (e.g. /programs.html#level-4) must beat the picker's default
     radio selection. These sit in `utilities` because the :nth-of-type rules
     that drive the picker are far more specific (0,6,1 vs 0,3,0) — layer
     order settles it without !important. */
  .picker:has(.picker__panel:target) .picker__panel:not(:target) { display: none; }
  .picker .picker__panel:target { display: block; }

  /* Lives in `utilities` on purpose: descendant paragraph rules in the
     `components` layer (.coach__body p, .section-head > p) set their own
     color and out-specify a bare .eyebrow. The layer order settles it. */
  .eyebrow {
    font-size: var(--step--1);
    font-weight: 600;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--pink-deep);
  }

  /* Honeypot. Taken out of the layout and off-screen rather than display:none,
     which some bots detect and skip. aria-hidden + tabindex -1 keep it away
     from screen readers and keyboard users. */
  .hp {
    position: absolute;
    left: -9999px;
    width: 1px;
    height: 1px;
    overflow: hidden;
  }

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

  /* ::before, not ::after — .card__link uses ::after for its arrow, and
     this rule (utilities layer) would otherwise win and erase it. */
  .stretched::before {
    content: "";
    position: absolute;
    inset: 0;
  }

  .center { text-align: center; }
}

/* Same-document view transitions for in-page nav (progressive enhancement) */
@view-transition { navigation: auto; }
