/* ==========================================================================
   Marston Athletics
   Gym print culture: rafter banners, framed photographs, painted court lines,
   screen-printed buttons, black & white roster photography.

   THE PALETTE
   The official brand colours are the five below and nothing else. They are
   declared once, at the top of :root, and every other colour on the site is
   mixed from them with color-mix(). If you need to adjust the brand, change a
   value here and it changes everywhere. Do not paste a hex code further down
   this file.

     Purple  #781FD8      Gold  #D4AF76      Silver  #B3B2B2
     Black   #000000      White #FFFFFF
   ========================================================================== */

/* font-display: optional, with every face a page uses preloaded in its <head>.
   A face is either there for the first layout or not used for that page view,
   so text never reflows under the reader after the page has appeared (swap
   made it reflow, and a reload then came back a line or two out of place). A
   face first needed late, such as the bold in a table inside a closed FAQ
   answer, must be preloaded too, or it arrives seconds after load. */
@font-face { font-family: 'Big Shoulders'; font-style: normal; font-weight: 700; font-display: optional; src: url('fonts/bigshoulders-700.woff2') format('woff2'); }
@font-face { font-family: 'Big Shoulders'; font-style: normal; font-weight: 800; font-display: optional; src: url('fonts/bigshoulders-800.woff2') format('woff2'); }
@font-face { font-family: 'Barlow'; font-style: normal; font-weight: 400; font-display: optional; src: url('fonts/barlow-400.woff2') format('woff2'); }
@font-face { font-family: 'Barlow'; font-style: italic; font-weight: 400; font-display: optional; src: url('fonts/barlow-400i.woff2') format('woff2'); }
@font-face { font-family: 'Barlow'; font-style: normal; font-weight: 500; font-display: optional; src: url('fonts/barlow-500.woff2') format('woff2'); }
@font-face { font-family: 'Barlow'; font-style: normal; font-weight: 600; font-display: optional; src: url('fonts/barlow-600.woff2') format('woff2'); }
@font-face { font-family: 'Barlow'; font-style: normal; font-weight: 700; font-display: optional; src: url('fonts/barlow-700.woff2') format('woff2'); }
@font-face { font-family: 'Saira Stencil One'; font-style: normal; font-weight: 400; font-display: optional; src: url('fonts/sairastencil-400.woff2') format('woff2'); }
@font-face { font-family: 'Zilla Slab'; font-style: italic; font-weight: 400; font-display: optional; src: url('fonts/zilla-400i.woff2') format('woff2'); }
@font-face { font-family: 'Zilla Slab'; font-style: italic; font-weight: 500; font-display: optional; src: url('fonts/zilla-500i.woff2') format('woff2'); }

:root {
  /* the five official brand colours */
  --purple: #781FD8;
  --gold:   #D4AF76;
  --silver: #B3B2B2;
  --black:  #000000;
  --white:  #FFFFFF;

  /* everything else is mixed from those five, never pasted in */
  --purple-deep: color-mix(in srgb, var(--purple) 74%, var(--black));  /* link and hover purple */
  --gold-tint:   color-mix(in srgb, var(--gold) 24%, var(--white));    /* tinted section grounds */
  --muted:       color-mix(in srgb, var(--silver) 60%, var(--black));  /* secondary text */
  --rule:        color-mix(in srgb, var(--silver) 45%, var(--white));  /* hairlines */

  --display: 'Big Shoulders', 'Arial Narrow', sans-serif;
  --body: 'Barlow', 'Helvetica Neue', Arial, sans-serif;
  --stencil: 'Saira Stencil One', 'Arial Black', sans-serif;
  --serif: 'Zilla Slab', Georgia, serif;
  --pad: clamp(1.25rem, 5vw, 4rem);
}

* { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; scroll-padding-top: 4.5rem; overflow-x: clip; }
body {
  font-family: var(--body);
  font-size: 1.0625rem;
  line-height: 1.6;
  color: var(--black);
  background: var(--white);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
  position: relative;
}
img { max-width: 100%; height: auto; display: block; }
[hidden] { display: none !important; }
a { color: var(--purple-deep); }

/* paper grain over everything, like a printed page. It belongs to the page,
   top to bottom, not to the window: fixed to the window, it covered only the
   first screen of a whole-page screenshot, and the page looked a shade whiter
   from there down, partway through whatever was there (on News, the first
   story). On screen the two look the same. */
body::after {
  content: '';
  position: absolute; inset: 0;
  z-index: 90;
  pointer-events: none;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.045 0'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ---------- shared type ---------- */
.eyebrow {
  font-family: var(--stencil);
  font-size: 0.8125rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--purple-deep);
  margin-bottom: 0.75rem;
}
h1.arc-head,
h2.arc-head {
  font-family: var(--display);
  font-weight: 800;
  font-size: clamp(2.25rem, 5.5vw, 3.75rem);
  line-height: 0.95;
  text-transform: uppercase;
  letter-spacing: 0.01em;
  text-wrap: balance;
  margin-bottom: 2.5rem;
  position: relative;
  padding-bottom: 1.25rem;
}
/* painted court marking: baseline + free-throw arc */
h1.arc-head::after,
h2.arc-head::after {
  content: '';
  position: absolute; left: 0; bottom: 0;
  width: min(220px, 60%);
  border-bottom: 3px solid currentColor;
}
h1.arc-head::before,
h2.arc-head::before {
  content: '';
  position: absolute;
  left: calc(min(220px, 60%) / 2 - 27px); bottom: 0;
  width: 54px; height: 27px;
  border: 3px solid currentColor;
  border-bottom: none;
  border-radius: 54px 54px 0 0;
}

/* ---------- screen-printed buttons ---------- */
.btn {
  display: inline-block;
  font-family: var(--display);
  font-weight: 700;
  font-size: 1.1rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  text-decoration: none;
  padding: 0.8rem 1.5rem;
  background: var(--purple);
  color: var(--white);
  border: 2px solid var(--black);
  box-shadow: 5px 5px 0 var(--black);
  transition: background-color 0.15s ease, translate 0.1s ease, box-shadow 0.1s ease, color 0.15s ease;
}
.btn:hover { background: var(--purple-deep); }
.btn:active { translate: 4px 4px; box-shadow: 1px 1px 0 var(--black); }
.btn:focus-visible { outline: 3px solid var(--purple); outline-offset: 3px; }
.btn-sm { font-size: 0.98rem; padding: 0.5rem 1rem; box-shadow: 4px 4px 0 var(--black); }
.btn-outline { background: transparent; color: var(--black); }
.btn-outline:hover { background: var(--black); color: var(--white); }
.btn-ghost {
  background: transparent; color: var(--white);
  border-color: rgba(255,255,255,0.85);
  box-shadow: none;
}
.btn-ghost:hover { background: rgba(255,255,255,0.14); }
/* Gold marks the way to Upcoming Events, as it does in the nav. The text stays
   black on dark sections too, where '.section-dark a.btn' would turn it white. */
.btn.btn-gold, .section-dark a.btn.btn-gold { background: var(--gold); color: var(--black); }
.btn.btn-gold:hover { background: color-mix(in srgb, var(--gold) 78%, var(--white)); }
.btn-ghost:active { translate: 2px 2px; }
.section-dark .btn, .hero .btn:not(.btn-ghost) {
  border-color: var(--black);
  box-shadow: 5px 5px 0 rgba(0,0,0,0.6);
}
.section-dark .btn:active, .hero .btn:not(.btn-ghost):active { box-shadow: 1px 1px 0 rgba(0,0,0,0.6); }

/* ---------- nav ---------- */
.nav {
  position: sticky; top: 0; z-index: 50;
  display: flex; align-items: center; gap: 1.5rem;
  padding: 0.6rem var(--pad);
  background: rgba(255, 255, 255, 0.95);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  border-bottom: 2px solid var(--black);
}
.nav-logo img { height: 42px; width: auto; }
.nav-links { display: flex; gap: 1.1rem; margin-left: auto; flex-wrap: wrap; }
.nav-links a {
  font-family: var(--display); font-weight: 700; font-size: 1.05rem;
  text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--black); text-decoration: none;
  display: inline-block; padding: 0.55rem 0.2rem;
}
.nav-links a:hover { color: var(--purple); }
.nav-links a.is-current { color: var(--purple-deep); box-shadow: inset 0 -3px 0 var(--purple); }
/* Upcoming Events is the page Marston Athletics most wants people to find, so
   it is painted gold in the nav, the same gold as the hero's events button. */
.nav-links a.nav-events { background: var(--gold); color: var(--black); padding-inline: 0.7rem; }
.nav-links a.nav-events:hover { background: color-mix(in srgb, var(--gold) 78%, var(--white)); color: var(--black); }
.nav-links a.nav-events.is-current { color: var(--black); box-shadow: inset 0 -4px 0 var(--purple); }
.nav-cta { white-space: nowrap; font-size: 0.95rem; padding: 0.5rem 1rem; box-shadow: 3px 3px 0 var(--black); }
.nav-cta:active { translate: 2px 2px; box-shadow: 1px 1px 0 var(--black); }

.nav-toggle {
  display: none;
  margin-left: auto;
  background: none; border: none; cursor: pointer;
  width: 48px; height: 44px;
  padding: 10px 8px;
  flex-direction: column; justify-content: space-between;
}
.nav-toggle span {
  display: block; height: 3px; width: 100%;
  background: var(--black);
  transition: transform 0.28s cubic-bezier(0.3, 0.7, 0.3, 1), opacity 0.2s ease;
}
.nav-toggle:focus-visible { outline: 3px solid var(--purple); outline-offset: 2px; }
.nav.open .nav-toggle span:nth-child(1) { transform: translateY(10.5px) rotate(45deg); }
.nav.open .nav-toggle span:nth-child(2) { opacity: 0; }
.nav.open .nav-toggle span:nth-child(3) { transform: translateY(-10.5px) rotate(-45deg); }

/* The full nav needs about 1045px on one line since News joined it (975px
   before), so below 1080px it folds into the menu button rather than
   wrapping onto a second line. */
@media (max-width: 1080px) {
  .nav { flex-wrap: wrap; gap: 0 1rem; padding-top: 0.5rem; padding-bottom: 0.5rem; }
  .nav-logo img { height: 34px; }
  .nav-toggle { display: flex; }
  .nav-links {
    order: 3; width: 100%;
    flex-direction: column; align-items: stretch; gap: 0;
    max-height: 0; overflow: hidden;
    opacity: 0; visibility: hidden;
    translate: 0 -8px;
    border-top: 0 solid var(--black);
    transition: max-height 0.42s cubic-bezier(0.25, 0.8, 0.35, 1), opacity 0.28s ease,
                translate 0.35s ease, visibility 0s 0.42s;
  }
  .nav.open .nav-links {
    max-height: 480px;
    opacity: 1; visibility: visible;
    translate: 0 0;
    margin-top: 0.5rem;
    padding: 0.5rem 0 0.25rem;
    border-top: 2px solid var(--black);
    transition: max-height 0.45s cubic-bezier(0.25, 0.8, 0.35, 1), opacity 0.3s ease 0.05s,
                translate 0.4s ease;
  }
  .nav-links a { font-size: 1.35rem; padding: 0.7rem 0.2rem; border-bottom: 1px solid var(--gold-tint); }
  .nav-links a.nav-events { padding-inline: 0.75rem; border-bottom-color: var(--gold); }
  .nav-links a.nav-events.is-current { box-shadow: inset 5px 0 0 var(--purple); }
  .nav-cta {
    order: 4; width: 100%; text-align: center;
    max-height: 0; overflow: hidden; opacity: 0; visibility: hidden;
    padding-top: 0; padding-bottom: 0; border-width: 0; margin: 0;
    transition: max-height 0.42s cubic-bezier(0.25, 0.8, 0.35, 1), opacity 0.28s ease, visibility 0s 0.42s;
  }
  .nav.open .nav-cta {
    max-height: 72px; opacity: 1; visibility: visible;
    padding: 0.7rem 1rem; border-width: 2px;
    margin: 0.9rem 0 0.6rem;
    transition: max-height 0.45s cubic-bezier(0.25, 0.8, 0.35, 1), opacity 0.3s ease 0.1s;
  }
  @media (prefers-reduced-motion: no-preference) {
    .nav.open .nav-links a { animation: navItem 0.35s cubic-bezier(0.25, 0.8, 0.35, 1) both; }
    .nav.open .nav-links a:nth-child(1) { animation-delay: 0.05s; }
    .nav.open .nav-links a:nth-child(2) { animation-delay: 0.09s; }
    .nav.open .nav-links a:nth-child(3) { animation-delay: 0.13s; }
    .nav.open .nav-links a:nth-child(4) { animation-delay: 0.17s; }
    .nav.open .nav-links a:nth-child(5) { animation-delay: 0.21s; }
    .nav.open .nav-links a:nth-child(6) { animation-delay: 0.25s; }
    .nav.open .nav-links a:nth-child(7) { animation-delay: 0.29s; }
    @keyframes navItem { from { opacity: 0; translate: 0 10px; } }
  }
}

/* ---------- hero ----------
   Centred on the crest, large, the way Marston Select presents its own logo:
   crest, strapline, headline, then the buttons. The crest is the on-dark
   artwork, because the hero is always a darkened photograph. */
.hero { position: relative; min-height: min(92vh, 900px); display: flex; align-items: center; justify-content: center; overflow: hidden; }
/* Everything in the hero animates in as the page loads (the crest scales up,
   the headline rises), so none of it may be what the browser lines the page
   up against when content above the screen changes height: mid-animation it
   is a few pixels out of place. (site.js keeps the position steady across a
   reload itself; see its scroll section.) */
.hero { overflow-anchor: none; }
.hero-photo {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover; object-position: center 30%;
}
.hero::after {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(0,0,0,0.4) 0%, rgba(0,0,0,0.62) 50%, rgba(0,0,0,0.9) 100%);
}
.hero-inner {
  position: relative; z-index: 1;
  width: 100%; max-width: 64rem;
  padding: clamp(2.25rem, 6vw, 4rem) var(--pad) clamp(3rem, 7vw, 4.5rem);
  display: flex; flex-direction: column; align-items: center;
  text-align: center;
}
.hero-logo {
  width: min(clamp(12rem, 60vw, 21rem), 38vh);
  min-width: 11rem;
  height: auto;
  margin-bottom: clamp(1.25rem, 3vw, 1.9rem);
  filter: drop-shadow(0 10px 24px rgba(0,0,0,0.55));
}
.hero-e { color: var(--gold); }
/* The strapline sits over a bright part of the photo, where the gold measured
   under 3:1 on half its pixels. A soft, blurred scrim behind the line plus a
   tight shadow round the letters bring every glyph pixel to 4.5:1 or better.
   The scrim is absolutely positioned, and the box only shrinks to the width
   of its own text. */
.hero-e {
  position: relative;
  width: fit-content;
  text-wrap: balance;
  text-shadow: 0 1px 2px rgba(0,0,0,0.9), 0 0 10px rgba(0,0,0,0.65);
}
.hero-e::before {
  content: '';
  position: absolute; z-index: -1;
  inset: -0.6em -1.1em;
  background: rgba(0,0,0,0.55);
  filter: blur(14px);
  border-radius: 999px;
}
.hero-h {
  font-family: var(--display);
  font-weight: 800;
  font-size: clamp(2.6rem, 7vw, 5rem);
  line-height: 0.92;
  text-transform: uppercase;
  color: var(--white);
  text-wrap: balance;
  margin-bottom: 1.25rem;
}
/* the two lines of the strapline, one under the other at every width */
.hero-h span { display: block; }
.hero-h-accent { color: var(--purple); }
/* on a small phone each line of the strapline stays whole, at full strength */
@media (max-width: 480px) { .hero-h { font-size: 10vw; } }
.hero-sub { color: rgba(255,255,255,0.92); font-size: clamp(1.05rem, 2vw, 1.3rem); max-width: 38rem; margin-bottom: 1.75rem; }
.hero-ctas { display: flex; gap: 1rem; flex-wrap: wrap; justify-content: center; }
/* on a phone the three buttons stack at one width, so the column reads cleanly */
@media (max-width: 560px) {
  .hero-ctas { flex-direction: column; align-items: stretch; width: 100%; max-width: 22rem; }
  .hero-ctas .btn { text-align: center; }
}

@media (prefers-reduced-motion: no-preference) {
  .hero-photo { animation: heroSettle 2.4s cubic-bezier(0.2, 0.6, 0.25, 1) both; }
  @keyframes heroSettle { from { scale: 1.07; } to { scale: 1; } }
  .hero-logo { animation: logoIn 0.8s cubic-bezier(0.2, 0.7, 0.3, 1) both; }
  @keyframes logoIn { from { opacity: 0; scale: 0.94; } }
  .hero-h span { opacity: 0; translate: 0 0.45em; animation: rise 0.6s cubic-bezier(0.2, 0.7, 0.3, 1) 0.2s forwards; }
  .hero-h span:nth-child(2) { animation-delay: 0.3s; }
  .hero-h span:nth-child(3) { animation-delay: 0.4s; }
  .hero-h span:nth-child(4) { animation-delay: 0.54s; }
  .hero-e, .hero-sub, .hero-ctas { opacity: 0; animation: fade 0.7s ease 0.7s forwards; }
  @keyframes rise { to { opacity: 1; translate: 0 0; } }
  @keyframes fade { to { opacity: 1; } }
}

/* ---------- ticker ---------- */
.ticker { background: var(--black); color: var(--white); overflow: hidden; border-bottom: 3px solid var(--purple); }
.ticker-track { display: flex; gap: 2.75rem; width: max-content; padding: 0.8rem 0; align-items: center; }
.ticker-track span { font-family: var(--display); font-weight: 700; font-size: 1.15rem; text-transform: uppercase; letter-spacing: 0.08em; white-space: nowrap; }
.ticker-track span::before { content: '/'; color: var(--purple); margin-right: 2.75rem; font-weight: 800; }
.ticker-label { color: var(--gold); }
.ticker-label::before { content: '' !important; margin: 0 !important; }
@media (prefers-reduced-motion: no-preference) {
  .ticker-track { animation: scroll 36s linear infinite; }
  @keyframes scroll { to { transform: translateX(-50%); } }
}
@media (prefers-reduced-motion: reduce) {
  .ticker-track { flex-wrap: wrap; width: auto; padding: 0.8rem var(--pad); }
  .ticker-track span[aria-hidden] { display: none; }
}

/* ---------- sections ---------- */
.section { padding: clamp(3.5rem, 8vw, 6.5rem) var(--pad); }
.section-dark { background: var(--black); color: var(--white); }
.section-dark a { color: var(--gold); }
.section-dark a.btn { color: var(--white); }
.section-dark .eyebrow { color: var(--gold); }
.section-tint { background: var(--gold-tint); }

/* scroll reveals: translate/rotate as separate properties so tilted items settle into place.
   The rise is a keyframe animation that only starts once an element is
   revealed, so until then it sits exactly where it will end up, just
   invisible. A resting offset would leave every unrevealed element 20px out
   of place for the browser to line the page up against when it restores or
   adjusts the scroll position, which made the page creep down on every
   refresh. */
.reveal { opacity: 0; }
.reveal.in { opacity: 1; animation: revealRise 0.65s cubic-bezier(0.22, 0.61, 0.36, 1) both; }
@keyframes revealRise { from { opacity: 0; translate: 0 20px; } }
@media (prefers-reduced-motion: reduce) { .reveal, .reveal.in { opacity: 1; animation: none; } }

/* ---------- framed photographs ----------
   A white print border and a soft drop shadow. The masking-tape strips that
   used to sit on the corners were taken off at Marston Athletics' request. */
/* width: 100% matters: a framed photo centred with auto margins would
   otherwise shrink to fit an image that has no width until it loads, and
   the page would grow by the photo's height when it arrived */
.framed { position: relative; width: 100%; box-shadow: 0 12px 26px rgba(0,0,0,0.22); }
.framed img { border: 8px solid var(--white); outline: 1px solid rgba(0,0,0,0.3); width: 100%; }

/* ---------- mission ---------- */
.mission-grid { display: grid; grid-template-columns: 1.2fr 0.8fr; gap: clamp(2.5rem, 5vw, 4.5rem); align-items: center; max-width: 72rem; margin: 0 auto; }
.mission-grid > div > p { max-width: 34rem; }
.mission-photo { rotate: 1.4deg; margin-top: 1rem; }
.pull {
  margin-top: 2rem;
  border-left: 4px solid var(--purple);
  padding-left: 1.25rem;
  max-width: 34rem;
}
.pull p {
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(1.2rem, 2vw, 1.45rem);
  line-height: 1.5;
}
.pull cite {
  display: block; margin-top: 0.75rem;
  font-family: var(--stencil); font-style: normal;
  font-size: 0.72rem; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--muted);
}
@media (max-width: 820px) { .mission-grid { grid-template-columns: 1fr; } .mission-photo { max-width: 24rem; margin: 1.5rem auto 0; } }

/* ---------- rafter banners ---------- */
.banners {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: clamp(0.9rem, 2.5vw, 1.75rem);
  max-width: 70rem;
  margin: 0 auto clamp(3rem, 7vw, 5rem);
}
.banner {
  clip-path: polygon(0 0, 100% 0, 100% 76%, 50% 100%, 0 76%);
  padding: 1.3rem 0.9rem 2.9rem;
  text-align: center;
  transform-origin: top center;
}
.banner small { display: block; font-family: var(--stencil); font-size: 0.66rem; letter-spacing: 0.2em; text-transform: uppercase; opacity: 0.85; }
.banner strong {
  display: block;
  font-family: var(--display); font-weight: 800;
  font-size: clamp(2rem, 4.5vw, 2.9rem);
  line-height: 1.05;
  font-variant-numeric: tabular-nums;
}
.banner span { display: block; font-size: 0.78rem; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; opacity: 0.9; }
.b-gold { background: var(--gold); color: var(--black); rotate: -1.1deg; }
.b-purple { background: var(--purple); color: var(--white); rotate: 0.9deg; }
.b-silver { background: var(--silver); color: var(--black); rotate: -0.7deg; }
.b-white { background: var(--white); color: var(--black); rotate: 1.2deg; }
/* banners drop from the rafters, and swing to their tilt, instead of rising */
.banner.reveal.in { animation-name: bannerDrop; }
@keyframes bannerDrop { from { opacity: 0; translate: 0 -26px; rotate: 0deg; } }
.banners .banner:nth-child(2) { animation-delay: 0.08s; }
.banners .banner:nth-child(3) { animation-delay: 0.16s; }
.banners .banner:nth-child(4) { animation-delay: 0.24s; }
/* on the training page the banners come after the programs, not before */
.banners.banners-after { margin: clamp(3rem, 7vw, 5rem) auto 0; }

/* ---------- programs: the price-board list ---------- */
.programs { max-width: 72rem; margin: 0 auto; }
.program {
  display: grid;
  grid-template-columns: minmax(180px, 320px) 1fr;
  gap: 0.5rem 3rem;
  align-items: start;
  padding: 1.9rem 0;
  border-top: 1px solid rgba(255,255,255,0.22);
}
.program:last-of-type { border-bottom: 1px solid rgba(255,255,255,0.22); }
.program-name h3 {
  font-family: var(--display); font-weight: 800;
  font-size: clamp(1.9rem, 3.6vw, 2.7rem);
  line-height: 0.95;
  text-transform: uppercase;
  color: var(--white);
  transition: color 0.25s ease;
}
.program:hover .program-name h3 { color: var(--gold); }
.program-tag {
  display: inline-block;
  font-family: var(--stencil); font-size: 0.62rem;
  letter-spacing: 0.16em; text-transform: uppercase;
  background: var(--purple); color: var(--white);
  padding: 0.25rem 0.55rem;
  margin-top: 0.5rem;
}
.program > p { font-size: 1rem; color: rgba(255,255,255,0.85); max-width: 46rem; }
.programs .program:nth-child(even).reveal { animation-delay: 0.06s; }
@media (max-width: 720px) { .program { grid-template-columns: 1fr; } }


/* ---------- page heads (interior pages) ---------- */
.page-head { padding-bottom: clamp(2.5rem, 5vw, 3.5rem); }
.page-head h1.arc-head { margin-bottom: 1.75rem; }
.lede { max-width: 46rem; font-size: clamp(1.05rem, 1.6vw, 1.18rem); }
.lede + .cta-row, .lede + .pay-policy { margin-top: 1.75rem; }
.lede + .lede { margin-top: 1rem; }
.lede-invert { color: rgba(255,255,255,0.88); }

/* ---------- the free-first-workout stamp ---------- */
.free-banner {
  display: block;
  width: fit-content;
  margin: 2.25rem auto 0;
  rotate: -0.6deg;
  background: var(--purple);
  color: var(--white);
  font-family: var(--stencil);
  font-size: 0.82rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-align: center;
  padding: 0.6rem 1.1rem;
  box-shadow: 4px 4px 0 var(--black);
}

/* ---------- the live schedule (Canva embed, training page only) ----------
   The design is 768 x 768, so the frame is held exactly square: at the
   design's own ratio Canva fills it edge to edge with no letterboxing. The
   gold rule is an outline, not a border, so it cannot eat into that ratio. */
.schedule-embed {
  position: relative;
  width: 100%;
  max-width: 44rem;
  aspect-ratio: 1 / 1;
  margin-top: 2rem;
  background: rgba(255,255,255,0.06);
  outline: 3px solid var(--gold);
}
.schedule-embed iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.schedule-embed + .cta-row { margin-top: 2.25rem; }

/* ---------- rows of buttons ---------- */
.cta-row { display: flex; gap: 1.1rem; flex-wrap: wrap; align-items: center; margin-top: 1.75rem; }
.consent-note { margin-top: 1.25rem; font-size: 0.92rem; color: var(--muted); }
.cta-row + .just-ask-email { margin-top: 1.5rem; }
.section-dark .consent-note { color: rgba(255,255,255,0.7); }
/* Outline buttons on a dark ground. On dark sections every button's border
   is darkened by '.section-dark .btn', which outranks a single class, so
   '.btn-on-dark' alone lost and outline buttons rendered as bare text. Both
   selectors below match that rule's weight and come after it in the file, so
   they win; the first also catches any outline button placed on a dark
   section without the extra class. */
.section-dark .btn-outline,
.btn.btn-on-dark { color: var(--white); border-color: var(--white); }
.section-dark .btn-outline:hover,
.btn.btn-on-dark:hover { background: var(--white); color: var(--black); }

/* ---------- the paid-in-advance note ----------
   The client was specific that this cannot live only in general copy, so it
   sits beside every registration and payment link on the site. Same markup
   every time, on light and dark sections both. */
.pay-policy {
  max-width: 46rem;
  margin-top: 1.5rem;
  border-left: 4px solid var(--purple);
  background: var(--gold-tint);
  padding: 0.85rem 1.1rem;
  font-size: 0.98rem;
}
.pay-policy a { white-space: nowrap; }
.section-dark .pay-policy { background: rgba(255,255,255,0.08); color: var(--white); }
.section-tint .pay-policy { background: rgba(255,255,255,0.6); }

/* the same statement, said once and loudly, at the top of the payment page */
.policy-statement {
  max-width: 46rem;
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1.4rem, 3vw, 2rem);
  line-height: 1.15;
  text-transform: uppercase;
  border-left: 6px solid var(--purple);
  padding: 0.75rem 0 0.75rem 1.25rem;
  margin-bottom: 1.75rem;
}
.policy-statement strong { display: block; color: var(--purple-deep); }

/* ---------- teaser grid (home page training preview) ---------- */
.teasers {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 1.75rem 2rem;
  max-width: 72rem;
  margin: 0 auto;
}
.teaser { border-top: 3px solid var(--gold); padding-top: 1rem; }
.teaser h3 {
  font-family: var(--display); font-weight: 800;
  font-size: clamp(1.5rem, 2.6vw, 2rem);
  line-height: 0.95; text-transform: uppercase;
  color: var(--white);
}
.teaser p { font-size: 0.96rem; color: rgba(255,255,255,0.82); margin-top: 0.5rem; }
.teasers .teaser:nth-child(2).reveal { animation-delay: 0.06s; }
.teasers .teaser:nth-child(3).reveal { animation-delay: 0.12s; }
.teasers .teaser:nth-child(4).reveal { animation-delay: 0.18s; }
.teaser-more { max-width: 72rem; margin: 2.75rem auto 0; }

/* ---------- Marston Select: a pointer to a separate program ---------- */
.next-step { max-width: 46rem; }
.next-step h2 {
  font-family: var(--display); font-weight: 800;
  font-size: clamp(1.9rem, 3.6vw, 2.7rem);
  line-height: 0.95; text-transform: uppercase;
  margin-bottom: 0.9rem;
}
.next-step .cta-row { margin-top: 1.4rem; }

/* ---------- generic cards ---------- */
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(255px, 1fr));
  gap: 2rem;
  max-width: 72rem;
  margin: 0 auto;
  align-items: start;
}
.card {
  border: 3px solid var(--black);
  background: var(--white);
  box-shadow: 9px 9px 0 var(--gold);
  padding: 1.6rem 1.5rem;
}
.card h3 { font-family: var(--display); font-weight: 800; font-size: 1.6rem; text-transform: uppercase; line-height: 1; margin-bottom: 0.75rem; }
.card p + p { margin-top: 0.8rem; }
.card p { font-size: 0.98rem; }
.card-invert { background: var(--black); border-color: var(--gold); box-shadow: 9px 9px 0 rgba(0,0,0,0.5); }
.card-invert h3 { color: var(--white); }
.card-invert p { color: rgba(255,255,255,0.85); }
.pay-handle { font-family: var(--display); font-weight: 800; font-size: clamp(1.3rem, 2.4vw, 1.75rem); word-break: break-word; }
.cards + .pay-policy, .cards + .pay-qrs { margin-top: 2.5rem; }
/* a flyer at the head of a card, shown whole: flyers are words */
.card-flyer { width: 100%; outline: 2px solid var(--black); margin-bottom: 1.25rem; }
.card-prices { list-style: none; margin-top: 0.9rem; border-top: 1px solid var(--rule); }
.card-prices li { display: flex; justify-content: space-between; gap: 1rem; padding: 0.45rem 0; border-bottom: 1px solid var(--rule); font-size: 0.98rem; }
.card-prices strong { font-variant-numeric: tabular-nums; }
.card .card-prices + p { margin-top: 1.1rem; }
/* small print right under at-home prices, as on Danielle's flyer: tolls and
   travel fees are extra. Muted, but at least 4.5:1 on white and on the tint. */
.fees-note, .card p.fees-note, .qa > p.fees-note { font-size: 0.86rem; line-height: 1.45; color: var(--muted); }
.card .card-prices + .fees-note { margin-top: 0.55rem; }
.card .fees-note + p { margin-top: 1.1rem; }
.pay-qrs + .pay-policy, .qr-hint + .pay-policy { margin-top: 2rem; }

/* ---------- split media (list beside a photo) ---------- */
.split-media {
  display: grid; grid-template-columns: 1.2fr 0.8fr;
  gap: clamp(2.5rem, 5vw, 4.5rem);
  max-width: 72rem; margin: 0 auto; align-items: center;
}
.skill-list { list-style: none; display: grid; gap: 1.1rem; }
.skill-list li { border-top: 1px solid var(--rule); padding-top: 0.85rem; }
.skill-list strong {
  display: block;
  font-family: var(--display); font-weight: 700; font-size: 1.3rem;
  text-transform: uppercase; letter-spacing: 0.02em;
}
.skill-list span { font-size: 0.96rem; color: var(--muted); }
@media (max-width: 820px) { .split-media { grid-template-columns: 1fr; } .split-media figure { max-width: 24rem; margin: 0 auto; } }

/* ---------- location tags ---------- */
.loc-tag {
  display: inline-block;
  font-family: var(--stencil); font-size: 0.78rem;
  letter-spacing: 0.12em; text-transform: uppercase;
  padding: 0.12rem 0.5rem;
  background: var(--purple); color: var(--white);
}
.loc-tag-alt { background: var(--gold); color: var(--black); }

/* ---------- links out to a Google Doc ---------- */
.doc-link { color: inherit; text-decoration: none; border-bottom: 1.5px dotted var(--purple); }
.doc-link::after { content: ' \2197'; font-size: 0.75em; color: var(--purple-deep); }
.doc-link:hover { color: var(--purple-deep); }

/* ---------- events ----------
   The cards are built by site.js from the Events tab of the Google Sheet: on
   the Upcoming Events page every live event, on the home page up to three.
   With nothing to show, the events page keeps its signpost paragraph and the
   home page block stays hidden. */
.events-feed {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(290px, 100%), 1fr));
  gap: 2.25rem 2rem;
  max-width: 76rem;
  margin: 0 auto;
  align-items: stretch;
}
.events-empty {
  grid-column: 1 / -1;
  max-width: 46rem;
  border: 3px dashed var(--muted);
  background: rgba(255,255,255,0.55);
  padding: 1.75rem 1.6rem;
  font-size: 1rem;
}
.events-empty strong { display: block; font-family: var(--display); font-weight: 800; font-size: 1.5rem; text-transform: uppercase; margin-bottom: 0.5rem; }
/* the empty state stands down as soon as there is a single real event, and
   waits out the first moment of loading so it does not flash up first */
.events-feed:has(.event-card) .events-empty { display: none; }
html[data-sheet-state="loading"] .events-feed > .events-empty { visibility: hidden; }

.event-card {
  display: flex; flex-direction: column;
  border: 3px solid var(--black);
  background: var(--white);
  box-shadow: 9px 9px 0 var(--gold);
  min-width: 0;
}
.event-body { display: flex; flex-direction: column; flex: 1; padding: 1.3rem 1.35rem 1.45rem; }
.event-when {
  font-family: var(--stencil); font-size: 0.76rem;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--purple-deep);
  margin-bottom: 0.5rem;
}
.event-what { font-family: var(--display); font-weight: 800; font-size: 1.7rem; line-height: 0.98; text-transform: uppercase; overflow-wrap: anywhere; }
.event-where, .event-note { font-size: 0.95rem; color: var(--muted); margin-top: 0.6rem; overflow-wrap: anywhere; }
.event-where .loc-tag { margin-right: 0.35rem; }
.event-note { white-space: pre-line; }
/* the button sits at the foot of the card, so a row of cards lines up */
.event-go { margin-top: auto; padding-top: 1.2rem; }
.event-card .pay-policy { margin-top: 0.9rem; font-size: 0.86rem; padding: 0.6rem 0.8rem; }

/* A flyer, shown whole: flyers are words, so they are never cropped. The box
   is always 4:5, the shape of most flyers, with any other shape centred in
   it on black: a box that took each flyer's shape as it loaded would move
   the rest of the card, and the page, after it had appeared. Until the flyer
   loads, and for good if the link is broken, private or slow to answer, the
   box shows the crest on black. */
.flyer {
  position: relative;
  aspect-ratio: 4 / 5;
  background: var(--black) url('images/logo-m-on-dark.svg') center / 44% no-repeat;
  border-bottom: 3px solid var(--black);
  overflow: hidden;
}
.flyer img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; opacity: 0; transition: opacity 0.35s ease; }
.flyer.is-loaded { background-image: none; }
.flyer.is-loaded img { opacity: 1; }

/* home page: up to three, centred, never stretched wide */
.home-events .events-feed-home {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: 2.25rem 2rem;
}
.events-feed-home .event-card { flex: 0 1 21rem; }
.events-feed-home .event-note { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.home-events-more { justify-content: center; margin-top: 2.75rem; }
@media (prefers-reduced-motion: no-preference) {
  .home-events:not([hidden]), .home-video:not([hidden]), .ig-row:not([hidden]) { animation: sheetIn 0.5s ease both; }
  @keyframes sheetIn { from { opacity: 0; } }
}

/* ---------- the announcement bar ----------
   One line of news above the nav on every page, from the Announcements tab.
   It scrolls away with the page, and Close hides it for the rest of the visit. */
.announce {
  display: flex; align-items: center; gap: 0.25rem 0.75rem;
  min-height: 44px;
  padding: 0.3rem calc(var(--pad) - 0.6rem) 0.3rem var(--pad);
  background: var(--purple); color: var(--white);
  border-bottom: 2px solid var(--black);
  font-size: 0.95rem; line-height: 1.35;
}
.announce-text { flex: 1; min-width: 0; text-align: center; text-wrap: balance; overflow-wrap: anywhere; }
.announce-link { position: relative; color: var(--white); font-weight: 700; text-underline-offset: 3px; white-space: nowrap; }
/* the link keeps its size in the line, with a taller invisible hit area */
.announce-link::before { content: ''; position: absolute; left: -0.25rem; right: -0.25rem; top: 50%; height: 44px; transform: translateY(-50%); }
.announce-link:hover { color: var(--gold); }
.announce-close {
  flex: none;
  min-width: 44px; min-height: 44px; padding: 0 0.6rem;
  background: none; border: 0; cursor: pointer;
  color: var(--white);
  font-family: var(--stencil); font-size: 0.72rem; letter-spacing: 0.14em; text-transform: uppercase;
}
.announce-close:hover { color: var(--gold); }
.announce-link:focus-visible, .announce-close:focus-visible { outline: 3px solid var(--white); outline-offset: 2px; }

/* ---------- the pop-up ----------
   A native modal dialog, from the Popup tab: it sits above everything,
   including the announcement bar, keeps focus inside, and closes with its
   button, Escape, or a tap outside. The flyer shrinks to leave room for the
   title and the button, so the whole thing fits a phone screen. */
.popup {
  margin: auto;
  width: min(32rem, calc(100% - 2rem));
  max-height: calc(100vh - 2rem);
  max-height: calc(100dvh - 2rem);
  padding: 0;
  border: 3px solid var(--black);
  background: var(--white); color: var(--black);
  box-shadow: 9px 9px 0 var(--gold);
  overflow: auto; overscroll-behavior: contain;
}
.popup::backdrop { background: rgba(0,0,0,0.72); }
html.has-popup { overflow: hidden; }
.popup-inner { display: grid; justify-items: center; gap: 0.85rem; padding: 0.4rem 1.25rem 1.4rem; text-align: center; }
.popup-close {
  justify-self: end;
  min-width: 44px; min-height: 44px; margin-right: -0.75rem; padding: 0 0.6rem;
  background: none; border: 0; cursor: pointer;
  font-family: var(--stencil); font-size: 0.74rem; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--purple-deep);
}
.popup-close:hover { color: var(--purple); }
.popup-close:focus-visible { outline: 3px solid var(--purple); outline-offset: 2px; }
.popup-title {
  margin-top: -0.4rem;
  font-family: var(--display); font-weight: 800;
  font-size: clamp(1.6rem, 6vw, 2.2rem); line-height: 0.98;
  text-transform: uppercase; text-wrap: balance; overflow-wrap: anywhere;
}
.popup-flyer { display: flex; justify-content: center; width: 100%; }
.popup-flyer img {
  display: block; width: auto; height: auto; max-width: 100%;
  max-height: calc(100vh - 20rem);
  max-height: calc(100dvh - 20rem);
  min-height: 7rem;
  object-fit: contain;
  border: 3px solid var(--black);
}
.popup-flyer.is-fallback {
  width: min(9rem, 40vw); aspect-ratio: 1;
  background: var(--black) url('images/logo-m-on-dark.svg') center / 72% no-repeat;
  border: 3px solid var(--black);
}
.popup-go { margin-top: 0.2rem; }
.popup .pay-policy { margin-top: 0; text-align: left; font-size: 0.88rem; padding: 0.6rem 0.85rem; }
@media (prefers-reduced-motion: no-preference) {
  .popup[open] { animation: popupIn 0.35s cubic-bezier(0.2, 0.7, 0.3, 1); }
  .popup[open]::backdrop { animation: backdropIn 0.3s ease; }
  @keyframes popupIn { from { opacity: 0; translate: 0 18px; } }
  @keyframes backdropIn { from { opacity: 0; } }
}

/* ---------- Instagram ----------
   Up to three posts from the Instagram tab, each Instagram's plain embed in
   the site's own card frame. Nothing inside an embed can be restyled or
   cropped, so the styling is all around it. On a wide screen the three sit in
   one row of equal height; below 960px they become a swipe row, with the next
   card peeking in from the edge. site.js sets each frame's height from the
   height Instagram reports; until then it is estimated from the width. */
.ig-row {
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 22rem);
  justify-content: center; align-items: stretch;
  gap: 2rem;
  max-width: 72rem; margin: 0 auto;
}
.ig-card {
  container-type: inline-size;
  border: 3px solid var(--black);
  background: var(--white);
  box-shadow: 9px 9px 0 var(--gold);
  padding: 0.55rem;
}
.ig-card iframe {
  display: block; width: 100%; border: 0;
  height: 560px;
  height: calc(125cqw + 215px);
  background: var(--white);
}
.ig-row:not([hidden]) + .ig-follow { margin-top: 2.75rem; }
.ig-follow { justify-content: center; }
/* with no posts on, the button lines up under the heading */
.ig-row[hidden] + .ig-follow { justify-content: flex-start; }
@media (max-width: 960px) {
  .ig-row {
    justify-content: start;
    grid-auto-columns: min(calc(100% - 2rem), 19rem);
    gap: 1rem;
    overflow-x: auto; overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    scroll-padding-inline: var(--pad);
    margin-inline: calc(var(--pad) * -1);
    padding: 0 var(--pad) 1.25rem;
  }
  .ig-card { scroll-snap-align: start; padding: 0.35rem; }
  .ig-row[data-count="1"] { grid-auto-columns: min(100%, 22rem); justify-content: center; }
}

/* ---------- videos ----------
   The homepage video and the News videos: a picture and a play button until
   it is pressed, then the player, in the same 16:9 box, so nothing moves.
   Until the picture arrives, and if it never does, the crest on black. A
   Drive video can be any shape, so its picture is shown whole and centred. */
.video {
  position: relative;
  aspect-ratio: 16 / 9;
  background: var(--black) url('images/logo-m-on-dark.svg') center / 22% no-repeat;
  border: 3px solid var(--black);
  overflow: hidden;
}
.video.is-loaded, .video.is-playing { background-image: none; }
.video-poster {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; opacity: 0; transition: opacity 0.35s ease;
}
.video.is-loaded .video-poster { opacity: 1; }
.video-play {
  position: absolute; inset: 0; width: 100%; height: 100%;
  display: flex; align-items: center; justify-content: center;
  background: rgba(0,0,0,0.2); border: 0; cursor: pointer;
}
.video-play-mark {
  position: relative;
  width: 84px; height: 58px;
  background: var(--purple);
  border: 2px solid var(--black);
  box-shadow: 5px 5px 0 var(--black);
  transition: background-color 0.15s ease, translate 0.1s ease, box-shadow 0.1s ease;
}
.video-play-mark::after {
  content: '';
  position: absolute; left: 50%; top: 50%;
  translate: -38% -50%;
  border-style: solid; border-width: 13px 0 13px 22px;
  border-color: transparent transparent transparent var(--white);
}
.video-play:hover .video-play-mark { background: var(--purple-deep); }
.video-play:active .video-play-mark { translate: 4px 4px; box-shadow: 1px 1px 0 var(--black); }
.video-play:focus-visible { outline: 3px solid var(--gold); outline-offset: -7px; }
.video iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
/* a Google Drive video is Drive's own player from the start (it does not
   play by itself, so a picture in front of it would mean pressing play
   twice); the crest shows in its box until the player arrives */
.video-drive.is-loaded { background-image: none; }
.video-spot { max-width: 60rem; margin: 0 auto; }
.video-spot .video { box-shadow: 9px 9px 0 var(--gold); }

/* ---------- News: Marston Happenings ----------
   The stories come from the News tab, newest first, in one column. The
   section is at least a screen tall, so stories arriving from the sheet never
   move anything already in view (the footer starts below the screen). With
   none, the signpost below stands in. */
.news { min-height: 100vh; min-height: 100svh; }
.news-feed { display: grid; gap: clamp(2.5rem, 5vw, 3.5rem); max-width: 48rem; }
/* Two columns on a wide screen (site.js decides, at NEWS_TWO): each story
   is placed under the shorter column, so the page holds the stories in
   order while each is drawn where it fits. Both columns are one width. */
.news-feed.is-two { position: relative; max-width: 72rem; gap: clamp(2rem, 3vw, 2.75rem); }
.news-feed.is-two > .story { position: absolute; top: 0; left: 0; width: calc((100% - clamp(2rem, 3vw, 2.75rem)) / 2); }
.news-feed.is-two > .story.news-right { left: auto; right: 0; }
.news-empty {
  max-width: 46rem;
  border: 3px dashed var(--muted);
  padding: 1.75rem 1.6rem;
  font-size: 1rem;
}
.news-empty strong { display: block; font-family: var(--display); font-weight: 800; font-size: 1.5rem; text-transform: uppercase; margin-bottom: 0.5rem; }
html[data-sheet-state="loading"] .news-empty { visibility: hidden; }
.story {
  border: 3px solid var(--black);
  background: var(--white);
  box-shadow: 9px 9px 0 var(--gold);
  min-width: 0;
  container-type: inline-size;
}
.story:focus { outline: none; }
.story .story-photo { aspect-ratio: 4 / 3; }
.story-body { padding: 1.4rem clamp(1.1rem, 4vw, 1.75rem) 1.25rem; }
.story-date {
  font-family: var(--stencil); font-size: 0.76rem;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--purple-deep);
  margin-bottom: 0.5rem;
}
.story-title {
  font-family: var(--display); font-weight: 800;
  font-size: clamp(1.7rem, 6.5cqi, 2.4rem); line-height: 0.98;
  text-transform: uppercase; text-wrap: balance; overflow-wrap: anywhere;
}
.story-text p { margin-top: 0.9rem; overflow-wrap: anywhere; }
.story .video { margin-top: 1.5rem; }
.story-go { margin-top: 1.4rem; }
.story-share {
  display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 1rem;
  margin-top: 1.4rem; padding-top: 0.9rem;
  border-top: 1px solid var(--rule);
}
.story-copy {
  min-height: 44px; padding: 0 1rem;
  font-family: var(--display); font-weight: 700; font-size: 1rem;
  text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--black); background: none;
  border: 2px solid var(--black); cursor: pointer;
}
.story-copy:hover { background: var(--black); color: var(--white); }
.story-copy:focus-visible { outline: 3px solid var(--purple); outline-offset: 3px; }
.story-copied { font-size: 0.92rem; color: var(--muted); }
/* a story opened by its own link lights up for a moment */
.story.is-target { animation: storyFound 2.6s ease; }
@keyframes storyFound {
  0%, 45% { box-shadow: 9px 9px 0 var(--gold), 0 0 0 6px var(--purple); }
}
.news-more { margin-top: 2.75rem; }

/* ---------- FAQ ---------- */
.qa-list { max-width: 56rem; border-top: 2px solid var(--black); }
.qa { border-bottom: 1px solid var(--rule); }
.qa summary {
  cursor: pointer;
  list-style: none;
  display: flex; align-items: baseline; gap: 0.9rem;
  font-family: var(--display); font-weight: 700;
  font-size: clamp(1.15rem, 2.2vw, 1.45rem);
  text-transform: uppercase; line-height: 1.15;
  padding: 1.15rem 0;
}
.qa summary::-webkit-details-marker { display: none; }
.qa summary::before {
  content: '+';
  flex: none;
  font-size: 1.1em; line-height: 1;
  color: var(--purple);
  transition: transform 0.2s ease;
}
.qa[open] summary::before { content: '\2013'; }
.qa summary:hover { color: var(--purple-deep); }
.qa summary:focus-visible { outline: 3px solid var(--purple); outline-offset: 2px; }
.qa > *:not(summary) { margin-left: 2rem; }
.qa > p, .qa > ul, .qa > table { margin-bottom: 1.15rem; font-size: 0.98rem; }
.qa > p:has(+ .fees-note) { margin-bottom: 0.35rem; }
/* an answer with a photo beside it (Who is RH2?), and the parking answer,
   each direction with its own photo. Every photo is shown whole. */
.qa-split { display: grid; grid-template-columns: 1fr 15rem; gap: 1.25rem 2rem; align-items: start; margin-bottom: 1.15rem; }
.qa-split p { font-size: 0.98rem; }
.qa-split p + p { margin-top: 1rem; }
.qa-photo { rotate: 1.2deg; margin-top: 0.35rem; }
@media (max-width: 719px) {
  .qa-split { grid-template-columns: 1fr; }
  .qa-photo { width: min(100%, 18rem); }
}
.parking { display: grid; gap: 2rem; margin-bottom: 1.15rem; }
.parking-spot p { font-size: 0.98rem; }
.parking-spot p + p { margin-top: 0.4rem; }
.qa-photo-wide { width: min(100%, 30rem); margin-top: 1rem; rotate: -0.6deg; }
.plain-list { list-style: none; display: grid; gap: 0.6rem; }

/* the answers carry a 2rem indent, which a 100%-wide table would push past
   the edge of the column, so the table subtracts it back */
.rates { border-collapse: collapse; width: calc(100% - 2rem); max-width: 34rem; }
/* on a phone the indent costs more than it gives: answers run full width */
@media (max-width: 560px) {
  .qa > *:not(summary) { margin-left: 0; }
  .rates { width: 100%; }
}
.rates th, .rates td { text-align: left; padding: 0.55rem 0.75rem 0.55rem 0; border-bottom: 1px solid var(--rule); font-size: 0.98rem; }
.rates th { font-weight: 600; }
.rates .rates-group th {
  font-family: var(--stencil); font-weight: 400; font-size: 0.72rem;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted);
  padding-top: 1.2rem; white-space: normal;
}
.rates tbody:first-of-type .rates-group th { padding-top: 0.2rem; }
.rates td { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.rates .rates-note td { text-align: left; white-space: normal; font-size: 0.9rem; color: var(--muted); padding-top: 0.2rem; }
/* the same table on the payment page, where it is not inside an indented answer */
.rates-wrap { max-width: 34rem; margin-top: 0.5rem; }
.rates-wrap .rates { width: 100%; }
.rates-wrap + .lede { margin-top: 1.75rem; }
/* On a phone the two columns cannot share the width: the long price cells
   squeeze the labels into stacks that break words, and the table runs past
   its panel. So each row stacks, label above price, and both wrap normally.
   The roles in the markup keep it a table for screen readers. Wider screens
   keep the two-column table exactly as it was. */
@media (max-width: 560px) {
  .rates, .rates tbody, .rates tr, .rates th, .rates td { display: block; }
  .rates tr { padding: 0.55rem 0; border-bottom: 1px solid var(--rule); }
  .rates .rates-group { padding-top: 0; }
  .rates th, .rates td { padding: 0; border-bottom: 0; text-align: left; white-space: normal; }
  .rates td { margin-top: 0.15rem; }
}
.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---------- review notes ----------
   Questions for Marston Athletics, shown on the preview so they can be
   answered in place. Every one is an <aside class="review-note"> headed "For
   Marston Athletics to confirm", and nothing else uses the class, so they can
   all be removed together at handover: `python3 check.py --launch` fails while
   any remain. The look is the dashed box the earlier notes used. */
.review-note {
  max-width: 46rem;
  margin-top: 1.75rem;
  border: 2px dashed var(--purple);
  padding: 1rem 1.1rem;
  font-size: 0.95rem;
  color: var(--muted);
}
.review-note-label {
  font-family: var(--stencil); font-size: 0.72rem;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--purple-deep);
  margin-bottom: 0.4rem;
}
.review-note p + p { margin-top: 0.5rem; }
/* inside an FAQ answer, a note keeps the answer's own spacing */
.qa > .review-note { margin-top: 0; margin-bottom: 1.15rem; }
/* at the head of a page, it keeps the space the draft notice had there */
.page-head > .review-note:first-child { margin: 0 0 clamp(2.5rem, 5vw, 3.5rem); }


/* ---------- coaches ---------- */
.pete {
  display: grid; grid-template-columns: minmax(240px, 370px) 1fr;
  gap: clamp(2.5rem, 4vw, 4rem);
  max-width: 72rem; margin: 0 auto 4rem;
  align-items: start;
}
.pete-photo { rotate: -1.1deg; margin-top: 0.75rem; }
.pete-bio h2 { font-family: var(--display); font-weight: 800; font-size: clamp(1.8rem, 3.5vw, 2.6rem); text-transform: uppercase; line-height: 1; }
.coach-role { font-family: var(--stencil); font-size: 0.72rem; letter-spacing: 0.15em; text-transform: uppercase; color: var(--purple-deep); margin: 0.4rem 0 1rem; }
.pete-bio p + p { margin-top: 0.9rem; }
/* Coach Pete's bio opens out the way the other coaches' do */
.pete-more { margin-top: 0.6rem; }
.pete-more p { margin-top: 0.9rem; }
.pete-creds { margin-top: 1.1rem; padding-left: 1.2rem; font-size: 0.95rem; display: grid; gap: 0.3rem; }
.pete-creds li::marker { color: var(--purple); }
@media (max-width: 820px) { .pete { grid-template-columns: 1fr; } .pete-photo { max-width: 19rem; margin: 0 auto; } }

/* roster: black & white until you meet them */
.staff {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 3rem 2.25rem;
  max-width: 76rem; margin: 0 auto;
}
.coach figure {
  border: 3px solid var(--black);
  box-shadow: 7px 7px 0 var(--gold);
  overflow: hidden;
}
.coach figure img {
  width: 100%; aspect-ratio: 4 / 5; object-fit: cover; object-position: center top;
  filter: grayscale(1) contrast(1.05);
  transition: filter 0.45s ease, scale 0.5s cubic-bezier(0.2, 0.6, 0.3, 1);
}
@media (hover: hover) {
  .coach:hover figure img { filter: grayscale(0) contrast(1); scale: 1.03; }
}
/* A touch screen has no hover, so there each photo turns to colour as it
   crosses the middle of the screen, with the same transition, and back as
   it leaves (site.js marks it .is-lit). With reduced motion it switches at
   once, and without the zoom. */
@media (hover: none) {
  .coach figure.is-lit img { filter: grayscale(0) contrast(1); scale: 1.03; }
}
@media (hover: none) and (prefers-reduced-motion: reduce) {
  .coach figure img { transition: none; }
  .coach figure.is-lit img { scale: none; }
}
.coach h3 { font-family: var(--display); font-weight: 700; font-size: 1.5rem; text-transform: uppercase; margin-top: 1.1rem; }
.coach .coach-role { margin: 0.25rem 0 0.5rem; }
.coach-motto { font-family: var(--serif); font-style: italic; font-size: 1.02rem; color: var(--muted); }
.coach-motto::before { content: '\201C'; }
.coach-motto::after { content: '\201D'; }
.coach details { margin-top: 0.6rem; font-size: 0.93rem; }
.person-bio { margin-top: 0.7rem; font-size: 0.95rem; }
.person figure img { filter: grayscale(1) contrast(1.05); }
.coach summary, .pete-more summary {
  cursor: pointer; width: fit-content;
  font-weight: 600; color: var(--purple-deep);
  text-decoration: underline; text-underline-offset: 3px;
  padding: 0.4rem 0;
}
.coach details p { margin-top: 0.4rem; }
.staff-group { max-width: 46rem; margin: 0 auto; rotate: 0.5deg; }   /* the Events photo's width: any wider and a 4:5 photo is taller than a screen */
.staff-group figcaption {
  font-family: var(--stencil); font-size: 0.78rem;
  letter-spacing: 0.15em; text-transform: uppercase;
  color: var(--muted);
  margin-top: 1rem; text-align: center;
}

.page-photo { max-width: 46rem; margin: 0 auto 3rem; rotate: -0.6deg; }
/* the payment page's photos sit beside the copy, tilted like the others */
.pay-photo { rotate: 1.2deg; }
.pay-photo-alt { rotate: -1deg; }
.page-head .split-media { align-items: center; }
.lede + .tees { margin-top: 2.75rem; }
@media (max-width: 820px) { .split-media .pay-photo { max-width: 19rem; } }
.page-photo figcaption {
  font-family: var(--stencil); font-size: 0.76rem;
  letter-spacing: 0.15em; text-transform: uppercase;
  color: var(--muted);
  margin-top: 1rem; text-align: center;
}

/* ---------- testimonials: the quote wall ---------- */
.quotes {
  display: grid; grid-template-columns: repeat(2, 1fr);
  gap: 3rem clamp(2.5rem, 6vw, 5.5rem);
  max-width: 68rem; margin: 0 auto;
  align-items: start;
}
.quote { position: relative; padding-left: 2.5rem; }
.quote::before {
  content: '\201C';
  position: absolute; left: 0; top: -0.55rem;
  font-family: var(--serif); font-style: italic;
  font-size: 4.4rem; line-height: 1;
  color: var(--purple);
}
.quote p {
  font-family: var(--serif); font-style: italic;
  font-size: 1.16rem; line-height: 1.55;
}
.quote footer {
  display: flex; align-items: center; gap: 0.7rem;
  margin-top: 0.9rem;
  font-family: var(--stencil); font-size: 0.74rem;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--purple-deep);
}
.quote footer::before { content: ''; width: 28px; height: 2px; background: var(--purple); }
.quotes .quote:nth-child(even) { margin-top: 3rem; }
@media (max-width: 720px) {
  .quotes { grid-template-columns: 1fr; }
  .quotes .quote:nth-child(even) { margin-top: 0; }
}

/* ---------- gear ----------
   The two tees, each shown whole, never cropped: side by side at the same
   height (each grows in proportion to its own shape, so their heights
   match), and one above the other on a phone. */
.tees {
  display: flex; gap: 2rem; justify-content: center; align-items: flex-start;
  max-width: 58rem; margin: 0 auto; padding-top: 0.75rem;
}
.tee { flex: 0 1 16px; min-width: 0; }
.tee-wide { flex-grow: 1.5; rotate: -1.2deg; }
.tee-tall { flex-grow: 0.800741; rotate: 1deg; }
@media (max-width: 599px) {
  .tees { flex-direction: column; align-items: center; }
  .tee { flex: none; width: min(100%, 28rem); }
}
.gear-note { text-align: center; margin-top: 2.25rem; color: var(--muted); }
.pay-qrs { display: flex; gap: 2.5rem; justify-content: center; flex-wrap: wrap; margin-top: 1.75rem; }
.qr { width: 148px; text-align: center; }
.qr img { border: 6px solid var(--white); outline: 1px solid rgba(0,0,0,0.3); box-shadow: 0 8px 18px rgba(0,0,0,0.18); }
/* each code is a button that opens it large (site.js) */
.qr-open {
  display: block; width: 100%; padding: 0;
  background: none; border: 0; cursor: zoom-in;
  transition: translate 0.15s ease;
}
.qr-open:hover { translate: 0 -2px; }
.qr-open:focus-visible { outline: 3px solid var(--purple); outline-offset: 4px; }

/* ---------- a QR code, large ----------
   One native modal dialog for every code: the code large on white, its
   caption, and a button that opens the same account in the app. The code is
   never shown larger than its own 500 pixels; where a high-density screen
   enlarges it past them, it is enlarged pixel for pixel, so its dots stay
   sharp edged rather than blurring. */
.qr-dialog {
  margin: auto;
  width: min(calc(100% - 1.5rem), 27rem);
  max-width: none;                 /* the browser's own cap would squeeze the code on a small phone */
  max-height: calc(100vh - 2rem);
  max-height: calc(100dvh - 2rem);
  padding: 0;
  border: 3px solid var(--black);
  background: var(--white); color: var(--black);
  box-shadow: 9px 9px 0 var(--gold);
  overflow: auto; overscroll-behavior: contain;
}
.qr-dialog::backdrop { background: rgba(0,0,0,0.72); }
html.has-qr { overflow: hidden; }
.qr-dialog-inner { display: grid; justify-items: center; gap: 0.9rem; padding: 0.4rem 0.75rem 1.5rem; text-align: center; }
.qr-close {
  justify-self: end;
  position: relative;
  width: 44px; height: 44px; margin-right: -0.75rem;
  background: none; border: 0; cursor: pointer;
}
.qr-close::before, .qr-close::after {
  content: '';
  position: absolute; left: 10px; right: 10px; top: 50%;
  height: 3px; margin-top: -1.5px;
  background: var(--black);
  rotate: 45deg;
}
.qr-close::after { rotate: -45deg; }
.qr-close:hover::before, .qr-close:hover::after { background: var(--purple); }
.qr-close:focus-visible { outline: 3px solid var(--purple); outline-offset: -2px; }
.qr-dialog-code { background: var(--white); padding: 0.5rem; max-width: 100%; }
.qr-big {
  width: min(80vw, 60vh, 360px); height: auto;
  max-width: 100%;
}
@media (min-resolution: 1.4dppx) { .qr-big { image-rendering: pixelated; } }
.qr-dialog-title {
  font-family: var(--stencil); font-size: 0.82rem;
  letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--purple-deep);
}
.qr-dialog-go { margin-top: 0.2rem; }
@media (prefers-reduced-motion: no-preference) {
  .qr-dialog[open] { animation: popupIn 0.3s cubic-bezier(0.2, 0.7, 0.3, 1); }
  .qr-dialog[open]::backdrop { animation: backdropIn 0.25s ease; }
}
.qr figcaption { font-family: var(--stencil); font-size: 0.66rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted); margin-top: 0.6rem; }
/* Under each pair of codes, a line saying a code opens. A mouse has the lift
   and the zoom cursor to say so; a touch screen has nothing, so only there is
   it shown. Whether it shows is decided once, before the page is first drawn,
   by the qr-tap class (set in the head of the pages with codes, on a touch
   screen whose browser can open them), never by a media query here: a browser
   can stop matching (hover: none) as a page is left, and the line's space
   vanishing then moved the position a reload came back to. */
.qr-hint { display: none; }
.qr-tap .qr-hint { display: block; margin-top: 1.4rem; text-align: center; font-family: var(--stencil); font-size: 0.66rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted); }
/* the muted grey is too faint on black for words this small */
.section-dark .qr figcaption, .section-dark .qr-hint { color: rgba(255,255,255,0.7); }

/* ---------- contact ---------- */
.contact-grid { display: grid; grid-template-columns: 1fr; gap: clamp(2rem, 5vw, 4rem); max-width: 72rem; margin: 0 auto; align-items: start; }
.contact-big { margin: 0.5rem 0; }
.contact-big a {
  font-family: var(--display); font-weight: 800;
  font-size: clamp(2.4rem, 6vw, 4rem);
  color: var(--white); text-decoration: none; line-height: 1;
  font-variant-numeric: tabular-nums;
}
.contact-big a:hover { color: var(--gold); }
.contact-links { display: flex; gap: 1.5rem; flex-wrap: wrap; margin-top: 1.5rem; }
.contact-links a {
  font-family: var(--display); font-weight: 700; font-size: 1.15rem;
  text-transform: uppercase; letter-spacing: 0.05em;
  text-underline-offset: 4px;
}
.locations { display: grid; gap: 1rem; margin-top: 2rem; font-size: 0.98rem; }

/* ---------- footer ---------- */
.footer { background: var(--black); color: rgba(255,255,255,0.75); text-align: center; padding: 3rem var(--pad) 2.5rem; border-top: 3px solid var(--gold); }
.footer-logo { width: 190px; height: auto; margin: 0 auto 1.25rem; }
.footer-line { font-family: var(--stencil); font-size: 0.85rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--gold); margin-bottom: 0.75rem; }
.footer-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 2.25rem;
  max-width: 72rem;
  margin: 2.5rem auto;
  text-align: left;
}
.footer-col h2 {
  font-family: var(--stencil); font-size: 0.72rem;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--gold);
  margin-bottom: 0.85rem;
}
.footer-col p + p { margin-top: 0.6rem; }
.footer-col p, .footer-col li { font-size: 0.95rem; }
.footer-col a { color: var(--white); text-underline-offset: 3px; }
.footer-col a:hover { color: var(--gold); }
.footer-phone a {
  font-family: var(--display); font-weight: 800;
  font-size: 1.6rem; line-height: 1;
  text-decoration: none;
  font-variant-numeric: tabular-nums;
}
.footer-list { list-style: none; display: grid; gap: 0.45rem; }
.footer .loc-tag { margin-bottom: 0.3rem; }
.footer-fine { font-size: 0.85rem; border-top: 1px solid rgba(255,255,255,0.18); padding-top: 1.5rem; max-width: 72rem; margin: 0 auto; }
.footer-fine a { color: inherit; }

/* ---------- tap targets on phones and touch screens ----------
   Every link or button that stands on its own, rather than inside a
   sentence, is at least 44px tall there, with room between neighbours to hit
   it reliably. Spacing only: type, colour and decoration are unchanged.
   A link in a stacked list (the footer's lists, its phone, email and map
   links, the FAQ's locations) takes the full width of its row, not just the
   width of its words, so a short one like "FAQ" is as easy to hit as a long
   one. Two kinds of link would visibly move if their box grew (one
   underlined with a border, and address links that flow on after a
   location tag), so those get an invisible, larger hit area instead. */
@media (max-width: 1080px), (pointer: coarse) {
  .nav-logo { display: flex; align-items: center; min-height: 44px; }
  .contact-links a { display: inline-flex; align-items: center; min-height: 44px; }
  .footer-phone a,
  .footer-col a[href^="mailto:"],
  .footer-list a { display: flex; align-items: center; width: 100%; min-height: 44px; }
  .footer-list { gap: 0; }
  .footer-col a[href*="maps.apple.com"] { display: block; width: 100%; }
  .card a[href*="maps.apple.com"] { display: inline-block; padding-block: 0.6rem; }
  .coach summary, .pete-more summary { padding-block: 0.65rem; }
  .plain-list { gap: 1.25rem; }
  .doc-link { position: relative; }
  .doc-link::before {
    content: ''; position: absolute; left: 0; right: 0; top: 50%;
    height: 44px; min-height: 100%; transform: translateY(-50%);
  }
  /* the FAQ's locations: the hit area spans the whole row, tag included */
  .plain-list li { position: relative; }
  .plain-list a::before {
    content: ''; position: absolute; left: 0; right: 0; top: 50%;
    height: 100%; min-height: 44px; transform: translateY(-50%);
  }
}
