/* ==========================================================================
   SECTIONS - layout only, in page order.
   ========================================================================== */

/* ==========================================================================
   01  NAV
   ========================================================================== */

/* The nav floats over the hero photo, so it starts transparent. .surface-base
   would otherwise paint it, hence the doubled class for specificity - and the
   stuck rule below has to come after this one to win. */
.nav.surface-base,
.nav.surface-alt,
.nav {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: var(--z-nav);
  background-color: transparent;
  border-bottom: 1px solid transparent;
  transition: background-color var(--dur-base) var(--ease-out),
              border-color     var(--dur-base) var(--ease-out);
}

.nav.surface-base.is-stuck,
.nav.is-stuck {
  background-color: rgb(var(--bg-rgb) / .88);
  backdrop-filter: blur(16px) saturate(140%);
  -webkit-backdrop-filter: blur(16px) saturate(140%);
  border-bottom-color: var(--edge);
}

.nav__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-6);
  height: var(--nav-h);
}

/* The ceiling is --sp-5 rather than --sp-6 because this gap is the one thing in
   the row that grows with the viewport while the container holding it does not.
   At its old maximum the row needed 1247px inside 1200, so flex shrank the logo
   and the links and two labels broke across two lines - on the widest screens
   first. */
.nav__links { display: flex; align-items: center; gap: clamp(var(--sp-4), 1.7vw, var(--sp-5)); }

.nav__link {
  position: relative;
  padding-block: var(--sp-2);
  /* A nav label is a name. Broken over two lines it stops reading as one. */
  white-space: nowrap;
  font-family: var(--font-display);
  font-size: var(--fs-caption);
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--fg-muted);
  transition: color var(--dur-base) var(--ease-out);
}
.nav__link:hover { color: var(--fg); }

.nav__link::after {
  content: '';
  position: absolute; left: 0; bottom: 0;
  width: 100%; height: 2px;
  background: var(--brand-fg);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur-base) var(--ease-out);
}
.nav__link:hover::after { transform: scaleX(1); }

.nav__actions { display: flex; align-items: center; gap: var(--sp-3); }

.nav__toggle {
  display: none;
  position: relative;
  width: 46px; height: 46px;
  align-items: center; justify-content: center;
  border: 1px solid var(--edge-strong);
  border-radius: var(--r-sm);
  color: var(--fg);
}

.nav__toggle-bars,
.nav__toggle-bars::before,
.nav__toggle-bars::after {
  display: block; width: 17px; height: 2px;
  background: currentColor; border-radius: 2px;
  transition: transform var(--dur-base) var(--ease-out), opacity var(--dur-fast) linear;
}
.nav__toggle-bars::before, .nav__toggle-bars::after { content: ''; position: absolute; }
.nav__toggle-bars::before { transform: translateY(-6px); }
.nav__toggle-bars::after  { transform: translateY(6px); }

.nav__toggle[aria-expanded='true'] .nav__toggle-bars { background: transparent; }
.nav__toggle[aria-expanded='true'] .nav__toggle-bars::before { transform: rotate(45deg); }
.nav__toggle[aria-expanded='true'] .nav__toggle-bars::after  { transform: rotate(-45deg); }

/* grid-template-rows so the drawer opens without a fixed height - no jump. */
.nav__drawer {
  display: none;
  overflow: hidden;
  border-top: 1px solid var(--edge);
  background: rgb(var(--bg-rgb) / .97);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--dur-base) var(--ease-out);
}
.nav__drawer > div {
  min-height: 0;
  /* The list is as tall as it needs to be, and the page behind it is locked, so
     on a short screen whatever fell past the fold could not be reached at all -
     Contact, Coach login and Get started were all unreachable at 375x667.
     Bounded to what is left below the bar, and scrolled. */
  max-height: calc(100vh - var(--nav-h));
  max-height: calc(100dvh - var(--nav-h));
  overflow-y: auto;
  overscroll-behavior: contain;
}
.nav.is-open .nav__drawer { grid-template-rows: 1fr; }

.nav__drawer-inner { display: flex; flex-direction: column; padding: var(--sp-3) 0 var(--sp-6); }

.nav__drawer-link {
  padding: var(--sp-4) var(--sp-1);
  border-bottom: 1px solid var(--edge);
  font-family: var(--font-display);
  font-size: var(--fs-lead);
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--fg);
}
.nav__drawer-cta { margin-top: var(--sp-5); }

/* The drawer takes over below the container's own width. The full row needs
   about 1165px and only gets it once the container has stopped shrinking; at
   980 it was being shown at widths where it had never fitted, and paid for it
   by wrapping its labels. */
@media (max-width: 1279px) {
  .nav__links, .nav__actions .btn { display: none; }
  .nav__toggle { display: inline-flex; }
  .nav__drawer { display: grid; }
}

/* ==========================================================================
   02  HERO
   ========================================================================== */

.hero {
  position: relative;
  display: flex;
  align-items: flex-end;
  min-height: min(100svh, 940px);
  padding-top: calc(var(--nav-h) + var(--sp-7));
  padding-bottom: var(--sp-7);
  overflow: hidden;
}

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

/* Three stacked grades. Together they turn any photograph into this brand's
   green and guarantee the headline has contrast wherever the image is light. */
.hero__media::after {
  content: '';
  position: absolute;
  inset: 0;
  background:
    linear-gradient(90deg, var(--bg) 4%, rgb(var(--bg-rgb) / .86) 42%, rgb(var(--bg-rgb) / .42) 78%),
    linear-gradient(to top, var(--bg) 1%, transparent 42%),
    linear-gradient(to bottom, rgb(var(--bg-rgb) / .92) 0%, transparent 34%);
}

.hero__inner { position: relative; z-index: 1; width: 100%; }

.hero__eyebrow { margin-bottom: var(--sp-5); }

.hero__title { max-width: 16ch; margin-bottom: var(--sp-6); }

/* Each line masks its own span so the reveal edge is exact. */
.line { display: block; overflow: hidden; padding-bottom: .06em; margin-bottom: -.06em; }

.line > span {
  display: block;
  transform: translate3d(0, 110%, 0);
  transition: transform var(--dur-reveal) var(--ease-out);
  transition-delay: var(--line-delay, 0ms);
}
.is-ready .line > span { transform: translate3d(0, 0, 0); }

.hero__bar {
  transform-origin: left;
  transform: scaleX(0);
  transition: transform var(--dur-reveal) var(--ease-out) 480ms;
  margin-right: var(--sp-4);
}
.is-ready .hero__bar { transform: scaleX(1); }

.hero__lead { max-width: 48ch; margin-bottom: var(--sp-7); }

.hero__actions { display: flex; flex-wrap: wrap; gap: var(--sp-4); margin-bottom: var(--sp-8); }

.hero__includes {
  display: flex;
  border-top: 1px solid var(--edge);
  padding-top: var(--sp-5);
}

.hero__include {
  flex: 1;
  min-width: 0;
  padding-inline: var(--sp-5);
  border-left: 1px solid var(--edge);
  font-family: var(--font-display);
  font-size: var(--fs-caption);
  font-weight: 700;
  letter-spacing: .03em;
  text-transform: uppercase;
  line-height: 1.35;
  color: var(--fg-muted);
}
.hero__include:first-child { padding-left: 0; border-left: 0; }

/* These are product names. The global break-word rule would split
   "MentalGame365" across two lines mid-word. */
.hero__include { overflow-wrap: normal; }

/* The strip used to hold five product names, where scrolling sideways to see
   the rest cost nothing. It now carries the three prices, and the brief is that
   a visitor must not have to scroll to learn them - so on a narrow screen the
   list wraps and every line is visible at once. */
@media (max-width: 980px) {
  .hero__includes { flex-wrap: wrap; row-gap: var(--sp-3); }
  .hero__include {
    flex: 1 1 auto;
    max-width: 100%;
    padding-block: var(--sp-1);
  }
  /* Wrapped, each price is its own row, so the rule between items reads as a
     bullet rather than a divider - and a bullet on two of the three looks like
     a mistake. Every row keeps it, first included. */
  .hero__include:first-child { border-left: 1px solid var(--edge); }
}

@media (max-width: 640px) {
  .hero__media::after {
    background:
      linear-gradient(180deg, rgb(var(--bg-rgb) / .86) 0%, rgb(var(--bg-rgb) / .72) 45%, var(--bg) 88%);
  }
}

/* ==========================================================================
   03  MODULES  - photo left, list right
   ========================================================================== */

.modules__layout {
  display: grid;
  grid-template-columns: minmax(0, .85fr) minmax(0, 1.15fr);
  gap: var(--grid-gap) clamp(var(--sp-7), 5vw, var(--sp-9));
  align-items: center;
}
.modules__layout > * { min-width: 0; }

/* No height:100% here. Combined with aspect-ratio it derives the WIDTH from
   the row height and the frame then overflows its grid column into the
   heading beside it. Width comes from the column; height follows. */
.modules__frame { aspect-ratio: 4 / 5; width: 100%; }

.modules__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  border-top: 1px solid var(--edge);
  border-left: 1px solid var(--edge);
}

.module {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  min-height: 132px;
  padding: var(--sp-5);
  border-right: 1px solid var(--edge);
  border-bottom: 1px solid var(--edge);
  transition: background var(--dur-base) var(--ease-out);
}
.module:hover { background: var(--panel-1); }

.module::before {
  content: '';
  position: absolute; inset: 0 0 auto 0;
  height: 3px; background: var(--brand-fg);
  transform: scaleX(0); transform-origin: left;
  transition: transform var(--dur-base) var(--ease-out);
}
.module:hover::before { transform: scaleX(1); }

.module__index {
  font-family: var(--font-mono);
  font-size: var(--fs-eyebrow);
  letter-spacing: .12em;
  color: var(--brand-fg);
}

.module__name {
  margin-top: auto;
  font-family: var(--font-display);
  font-size: var(--fs-h5);
  font-weight: 800;
  letter-spacing: var(--ls-heading);
  text-transform: uppercase;
  color: var(--fg);
}

@media (max-width: 900px) {
  .modules__layout { grid-template-columns: minmax(0, 1fr); }
  .modules__frame  { aspect-ratio: 16 / 10; }
}
@media (max-width: 420px) {
  .modules__grid { grid-template-columns: minmax(0, 1fr); }
}

/* ==========================================================================
   04  STALL
   ========================================================================== */

.stall__layout {
  display: grid;
  grid-template-columns: minmax(0, .9fr) minmax(0, 1.1fr);
  gap: var(--grid-gap) clamp(var(--sp-7), 6vw, var(--sp-10));
  align-items: start;
}

.stall__aside { position: sticky; top: 118px; }

.stall__payoff {
  margin-top: var(--sp-7);
  padding-top: var(--sp-6);
  border-top: 1px solid var(--edge);
}
.stall__payoff p {
  font-family: var(--font-display);
  font-size: clamp(1.375rem, 1.05rem + 1.5vw, 2.125rem);
  font-weight: 800;
  line-height: 1.14;
  letter-spacing: var(--ls-heading);
  text-transform: uppercase;
  color: var(--fg);
  max-width: 20ch;
}
.stall__payoff em { font-style: normal; color: var(--brand-fg); }

@media (max-width: 900px) {
  .stall__layout { grid-template-columns: minmax(0, 1fr); }
  .stall__aside  { position: static; }
}

/* ==========================================================================
   05  PLAN / TRACK
   ========================================================================== */

.plan { text-align: center; }
.plan__title { max-width: 18ch; margin-inline: auto; }

.track { position: relative; margin-top: var(--sp-9); padding-top: var(--sp-7); }

.track__rail {
  position: absolute; inset: 0 0 auto 0;
  height: 3px; background: var(--edge); border-radius: 3px; overflow: hidden;
}

.track__fill {
  position: absolute; inset: 0 auto 0 0; width: 100%;
  background: linear-gradient(90deg,
    var(--tone-1) 0%, var(--tone-2) 34%, var(--tone-3) 67%, var(--tone-4) 100%);
  transform: scaleX(var(--track-progress, 0));
  transform-origin: left;
  /* Driven directly from scroll position - a transition here would lag. */
}

/* One column per step, counted from the markup rather than hardcoded: the
   track went from four levels to five when Pro was added, and a fixed
   repeat(4) wrapped the fifth onto a second row where its dot landed on top of
   the first one's label. */
.track__steps {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  gap: var(--sp-4);
}

.track__step {
  position: relative;
  display: flex; flex-direction: column; align-items: center; gap: var(--sp-3);
  text-align: center;
}

.track__dot {
  position: absolute;
  top: calc(var(--sp-7) * -1 - 6px);
  width: 15px; height: 15px; border-radius: 50%;
  background: var(--bg);
  border: 3px solid var(--edge-strong);
  transition: border-color var(--dur-base) var(--ease-out),
              transform    var(--dur-base) var(--ease-spring);
}
.track__step.is-lit .track__dot { border-color: var(--step-tone); transform: scale(1.3); }

.track__name {
  font-family: var(--font-display);
  font-size: var(--fs-small);
  font-weight: 800;
  letter-spacing: .03em;
  text-transform: uppercase;
  color: var(--fg-dim);
  transition: color var(--dur-base) var(--ease-out);
}
/* The lit name goes to full foreground, not to its tier colour. This track
   sits on surface-brand, and the tier palette is tuned for the near-black
   page ground: on the orange it lands at 3.64 to 4.24, and Advanced is
   orange on orange. The dot keeps the tier colour, so the colour coding
   survives without a contrast failure carrying it. */
.track__step.is-lit .track__name { color: var(--fg); }

.track__range {
  font-family: var(--font-mono);
  font-size: var(--fs-eyebrow);
  letter-spacing: .07em;
  color: var(--fg-dim);
}

@media (max-width: 680px) {
  .track__steps { grid-auto-flow: row; grid-template-columns: repeat(2, minmax(0, 1fr)); row-gap: var(--sp-6); }
  .track__rail  { display: none; }
  .track__dot   { position: static; }
  .track__step  { flex-direction: row; align-items: center; gap: var(--sp-3); text-align: left; }
  .track__step > .stack { align-items: flex-start; }
}

/* ==========================================================================
   06  LEVELS
   ========================================================================== */

/* Five levels, so the minimum column is set to fit all five on a wide screen.
   At 248px the fifth wrapped alone onto a second row, which read as an
   afterthought rather than the last stage of a progression. Still auto-fit, so
   it drops to 3, 2 and 1 as the viewport narrows. */
.levels__grid { --min: 214px; }
.level { gap: var(--sp-4); }

.level__head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-4); }

.level__name {
  font-family: var(--font-display);
  font-size: var(--fs-h5);
  font-weight: 800;
  letter-spacing: var(--ls-heading);
  text-transform: uppercase;
  color: var(--tier-tone);
}

.level__index { font-family: var(--font-mono); font-size: var(--fs-eyebrow); letter-spacing: .12em; color: var(--fg-dim); }

.level__handicap {
  display: inline-flex; align-items: baseline; gap: var(--sp-2);
  font-family: var(--font-mono);
  font-size: var(--fs-caption);
  font-weight: 500;
  color: var(--fg);
}
.level__handicap span {
  color: var(--fg-dim); text-transform: uppercase;
  letter-spacing: .12em; font-size: var(--fs-eyebrow);
}

.levels__note { margin-top: var(--sp-6); font-size: var(--fs-caption); color: var(--fg-muted); }

/* ==========================================================================
   06b MEASURE CAPS

   The container grows on a wide screen; a line of text must not grow with it.
   Most prose here was already capped in ch - .lead at 54, the hero lead at 48 -
   but these five were not, and at 1920 they ran to between 104 and 185
   characters, which is past reading and into scanning.

   Capped in ch rather than px so the limit is a number of characters at
   whatever size the text happens to be, and because a max-width only binds
   once a box is wider than it: below the large-screen step these change
   nothing at all.
   ========================================================================== */

/* 1202px inside a level row, 806px in a split card. */
.card__body { max-width: 68ch; }

/* Caption-sized, so it carries more characters comfortably. Was 1840px. */
.levels__note { max-width: 80ch; }

/* Was 1102px. */
.plan-card__body { max-width: 60ch; }

/* Both were 828-884px. */
.inapp__point p,
.inapp__note { max-width: 66ch; }

/* ==========================================================================
   07  PERFORMANCE
   ========================================================================== */

.perf__layout {
  display: grid;
  grid-template-columns: minmax(0, .88fr) minmax(0, 1.12fr);
  gap: var(--grid-gap) clamp(var(--sp-7), 5vw, var(--sp-9));
  align-items: center;
}

/* Nothing loads until this is clicked. */
.player {
  position: relative;
  aspect-ratio: 16 / 10;
  border-radius: var(--r-lg);
  overflow: hidden;
  border: 1px solid var(--edge);
  background: var(--bg-deep);
  box-shadow: var(--shadow-float);
}

.player__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  background: var(--bg-deep);
}

/* Controls float over the video, bottom-left, out of the speaker's face. */
.player__ui {
  position: absolute;
  inset: auto var(--sp-4) var(--sp-4) var(--sp-4);
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  pointer-events: none;
}
.player__ui > * { pointer-events: auto; }

.player__sound,
.player__full {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  height: 38px;
  padding-inline: var(--sp-4);
  border-radius: var(--r-full);
  border: 1px solid rgb(255 255 255 / .22);
  background: rgb(0 0 0 / .5);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  color: #fff;
  font-family: var(--font-display);
  font-size: var(--fs-eyebrow);
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  white-space: nowrap;
  transition: background var(--dur-base) var(--ease-out),
              border-color var(--dur-base) var(--ease-out);
}
.player__sound:hover,
.player__full:hover { background: rgb(0 0 0 / .72); border-color: var(--brand-fg); }

/* Pressed = sound on. */
.player__sound[aria-pressed='true'] { background: var(--brand-fg); border-color: var(--brand-fg); color: var(--on-brand); }

.player__ui .icon { stroke-width: 2; }

@media (max-width: 480px) {
  .player__sound-label { display: none; }
  .player__sound, .player__full { padding-inline: var(--sp-3); }
}

/* 38px is under the 44px minimum, and these two sit over a playing video where
   a missed tap unmutes nothing and looks broken. Pointer as well as width, for
   the same reason as the buttons in components.css. */
@media (max-width: 600px), (pointer: coarse) {
  .player__sound, .player__full { height: 44px; }
}

.perf__stats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--grid-gap);
  margin-top: var(--sp-7);
  padding-top: var(--sp-6);
  border-top: 1px solid var(--edge);
}

@media (max-width: 900px) { .perf__layout { grid-template-columns: minmax(0, 1fr); } }
@media (max-width: 560px) { .perf__stats { grid-template-columns: minmax(0, 1fr); gap: var(--sp-5); } }

/* ==========================================================================
   08  PRICING
   ========================================================================== */

.pricing__grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--grid-gap); }

.plan-card { gap: var(--sp-5); padding: var(--sp-7) var(--sp-6); }

/* The featured plan is distinguished by a brand border, a stronger shadow and
   the badge - NOT by a tinted fill. A wash here reads as a darker, muddier
   card sitting between two clean white ones. */
.plan-card--featured {
  border-color: rgb(var(--brand-rgb) / .50);
  background: var(--card-bg-featured);
  box-shadow: var(--card-shadow-hover);
}
.plan-card--featured::after {
  content: 'Most popular';
  position: absolute; top: 0; left: 50%;
  translate: -50% -50%;
  padding: 6px var(--sp-4);
  border-radius: var(--r-full);
  /* Orange, not brand green - it has to differ from the green button
     directly beneath it. Ink is dark: white on #E07A1F is only 3.01:1. */
  background: var(--accent);
  color: #1D1916;
  font-family: var(--font-mono);
  font-size: var(--fs-eyebrow);
  font-weight: 500;
  letter-spacing: .1em;
  text-transform: uppercase;
  white-space: nowrap;
}

.plan-card__tier {
  font-family: var(--font-mono);
  font-size: var(--fs-eyebrow);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  /* --fg-dim is documented as large-text-and-UI only; this is 11px, so on a
     card it came out at 4.07:1. --fg-muted is the token for small copy. */
  color: var(--fg-muted);
}

.plan-card__name {
  font-family: var(--font-display);
  font-size: var(--fs-h4);
  font-weight: 800;
  line-height: 1.1;
  letter-spacing: var(--ls-heading);
  text-transform: uppercase;
}

.plan-card__price {
  display: flex; align-items: baseline; gap: var(--sp-2);
  padding-block: var(--sp-4);
  border-bottom: 1px solid var(--edge);
}

.plan-card__amount {
  font-family: var(--font-display);
  font-size: clamp(2rem, 1.6rem + 1.7vw, 2.75rem);
  font-weight: 800;
  letter-spacing: -0.045em;
  line-height: 1;
  color: var(--fg);
}
/* A word where a figure normally goes.
   The amount is sized for "$30" - two glyphs at display weight - and midnight
   gives it a fixed grid column to match. "Complimentary" at that size ran out
   of the column and over the description beside it, so a worded price steps
   down to a size that fits and wraps instead of overflowing. */
.plan-card__amount--word {
  font-size: clamp(1.05rem, 0.9rem + 0.6vw, 1.35rem);
  letter-spacing: -0.02em;
  line-height: 1.15;
}
.plan-card__price:has(.plan-card__amount--word) { flex-wrap: wrap; }

.plan-card__period { font-size: var(--fs-caption); color: var(--fg-muted); }
.plan-card__body   { font-size: var(--fs-small); line-height: 1.6; color: var(--fg-muted); }

@media (max-width: 1040px) {
  .pricing__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* The featured card would otherwise sit alone on row 2 at half width. */
  .plan-card--featured { order: -1; grid-column: 1 / -1; }
}
@media (max-width: 700px) {
  .pricing__grid { grid-template-columns: minmax(0, 1fr); }
  .plan-card--featured { grid-column: auto; margin-top: var(--sp-4); }
}

/* ==========================================================================
   09  FAQ
   ========================================================================== */

.faq__layout {
  display: grid;
  grid-template-columns: minmax(0, .7fr) minmax(0, 1.3fr);
  gap: var(--grid-gap) clamp(var(--sp-7), 6vw, var(--sp-10));
  align-items: start;
}
.faq__aside { position: sticky; top: 118px; }

@media (max-width: 900px) {
  .faq__layout { grid-template-columns: minmax(0, 1fr); }
  .faq__aside  { position: static; }
}

/* ==========================================================================
   10  BLOG
   ========================================================================== */

.blog__grid { --min: 268px; }
.post { gap: var(--sp-4); padding: 0; overflow: hidden; }
.post__frame { aspect-ratio: 16 / 10; border: 0; border-radius: 0; }
.post__body  { display: flex; flex-direction: column; gap: var(--sp-3); padding: var(--sp-5) var(--sp-5) var(--sp-6); flex: 1; }

.post__date {
  font-family: var(--font-mono);
  font-size: var(--fs-eyebrow);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--fg-muted);
}

.post__title {
  font-family: var(--font-display);
  font-size: var(--fs-h5);
  font-weight: 800;
  line-height: 1.16;
  letter-spacing: var(--ls-heading);
  text-transform: uppercase;
  transition: color var(--dur-base) var(--ease-out);
}
.post:hover .post__title { color: var(--brand-fg); }

/* ==========================================================================
   11  CTA
   ========================================================================== */

.cta { position: relative; overflow: hidden; text-align: center; }

.cta__media { position: absolute; inset: 0; z-index: 0; }
.cta__media img { width: 100%; height: 100%; object-fit: cover; }
.cta__media::after {
  content: '';
  position: absolute; inset: 0;
  background:
    linear-gradient(to bottom, var(--bg) 0%, rgb(var(--bg-rgb) / .82) 40%, var(--bg) 100%);
}

.cta__inner { position: relative; z-index: 1; }
.cta__title { max-width: 16ch; margin-inline: auto; }
.cta__lead  { margin-inline: auto; }
.cta__actions { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--sp-4); margin-top: var(--sp-7); }

/* ==========================================================================
   12  FOOTER
   ========================================================================== */

.footer { border-top: 1px solid var(--edge); padding-block: var(--sp-8) var(--sp-6); }

.footer__top {
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) repeat(3, minmax(0, 1fr));
  gap: var(--grid-gap) var(--sp-6);
  padding-bottom: var(--sp-8);
  border-bottom: 1px solid var(--edge);
}

.footer__blurb {
  margin-top: var(--sp-5);
  max-width: 36ch;
  font-size: var(--fs-small);
  line-height: 1.65;
  color: var(--fg-muted);
}

/* The TrackMan lockup - a partner credit, deliberately quiet and never in
   the position where the company's own mark belongs. */
.footer__tech {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  margin-top: var(--sp-6);
  padding-top: var(--sp-5);
  border-top: 1px solid var(--edge);
  max-width: 36ch;
}
.footer__tech-label {
  font-family: var(--font-mono);
  font-size: var(--fs-eyebrow);
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--fg-muted);
  white-space: nowrap;
}

/* The TrackMan lockup. --orange no longer exists (it became --accent when the
   tokens were rebuilt), so this fill was resolving to nothing and the mark
   fell back to black - invisible on a dark ground. */
/* The lockup is drawn through <use>, so a descendant selector cannot reach
   its paths - that shadow tree is not addressable that way, which is why the
   mark was rendering black. `color` and custom properties DO inherit into it,
   so the symbol's paths read var(--wm-type) / var(--wm-mark) instead. */
.footer__tech svg {
  height: 34px;
  width: auto;
  color: var(--fg-muted);
  --wm-type: currentColor;
  --wm-mark: var(--accent);
}

/* 11px uppercase. --fg-dim is specified for large text and UI only and
   measures 3.7-4.1:1, which fails at this size. */
.footer__col-title {
  margin-bottom: var(--sp-4);
  font-family: var(--font-mono);
  font-size: var(--fs-eyebrow);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--fg-muted);
}

.footer__list { display: grid; gap: var(--sp-3); }
/* The Studio column holds a street address and an email - both long tokens
   that will otherwise push the four-column footer past the viewport. */
.footer__link {
  display: block;
  font-size: var(--fs-small);
  color: var(--fg-muted);
  overflow-wrap: anywhere;
  transition: color var(--dur-base) var(--ease-out);
}
.footer__link:hover { color: var(--brand-fg); }

/* A 24px link with a 12px gap is a 36px row and a 24px target. Moving the gap
   into the link makes the whole row tappable at 44px and costs the column
   8px a line, rather than the 20px that adding padding on top would. */
@media (max-width: 600px) {
  .footer__list { gap: 0; }
  .footer__link { padding-block: 10px; }
}

.footer__bottom {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: var(--sp-4);
  padding-top: var(--sp-6);
  font-size: var(--fs-caption);
  color: var(--fg-dim);
}
.footer__legal { display: flex; flex-wrap: wrap; gap: var(--sp-5); }

@media (max-width: 1100px) {
  .footer__top { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .footer__brand-col { grid-column: 1 / -1; }
}
@media (max-width: 520px) {
  .footer__top    { grid-template-columns: minmax(0, 1fr); gap: var(--sp-7); }
  .footer__bottom { flex-direction: column; align-items: flex-start; }
}

/* Below 720px the inline lime bar steals enough of the line to break
   "Play Better." across two lines. Give it its own row instead. */
@media (max-width: 720px) {
  .hero__bar {
    display: block;
    margin: 0 0 var(--sp-3);
    width: clamp(64px, 22vw, 110px);
  }
  .hero__title .line:last-child { overflow: visible; }
}


/* Grid and flex children default to min-width:auto, which lets long content
   push a track past its container. This is the single guard that keeps the
   page from ever scrolling sideways. */
.modules__layout > *,
.stall__layout > *,
.perf__layout > *,
.faq__layout > *,
.footer__top > *,
.pricing__grid > *,
.grid-auto > * { min-width: 0; }

/* ==========================================================================
   INSIDE THE APP
   ========================================================================== */

.inapp__layout {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr);
  gap: var(--grid-gap) clamp(var(--sp-7), 5vw, var(--sp-9));
  align-items: center;
}
.inapp__layout > * { min-width: 0; }

.inapp__points { display: grid; gap: var(--sp-5); margin-top: var(--sp-7); }

.inapp__point {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--sp-4);
  align-items: start;
  padding-top: var(--sp-5);
  border-top: 1px solid var(--edge);
}

.inapp__point-num {
  font-family: var(--font-mono);
  font-size: var(--fs-eyebrow);
  letter-spacing: .12em;
  color: var(--brand-fg);
  padding-top: 3px;
}

.inapp__point b {
  display: block;
  font-family: var(--font-display);
  font-size: var(--fs-h5);
  font-weight: 700;
  letter-spacing: var(--ls-heading);
  text-transform: uppercase;
  color: var(--fg);
  margin-bottom: var(--sp-2);
}
.inapp__point p { font-size: var(--fs-small); line-height: 1.55; color: var(--fg-muted); }

@media (max-width: 900px) {
  .inapp__layout { grid-template-columns: minmax(0, 1fr); }

  /* The phone leads, but only the phone. Hoisting the whole column took the
     closing note and the link out of this section up with it, so a reader met
     "See how Trackman works" before the section had said what Trackman does
     here. The wrapper carries no styles of its own, so dropping it out of the
     box tree costs nothing and lets the three pieces order independently:
     screen, then the copy, then the note and the way onward. */
  .inapp__phone { display: contents; }
  .inapp__phone > .phone { order: -1; }
}

/* ==========================================================================
   TESTIMONIALS
   ========================================================================== */

.quotes__grid { --min: 280px; }

.quote { gap: var(--sp-5); }

.quote__mark {
  font-family: var(--font-display);
  font-size: 3rem;
  font-weight: 800;
  line-height: .7;
  color: var(--brand-fg);
  opacity: .5;
}

.quote__text {
  font-size: var(--fs-lead);
  line-height: 1.5;
  letter-spacing: var(--ls-body);
  color: var(--fg);
}

.quote__by {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  margin-top: auto;
  padding-top: var(--sp-5);
  border-top: 1px solid var(--edge);
}

.quote__avatar {
  display: grid;
  place-items: center;
  width: 38px; height: 38px;
  flex: none;
  border-radius: 50%;
  background: rgb(var(--brand-rgb) / .10);
  font-family: var(--font-display);
  font-size: var(--fs-caption);
  font-weight: 800;
  color: var(--brand-fg);
}

.quote__name { font-size: var(--fs-small); font-weight: 600; color: var(--fg); }
.quote__meta {
  font-family: var(--font-mono);
  font-size: var(--fs-eyebrow);
  letter-spacing: .08em;
  color: var(--fg-dim);
}



/* ==========================================================================
   CONTACT
   ========================================================================== */

.contact__layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
  gap: var(--grid-gap) clamp(var(--sp-7), 5vw, var(--sp-9));
  align-items: start;
}
.contact__layout > * { min-width: 0; }

.contact__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--grid-gap);
}

.contact__item {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  padding: var(--sp-5);
  border: 1px solid var(--edge);
  border-radius: var(--r-lg);
  background: var(--card-bg);
  box-shadow: var(--card-shadow);
  transition: border-color var(--dur-base) var(--ease-out),
              background   var(--dur-base) var(--ease-out);
}
a.contact__item:hover { border-color: var(--brand-fg); background: var(--card-bg-hover); box-shadow: var(--card-shadow-hover); }

.contact__label {
  font-family: var(--font-mono);
  font-size: var(--fs-eyebrow);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--fg-dim);
}

.contact__value {
  font-size: var(--fs-small);
  font-weight: 600;
  line-height: 1.45;
  color: var(--fg);
  overflow-wrap: anywhere;
}

.contact__cta { margin-top: var(--sp-6); }

@media (max-width: 900px) { .contact__layout { grid-template-columns: minmax(0, 1fr); } }
@media (max-width: 520px) { .contact__grid   { grid-template-columns: minmax(0, 1fr); } }

/* ============================================================ 17 NAV MENU */
/* The Resources dropdown. A <details>, so it is a working menu with no JS at
   all. It does NOT close on Escape or on an outside click on its own - that
   is added in main.js. The panel is absolutely positioned so opening it does
   not push the rest of the nav sideways. */
.nav__menu { position: relative; }
.nav__menu > summary { list-style: none; cursor: pointer; }
.nav__menu > summary::-webkit-details-marker { display: none; }
.nav__link--menu::after {
  content: "";
  position: static;
  display: inline-block;
  width: 0;
  height: 0;
  margin-left: 6px;
  background: none;
  border: 4px solid transparent;
  border-top-color: currentColor;
  transform: translateY(2px);
  transition: transform var(--dur-fast) var(--ease-out);
}
.nav__menu[open] .nav__link--menu::after { transform: translateY(-2px) rotate(180deg); }
.nav__menu-panel {
  position: absolute; top: calc(100% + 10px); left: 50%; transform: translateX(-50%);
  display: grid; gap: 2px; min-width: 190px; padding: var(--sp-3);
  background: var(--bg-deep); border: 1px solid var(--edge-strong);
  border-radius: var(--r-md); box-shadow: var(--card-shadow); z-index: 60;
}

/* Bridges the 10px gap between the summary and the panel, so travelling to
   the menu's own links never takes the pointer outside the menu. Invisible,
   and it only exists while the menu is open. */
.nav__menu-panel::before {
  content: "";
  position: absolute;
  inset: -10px 0 100% 0;
}
.nav__menu-link {
  padding: var(--sp-3) var(--sp-4); border-radius: var(--r-sm);
  color: var(--fg); font-size: .9375rem; text-decoration: none;
}
.nav__menu-link:hover { background: var(--panel-1); color: var(--brand-fg); }

.nav__link:focus-visible,
.nav__menu-link:focus-visible,
.nav__menu > summary:focus-visible {
  outline: 2px solid var(--brand-fg);
  outline-offset: 3px;
  border-radius: var(--r-xs);
}
.nav__login { margin-right: var(--sp-4); white-space: nowrap; }

@media (max-width: 600px) {
  .nav__login { display: inline-flex; align-items: center; min-height: 44px; }
}

/* ======================================================= 18 MODULE NOTES */
.module__note {
  display: block; margin-top: var(--sp-2);
  color: var(--fg-muted); font-size: .875rem; line-height: 1.5;
}

/* ==================================================== 19 PLAYER / COACH */
/* Two doors into the same system, so the cards are deliberately identical in
   weight - one is not the featured option. */
.split__grid {
  display: grid; gap: var(--sp-6); margin-top: var(--sp-8);
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
.split__card { display: flex; flex-direction: column; padding: var(--sp-7); }
.split__title { margin: var(--sp-3) 0 var(--sp-4); }
.split__list { margin-top: var(--sp-5); }
.split__price {
  margin-top: var(--sp-5); font-weight: 600; color: var(--brand-fg);
}
.split__card .card__footer { margin-top: auto; padding-top: var(--sp-6); }
@media (max-width: 900px) { .split__grid { grid-template-columns: minmax(0, 1fr); } }

/* ========================================================= 20 HOW IT WORKS */
.steps__grid {
  display: grid; gap: var(--sp-5); margin-top: var(--sp-8);
  grid-template-columns: repeat(4, minmax(0, 1fr));
}
.step { padding: var(--sp-6); }
.step__index {
  display: block; font-family: var(--font-mono); font-size: .8125rem;
  color: var(--brand-fg); letter-spacing: .08em;
}
.step__name { margin: var(--sp-3) 0 var(--sp-3); font-size: 1.25rem; }
.steps__cta, .plan__cta { display: flex; justify-content: center; margin-top: var(--sp-8); }
@media (max-width: 900px) { .steps__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 520px) { .steps__grid { grid-template-columns: minmax(0, 1fr); } }

/* ============================================================= 21 TRACKMAN */
.inapp__note {
  margin-top: var(--sp-6); padding: var(--sp-4) var(--sp-5);
  border-left: 3px solid var(--brand-fg); background: var(--panel-1);
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
  color: var(--fg); font-weight: 500;
}

/* ======================================================== 22 COACH FEATURE */
.perf__highlight {
  margin-top: var(--sp-6); font-size: 1.25rem; font-weight: 600; color: var(--brand-fg);
}
.perf__actions { display: flex; flex-wrap: wrap; gap: var(--sp-4); margin-top: var(--sp-6); }

/* =========================================================== 23 GET THE APP */
.getapp__badges {
  display: flex; flex-wrap: wrap; gap: var(--sp-4);
  justify-content: center; align-items: center; margin-top: var(--sp-7);
  /* The height both store badges are drawn at. Set here rather than in the
     badge rules so the pair stays one decision. */
  --badge-h: 3rem;
}

/* ====================================================== 24 REMOTE CONTENT */
/* Shown only when a section's list came back empty, so an unreachable API
   leaves an honest line rather than a collapsed layout. */
.content__empty {
  grid-column: 1 / -1; margin: 0; padding: var(--sp-6) 0;
  color: var(--fg-muted); text-align: center;
}
img.quote__avatar { object-fit: cover; }

/* ==================================================== 25 THE PROBLEM (centred) */
.stall__copy {
  max-width: 62ch;
  margin: var(--sp-6) auto 0;
  text-align: center;
  color: var(--fg-muted);
  display: grid;
  gap: var(--sp-4);
}

.qcards {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--sp-5);
  margin-top: var(--sp-8);
}

/* A question, not a step: no numbering, because these four are asked at the
   same time rather than in an order. */
.qcard {
  display: flex;
  align-items: center;
  min-height: 7.5rem;
  padding: var(--sp-6);
}

.qcard p {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--fs-h5);
  line-height: 1.3;
  color: var(--fg);
}

.stall__answer {
  margin-top: var(--sp-7);
  text-align: center;
  font-family: var(--font-display);
  font-size: var(--fs-h4);
  color: var(--brand-fg);
}

@media (max-width: 900px) { .qcards { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 520px) { .qcards { grid-template-columns: minmax(0, 1fr); } .qcard { min-height: 0; } }

/* ================================================ 26 DEVELOPMENT PILLARS */
.pillars {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--sp-5);
  margin-top: var(--sp-8);
}

.pillar { padding: var(--sp-6); }

.pillar__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  margin-bottom: var(--sp-5);
  border-radius: var(--r-sm);
  background: rgb(var(--brand-rgb) / .14);
  color: var(--brand-fg);
}

.pillar__icon svg {
  width: 1.35rem;
  height: 1.35rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.pillar__name { margin: 0 0 var(--sp-3); font-size: var(--fs-h5); }

.section-cta { display: flex; justify-content: center; margin-top: var(--sp-8); }

@media (max-width: 900px) { .pillars { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) { .pillars { grid-template-columns: minmax(0, 1fr); } }

/* Sits under the complimentary line: the free tier is the headline, Coach Plus
   is the follow-up, so it reads quieter than the highlight above it. */
.perf__note {
  margin-top: var(--sp-3);
  max-width: 46ch;
  color: var(--fg-muted);
  font-size: var(--fs-small);
}

/* Marks a placeholder testimonial on the card itself. A story with no name
   behind it must never be mistakable for a real one. */
.quote__sample {
  display: inline-block;
  align-self: flex-start;
  margin-bottom: var(--sp-3);
  padding: .2rem .5rem;
  border-radius: var(--r-xs);
  background: var(--panel-2);
  color: var(--fg-muted);
  font-family: var(--font-mono);
  font-size: .625rem;
  letter-spacing: .1em;
  text-transform: uppercase;
}

/* ===================================================== 26 TRACKMAN WALKTHROUGH */
/* Four alternating rows, each a phone beside the copy that explains it. The
   phone is a fixed 320px so the mock renders at the size it was drawn for;
   the copy takes whatever is left. */

.walk { display: grid; gap: var(--sp-9); margin-top: var(--sp-8); }

.walk__row {
  display: grid;
  grid-template-columns: minmax(0, 320px) minmax(0, 1fr);
  gap: clamp(var(--sp-7), 5vw, var(--sp-9));
  align-items: center;
}
.walk__row > * { min-width: 0; }

/* Phone on the right for every other row. Placed with grid-column rather than
   by reordering the markup, so the reading order stays phone-then-copy. */
.walk__row--flip { grid-template-columns: minmax(0, 1fr) minmax(0, 320px); }
.walk__row--flip .walk__phone { grid-column: 2; grid-row: 1; }
.walk__row--flip .walk__copy  { grid-column: 1; grid-row: 1; }

.walk__index {
  display: block;
  font-family: var(--font-mono);
  font-size: .8125rem;
  letter-spacing: .08em;
  color: var(--brand-fg);
}

.walk__name {
  margin: var(--sp-3) 0 var(--sp-4);
  font-family: var(--font-display);
  font-size: var(--fs-h4);
  font-weight: 700;
  letter-spacing: var(--ls-heading);
  text-wrap: balance;
}

.walk__body { color: var(--fg-muted); line-height: 1.65; max-width: 52ch; }

.walk__points {
  display: grid;
  gap: var(--sp-3);
  margin-top: var(--sp-5);
  padding: 0;
  list-style: none;
}
.walk__points li {
  position: relative;
  padding-left: var(--sp-6);
  font-size: var(--fs-small);
  line-height: 1.55;
  color: var(--fg-muted);
}
.walk__points li::before {
  content: '';
  position: absolute;
  left: 0;
  top: .5em;
  width: 12px;
  height: 2px;
  border-radius: 2px;
  background: var(--brand-fg);
}
.walk__points b { color: var(--fg); font-weight: 600; }

@media (max-width: 900px) {
  .walk { gap: var(--sp-8); }
  .walk__row,
  .walk__row--flip { grid-template-columns: minmax(0, 1fr); }
  .walk__row--flip .walk__phone,
  .walk__row--flip .walk__copy { grid-column: 1; grid-row: auto; }
}

/* ---- A real app capture in the phone frame ---- */
/* The captures are 640x1303 with the iOS status bar cropped off, so the frame
   takes their ratio rather than the mock's. No notch: the app's own header is
   the first thing in the image. */
.phone--shot {
  /* No fixed ratio. The bezel is a px padding, so any hard aspect-ratio is
     only correct at one width and crops the capture at every other one. The
     image sets the height and the frame follows it, exactly, at any size. */
  aspect-ratio: auto;
  padding: 12px;
  border-radius: 46px;
  /* Overrides .phone's ground-derived body - see --device-frame. */
  background: var(--device-frame);
  box-shadow:
    /* Hairline plus a soft halo, both wash-derived, so the shell separates
       from a pale ground by being dark and from a near-black one by carrying
       its own light edge. Without the halo the device disappears into the
       dark sections. */
    0 0 0 1px var(--device-frame-ring),
    0 0 0 6px rgb(var(--wash-rgb) / .05),
    inset 0 1.5px 0 rgb(255 255 255 / .15),
    inset 0 -1.5px 0 rgb(0 0 0 / .40),
    var(--shadow-float);
}

.phone--shot .phone__screen { height: auto; border-radius: 34px; }

.shot {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 34px;
}

/* ============================================== 27 SCROLL-DRIVEN MOTION */
/* A refinement layer on top of the .reveal entrance in base.css, not a
   replacement for it.
 *
 * These animations move things. They never touch opacity, and that is a rule
 * rather than a preference: a scroll-driven animation only completes if the
 * page can actually scroll through its whole range, which is false for
 * anything already on screen at load (its entry range sits at scroll offsets
 * you cannot reach) and false again for anything near the end of the document.
 * Driving opacity here leaves the hero buttons at half alpha and the last CTA
 * faded, permanently. Opacity stays with the observer in main.js, which knows
 * how to finish; scroll position only ever adds parallax on top.
 *
 * Progressive: no scroll timelines, or reduced motion asked for, means the
 * .reveal entrance alone and nothing lost but polish.
 */

@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {

    /* Hero photograph eases out of its own scale as the hero leaves, so the
       first scroll of the page has depth rather than sliding a flat slab. */
    .hero__media { overflow: hidden; }
    .hero__media img {
      animation: hero-settle linear both;
      animation-timeline: view();
      animation-range: entry 0% exit 100%;
    }
    @keyframes hero-settle {
      from { transform: scale(1.14) translate3d(0, -1.5%, 0); }
      to   { transform: scale(1.00) translate3d(0,  1.5%, 0); }
    }

    /* The device rises into place, settles, then keeps drifting a little
       slower than the page it sits on. One keyframe set rather than two
       animations, because two animations on the same property replace each
       other instead of composing. */
    .walk__phone {
      animation: device-pass linear both;
      animation-timeline: view();
      animation-range: entry 0% exit 40%;
    }
    @keyframes device-pass {
      0%   { transform: translate3d(0, 72px, 0) scale(.94); }
      36%  { transform: translate3d(0,  0,   0) scale(1); }
      100% { transform: translate3d(0, -34px, 0) scale(1); }
    }

    /* Copy trails the device in rather than landing with it. */
    .walk__copy {
      animation: copy-drift linear both;
      animation-timeline: view();
      animation-range: entry 10% cover 34%;
    }
    @keyframes copy-drift {
      from { transform: translate3d(0, 26px, 0); }
      to   { transform: none; }
    }
  }
}
