/* ==========================================================================
   Mile Gobbler - Chennai's Finest 4x4 Community

   One scroll equals one day on the trail. A single fixed gradient sits behind
   every section; scroll position drives it from first light to midnight, and
   the club silhouette closes the page black against the dark sky.

   That gradient is the identity. Everything else stays out of its way: flat
   surfaces, silhouette-only illustration, no drop shadows (0-offset rings
   stand in for borders, so a hairline costs no layout), softened corners.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Design tokens

   The complete palette. Anything outside this list is a bug - with one
   deliberate exception, the WhatsApp green on the floating button, which is a
   platform affordance rather than club colour. It is marked where it appears.
   -------------------------------------------------------------------------- */
:root {
  /* Sky ramp. JS writes --sky-top/-mid/-low each frame by interpolating
     between these stops in OKLCH; the named stops are the reference values
     and the reduced-motion path snaps between them. One scroll is one whole
     day - pre-dawn blue, clear midday blue, sunset, night - so blue is the
     ground for most of the page rather than a detail on top of it. */
  --sky-predawn:   #7E9BBE;
  --sky-predawn-lo:#F2D6A4;
  --sky-day-high:  #2F7FC9;
  --sky-day:       #6DAEE0;
  --sky-day-low:   #C4E0F2;
  --sky-afternoon: #A6BCCE;
  --sky-evening:   #AC7291;
  --sky-purple:    #6B5E8E;
  --sky-dawn-high: #FFF0C9;
  --sky-dawn:      #FFC145;
  --sky-morning:   #F79E3C;
  --sky-ember:     #F2743B;
  --sky-rust:      #C4442A;
  --sky-wine:      #8E3556;
  --sky-dusk:      #5B3A70;
  --sky-night:     #1B0F2E;
  --sky-void:      #0A0616;

  /* Fixed palette */
  --ink:      #0A0A0A;
  --ink-deep: #05030A;
  --mist:     #A8C4D8;
  --slate:    #3E5C77;
  --cloud:    #EEF3F7;
  --sun-core: #FFF6D8;
  --signal:   #FF7A2F;

  /* Metals - tier and badge UI only */
  --silver:   #B9C2C9;
  --gold:     #D9A548;
  --platinum: #E4E8EA;

  /* --- v2 palette (docs/brand/design-language.md §3) ------------------------
     These are FOREGROUND colours. The scroll-driven sky remains the background;
     these are the surfaces, type and components that float on it.

     That split is deliberate and fixes a real defect: body text currently
     switches colour at 85% scroll because it sits directly on a ground that
     runs from pale to near-black, which is why the contrast audit finds
     failures on the live site. Snow White on a dark panel is legible at every
     hour of the page, because the pair no longer depends on scroll position. */
  --mg-black: #030303;
  --mg-navy:  #213347;
  --mg-blue:  #0D5292;
  --mg-snow:  #F7F7F5;
  --mg-steel: #969FA8;
  --mg-sand:  #EBC999;
  --mg-trail: #D1D3D4;

  /* Live scroll state. JS overwrites these; the values here are the top of
     the page, so the first paint is correct before any script runs. */
  --p: 0;
  --sky-top: #7E9BBE;
  --sky-mid: #A9C1D8;
  --sky-low: #F2D6A4;
  --text:    #0A0A0A;
  --ground:  #FFF6D8;

  /* Type */
  --font-display: "Teko", "Oswald", Impact, sans-serif;
  --font-body: "Space Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --font-mono: "Martian Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  /* Scale, in rem */
  --t-xs: 0.6875rem;
  --t-sm: 0.875rem;
  --t-md: 1rem;
  --t-lg: 1.25rem;
  --t-xl: 1.75rem;
  --t-2xl: 2.75rem;
  --t-3xl: 4.5rem;
  --t-4xl: 7rem;

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

  /* Layout. v2 softens the radii for the panel surfaces (see §20); depth still
     comes from the sky rather than from elevation - both shadow tokens are none,
     which retires every shadow in the sheet at once. */
  --wrap: 1200px;
  --gutter: 1.25rem;
  --radius: 14px;
  --radius-lg: 28px;
  --header-h: 68px;
  --shadow: none;
  --shadow-lg: none;
  --ease: cubic-bezier(0.16, 1, 0.3, 1);

  /* ---- Compatibility layer -------------------------------------------
     The rules below this block were written against a --clr-* palette. They
     are remapped onto the tokens above rather than rewritten one by one, so
     surfaces, borders and text follow the sky everywhere at once. New work
     should use the tokens above directly. */
  --clr-bg:        transparent;                                        /* the sky shows through */
  /* Surfaces and rules are where the logo's cold blue lives - §2 gives it the
     job of keeping the warm ramp from going syrupy, and at 8% mist over a
     saturated orange it was not doing that job; it was indistinguishable from
     grey. At these strengths a card reads distinctly cool against the sky,
     which is the contrast the derivation table is asking for. Still never
     opaque: an opaque panel punches a hole in the gradient. */
  --clr-surface:   color-mix(in srgb, var(--mist) 18%, transparent);
  --clr-surface-2: color-mix(in srgb, var(--slate) 14%, transparent);
  --clr-text:      var(--text);
  --clr-muted:     color-mix(in srgb, var(--text) 97%, transparent);
  --signal-ink:    color-mix(in oklab, var(--signal) 9%, var(--text));
  --clr-accent:    var(--signal-ink);
  --clr-accent-hi: var(--signal);
  --clr-steel:     var(--slate);
  /* Where the logo's blue actually lives. Two things had to be true at once
     and neither alone was enough: a translucent blue over saturated orange
     just desaturates it and leaves the hue where it was (ember 19deg -> 18deg
     at 18% mist), while solid --slate disappears on the rust stop, where its
     luminance and the sky's are nearly equal. Mixing slate toward the live
     text colour keeps the blue hue and guarantees the line is always darker
     than the sky above the switch and lighter than it below. */
  --clr-line:      color-mix(in oklab, var(--slate) 62%, var(--text));

  /* Difficulty ratings. Read against both halves of the ramp, so they are
     tinted toward the current text colour rather than fixed dark greens. */
  --clr-green: color-mix(in srgb, var(--mist) 60%, var(--text));
  --clr-blue:  color-mix(in srgb, var(--slate) 55%, var(--text));
  --clr-black: var(--text);
}

/* --------------------------------------------------------------------------
   2. Reset & base
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

a, button, summary, .gallery-item, label, [role="button"] {
  touch-action: manipulation;
  -webkit-tap-highlight-color: color-mix(in srgb, var(--signal) 22%, transparent);
}

html {
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + 1rem);
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--sky-void);   /* only ever seen past the end of the sky layer */
  color: var(--text);
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

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

/* Links wipe an underline in from the left rather than carrying one. */
a {
  color: var(--clr-accent);
  text-decoration: none;
  background-image: linear-gradient(var(--signal), var(--signal));
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 0 1px;
  transition: background-size 0.14s var(--ease), color 0.14s var(--ease);
}
a:hover, a:focus-visible { color: var(--clr-accent-hi); background-size: 100% 1px; }

p { margin: 0 0 var(--sp-4); }
p:last-child { margin-bottom: 0; }

ul, ol { margin: 0 0 var(--sp-4); padding-left: 1.25rem; }
li { margin-bottom: var(--sp-2); }

hr { border: 0; border-top: 1px solid var(--clr-line); margin: var(--sp-7) 0; }

:focus-visible {
  outline: 2px solid var(--signal);
  outline-offset: 2px;
  border-radius: 2px;
  box-shadow: 0 0 0 5px var(--ground, var(--ink));
}

::selection { background: var(--signal); color: var(--sun-core); }

/* --------------------------------------------------------------------------
   2b. The sky

   One fixed gradient layer behind everything, not per-section backgrounds -
   those band at the seams and break the illusion. Costs one composited paint
   per frame, so nothing else animates transform or opacity during scroll.
   -------------------------------------------------------------------------- */
.sky {
  position: fixed;
  inset: 0;
  z-index: -2;
  background: linear-gradient(
    to bottom,
    var(--sky-top) 0%,
    var(--sky-mid) 58%,
    var(--sky-low) 108%
  );
}

/* The rust and wine stops sit at exactly the luminance where neither ink nor
   cloud text clears 4.5:1 on its own. A haze fixes that, but it has to run in
   whichever direction the text needs: cream while the text is still ink, so
   the band lifts away from it, then ink once the text has gone light, so the
   band drops away instead. js/main.js sets both, and reads as haze near the
   horizon either way. */
.sky-scrim {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: var(--ground, var(--ink));
  opacity: var(--scrim-alpha, 0);
  transition: background-color 200ms linear, opacity 200ms linear;
}

/* The sun. Flat disc, soft glow, descending as the page darkens; JS sets the
   position and both colours from the ramp table. It holds at 72% width so it
   sets behind the right-hand mass of the silhouette. */
.sun {
  position: fixed;
  left: 72%;
  top: var(--sun-y, 78vh);
  z-index: -2;
  width: 220px;
  height: 220px;
  margin: -110px 0 0 -110px;
  border-radius: 50%;
  background: var(--sun-fill, var(--sun-core));
  opacity: var(--sun-opacity, 1);
  pointer-events: none;
}
.sun::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: calc(220px + var(--sun-glow, 90px) * 4);
  height: calc(220px + var(--sun-glow, 90px) * 4);
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: radial-gradient(closest-side,
    var(--sun-halo, color-mix(in srgb, var(--sun-core) 35%, transparent)) 0%,
    transparent 100%);
}
@media (max-width: 700px) {
  .sun { width: 150px; height: 150px; margin: -75px 0 0 -75px; }
}

/* Stars cross-fade in over the last third of the scroll. */
.starfield {
  position: fixed;
  inset: 0;
  z-index: -2;
  pointer-events: none;
  opacity: clamp(0, calc((var(--p) - 0.86) / 0.10), 1);
}
.starfield svg { width: 100%; height: 100%; }
.starfield .constellation { pointer-events: auto; }
.starfield .constellation__line { stroke: var(--cloud); stroke-width: 0.7; opacity: 0; transition: opacity 0.3s var(--ease); }
.starfield .constellation__label {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  fill: var(--cloud);
  opacity: 0;
  transition: opacity 0.3s var(--ease);
}
.starfield .constellation:hover .constellation__line,
.starfield .constellation:hover .constellation__label { opacity: 0.75; }

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

   Display is Teko at its heaviest (and only loaded) weight, 700 - a condensed
   face with no width axis. Body is Space Grotesk. Martian Mono carries every
   real number the club can document - the credibility is in the figures, not
   the adjectives.
   -------------------------------------------------------------------------- */
h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 700;
  line-height: 0.95;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  text-wrap: balance;
  margin: 0 0 var(--sp-4);
  color: var(--text);
}

/* Below 2.75rem the headline breaks the word rather than shrinking further -
   display type should feel slightly too large for its viewport. */
h1 { font-size: clamp(var(--t-2xl), 9vw, var(--t-4xl)); overflow-wrap: anywhere; }
h2 { font-size: clamp(var(--t-xl), 4.2vw, var(--t-2xl)); }
h3 { font-size: var(--t-lg); }
h4 { font-size: var(--t-md); letter-spacing: 0; }

/* Utility type: coordinates, distances, dates, grades, tier codes, eyebrows */
.mono, .eyebrow, .stat__num, .duration, .badge, .status, .tier__gate,
.trail-card__date, .colophon {
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  font-weight: 400;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  /* Figures have to line up, or the whole "numbers are the credibility" idea
     falls over the moment two of them sit above each other. */
  font-variant-numeric: tabular-nums;
}

.eyebrow {
  color: var(--signal-ink);
  margin: 0 0 var(--sp-3);
  display: flex;
  align-items: center;
  gap: var(--sp-3);
}
.eyebrow::before {
  content: "";
  width: 30px;
  height: 1px;
  background: var(--signal);
  flex: none;
}

.lede {
  font-size: var(--t-lg);
  color: var(--clr-muted);
  max-width: 62ch;
}

.muted { color: var(--clr-muted); }

p, li, .lede, dd { max-width: 62ch; }

/* The ink-to-cloud crossover is a step in scroll position (see js/main.js) so
   that no resting position leaves text mid-grey. This turns that step into a
   fade in time, which is what keeps it from reading as a jolt. Zero-specificity
   so any component's own transition still wins. */
:where(body, h1, h2, h3, h4, p, li, dt, dd, span, b, strong, em, summary,
       figcaption, label, td, th, blockquote) {
  transition: color 200ms linear;
}

/* --------------------------------------------------------------------------
   4. Layout
   -------------------------------------------------------------------------- */
.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.wrap--narrow { max-width: 820px; }

/* Sections float on the sky. --alt no longer fills - it marks itself with
   hairlines instead, because a filled band would show its seams against a
   gradient that is still moving. */
/* The gap a reader sees between two panels is the sum of two sections'
   padding, so this is half the intended rhythm. At --sp-8 it produced 128px
   between sections against 48px between sibling panels - one relationship
   rendered two different ways. At --sp-6 both come to 64. */
.section { padding-block: var(--sp-6); }
.section--tight { padding-block: var(--sp-5); }

.section-head { max-width: 62ch; margin-bottom: var(--sp-6); }

.skip-link {
  position: absolute;
  left: var(--sp-4);
  top: -100px;
  z-index: 999;
  background: var(--ink);
  color: var(--sun-core);
  font-weight: 700;
  padding: var(--sp-3) var(--sp-5);
  border-radius: var(--radius);
  transition: top 0.2s var(--ease);
}
.skip-link:focus { top: var(--sp-3); color: var(--sun-core); }

/* --------------------------------------------------------------------------
   5. Buttons - flat ink fill, sun-core label, 1px press-down. No lift.
   -------------------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  font-weight: 400;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 0.95rem 1.75rem;
  border: 1px solid var(--clr-line);
  border-radius: var(--radius);
  background: var(--ink);
  color: var(--sun-core);
  background-image: none;
  cursor: pointer;
  transition: color 0.14s var(--ease), box-shadow 0.14s var(--ease), border-color 0.14s var(--ease);
}
.btn:hover {
  color: var(--signal);
  box-shadow: inset 0 0 0 2px var(--signal);
}
.btn:active { transform: translateY(1px); transition-duration: 60ms; }
.btn--ghost { background: transparent; color: var(--text); border-color: var(--clr-line); }
/* The ghost button has no fill to keep it visible, so it inverts instead:
   --text fills it and --ground labels it, which flips with the sky and so
   always contrasts in both directions. */
.btn--ghost:hover {
  background: var(--text);
  color: var(--ground);
  border-color: var(--text);
  box-shadow: none;
}

.btn-row { display: flex; flex-wrap: wrap; gap: var(--sp-4); }

/* --------------------------------------------------------------------------
   6. Header & navigation
   -------------------------------------------------------------------------- */
/* Tinted with the live sky rather than a fixed pale blue, so the bar stays
   part of the gradient instead of sitting on top of it as a grey slab. */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: color-mix(in oklab, var(--sky-top) 72%, transparent);
  backdrop-filter: blur(12px) saturate(1.1);
  border-bottom: 1px solid var(--clr-line);
}

.site-header .wrap {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  min-height: var(--header-h);
}

.brand { display: flex; align-items: center; gap: var(--sp-3); color: var(--text); background-image: none; }
.brand:hover { color: var(--text); }
/* The wordmark, not the roundel. It is 4.83:1, so it is sized by height and
   left to find its own width - a square box would squash it. No disc, no
   border: it is lettering, not a badge. */
/* Stacked, as the name and tagline were before: the tagline is far wider than
   the wordmark, and side by side the longer line reads as the louder one. */
.brand { flex-direction: column; align-items: flex-start; gap: 5px; }
.brand-wordmark {
  /* Not a picture - a shape filled with the page's own ink.
     A white wordmark is invisible on the dawn sky (1.7:1) and a black one is
     invisible at night; the sky runs through both. Masking it with --text means
     it flips at exactly the crossover the body copy already uses, measured at
     p=0.46, with no second mechanism to keep in step. */
  display: block;
  flex: none;
  width: 145px;
  height: 30px;
  background-color: var(--text);
  -webkit-mask: url("/assets/logo-wordmark.png") no-repeat center / contain;
  mask: url("/assets/logo-wordmark.png") no-repeat center / contain;
}
.brand-wordmark--lg { width: 184px; height: 38px; }

.brand-tag {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  letter-spacing: 0.12em;
  color: var(--clr-muted);
  text-transform: uppercase;
  margin-top: 5px;
}

.nav-toggle {
  display: inline-flex;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 44px;
  height: 44px;
  padding: 0 9px;
  background: transparent;
  border: 1px solid var(--clr-line);
  border-radius: var(--radius);
  cursor: pointer;
}
.nav-toggle span {
  display: block;
  height: 2px;
  background: var(--clr-text);
  transition: transform 0.22s var(--ease), opacity 0.22s var(--ease);
}
.nav-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

.site-nav ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  align-items: center;
  gap: var(--sp-2);
}
.site-nav li { margin: 0; }
.site-nav a {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text);
  padding: 0.55rem 0.85rem;
  border-radius: var(--radius);
  position: relative;
  background-image: none;
}
.site-nav a:hover { color: var(--signal-ink); }
.site-nav a.is-active { color: var(--signal-ink); }
.site-nav a.is-active::after {
  content: "";
  position: absolute;
  left: 0.85rem;
  right: 0.85rem;
  bottom: 0.15rem;
  height: 1px;
  background: var(--signal);
}
.site-nav a.nav-cta {
  background: var(--ink);
  color: var(--sun-core);
  margin-left: var(--sp-2);
}
.site-nav a.nav-cta:hover { color: var(--signal); box-shadow: inset 0 0 0 2px var(--signal); }
.site-nav a.nav-cta.is-active { color: var(--sun-core); }
.site-nav a.nav-cta.is-active::after { display: none; }

/* Mobile nav. Switches at 1024px rather than 900px because seven nav items
   plus the brand lockup no longer fit comfortably on a narrow desktop. */
@media (max-width: 1023px) {
  /* The open menu overlays page content, so this is the one surface that has
     to be near-opaque. It is mixed from the live sky to stay in the gradient. */
  .site-nav {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    background: color-mix(in oklab, var(--sky-top) 94%, transparent);
    backdrop-filter: blur(12px);
    border-bottom: 1px solid var(--clr-line);
    display: none;
  }
  .site-nav.is-open { display: block; }
  .site-nav ul { flex-direction: column; align-items: stretch; gap: 0; padding: var(--sp-3) var(--gutter) var(--sp-5); }
  .site-nav a { padding: 0.85rem 0.25rem; border-bottom: 1px solid var(--clr-line); border-radius: 0; }
  .site-nav a.is-active::after { display: none; }
  .site-nav li:last-child a { border-bottom: 0; }
  .site-nav a.nav-cta { margin: var(--sp-4) 0 0; text-align: center; border-radius: var(--radius); }
}
@media (min-width: 1024px) {
  .nav-toggle { display: none; }
  .site-nav { display: block !important; }
}

/* --------------------------------------------------------------------------
   7. Hero
   -------------------------------------------------------------------------- */
.hero {
  position: relative;
  min-height: min(88vh, 780px);
  display: flex;
  align-items: center;
  padding-block: var(--sp-9) var(--sp-8);
  overflow: hidden;
}
/* Feathered top and bottom, so the photo dissolves into the sky rather than
   ending on a hard line. A full-width band with a crisp edge is exactly the
   seam the single-gradient rule exists to avoid - and it hides the sun and
   stars behind it. */
.hero__media, .cta-band__media {
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 18%, #000 68%, transparent 100%);
  mask-image: linear-gradient(180deg, transparent 0%, #000 18%, #000 68%, transparent 100%);
}
.hero__media {
  position: absolute;
  inset: 0;
  z-index: 0;
}
/* The hero photo is graded to sit inside a sky that is still changing colour:
   warmed, desaturated, blacks lifted toward slate. */
.hero__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: saturate(0.92) sepia(0.06) contrast(0.96);
}
/* Scrim mixed from the live sky rather than a fixed pale blue, so the photo
   dissolves into the gradient instead of sitting in a grey box on top of it.
   Text still needs its ground, so it stays heavy on the left. */
/* The veil over the hero photograph. These were tuned against a grey
   placeholder, where nothing was lost by covering it at 95% - there is a real
   photograph of the club behind this now and the point is to see it. Lifted to
   72/60/22 after measuring: the statement holds 4.45:1 against a 3.0
   requirement at 112px, so there was room to give back. */
.hero__media::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(90deg,
      color-mix(in oklab, var(--sky-mid) 72%, transparent) 0%,
      color-mix(in oklab, var(--sky-mid) 60%, transparent) 48%,
      color-mix(in oklab, var(--sky-mid) 22%, transparent) 100%),
    linear-gradient(180deg, transparent 0%, transparent 45%,
      color-mix(in oklab, var(--sky-low) 70%, transparent) 100%);
}
@media (max-width: 899px) {
  /* Narrow screens put text across the full width, so the scrim goes flat */
    .hero__media::after {
    background: linear-gradient(180deg,
      color-mix(in oklab, var(--sky-top) 92%, transparent) 0%,
      color-mix(in oklab, var(--sky-mid) 90%, transparent) 55%,
      color-mix(in oklab, var(--sky-low) 92%, transparent) 100%);
  }
}
.hero .wrap { position: relative; z-index: 1; }
.hero h1 { margin-bottom: var(--sp-3); }
.hero__tagline {
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--signal-ink);
  margin: 0 0 var(--sp-5);
}

.page-hero {
  position: relative;
  padding-block: var(--sp-8) var(--sp-7);
  border-bottom: 1px solid var(--clr-line);
}
.page-hero h1 { font-size: clamp(var(--t-xl), 7vw, var(--t-3xl)); }

/* --------------------------------------------------------------------------
   8. Stats strip
   -------------------------------------------------------------------------- */


/* Documented numbers are the club's credibility, so they get the largest type
   on the strip and the mono face that marks a real figure. */


@media (min-width: 700px) { .stats { grid-template-columns: repeat(4, 1fr); } }

/* --------------------------------------------------------------------------
   9. Generic card grid
   -------------------------------------------------------------------------- */
.grid { display: grid; gap: var(--sp-5); }
.grid--2 { grid-template-columns: 1fr; }


@media (min-width: 640px) {
  .grid--2 { grid-template-columns: repeat(2, 1fr); }

}
@media (min-width: 960px) {


}

/* Nothing moves on hover, anywhere. The hairline shifts slate to signal and
   that is the whole interaction - restraint here keeps attention on the sky. */
.card {
  background: var(--clr-surface);
  border: 1px solid var(--clr-line);
  border-radius: var(--radius-lg);
  padding: var(--sp-6);
  transition: border-color 0.2s var(--ease);
}
.card:hover { border-color: var(--signal); }
.card h3 { margin-bottom: var(--sp-3); }
.card p { color: var(--clr-muted); }
.card__icon {
  width: 46px;
  height: 46px;
  display: grid;
  place-items: center;
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--mist) 14%, transparent);
  border: 1px solid var(--clr-line);
  color: var(--clr-line);
  margin-bottom: var(--sp-4);
}
.card__icon svg { width: 24px; height: 24px; }

/* Split feature (image + text) */
.split { display: grid; gap: var(--sp-6); align-items: center; }
@media (min-width: 900px) { .split { grid-template-columns: 1fr 1fr; gap: var(--sp-8); } }
.split img { border-radius: var(--radius); border: 1px solid var(--clr-line); width: 100%; filter: saturate(0.92) sepia(0.06); }

/* --------------------------------------------------------------------------
   10. Trails
   -------------------------------------------------------------------------- */


.badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-display);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 0.28rem 0.6rem;
  border-radius: 999px;
  border: 1px solid currentColor;
  background: color-mix(in srgb, var(--ground, var(--ink)) 45%, transparent);
  white-space: nowrap;
}
.badge::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: currentColor; }

/* Event-type tags used on the season calendar */
.badge--sand   { color: color-mix(in oklab, var(--sky-dawn) 34%, var(--text)); }
.badge--hills  { color: color-mix(in oklab, var(--mist) 34%, var(--text)); }
.badge--rain   { color: color-mix(in oklab, var(--slate) 34%, var(--text)); }
.badge--learn  { color: color-mix(in oklab, var(--signal) 34%, var(--text)); }
.badge--social { color: color-mix(in oklab, var(--sky-wine) 34%, var(--text)); }

/* Registration status pill. Derived at build time from the event data. */
.status {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-display);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 0.28rem 0.7rem;
  border-radius: 999px;
  white-space: nowrap;
  border: 1px solid currentColor;
  background: color-mix(in srgb, var(--ground, var(--ink)) 45%, transparent);
}
.status::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentColor;
}
.status--announced { color: var(--clr-muted); }
.status--open      { color: var(--signal-ink); background: color-mix(in srgb, var(--signal) 10%, transparent); }
.status--filling   { color: color-mix(in oklab, var(--sky-dawn) 34%, var(--text)); background: color-mix(in srgb, var(--sky-dawn) 10%, transparent); }
.status--full      { color: color-mix(in oklab, var(--sky-rust) 34%, var(--text)); background: color-mix(in srgb, var(--sky-rust) 10%, transparent); }
.status--completed { color: var(--clr-muted); border-style: dashed; }
.status--completed::before { opacity: 0.5; }

/* Trip length chip, e.g. "2 Nights / 3 Days" */
.duration {
  display: inline-flex;
  align-items: center;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 400;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--clr-text);
  background: var(--clr-surface-2);
  border: 1px solid var(--clr-line);
  border-radius: 999px;
  padding: 0.28rem 0.7rem;
  white-space: nowrap;
}


@media (min-width: 760px) { .trail-card { grid-template-columns: 320px 1fr; } }


.meta {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-5);
  font-size: 0.85rem;
  color: var(--clr-muted);
}
.meta li { margin: 0; display: flex; align-items: center; gap: 6px; }
.meta b {
  color: var(--clr-text);
  font-weight: 600;
  font-size: 0.8rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}


/* --------------------------------------------------------------------------
   11. Gallery & lightbox
   -------------------------------------------------------------------------- */
/* A mosaic rather than a uniform grid: most tiles are one cell, some span two
   columns or two rows, so the page has a rhythm instead of a chequerboard.
   Row height is fixed per breakpoint and tiles span whole rows, which is what
   lets the sizes mix cleanly. */
.gallery-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  grid-auto-rows: 44vw;
  gap: var(--sp-3);
  /* Backfills the holes a mixed-size layout leaves behind. Safe here: the
     order of holiday snaps carries no meaning. */
  grid-auto-flow: dense;
}
@media (min-width: 700px) {
  .gallery-grid { grid-template-columns: repeat(3, 1fr); grid-auto-rows: 22vw; gap: var(--sp-4); }
}
@media (min-width: 1024px) {
  .gallery-grid { grid-template-columns: repeat(4, 1fr); grid-auto-rows: 15.5vw; }
}
@media (min-width: 1400px) {
  .gallery-grid { grid-auto-rows: 215px; }
}

.gallery-item--wide { grid-column: span 2; }
.gallery-item--tall { grid-row: span 2; }
.gallery-item--big  { grid-column: span 2; grid-row: span 2; }

/* On the narrowest screens a two-wide tile would fill the row and a tall one
   would tower, so large tiles collapse back to a single cell. */
@media (max-width: 520px) {
  .gallery-item--wide, .gallery-item--big { grid-column: span 2; grid-row: span 1; }
  .gallery-item--tall { grid-row: span 1; }
}

.gallery-item {
  position: relative;
  display: block;
  width: 100%;
  height: 100%;
  padding: 0;
  border: 1px solid var(--clr-line);
  border-radius: var(--radius);
  background: var(--clr-surface);
  overflow: hidden;
  cursor: zoom-in;
  transition: border-color 0.2s var(--ease);
}
.gallery-item img { width: 100%; height: 100%; object-fit: cover; filter: saturate(0.92) sepia(0.06); }
.gallery-item:hover, .gallery-item:focus-visible {
  border-color: var(--signal);
  z-index: 2;
}

/* Caption slides up on hover and on keyboard focus. Hidden from screen readers
   because the button already has an accessible name from its alt text. */
.gallery-item__cap {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 3;
  padding: var(--sp-5) var(--sp-4) var(--sp-3);
  text-align: left;
  font-size: 0.82rem;
  line-height: 1.35;
  color: var(--cloud);
  background: linear-gradient(180deg, transparent 0%, color-mix(in srgb, var(--ink) 82%, transparent) 55%);
  transform: translateY(101%);
  transition: transform 0.28s var(--ease);
}
.gallery-item:hover .gallery-item__cap,
.gallery-item:focus-visible .gallery-item__cap { transform: none; }

/* Touch screens have no hover, so the caption sits visible on the big tiles
   where there is room for it. */
@media (hover: none) {
  .gallery-item__cap { transform: none; }
  .gallery-item:not(.gallery-item--big):not(.gallery-item--wide) .gallery-item__cap { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .gallery-item:hover, .gallery-item:focus-visible { transform: none; }
  .gallery-item:hover img, .gallery-item:focus-visible img { transform: none; }
  .gallery-item__cap { transition: none; }
}

/* Video tiles: a play badge over the thumbnail. The YouTube player itself is
   not loaded until the tile is clicked. */
.gallery-item--video::after {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  width: 54px;
  height: 54px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--ink) 72%, transparent) no-repeat center;
  border: 1px solid color-mix(in srgb, var(--cloud) 90%, transparent);
  /* white play triangle */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23fff'%3E%3Cpath d='M9 6.5v11l9-5.5z'/%3E%3C/svg%3E");
  background-size: 24px 24px;
  background-position: 54% center;
  transition: transform 0.2s var(--ease), background-color 0.2s var(--ease);
  pointer-events: none;
}
.gallery-item--video:hover::after {
  transform: scale(1.08);
  background-color: color-mix(in srgb, var(--signal) 92%, transparent);
}
.gallery-item--video::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, color-mix(in srgb, var(--ink) 5%, transparent), color-mix(in srgb, var(--ink) 35%, transparent));
  z-index: 1;
  pointer-events: none;
}
@media (max-width: 480px) {
  .gallery-item--video::after { width: 44px; height: 44px; background-size: 20px 20px; }
}
@media (prefers-reduced-motion: reduce) {
  .gallery-item--video:hover::after { transform: none; }
}

/* Video fills the lightbox at 16:9 rather than the image's natural size */
.lightbox__video {
  position: relative;
  width: 100%;
  max-width: 1100px;
  margin-inline: auto;
  aspect-ratio: 16 / 9;
  background: var(--ink-deep);
  border-radius: var(--radius);
  overflow: hidden;
}
.lightbox__video iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

/* A self-hosted clip keeps its own shape rather than being forced into 16:9.
   Phone footage from a trail is usually portrait, and letterboxing a 9:16 reel
   into a landscape box wastes most of the screen it is being watched on. */
.lightbox__video--file {
  aspect-ratio: auto;
  background: transparent;
  overflow: visible;
}
.lightbox__video--file video {
  display: block;
  width: auto;
  max-width: 100%;
  max-height: 78vh;
  margin-inline: auto;
  border-radius: var(--radius);
  background: var(--ink-deep);
}

/* Home page strip */
.gallery-strip { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--sp-3); }
@media (min-width: 700px) { .gallery-strip { grid-template-columns: repeat(4, 1fr); } }
.gallery-strip a { display: block; border-radius: var(--radius); overflow: hidden; border: 1px solid var(--clr-line); aspect-ratio: 4/3; }
.gallery-strip img { width: 100%; height: 100%; object-fit: cover; filter: saturate(0.92) sepia(0.06); }
.gallery-strip a:hover { border-color: var(--signal); }

/* The viewer stays dark so photographs carry the screen */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: none;
  align-items: center;
  justify-content: center;
  background: color-mix(in srgb, var(--sky-void) 96%, transparent);
  padding: var(--sp-5);
  overscroll-behavior: contain;
}
.lightbox.is-open { display: flex; }
.lightbox__figure { margin: 0; max-width: 1100px; width: 100%; text-align: center; }
.lightbox__media img {
  max-height: 78vh;
  width: auto;
  margin-inline: auto;
  border-radius: var(--radius);
}
.lightbox__caption {
  color: var(--mist);
  font-size: 0.9rem;
  margin-top: var(--sp-4);
}
.lightbox__btn {
  position: absolute;
  background: color-mix(in srgb, var(--cloud) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--cloud) 35%, transparent);
  color: var(--cloud);
  width: 48px;
  height: 48px;
  border-radius: 50%;
  font-size: 1.4rem;
  line-height: 1;
  display: grid;
  place-items: center;
  cursor: pointer;
  transition: background 0.2s var(--ease), border-color 0.2s var(--ease);
}
.lightbox__btn:hover { background: color-mix(in srgb, var(--cloud) 22%, transparent); border-color: var(--cloud); }
.lightbox__btn:focus-visible { outline-color: var(--cloud); }
.lightbox__close { top: var(--sp-5); right: var(--sp-5); }
.lightbox__prev { left: var(--sp-4); top: 50%; transform: translateY(-50%); }
.lightbox__next { right: var(--sp-4); top: 50%; transform: translateY(-50%); }
body.no-scroll { overflow: hidden; }

/* --------------------------------------------------------------------------
   11b. Membership badges (Silver / Gold / Platinum)
   Each tier sets --tier-bar and --tier-ink; everything else is shared.
   -------------------------------------------------------------------------- */
/* The three tier cards are not `.card` (a claim to drop) and not a roster of
   people - they keep their own grid rather than share the removed
   `.grid.grid--3` card-grid utility. Same columns that rule had. */
.tier-grid { display: grid; gap: var(--sp-5); grid-template-columns: 1fr; }
@media (min-width: 640px) { .tier-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 960px) { .tier-grid { grid-template-columns: repeat(3, 1fr); } }
.tier {
  position: relative;
  background: var(--clr-surface);
  border: 1px solid var(--clr-line);
  border-radius: var(--radius-lg);
  padding: var(--sp-6) var(--sp-5) var(--sp-5);
  overflow: hidden;
  transition: border-color 0.2s var(--ease);
}
.tier::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 5px;
  background: var(--tier-bar);
}
.tier:hover { border-color: var(--signal); }

.tier--silver   { --tier-bar: var(--silver);   --tier-ink: color-mix(in oklab, var(--silver) 16%, var(--text)); }
.tier--gold     { --tier-bar: var(--gold);     --tier-ink: color-mix(in oklab, var(--gold) 18%, var(--text)); }
.tier--platinum { --tier-bar: var(--platinum); --tier-ink: color-mix(in oklab, var(--platinum) 15%, var(--text)); }
.tier--platinum::before { box-shadow: inset 0 0 0 1px var(--slate); }

.tier__medal { width: 72px; height: 72px; margin-bottom: var(--sp-4); }

.tier__name {
  font-size: 1.35rem;
  letter-spacing: 0.08em;
  color: var(--tier-ink);
  margin: 0 0 var(--sp-3);
}

.tier__gate {
  display: inline-block;
  font-size: var(--t-xs);
  font-weight: 400;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--clr-muted);
  border: 1px solid var(--clr-line);
  border-radius: 999px;
  padding: 0.22rem 0.7rem;
  margin: 0 0 var(--sp-5);
}

/* Sub-heading inside a tier card: "Eligibility" / "What you get" */
.tier__label {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 400;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--tier-ink);
  margin: 0 0 var(--sp-4);
}
.tier__label::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--clr-line);
}
.tier__label + ul { margin-bottom: var(--sp-5); }
.tier__label--perks { margin-top: var(--sp-5); }

.tier__req { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--sp-3); }
.tier__req li {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  margin: 0;
  font-size: 0.94rem;
  color: var(--clr-muted);
  line-height: 1.5;
}
.tier__req li::before {
  content: "";
  flex: none;
  width: 8px;
  height: 8px;
  margin-top: 8px;
  border-radius: 50%;
  background: var(--tier-ink);
}
.tier__req b { color: var(--clr-text); font-weight: 600; }

/* Benefits list - ticks rather than dots, so the two lists read differently */
.tier__perks { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--sp-3); }
.tier__perks li {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  margin: 0;
  font-size: 0.94rem;
  color: var(--clr-muted);
  line-height: 1.5;
}
.tier__perks li::before {
  content: "\2713";
  flex: none;
  width: 1em;
  color: var(--tier-ink);
  font-weight: 700;
  line-height: 1.5;
}
.tier__perks b { color: var(--clr-text); font-weight: 600; }

/* Section tagline, straight from the club's own badge announcement */
.tier-tagline {
  font-family: var(--font-mono);
  font-size: clamp(1rem, 2vw, 1.2rem);
  font-weight: 400;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--clr-accent);
  margin: 0 0 var(--sp-4);
}

/* Closing creed band. Used under the badge tiers and on the Learn With MG page. */
.creed {
  margin-top: var(--sp-7);
  padding: var(--sp-6) var(--sp-5);
  border-top: 1px solid var(--clr-line);
  border-bottom: 1px solid var(--clr-line);
  text-align: center;
}
.creed__line {
  font-family: var(--font-display);
  font-size: clamp(1.3rem, 3vw, 1.9rem);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--clr-text);
  margin: 0 0 var(--sp-5);
}
.creed__line em { font-style: normal; color: var(--clr-accent); }
.creed__values {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--sp-3) var(--sp-6);
}
.creed__values li {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 0.85rem;
  font-weight: 400;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--clr-muted);
  display: flex;
  align-items: center;
  gap: var(--sp-3);
}
.creed__values li + li::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--clr-steel);
}

/* The three standing rules under the tier cards */
.tier-notes { margin-top: var(--sp-6); display: grid; gap: var(--sp-4); }
@media (min-width: 900px) { .tier-notes { grid-template-columns: repeat(3, 1fr); } }
.tier-note {
  border-left: 2px solid var(--clr-line);
  background: var(--clr-surface-2);
  border-radius: 0 var(--radius) var(--radius) 0;
  padding: var(--sp-4) var(--sp-5);
}
.tier-note b {
  display: block;
  font-family: var(--font-display);
  font-size: 0.95rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin-bottom: var(--sp-2);
}
.tier-note span { color: var(--clr-muted); font-size: 0.92rem; }

/* Compact tier row, used as the home page teaser */
.tier-mini-row { display: grid; gap: var(--sp-4); }
@media (min-width: 760px) { .tier-mini-row { grid-template-columns: repeat(3, 1fr); } }
.tier-mini {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  background: var(--clr-surface);
  border: 1px solid var(--clr-line);
  border-radius: var(--radius-lg);
  padding: var(--sp-4) var(--sp-5);
  overflow: hidden;
  transition: border-color 0.2s var(--ease);
}
.tier-mini::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  width: 4px;
  background: var(--tier-bar);
}
.tier-mini:hover { border-color: var(--signal); }
.tier-mini svg, .tier-mini img { width: 54px; height: 54px; flex: none; }
.tier-mini b {
  display: block;
  font-family: var(--font-display);
  font-size: 1.1rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--tier-ink);
}
.tier-mini > div { min-width: 0; }
.tier-mini span { display: block; color: var(--clr-muted); font-size: 0.88rem; }
.tier-mini__perk { color: var(--tier-ink) !important; font-weight: 600; margin-top: 2px; }

/* --------------------------------------------------------------------------
   12. Crew
   -------------------------------------------------------------------------- */


/* Marshal roster sub-headings */
.roster-heading {
  font-size: 1.25rem;
  letter-spacing: 0.06em;
  margin-bottom: var(--sp-2);
  padding-top: var(--sp-2);
  border-top: 2px solid var(--clr-steel);
}
.roster-blurb {
  color: var(--clr-muted);
  font-size: 0.95rem;
  max-width: 60ch;
  margin-bottom: var(--sp-5);
}

/* Marshal cards are the crew card at a smaller scale */

/* Obvious empty slot until a real name and photo replace it */


/* Wide group photo closing the team section */
.team-photo { margin: var(--sp-8) 0 0; }
.team-photo img {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: var(--radius-lg);
  border: 1px solid var(--clr-line);
}
.team-photo figcaption {
  margin-top: var(--sp-3);
  text-align: center;
  color: var(--clr-muted);
  font-size: 0.9rem;
}

/* --------------------------------------------------------------------------
   13. FAQ (details / summary)
   -------------------------------------------------------------------------- */
.faq { border-top: 1px solid var(--clr-line); }
.faq details { border-bottom: 1px solid var(--clr-line); }
.faq summary {
  cursor: pointer;
  list-style: none;
  padding: var(--sp-5) 2.5rem var(--sp-5) 0;
  position: relative;
  font-family: var(--font-display);
  font-size: 1.1rem;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: "+";
  position: absolute;
  right: 0.25rem;
  top: 50%;
  transform: translateY(-50%);
  font-size: 1.6rem;
  color: var(--clr-accent);
  line-height: 1;
}
.faq details[open] summary::after { content: "\2212"; }
.faq summary:hover { color: var(--signal-ink); }
.faq details > div { padding-bottom: var(--sp-5); color: var(--clr-muted); max-width: 70ch; }

/* --------------------------------------------------------------------------
   14. Rules, checklists, requirements
   -------------------------------------------------------------------------- */
.rules-list { counter-reset: rule; list-style: none; padding: 0; margin: 0; display: grid; gap: var(--sp-4); }
.rules-list li {
  counter-increment: rule;
  position: relative;
  padding: var(--sp-4) var(--sp-5) var(--sp-4) 4.25rem;
  background: var(--clr-surface);
  border: 1px solid var(--clr-line);
  border-radius: var(--radius-lg);
  margin: 0;
}
.rules-list li::before {
  content: counter(rule, decimal-leading-zero);
  position: absolute;
  left: var(--sp-5);
  top: var(--sp-4);
  font-family: var(--font-display);
  font-size: 1.5rem;
  font-weight: 400;
  font-family: var(--font-mono);
  color: var(--clr-line);
  line-height: 1;
}
.rules-list b { display: block; margin-bottom: var(--sp-1); }
.rules-list span { color: var(--clr-muted); }

.checklist { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--sp-3); }
@media (min-width: 700px) { .checklist { grid-template-columns: repeat(2, 1fr); } }
.checklist li {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  margin: 0;
  padding: var(--sp-3) var(--sp-4);
  background: var(--clr-surface);
  border: 1px solid var(--clr-line);
  border-radius: var(--radius);
}
.checklist li::before {
  content: "";
  flex: none;
  width: 18px;
  height: 18px;
  margin-top: 4px;
  border-radius: 2px;
  border: 1px solid var(--clr-line);
  background:
    linear-gradient(45deg, transparent 44%, var(--clr-line) 44%, var(--clr-line) 56%, transparent 56%),
    linear-gradient(-45deg, transparent 44%, var(--clr-line) 44%, var(--clr-line) 56%, transparent 56%);
}
.checklist b { display: block; }
.checklist span { color: var(--clr-muted); font-size: 0.9rem; }

.callout {
  border-left: 2px solid var(--clr-line);
  background: var(--clr-surface);
  border-top: 1px solid var(--clr-line);
  border-right: 1px solid var(--clr-line);
  border-bottom: 1px solid var(--clr-line);
  padding: var(--sp-5) var(--sp-6);
  border-radius: 0 var(--radius-lg) var(--radius-lg) 0;
  margin-block: var(--sp-6);
}
.callout h3 { margin-bottom: var(--sp-3); }
.callout p { color: var(--clr-muted); }
.callout--warn { border-left-color: var(--clr-black); }

/* --------------------------------------------------------------------------
   15. Join / form embed
   -------------------------------------------------------------------------- */
.form-embed {
  background: var(--clr-surface);
  border: 1px solid var(--clr-line);
  border-radius: var(--radius-lg);
  padding: var(--sp-4);
}
.form-embed__frame {
  position: relative;
  width: 100%;
  aspect-ratio: 3 / 4;
  min-height: 620px;
  max-height: 1400px;
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--clr-surface-2);
}
.form-embed__frame iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
@media (min-width: 760px) { .form-embed__frame { aspect-ratio: 4 / 3; } }

.form-fallback {
  margin-top: var(--sp-4);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--clr-line);
  font-size: 0.92rem;
  color: var(--clr-muted);
  text-align: center;
}

.steps { list-style: none; counter-reset: step; padding: 0; margin: 0; display: grid; gap: var(--sp-4); }
@media (min-width: 800px) { .steps { grid-template-columns: repeat(3, 1fr); } }
.steps li { counter-increment: step; margin: 0; padding-top: var(--sp-4); border-top: 2px solid var(--clr-steel); }
.steps li::before {
  content: "Step " counter(step);
  display: block;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--clr-accent);
  margin-bottom: var(--sp-2);
}
.steps b { display: block; font-family: var(--font-display); font-size: 1.15rem; text-transform: uppercase; margin-bottom: var(--sp-2); }
.steps span { color: var(--clr-muted); font-size: 0.94rem; }

/* --------------------------------------------------------------------------
   15b. Learn With MG
   -------------------------------------------------------------------------- */

/* Dated launch pill, sits under the page-hero heading */
.launch-pill {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  background: var(--ink);
  color: var(--sun-core);
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 0.45rem 1rem;
  border-radius: 999px;
  margin-bottom: var(--sp-5);
}
.launch-pill::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--signal);
}

/* Home page announcement strip */
.announce {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-3) var(--sp-4);
  border-block: 1px solid var(--clr-line);
  padding: var(--sp-4) var(--gutter);
  color: var(--text);
  background-image: none;
  transition: border-color 0.2s var(--ease);
}
.announce:hover { border-block-color: var(--signal); color: var(--text); }
.announce__inner {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-3) var(--sp-4);
}
.announce__tag {
  flex: none;
  background: var(--ink);
  color: var(--sun-core);
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 0.25rem 0.7rem;
  border-radius: 999px;
}
.announce__text { flex: 1 1 20rem; font-size: 0.95rem; }
.announce__text b { font-weight: 600; }
.announce__go {
  flex: none;
  font-family: var(--font-mono);
  font-size: 0.82rem;
  font-weight: 400;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--signal-ink);
}
.announce:hover .announce__go { color: var(--signal); }

/* The two programme levels. Named .programme, not .level: the trail
   difficulty scale owns .level/.level__dots/.level__text as a shared
   contract with the trails pages, and this learn-page card predates it. */
.programme {
  position: relative;
  background: var(--clr-surface);
  border: 1px solid var(--clr-line);
  border-radius: var(--radius-lg);
  padding: var(--sp-6);
  overflow: hidden;
  transition: border-color 0.2s var(--ease);
}
.programme:hover { border-color: var(--signal); }
.programme::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 5px;
  background: var(--level-bar);
}
.programme--1 { --level-bar: var(--mist);   --level-ink: color-mix(in oklab, var(--mist) 16%, var(--text)); }
.programme--2 { --level-bar: var(--signal); --level-ink: var(--signal-ink); }

.programme__num {
  display: block;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 400;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--level-ink);
  margin-bottom: var(--sp-2);
}
.programme__name { font-size: 1.6rem; color: var(--level-ink); margin-bottom: var(--sp-3); }
.programme p { color: var(--clr-muted); }

/* --------------------------------------------------------------------------
   16. CTA band
   -------------------------------------------------------------------------- */
.cta-band { position: relative; overflow: hidden; padding-block: var(--sp-9); text-align: center; }
.cta-band__media { position: absolute; inset: 0; z-index: 0; }
.cta-band__media img { width: 100%; height: 100%; object-fit: cover; filter: saturate(0.92) sepia(0.06); }
.cta-band__media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, color-mix(in oklab, var(--sky-mid) 90%, transparent), color-mix(in oklab, var(--sky-low) 93%, transparent));
}
.cta-band .wrap { position: relative; z-index: 1; }
.cta-band .btn-row { justify-content: center; }
.cta-band p { margin-inline: auto; }

/* --------------------------------------------------------------------------
   16b. Floating WhatsApp button
   Sits below the lightbox (z 200) and above the sticky header (z 100).
   -------------------------------------------------------------------------- */
.wa-float {
  position: fixed;
  right: max(var(--sp-5), env(safe-area-inset-right));
  bottom: max(var(--sp-5), env(safe-area-inset-bottom));
  z-index: 150;
  width: 56px;
  height: 56px;
  display: grid;
  place-items: center;
  /* Not WhatsApp's #25D366: a white icon on it is only 1.98:1, under the 3:1
     WCAG requires for graphical objects. This darker green still reads as
     WhatsApp and clears both the icon and the button boundary at 3.5:1. */
  background: #1A9D4E;
  color: var(--cloud);
  border: 1px solid color-mix(in srgb, var(--cloud) 30%, transparent);
  border-radius: 50%;
  background-image: none;
  transition: border-color 0.18s var(--ease);
}
.wa-float:hover { color: var(--cloud); border-color: var(--cloud); }
.wa-float:focus-visible { outline: 2px solid var(--signal); outline-offset: 2px; }
.wa-float svg { width: 30px; height: 30px; }
@media (max-width: 480px) { .wa-float { width: 50px; height: 50px; } .wa-float svg { width: 27px; height: 27px; } }
@media (prefers-reduced-motion: reduce) { .wa-float:hover { transform: none; } }

/* --------------------------------------------------------------------------
   16c. 404
   -------------------------------------------------------------------------- */
.notfound { text-align: center; padding-block: var(--sp-9); }
.notfound__code {
  font-family: var(--font-display);
  font-family: var(--font-mono);
  font-size: clamp(var(--t-3xl), 18vw, 11rem);
  font-weight: 400;
  line-height: 0.9;
  letter-spacing: -0.04em;
  color: color-mix(in srgb, var(--text) 60%, transparent);
  margin: 0 0 var(--sp-4);
}
.notfound .btn-row { justify-content: center; }
.notfound__links {
  list-style: none;
  padding: 0;
  margin: var(--sp-7) 0 0;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--sp-3) var(--sp-5);
  font-size: 0.9rem;
}
.notfound__links li { margin: 0; }

/* --------------------------------------------------------------------------
   17. Footer - the silhouette ridge

   The closing frame, and the payoff for the whole scroll. The ridge is
   revealed as the last section passes while the sun descends behind it, so
   the two meet. Below it the page bottoms out on --sky-void.

   The artwork is a raster mask rather than SVG: the supplied PDF turned out to
   hold one flat 3072x2048 bitmap, not paths. Driving it through mask-image
   keeps the per-layer tinting that `fill: currentColor` would have given.
   See tools/build-silhouette.py.
   -------------------------------------------------------------------------- */
/* The box carries the artwork's own proportions, so the band is never a fixed
   height the mask has to be stretched into. It was: at 1920 the silhouette was
   squashed 31% vertically and at 360 stretched 75%, because mask-size 100% 100%
   fills the box regardless of aspect. */
.ridge {
  position: relative;
  aspect-ratio: 3018 / 959;
  margin-top: var(--sp-9);
  pointer-events: none;
  overflow: hidden;
}
/* Below the phone breakpoint the artwork is only ~110px tall at full width, so
   the band is given a fixed height and the silhouette sits on the bottom of it
   with sky above. The whole group stays visible rather than being cropped to
   the middle, which matters more here than the figures being large. */
@media (max-width: 760px) {
  .ridge { aspect-ratio: auto; height: 230px; }
}
.ridge__layer {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 100%;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  /* contain, never 100% 100%: the artwork scales up past 1600px rather than
     tiling, and can never be squeezed to fit a box of the wrong shape. */
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-position: bottom center;
  mask-position: bottom center;
}
.ridge__back {
  -webkit-mask-image: url("/assets/silhouette/ridge-back.png");
  mask-image: url("/assets/silhouette/ridge-back.png");
  background: color-mix(in oklab, var(--mist) 52%, var(--sky-low));
  /* Parallax: travels up 40px slower than the scroll */
  transform: translateY(var(--ridge-parallax, 0px));
}
.ridge__front {
  -webkit-mask-image: url("/assets/silhouette/ridge-front.png");
  mask-image: url("/assets/silhouette/ridge-front.png");
  /* Deliberately darker than --ink: a silhouette against a night sky should be
     the darkest thing on the page. */
  background: var(--ink-deep);
}

.site-footer {
  position: relative;
  background: var(--sky-void);
  color: var(--cloud);
  padding-block: var(--sp-7) var(--sp-5);
  font-size: var(--t-sm);
}
/* Type keeps clear of the column the figure on the roof stands in. He is the
   focal point, and he lands at 86% width in the supplied artwork - not the 68%
   the spec assumed, which was measured before the file was split. */
@media (min-width: 900px) {
  .site-footer .wrap { max-width: min(var(--wrap), 84%); margin-inline: 0 auto; }
}
.site-footer__grid { display: grid; gap: var(--sp-6); }
@media (min-width: 760px) { .site-footer__grid { grid-template-columns: 1.4fr 1fr 1fr; gap: var(--sp-7); } }
.site-footer h4 {
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  font-weight: 400;
  letter-spacing: 0.12em;
  color: color-mix(in srgb, var(--cloud) 62%, transparent);
  margin-bottom: var(--sp-4);
}
/* 72px below the ridge, per the closing composition - larger than the header
   mark, because down here it is the sign-off rather than navigation. */
.site-footer .brand img {
  width: 72px;
  height: 72px;
  border-color: color-mix(in srgb, var(--cloud) 25%, transparent);
}

/* The closing line, in the utility face */
.ridge-signoff {
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--cloud) 70%, transparent);
  margin: var(--sp-6) 0 0;
  max-width: none;
}
.site-footer ul { list-style: none; padding: 0; margin: 0; }
.site-footer li { margin-bottom: var(--sp-2); }
.site-footer a { color: var(--cloud); }
.site-footer a:hover { color: var(--signal); }
.site-footer p, .site-footer .muted { color: color-mix(in srgb, var(--cloud) 70%, transparent); max-width: 40ch; }
.site-footer .brand-tag { color: color-mix(in srgb, var(--cloud) 60%, transparent); }

.social { display: flex; gap: var(--sp-3); margin-top: var(--sp-4); }
.social a {
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  border: 1px solid color-mix(in srgb, var(--cloud) 25%, transparent);
  border-radius: var(--radius);
  color: var(--cloud);
  background-image: none;
  transition: border-color 0.2s var(--ease), color 0.2s var(--ease);
}
.social a:hover { border-color: var(--signal); color: var(--signal); }
.social svg { width: 20px; height: 20px; }

/* Clears the floating WhatsApp button, which otherwise lands on top of the
   colophon once the footer stacks on a narrow screen. */
@media (max-width: 700px) {
  .site-footer { padding-bottom: calc(var(--sp-8) + env(safe-area-inset-bottom)); }
}

.colophon {
  margin-top: var(--sp-6);
  padding-top: var(--sp-4);
  border-top: 1px solid color-mix(in srgb, var(--cloud) 18%, transparent);
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3) var(--sp-5);
  justify-content: space-between;
  color: color-mix(in srgb, var(--cloud) 62%, transparent);
}

/* --------------------------------------------------------------------------
   18. Scroll reveal - 12px rise, once only, 60ms stagger
   -------------------------------------------------------------------------- */
.reveal { opacity: 0; transform: translateY(12px); }
.reveal.is-visible {
  opacity: 1;
  transform: none;
  transition: opacity 420ms var(--ease), transform 420ms var(--ease);
  transition-delay: var(--reveal-delay, 0ms);
}

@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;
  }
  /* The sky is content, not decoration, so it still changes with scroll - JS
     snaps it to the six named stops instead of easing between them. Parallax
     is off and the star field cross-fades once. */
  .ridge__back { transform: none !important; }
  .starfield { transition: opacity 0.001ms; }
  .reveal { opacity: 1; transform: none; }
  .gallery-item:hover img, .gallery-strip a:hover img { transform: none; }
  .btn:hover, .card:hover, .crew-card:hover, .gallery-item:hover { transform: none; }
}

/* "What it does not cover" - same list, read the other way round. */


/* The day-by-day itinerary on a trail page.
   Not .steps: that is a three-column grid labelled "Step N", built for the
   three-stage join process. A trail runs down the page, one day at a time.

   The day label is real text, not a CSS counter. A counter numbered every list
   item, so Kodai's hour-by-hour schedule - which carries its own "Day 1 -
   Friday 9 October" headings - rendered as a nineteen-day trip. The counter
   also could not show the date, which is the useful half of the label. */
.itinerary {
  list-style: none;
  padding: 0;
  margin: var(--sp-5) 0 0;
  display: grid;
  gap: var(--sp-6);
}
.itinerary__day { margin: 0; max-width: 62ch; }
.itinerary__label {
  /* A day heading, not a tag. At 11px mono above 17px body it was smaller and
     lighter than the steps beneath it - the hierarchy upside down. It carries a
     date now ("Day 1 - Friday 9 October") rather than a bare ordinal, which is
     a heading's job. */
  margin: 0 0 var(--sp-3);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--t-lg);
  line-height: 0.95;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--clr-accent);
}
.itinerary__steps {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: var(--sp-3);
}
.itinerary__steps li {
  margin: 0;
  padding-top: var(--sp-3);
  border-top: 1px solid var(--clr-line);
}
.itinerary__steps li:first-child { padding-top: 0; border-top: 0; }

/* Terrain on a trail page. Tags, not a checklist: they describe the ground
   rather than listing things to do, so they read as a set of labels. */
.terrain-tags {
  list-style: none;
  padding: 0;
  margin: var(--sp-5) 0 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
}
.terrain-tags li {
  margin: 0;
  padding: 0.3rem 0.6rem;
  border: 1px solid var(--clr-line);
  border-radius: var(--radius);
  background: var(--clr-surface);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.02em;
}

/* =============================================================================
   19. The instrument

   The club's facts, presented the way a trail log presents them: labelled,
   aligned, dense. This replaces the card grid, which was the single most
   templated thing on the site - a bordered box with a heading and a paragraph
   is the shape of every website since 2015.

   Depth still comes from the sky, so these are hairlines and alignment, never
   boxes and shadows.
   ============================================================================= */

/* The rail: labels and figures left, content right. Asymmetric on purpose -
   a centred wrap with a centred heading is what "templated" looks like. */
.rail {
  display: grid;
  gap: var(--sp-4);
  align-items: start;
}
@media (min-width: 800px) {
  .rail { grid-template-columns: 12rem 1fr; gap: var(--sp-6); }
}

.rail__label {
  font-family: var(--font-mono);
  font-size: var(--t-xs);   /* 11px — the floor */
  line-height: 1.4;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--clr-muted);
  padding-top: 0.35rem;   /* optically aligns with the first line of body text */
}
.rail__body { min-width: 0; }   /* lets long content shrink instead of overflowing the grid */

/* A wrapping row of labelled facts. The label is the interface. */
.spec {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-5) var(--sp-6);
  margin: var(--sp-5) 0;
  padding: var(--sp-5) 0;
  border-top: 1px solid var(--clr-line);
  border-bottom: 1px solid var(--clr-line);
}
.spec__item { min-width: 8rem; }
.spec__label {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--clr-muted);
  margin-bottom: var(--sp-2);
}
.spec__value {
  display: block;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--t-md);
  color: var(--text);
}

/* Hairline-ruled lists, replacing .grid + .card. */
.ruled { list-style: none; margin: 0; padding: 0; }
.ruled__row {
  display: grid;
  gap: var(--sp-2) var(--sp-5);
  padding: var(--sp-5) 0;
  border-top: 1px solid var(--clr-line);
  margin: 0;
}
.ruled__row:last-child { border-bottom: 1px solid var(--clr-line); }
@media (min-width: 800px) {
  .ruled__row { grid-template-columns: 12rem 1fr; align-items: baseline; }
}

/* --- A trail as a block ----------------------------------------------------
   The previous design gave every trail the same six columns, and thirteen of
   fifteen filled one of them. A block sizes itself to what is known. */
/* .panel.trailblock, not .trailblock: `.panel { padding }` is declared later
   in this file at equal specificity, so a single-class override loses on
   source order and the photo stops bleeding to the edge. Measured: 32px of
   padding where the design calls for none. */
.panel.trailblock { display: grid; gap: 0; padding: 0; overflow: hidden; margin-bottom: var(--sp-6); }
/* Stacked panels need air between them. Only .trailblock carried a margin,
   so the calendar list and the archive sat flush against each other and
   read as one long surface. Rules separate sections; here space does. */
.panel + .panel { margin-top: var(--sp-8); }
@media (min-width: 860px) { .trailblock { grid-template-columns: 5fr 7fr; align-items: stretch; } }
.trailblock__photo { width: 100%; height: 100%; min-height: 14rem; object-fit: cover; }
.trailblock__body { padding: var(--sp-6); }
.trailblock__facts {
  display: flex; flex-wrap: wrap; gap: var(--sp-4) var(--sp-6);
  margin: var(--sp-5) 0;
}
.trailblock__facts div { min-width: 7rem; }
.trailblock__facts dt { margin-bottom: var(--sp-1); }
.trailblock__facts dd {
  margin: 0;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--t-sm);
  color: var(--mg-snow);
}

/* --- The calendar entries --------------------------------------------------
   One line each. Rules between rows, not around them. */
.runlist { list-style: none; padding: 0; margin: var(--sp-6) 0 0; }
.runlist__row {
  display: grid;
  grid-template-columns: 4rem 1fr auto;
  gap: var(--sp-4);
  align-items: baseline;
  padding: var(--sp-4) 0;
  border-top: 1px solid color-mix(in srgb, var(--mg-trail) 16%, transparent);
}
.runlist__row:last-child { border-bottom: 1px solid color-mix(in srgb, var(--mg-trail) 16%, transparent); }
.runlist__name { font-size: var(--t-md); }
.runlist__aside { display: flex; flex-wrap: wrap; gap: var(--sp-3); align-items: baseline; justify-content: flex-end; }
.runlist__type { font-family: var(--font-mono); font-size: var(--t-xs); text-transform: uppercase; letter-spacing: 0.1em; color: var(--mg-steel); }
@media (max-width: 560px) {
  .runlist__row { grid-template-columns: 4rem 1fr; }
  .runlist__aside { grid-column: 2; justify-content: flex-start; }
}

/* .spec is a <dl>, so its children need resetting from browser defaults. */
.spec dd { margin: 0; }
.spec dt { margin: 0; }

/* =============================================================================
   20. Panels — the v2 surface
   
   A dark panel floating on the sky. This is the whole of the v2 structural
   idea: the club's palette stops being a background and becomes the thing that
   sits on one.
   
   Text inside a panel is always Snow White on a near-black ground, so contrast
   is constant regardless of where the reader is in the day. The sky shows
   between and behind panels, never underneath the words.
   ============================================================================= */
.panel {
  background: color-mix(in srgb, var(--mg-black) 88%, transparent);
  color: var(--mg-snow);
  border-radius: var(--radius-lg);
  padding: var(--sp-6);
  /* A single hairline of Trail Grey at low alpha, so the panel has an edge
     against a bright midday sky without drawing a hard line. */
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--mg-trail) 18%, transparent);
}
.panel--tight { padding: var(--sp-5); }

.panel h1, .panel h2, .panel h3 { color: var(--mg-snow); }
.panel p, .panel li { color: var(--mg-snow); }
.panel .muted, .panel .lede { color: var(--mg-steel); }
.panel a { color: var(--mg-sand); }

/* The instrument's labels and figures (.spec, .rail__label) predate the panel
   and set --clr-muted / --text directly on a <dt>/<dd>/<span> that `.panel p,
   .panel li` cannot reach - same failure shape as the tier ink below: correct
   on a light page, invisible once the ground is fixed near-black. */
.panel .spec__label, .panel .rail__label { color: var(--mg-steel); }
.panel .spec__value { color: var(--mg-snow); }

/* Labels inside a panel. The field-log vocabulary the brand document asks for,
   at the 11px floor and never below. */
.panel__label {
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--mg-steel);
}

/* --- The v2 hero -----------------------------------------------------------
   A photograph, the mark, and a statement. design-language.md §7 asks for the
   home page to feel like opening a 4x4 magazine, so the hero carries weight
   and little else. The introductory paragraph that used to sit here is gone:
   the statement says the same thing in eight words. */
/* text-align alone does not centre this hero.
   .hero__tagline is a max-width block, so centring its text just centres it
   inside a box still pinned to the left edge - it needs auto margins. And
   .btn-row is a flex row, which text-align cannot reach at all; its items
   packed to flex-start while everything above them looked centred. */
.hero--v2 { text-align: center; }
.hero--v2 .hero__tagline { margin-inline: auto; }
.hero--v2 .btn-row { justify-content: center; }
.hero__mark {
  /* The hero is the one place the wordmark is the subject rather than a label,
     so it is sized by width and capped so it cannot outgrow the statement
     beneath it. Masked like the others, for the same reason. */
  width: min(340px, 72vw);
  aspect-ratio: 841 / 174;
  margin: 0 auto var(--sp-5);
  display: block;
  background-color: var(--text);
  -webkit-mask: url("/assets/logo-wordmark.png") no-repeat center / contain;
  mask: url("/assets/logo-wordmark.png") no-repeat center / contain;
}
.hero__statement {
  /* It is an h1, so family, weight, transform and tracking already apply.
     Only what differs from the shared heading rule belongs here. */
  line-height: 0.92;
  margin: 0 auto var(--sp-4);
  max-width: 18ch;
}

/* --- Club principles -------------------------------------------------------
   Not cards. A card grid is the shape of every website, and the brand document
   asks the site to look like evidence rather than advertising. These are
   labelled statements separated by space, inside one panel. */
.principles {
  list-style: none;
  padding: 0;
  margin: var(--sp-6) 0 0;
  display: grid;
  gap: var(--sp-6);
}
@media (min-width: 760px) { .principles { grid-template-columns: 1fr 1fr; } }
.principle { margin: 0; }
.principle p:last-child { margin: var(--sp-2) 0 0; max-width: 46ch; }

/* --- Figures ---------------------------------------------------------------
   Large, monospaced, tabular. design-language.md §6 asks for large numbers as
   a layout device; the existing stylesheet already argued "the credibility is
   in the figures". Both only hold if the figures are true. */
.figures__row { display: flex; flex-wrap: wrap; gap: var(--sp-7); }
.figure { display: flex; flex-direction: column; gap: var(--sp-2); }
.figure__num {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: clamp(var(--t-2xl), 8vw, var(--t-3xl));
  line-height: 1;
  color: var(--mg-snow);
}

/* --- The featured run ------------------------------------------------------
   Photograph and metadata in one panel. Facts render only when known, so a
   thin run reads short rather than showing a row of dashes - the failure that
   sank the previous design. */
/* Compound for the same reason, though this one happens to sit after .panel. */
.panel.runcard { display: grid; gap: var(--sp-5); padding: 0; overflow: hidden; }
@media (min-width: 860px) { .runcard { grid-template-columns: 1fr 1fr; align-items: stretch; } }
.runcard__photo {
  width: 100%; height: 100%; min-height: 15rem;
  object-fit: cover;
  filter: saturate(0.92) sepia(0.06);
}
.runcard__body { padding: var(--sp-6); }
.runcard__meta {
  display: flex; flex-wrap: wrap; gap: var(--sp-4) var(--sp-6);
  margin: var(--sp-5) 0;
}
.runcard__meta div { min-width: 7rem; }
.runcard__meta dt { margin-bottom: var(--sp-1); }
.runcard__meta dd {
  margin: 0;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--t-sm);
  color: var(--mg-snow);
}

/* --- Tier chips on a dark panel --------------------------------------------
   --tier-ink mixes the tier's metal into --text, which is near-black. That is
   right on the light page it was designed for and invisible on a panel: the
   contrast audit measured 1.25 against the required 4.5, at every scroll stop
   between 0.45 and 0.60. Inside a panel the same mix runs toward Snow White.

   The supporting line goes to Trail Grey rather than Steel Grey. Steel measures
   4.58 against a panel over a midday sky - passing, but with 0.08 to spare,
   which is not a margin worth shipping on text this small. */
.panel .tier--silver   { --tier-ink: color-mix(in oklab, var(--silver)   25%, var(--mg-snow)); }
.panel .tier--gold     { --tier-ink: color-mix(in oklab, var(--gold)     25%, var(--mg-snow)); }
.panel .tier--platinum { --tier-ink: color-mix(in oklab, var(--platinum) 25%, var(--mg-snow)); }
.panel .tier-mini span { color: var(--mg-trail); }

/* --- Three more of the same failure shape, found converting the about page -
   a fixed dark colour set directly on a child element that `.panel p` /
   `.panel li` cannot reach, correct on the light page this was written for
   and measured near 1:1 on a near-black panel. Confirmed empirically with
   the contrast audit before adding these, not assumed. */
.panel .tier__req b, .panel .tier__perks b { color: var(--mg-snow); }
.panel .creed__line em { color: var(--mg-sand); }
.panel .team-photo figcaption { color: var(--mg-steel); }
.panel .tier-note span { color: var(--mg-trail); }
/* The FAQ's own +/- glyph and its hover state use the same --clr-accent mix
   (measured above, on .creed__line em) and sit behind the same near-black
   panel background, so they fail identically even though ::after content
   cannot be pointed at by a DOM query to prove it directly. */
.panel .faq summary::after, .panel .faq summary:hover { color: var(--mg-sand); }

/* --- The same failure shape again, converting join: `.steps` sets
   --clr-muted on a <span> that `.panel p`/`.panel li` cannot reach, and its
   "Step N" `::before` label sets --clr-accent directly - both resolve mostly
   to --text, which is near-black over the day half of the scroll. Measured
   near 1:1 against the panel before adding these; ::before content can't be
   pointed at by a DOM query, so it was confirmed by reading
   getComputedStyle(el, '::before') instead. */
.panel .steps span { color: var(--mg-steel); }
.panel .steps li::before { color: var(--mg-sand); }

/* --- Converting rules: `.rules-list` and `.checklist` have the same shape as
   `.steps` above, plus their numbered/checkbox `::before` sets --clr-line
   directly. Their <li> keeps its own pale surface tint, which raises the
   effective background enough that Steel Grey (used above, sitting directly
   on the panel) falls just short - measured 4.2-4.47 against the required
   4.5 across several scroll stops. Trail Grey clears it with margin. */
.panel .rules-list span, .panel .checklist span { color: var(--mg-trail); }
.panel .rules-list li::before { color: var(--mg-trail); }
.panel .checklist li::before {
  border-color: var(--mg-trail);
  background:
    linear-gradient(45deg, transparent 44%, var(--mg-trail) 44%, var(--mg-trail) 56%, transparent 56%),
    linear-gradient(-45deg, transparent 44%, var(--mg-trail) 44%, var(--mg-trail) 56%, transparent 56%);
}

/* --- Difficulty ------------------------------------------------------------
   The dots carry the difficulty; there is no colour ramp. A five-step colour
   scale would need a red at the top, and red is the Marshall sticker marking,
   not a club colour. The dots are aria-hidden because "black circle black
   circle black circle white circle white circle" is not a difficulty. */
.level {
  display: inline-flex;
  align-items: baseline;
  gap: var(--sp-2);
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  /* The chip carries its own ground. On the trails page it sits on a panel,
     but on a trail page it sits on the sky - and the audit measured Steel Grey
     on a pale dawn blue at 1.01 against the required 4.5, because the ground
     changes as you scroll. Text on this site does not sit on the sky; that is
     the whole point of the v2 surfaces, and a component reused across pages
     has to carry the rule with it rather than depend on where it is dropped. */
  background: color-mix(in srgb, var(--mg-black) 88%, transparent);
  border-radius: var(--radius);
  padding: 0.3rem var(--sp-3);
  color: var(--mg-trail);
}
.level__dots { letter-spacing: 0.16em; color: var(--mg-sand); }

/* --- A callout inside a panel ----------------------------------------------
   The callout is already a bordered box. Inside a panel that reads as a box in
   a box, so on a panel it becomes an inset note: one rule down its edge, no
   border, no second background. Eleven callouts across five templates keep
   their class and change meaning here rather than in the markup. */
.panel .callout {
  background: none;
  border: 0;
  border-left: 2px solid var(--mg-sand);
  border-radius: 0;
  padding: var(--sp-2) 0 var(--sp-2) var(--sp-5);
  margin: var(--sp-5) 0;
}
.panel .callout h3 { margin-bottom: var(--sp-2); }
/* .callout p sets --clr-muted, a light-page colour. `.panel p` currently wins
   on source order alone, which is not a thing to rely on - say it here. */
.panel .callout p { color: var(--mg-trail); }
.panel .callout--warn { border-left-color: var(--mg-blue); }

/* --- A roster of people ----------------------------------------------------
   Crew and marshals are not a card grid of claims; they are a list of people.
   No boxes, no hover lift - a name, a role, and space. */
.roster {
  list-style: none;
  padding: 0;
  margin: var(--sp-6) 0 0;
  display: grid;
  gap: var(--sp-6);
}
@media (min-width: 640px) { .roster { grid-template-columns: 1fr 1fr; } }
@media (min-width: 960px) { .roster { grid-template-columns: repeat(3, 1fr); } }
.roster__name { display: block; font-size: var(--t-md); color: var(--mg-snow); }
.roster__role {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--mg-steel);
  margin-top: var(--sp-1);
}
.roster p { margin: var(--sp-2) 0 0; color: var(--mg-trail); max-width: 44ch; }

/* --- A panel that is only a photograph -------------------------------------
   The trail page's poster. Inset inside 32px of dark padding it reads as a
   framed print; the trails page shows the same photograph bleeding to the
   panel edge, and two treatments of one image is worse than either. */
.panel--media { padding: 0; overflow: hidden; }
.panel--media img { display: block; width: 100%; height: auto; }

/* --- Ruled lists inside a panel --------------------------------------------
   .rules-list and .checklist give every item a pale surface and a border. That
   was right on a light page; inside a panel it is ten boxes nested in a box,
   which is the "rules only between sections, never between every row" failure
   the spec names by name. Same treatment the callout got: drop the box, keep
   the rhythm, separate with a hairline. */
.panel .rules-list li,
.panel .checklist li {
  background: none;
  border: 0;
  border-radius: 0;
  border-top: 1px solid color-mix(in srgb, var(--mg-trail) 14%, transparent);
}
.panel .rules-list li:first-child,
.panel .checklist li:first-child { border-top: 0; }
.panel .rules-list { gap: 0; }
.panel .checklist { gap: 0; }
.panel .rules-list li { padding: var(--sp-4) 0 var(--sp-4) 4.25rem; }
.panel .checklist li { padding: var(--sp-3) 0 var(--sp-3) var(--sp-6); }

/* --- Course-level cards inside a panel --------------------------------------
   --level-ink mixes the level's colour into --text, which is near-black. The
   name escapes it because `.panel h3` overrides; the number is a <span> and
   nothing reaches it, so it measured 1.29 against the required 4.5. Same shape
   as the badge tiers and everything else recipe step 7 keeps finding.

   The cards keep their own tinted surface deliberately: two course tiers read
   as a pair of tiles, unlike the ten ruled rows that were de-boxed. */
.panel .programme--1 { --level-ink: color-mix(in oklab, var(--mist) 25%, var(--mg-snow)); }
.panel .programme--2 { --level-ink: var(--mg-sand); }
.panel .programme p { color: var(--mg-trail); }

/* --- The masthead and footer as surfaces -----------------------------------
   Measured on the live site: the sticky masthead's tagline runs from 6.90 at
   first light down to 1.54 at dusk, because it sits on the bare sky and --text
   switches only at p=0.855 - while the comment beside that constant says ink
   stops holding 4.5:1 at p=0.46. Between those two numbers the top of every
   page is below contrast.

   The contrast audit never saw it: .brand-tag is not in its selector list and
   is not inside a panel, so sky-mounted chrome had no coverage at all. That is
   the same gap that let the app ship an unreadable tab bar.

   The fix is the one the rest of the site already uses - put the text on a
   surface instead of on the sky. */
.site-header {
  background: color-mix(in srgb, var(--mg-black) 82%, transparent);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border-bottom: 1px solid color-mix(in srgb, var(--mg-trail) 14%, transparent);
}
.site-header .brand-wordmark { background-color: var(--mg-snow); }
.site-header .brand-tag,
.site-header .site-nav a { color: var(--mg-trail); }
.site-header .site-nav a[aria-current="page"] { color: var(--mg-snow); }

.site-footer {
  background: color-mix(in srgb, var(--mg-black) 82%, transparent);
  border-top: 1px solid color-mix(in srgb, var(--mg-trail) 14%, transparent);
}
.site-footer .brand-wordmark { background-color: var(--mg-snow); }
.site-footer .brand-tag { color: var(--mg-trail); }


/* A btn-row that follows a panel is the section's own call to action, sitting
   on the sky beneath it. Three of these carried hand-written inline margins,
   which is why the home page's panel gaps read 32, 64, 64, 147, 64 where every
   other page read a flat 64. */
.panel + .btn-row { margin-top: var(--sp-6); }
