/** Shopify CDN: Minification failed

Line 1716:0 Unexpected "255"
Line 1716:51 Unterminated string token
Line 1717:51 Unterminated string token
Line 1718:49 Unterminated string token

**/
/* ============================================================
   Benchmark Golf — PDP styles ported from the static site
   (base.css primitives scoped to .bm-pdp + product.css)
   Figma: Golf Daddy 34516-90746 (desktop) / 34516-35407 (mobile)
   ============================================================ */

:root {
  --ink: #0f1010;
  --ink-deep: #090a0b;
  --dark: #121415;
  --dark-2: #1a1d1f;
  --paper: #ffffff;
  --surface: #f4f3f1;
  --surface-2: #eae7e3;
  --chip: #eeece8;
  --muted: #6d6a67;
  --muted-dark: #b6b6b6;
  /* figma tokens: Colors/Gray, Colors/Main Grey, buy-button blue */
  --gray: #6d6d6d;
  --surface-cool: #f3f3f4;
  --blue-cta: #1284b9;
  --line: #e6e3de;
  --line-card: #e3dfd9;
  --blue: #0084bd;
  --blue-tint: rgba(0, 132, 189, 0.12);
  --yellow: #ffc32c;
  --green: #42ac29;
  --green-deep: #0f794a;
  --red: #e16464;
  --grad-a: #24b5f4;
  --grad-b: #62d947;
  --scrim: rgba(9, 10, 11, 0.4);

  --font: 'Manrope', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --text-display: clamp(44px, 30.4px + 4.6vw, 80px);
  --text-statement: clamp(40px, 20.8px + 6.4vw, 108px);
  --text-h1: clamp(32px, 26.56px + 1.5vw, 44px);
  --text-h2: clamp(26.4px, 22.4px + 1.1vw, 36px);
  --text-h5: clamp(20px, 18.56px + 0.4vw, 24px);
  --text-sub: clamp(17px, 16px + 0.35vw, 20px);
  --text-body-lg: 18px;
  --text-body: 16px;
  --text-sm: 14px;
  --text-xs: 12px;

  --header-h: 64px;
  --container: 1360px;
  --pad-x: clamp(16px, 4vw, 48px);
  --section-y: clamp(72px, 5vw + 44px, 128px);

  --r-sm: 6px;
  --r-md: 10px;
  --r-lg: 16px;
  --r-xl: 24px;
  --r-sheet: 28px;
  --r-pill: 999px;

  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-inout: cubic-bezier(0.6, 0, 0.2, 1);
  --dur-1: 0.3s;
  --dur-2: 0.6s;
  --dur-3: 1s;

  --shadow-header: 0 12px 27px rgba(0, 0, 0, 0.08);
  --shadow-pill: 0 12px 32px rgba(9, 10, 11, 0.14);
  --shadow-card: 0 24px 64px rgba(9, 10, 11, 0.1);
  --shadow-drawer: 0 24px 80px rgba(9, 10, 11, 0.25);
}

/* the page gutter is figma's 200px at the 1920 design width and scales with the
   window from there — 10.42vw is 200/1920. Redefining --bm-gutter (its shipped
   value holds a flat 200 all the way down to 1472) keeps the FAQ, the CTA and
   the footer on the same line as the sections above them at every width.
   This file only loads on the benchmark PDP templates. */
@media screen and (min-width: 750px) {
  /* html:root, not :root — benchmark-tokens.css loads after this file */
  html:root { --bm-gutter: clamp(16px, 10.42vw, 200px); }
}

@media (min-width: 990px) {
  :root {
    --header-h: 78px;
    /* one gutter for the whole page */
    --pad-x: var(--bm-gutter);
  }
}

/* ---------- Scoped reset (the static site had a global reset) ---------- */
.bm-pdp {
  font-family: var(--font);
  font-size: var(--text-body);
  line-height: 1.5;
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

.bm-pdp :where(*, *::before, *::after) { box-sizing: border-box; }
.bm-pdp :where(h1, h2, h3, h4, h5, h6, p, figure, ul, ol, address) { margin: 0; padding: 0; }
.bm-pdp :where(ul, ol) { list-style: none; }
.bm-pdp :where(h1, h2, h3, h4, h5, h6) { font-family: inherit; color: inherit; line-height: inherit; word-break: normal; }
.bm-pdp :where(img, svg, video) { display: block; max-width: 100%; }
.bm-pdp :where(img) { height: auto; }
.bm-pdp :where(a) { color: inherit; text-decoration: none; }
.bm-pdp :where(button) {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  cursor: pointer;
}
.bm-pdp :where(s) { text-decoration: line-through; }
.bm-pdp :focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 3px;
  border-radius: 4px;
}

/* ---------- Layout helpers ---------- */
:where(.bm-pdp) .bm-container {
  max-width: calc(var(--container) + var(--pad-x) * 2);
  margin-inline: auto;
  padding-inline: var(--pad-x);
}

/* figma runs its content sections on a 1520px band (x=200 at the 1920 frame),
   sections on the narrower default sit inside it */
:where(.bm-pdp) .bm-container--wide { max-width: calc(1520px + var(--pad-x) * 2); }

/* on desktop the 200px gutter is the band: at 1920 that leaves figma's 1520
   exactly, and the content follows the gutter down so every section shares one
   edge. past 1920 the gutter is pinned at 200 and the band would keep growing
   with the window (a 4k/1x monitor blew the gallery to ~2170px wide while the
   type stayed put), so the band itself caps at the figma frame and centres. */
@media (min-width: 990px) {
  :where(.bm-pdp) .bm-container,
  :where(.bm-pdp) .bm-container--wide { max-width: calc(1520px + var(--pad-x) * 2); }
  :where(.bm-pdp) .rail { padding-inline: var(--pad-x); }
}

:where(.bm-pdp) .bm-section { padding-block: var(--section-y); }
:where(.bm-pdp) .bm-section--flush-top { padding-top: 0; }

:where(.bm-pdp) .section-head {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  text-align: center;
  margin-bottom: clamp(32px, 4vw, 56px);
}

/* ---------- Typography ---------- */
:where(.bm-pdp) .bm-h1 {
  font-family: var(--font);
  font-size: var(--text-h1);
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -0.02em;
  color: inherit;
}

:where(.bm-pdp) .bm-h5 {
  font-family: var(--font);
  font-size: var(--text-h5);
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: -0.01em;
}

:where(.bm-pdp) .bm-sub {
  font-size: var(--text-body);
  font-weight: 400;
  line-height: 1.5;
}

/* figma runs section subs at Colors/Black, not the grey this class implies */
:where(.bm-pdp) .bm-sub--muted { color: var(--ink); }

:where(.bm-pdp) .bm-eyebrow {
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--blue);
}

/* ---------- Buttons ---------- */
:where(.bm-pdp) .bm-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  height: 54px;
  padding-inline: 32px;
  border-radius: var(--r-pill);
  font-size: var(--text-body);
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
  transition:
    background-color var(--dur-1) var(--ease-out),
    color var(--dur-1) var(--ease-out),
    transform var(--dur-1) var(--ease-out),
    box-shadow var(--dur-1) var(--ease-out);
  will-change: transform;
}

:where(.bm-pdp) .bm-btn:hover { transform: translateY(-2px); }
:where(.bm-pdp) .bm-btn:active { transform: translateY(0) scale(0.97); transition-duration: 0.1s; }

:where(.bm-pdp) .bm-btn--dark { background: var(--ink); color: var(--paper); }
:where(.bm-pdp) .bm-btn--dark:hover { background: var(--ink-deep); box-shadow: var(--shadow-pill); }

:where(.bm-pdp) .bm-btn--outline {
  background: transparent;
  color: var(--ink);
  box-shadow: inset 0 0 0 1px var(--ink);
}
:where(.bm-pdp) .bm-btn--outline:hover { background: var(--ink); color: var(--paper); }

/* Add to Cart (buy box, both sticky bars, the upsell modal upgrade, the
   Launch Bundle CTAs and the pad PDP all paint from here). The base layer IS
   the action pill (design.md) since the GAH-BLUE-01 rollout, so a page that
   loads this file without benchmark-action-button.css still renders the
   winner. The colour stays in background-color and the crown rides in
   background-image, so :hover and :active can recolour with background-color
   and leave the gloss in place; a `background:` shorthand anywhere below
   would silently flatten it. */
:where(.bm-pdp) .bm-btn--buy {
  width: 100%;
  height: 54px;
  gap: 12px;
  border-radius: 999px;
  background-color: #0a78d4;
  background-image: linear-gradient(180deg, rgba(255, 255, 255, 0.38) 0, rgba(255, 255, 255, 0.38) 1px, rgba(255, 255, 255, 0) 1px);
  box-shadow: 0 1px 1px 0 rgba(20, 22, 27, 0.16);
  color: var(--paper);
  border: 0;
  font-weight: 700;
}
/* pressed: the face holds; bm-abtn owns the 0.97 press scale */
:where(.bm-pdp) .bm-btn--buy:active { background-color: #0a78d4; }
/* the lift + shadow used to stick after a tap on iPhone, which is 80% of the
   traffic; keep them for pointers that can actually hover */
@media (-moz-touch-enabled: 0), (hover: hover), (pointer: fine) {
  :where(.bm-pdp) .bm-btn--buy:hover {
    background-color: color-mix(in srgb, #0a78d4 94%, black);
    transform: translateY(-1px);
    box-shadow: 0 1px 1px 0 rgba(20, 22, 27, 0.16);
  }
}
:where(.bm-pdp) .bm-btn--buy[disabled] { opacity: 0.7; pointer-events: none; }

:where(.bm-pdp) .bm-btn--sm { height: 46px; padding-inline: 24px; }

/* ---------- Badges ---------- */
:where(.bm-pdp) .bm-badge {
  display: inline-flex;
  align-items: center;
  padding: 4px 8px;
  border: 0;
  border-radius: 4px;
  font-size: var(--text-sm);
  font-weight: 600;
  line-height: 1.4;
  white-space: nowrap;
}

:where(.bm-pdp) .bm-badge--yellow { background: var(--yellow); color: var(--ink); }
:where(.bm-pdp) .bm-badge--green { background: #ade7a6; color: var(--ink); }

/* ---------- Rails ---------- */
:where(.bm-pdp) .rail-wrap { position: relative; }

:where(.bm-pdp) .rail {
  display: flex;
  gap: clamp(12px, 1.5vw, 24px);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  overscroll-behavior-x: contain;
  padding-inline: max(var(--pad-x), calc((100vw - var(--container)) / 2));
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}

:where(.bm-pdp) .rail::-webkit-scrollbar { display: none; }
:where(.bm-pdp) .rail > * { flex: none; scroll-snap-align: center; }

:where(.bm-pdp) .rail.is-dragging { scroll-snap-type: none; cursor: grabbing; user-select: none; }

:where(.bm-pdp) .rail-nav {
  position: absolute;
  top: 50%;
  translate: 0 -50%;
  z-index: 2;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: var(--paper);
  box-shadow: var(--shadow-pill);
  display: none;
  align-items: center;
  justify-content: center;
  transition: transform var(--dur-1) var(--ease-out), opacity var(--dur-1);
}
:where(.bm-pdp) .rail-nav:hover { transform: scale(1.08); }
:where(.bm-pdp) .rail-nav[disabled] { opacity: 0; pointer-events: none; }
:where(.bm-pdp) .rail-nav--prev { left: 24px; }
:where(.bm-pdp) .rail-nav--next { right: 24px; }

@media (min-width: 990px) and (hover: hover) {
  .bm-pdp .rail-nav { display: inline-flex; }
}

/* Reveal variants the shared benchmark-reveal.css does not ship */
:where(.bm-pdp) [data-reveal='left'].pre-reveal:not(.in-view) { transform: translateX(-36px); }
:where(.bm-pdp) [data-reveal='right'].pre-reveal:not(.in-view) { transform: translateX(36px); }

/* ---------- Accordion primitive ---------- */
:where(.bm-pdp) .acc-item { border-bottom: 1px solid var(--line); }

:where(.bm-pdp) .acc-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  width: 100%;
  padding-block: 22px;
  text-align: left;
  font-size: clamp(18px, 16px + 0.7vw, 24px);
  font-weight: 600;
  letter-spacing: -0.01em;
}

:where(.bm-pdp) .acc-icon {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 8px;
  background: var(--chip);
  transition: background-color var(--dur-1);
}

:where(.bm-pdp) .acc-icon svg { transition: transform 0.45s var(--ease-out); }
:where(.bm-pdp) .acc-icon .v-bar { transform-origin: center; transition: transform 0.45s var(--ease-out), opacity 0.3s; }

:where(.bm-pdp) .acc-item.open .acc-icon .v-bar { transform: scaleY(0); opacity: 0; }
:where(.bm-pdp) .acc-item.open .acc-icon svg { transform: rotate(90deg); }

:where(.bm-pdp) .acc-panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.5s var(--ease-out);
}

:where(.bm-pdp) .acc-panel > div {
  overflow: hidden;
  visibility: hidden;
  transition: visibility 0s linear 0.5s;
}

:where(.bm-pdp) .acc-item.open .acc-panel { grid-template-rows: 1fr; }
:where(.bm-pdp) .acc-item.open .acc-panel > div { visibility: visible; transition: visibility 0s; }

:where(.bm-pdp) .acc-body {
  padding-bottom: 24px;
  max-width: 70ch;
  color: var(--ink);
  font-size: var(--text-body-lg);
  line-height: 1.55;
  opacity: 0;
  translate: 0 6px;
  transition: opacity 0.4s var(--ease-out) 0.1s, translate 0.4s var(--ease-out) 0.1s;
}

:where(.bm-pdp) .acc-item.open .acc-body { opacity: 1; translate: 0 0; }

/* ---------- Toast (element is appended to body, outside .bm-pdp) ---------- */
.bm-toast {
  position: fixed;
  left: 50%;
  bottom: calc(24px + env(safe-area-inset-bottom));
  translate: -50% 16px;
  /* above the cart drawer (1000) and the Founding Members modal (60) — at 200 the
     add-to-cart error was painted behind the open drawer and never seen */
  z-index: 1100;
  padding: 14px 24px;
  border-radius: var(--r-pill);
  background: var(--ink-deep);
  color: var(--paper);
  font-family: var(--font);
  font-size: var(--text-sm);
  font-weight: 600;
  box-shadow: var(--shadow-drawer);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur-1) var(--ease-out), translate var(--dur-1) var(--ease-out);
}

.bm-toast.show { opacity: 1; translate: -50% 0; }

/* ============================================================
   Benchmark Golf — product.css
   ============================================================ */

/* ---------- Timer bar ---------- */

/* ---------- PDP layout ---------- */
.pdp {
  display: grid;
  gap: clamp(24px, 4vw, 64px);
  padding-block: clamp(16px, 3vw, 48px) var(--section-y);
  grid-template-columns: minmax(0, 1fr);
}

@media (min-width: 990px) {
  .pdp {
    /* figma 1920 frame (34618:49531): 940px gallery, 520px buy box. the fr
       shares add up to 1460, so on the 1520 band the 200px gutter leaves they
       resolve to exactly 940 and 520 with a 60px gutter between them (figma
       draws 64 on its 1524 band — the 4px goes to the page edges instead).
       35px top gap is figma's, measured from the sale bar (which ends at 110).
       no max-width override here: the hero follows .bm-container's 1520-band
       cap so a 4k/1x window centres it instead of scaling it up forever */
    grid-template-columns: minmax(0, 940fr) minmax(380px, 520fr);
    gap: 60px;
    padding-block-start: 35px;
    /* keep the gallery its natural height so it can stick while the buy column scrolls */
    align-items: start;
  }
}

/* Gallery */
.pdp-gallery {
  display: grid;
  gap: 16px;
  grid-template-columns: 1fr;
  align-items: start;
}

@media (min-width: 990px) {
  .pdp-gallery {
    grid-template-columns: 1fr;
    gap: 24px;
    position: sticky;
    /* clear the sticky sale bar too, with breathing room */
    top: calc(var(--header-h) + 76px);
  }
  /* wide stage on top, thumbnail row centered beneath (per design) */
  .pdp-stage { order: 1; }
  .pdp-thumbs { order: 2; }
}

.pdp-thumbs {
  display: none;
  flex-direction: row;
  justify-content: center;
  gap: 8px;
}

@media (min-width: 990px) { .pdp-thumbs { display: flex; } }

/* figma 34516:92318: 64px tile, 4px radius, Colors/Main Grey plate, 1px
   Colors/Black ring on the active one */
.pdp-thumb {
  width: 64px;
  height: 64px;
  /* kill the UA button padding: it shrank the img box to 52x62, so cover
     side-cropped the square thumb art */
  padding: 0;
  border-radius: 4px;
  overflow: clip;
  background: var(--surface-cool);
  outline-offset: -1px;
  border: 1px solid transparent;
  transition: border-color var(--dur-1), transform 0.3s var(--ease-out);
}

.pdp-thumb:hover { transform: translateY(-2px); }
.pdp-thumb.is-active { border-color: var(--ink); }

.pdp-thumb img { width: 100%; height: 100%; object-fit: cover; }

.pdp-stage { position: relative; }

.pdp-rail {
  padding-inline: 0;
  border-radius: var(--r-md);
  scroll-snap-type: x mandatory;
}

/* the mobile art direction wraps each slide in a <picture>; display: contents keeps
   the img itself as the rail's flex item so every rule below still applies */
.pdp-rail > picture { display: contents; }
.pdp-rail > picture > img { flex: none; scroll-snap-align: center; }

/* Paul (Aug 24): the hero slide is a video and has to lay out byte-identical
   to an image slide, or the rail's snap points and the scroll-to-slide maths
   drift. object-fit + the same aspect ratio do that; the mobile override below
   swaps it to 1:1 alongside the images. */
.pdp-rail video.pdp-hero-video {
  flex: none;
  scroll-snap-align: center;
  width: 100%;
  /* height:auto is required, not cosmetic: the width/height ATTRIBUTES on the
     <video> give it an intrinsic 1080px height, and aspect-ratio is ignored
     unless one axis is auto. Without this the slide renders 366x1080. */
  height: auto;
  aspect-ratio: 940 / 680;
  object-fit: cover;
  border-radius: var(--r-md);
  background: var(--surface);
  display: block;
}

.pdp-rail img {
  width: 100%;
  /* the desktop exports are 1600x1157, close enough to this box that nothing
     meaningful crops; mobile swaps in square sources and overrides the ratio */
  aspect-ratio: 940 / 680;
  object-fit: cover;
  border-radius: var(--r-md);
  background: var(--surface);
}

/* the overhead slide is a <figure> so the footprint overlay has a box to sit on.
   the figure is the flex slide (the shared .rail > * rule gives it snap and
   flex: none); the img inside keeps every .pdp-rail img rule above (ratio, cover,
   radius, mobile square) and sizes the figure, and the svg mirrors object-fit:
   cover with xMidYMid slice so its traced quad stays on the photo's white dashes
   however the box is cropped */
.pdp-rail > .pdp-floor {
  position: relative;
  width: 100%;
  margin: 0;
}
.pdp-floor > picture { display: contents; }
.pdp-floor__svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
/* one svg per export, on the same line as the <source> art direction */
.pdp-floor__svg--mobile { display: none; }
@media (max-width: 989.98px) {
  .pdp-floor__svg--desktop { display: none; }
  .pdp-floor__svg--mobile { display: block; }
}
.pdp-floor__fill { fill: var(--blue); fill-opacity: 0.16; opacity: 0; }
.pdp-floor__tape {
  fill: none;
  stroke: var(--blue);
  stroke-linejoin: round;
  stroke-linecap: round;
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
}
/* the tick path is pathLength 49, so one dash period is one unit and the same
   dasharray gives both exports the same ~49 ticks round the footprint */
.pdp-floor__tick {
  fill: none;
  stroke: #fff;
  stroke-opacity: 0.85;
  stroke-linecap: round;
  stroke-dasharray: 0.42 0.58;
  opacity: 0;
}
/* one 4s cycle, ported from the how-it-works page: the tape traces round the
   footprint (0-40%) and hides the photo's own dashes, ticks march along it while
   it holds (40-84%), everything fades (84-94%) and the cycle restarts. only runs
   while the slide is on screen (benchmark-pdp.js toggles .is-tracing) */
.is-tracing .pdp-floor__tape { animation: pdp-floor-draw 4s cubic-bezier(0.22, 1, 0.36, 1) infinite; }
.is-tracing .pdp-floor__fill { animation: pdp-floor-fill 4s ease-in-out infinite; }
.is-tracing .pdp-floor__tick { animation: pdp-floor-march 1.4s linear infinite, pdp-floor-tick 4s linear infinite; }
@keyframes pdp-floor-draw {
  0% { stroke-dashoffset: 1; opacity: 1; }
  40%, 84% { stroke-dashoffset: 0; opacity: 1; }
  94%, 100% { stroke-dashoffset: 0; opacity: 0; }
}
@keyframes pdp-floor-fill {
  0% { opacity: 0; }
  40%, 84% { opacity: 1; }
  94%, 100% { opacity: 0; }
}
@keyframes pdp-floor-tick {
  0%, 38% { opacity: 0; }
  46%, 84% { opacity: 1; }
  94%, 100% { opacity: 0; }
}
@keyframes pdp-floor-march { to { stroke-dashoffset: -1; } }
/* without JS nothing adds .is-tracing, so show the settled footprint instead */
.no-js .pdp-floor__tape { stroke-dashoffset: 0; }
.no-js .pdp-floor__fill,
.no-js .pdp-floor__tick { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .is-tracing .pdp-floor__tape,
  .is-tracing .pdp-floor__fill,
  .is-tracing .pdp-floor__tick { animation: none; }
  .pdp-floor__tape { stroke-dashoffset: 0; }
  .pdp-floor__fill,
  .pdp-floor__tick { opacity: 1; }
}

/* desktop stage: figma 940x680 (34516:92316), 16px radius, 48px arrows sat
   32px in from the left edge and 30px from the right, centred on y=334 */
@media (min-width: 990px) {
  .pdp-rail { gap: 24px; }
  /* figma's 940x680 stage: a 1:1 square at the ~840px column the 1360+ band
     resolves blew past the fold and buried the thumbs. the v4 exports are
     1600x1157 (same 1.38 ratio) so cover loses nothing; max-height caps
     runaway growth on >1920 monitors where the band keeps widening */
  .pdp-rail img { border-radius: 16px; aspect-ratio: 940 / 680; max-height: 680px; }
  .pdp-stage .rail-nav { top: 49.12%; box-shadow: none; color: var(--gray); }
  .pdp-stage .rail-nav--prev { left: 32px; }
  .pdp-stage .rail-nav--next { right: 30px; }

  /* the stage fills its 940px column: sizing it off the fold (100svh) made the
     gallery shrink and re-centre on every window resize and browser zoom.
     min-width: 0 keeps the grid's auto minimum from letting the slide's
     intrinsic width push the stage out over the buy box on narrow desktops */
  .pdp-stage,
  .pdp-gallery,
  .pdp-rail { min-width: 0; }
  /* the six 64px thumbs measure 424 wide; without this the gallery's 1fr column
     sizes to that instead of its share and the stage rides over the buy box on
     narrow desktops. below ~1230 they wrap onto a second row instead. */
  .pdp-thumbs { min-width: 0; flex-wrap: wrap; }
  .pdp-stage { max-width: none; margin-inline: 0; }
}

/* mobile: full-bleed gallery, 1:1 square slides — the <picture> in the section
   swaps in the square exports here, so nothing gets cropped */
@media (max-width: 989.98px) {
  /* Paul (Aug 24): the gallery is an inset card, not a full bleed. Rounding
     all four corners only works once the photo has a gutter to curve against
     - bled to the screen edge the same radius just shaves slivers off the
     corners and reads as a fault. This also moves the page toward its actual
     category peers: Amazon, Nike, IKEA, Away and Peloton all inset a hardgood
     on a padded card, while full-bleed is the apparel/beauty DTC pattern.
     A small top gap lets the top corners breathe like the bottom two do.
     overflow:hidden sits on the stage (not the img) so the bottom scrim
     clips to the same curve instead of squaring off the corners. */
  .pdp { padding-top: 10px; }
  .pdp-gallery { margin-inline: 0; }
  .pdp-stage { border-radius: 16px; overflow: hidden; }
  .pdp-rail, .pdp-rail img, .pdp-rail video.pdp-hero-video { border-radius: 0; }
  /* the 12px inter-slide gap is inherited from the shared .rail component,
     where it exists so a neighbouring card can peek. Here the slide is exactly
     the stage width, so it never peeks - the gap only ever showed as a white
     strip sliding between two photos mid-swipe. Zero on mobile; desktop keeps
     its own 24px, where the slides are inset cards and the gap is the design. */
  .pdp-rail { gap: 0; }
  /* figma runs the mobile stage as a 375x375 square (34812:95137), not the
     desktop 940/680 crop */
  .pdp-rail img, .pdp-rail video.pdp-hero-video { aspect-ratio: 1; }


  /* mobile rhythm from the figma mobile frame (34812:95113): the buy box opens
     16px under the stage (34812:95149), the bento band runs 16/16 (34812:99668,
     not the 40 the shared section token gives it), Play at Home breaks 24px
     between its head and its cards (34812:99826) and the cards are the band. */
  .section-benchmark-pdp-main .pdp { gap: 16px; }
  .bento { padding-block: 16px; }
  .tiles .section-head { margin-bottom: 24px; }
}

/* the rail's 8/16 scroll padding is chrome from the shared component; figma has
   the cards sitting on the band edge at both breakpoints */
.tiles .rail { padding-block: 0; }

.pdp-dots {
  position: absolute;
  left: 50%;
  bottom: 14px;
  translate: -50%;
  display: flex;
  align-items: center;
  gap: 6px;
}

@media (min-width: 990px) { .pdp-dots { display: none; } }

/* Paul (Aug 24): the white-room swing was the seventh slide and mobile-only;
   it is now the hero shot, so all seven run at every breakpoint and the
   desktop-drops-the-seventh rule is gone. The clone rule stays: the JS mobile
   wrap appends clones that desktop must not show, since desktop wraps via the
   arrows instead. */
@media (min-width: 990px) {
  .pdp-rail > [data-gallery-clone] {
    display: none;
  }
}

.pdp-dots span {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: rgba(15, 16, 16, 0.35);
  border: 1px solid rgba(255, 255, 255, 0.6);
  transition: transform 0.3s var(--ease-out), background-color var(--dur-1);
}

.pdp-dots span.is-active {
  width: 8px;
  height: 8px;
  background: var(--paper);
}

/* ---------- Buy box ---------- */
.buybox {
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding-inline: 0;
}

.bb-title {
  font-size: clamp(32px, 25.6px + 1.6vw, 36px);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.3;
}

/* figma 34812:114466 stacks the buy column on a flat 20px rhythm, with two
   exceptions: 12px between the title and its rating row, and 16px between the
   Add to Cart button and the delivery line. the column itself starts 40px
   below the gallery top */
@media (min-width: 990px) {
  .buybox { gap: 20px; padding-top: 40px; }
  .bb-title { font-size: 36px; letter-spacing: 0; }
  .bb-rating { margin-top: -8px; }
  .bb-getit { margin-top: -4px; }
}

/* Paul (Aug 23): mobile follows the same stack as desktop — title, rating on
   its own row, price row, bullets. The old grid that parked the rating on the
   price row is gone. */
@media (max-width: 989.98px) {
  .buybox > * { min-width: 0; }
}

/* the rating is an anchor down to #reviews; keep it reading as plain text */
.bb-rating {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  color: inherit;
  text-decoration: none;
}

/* #reviews target: land the heading clear of the sticky header + sale bar,
   and glide there instead of jumping (stylesheet is PDP-only) */
html { scroll-behavior: smooth; }
.jm-reviews-anchor { display: block; scroll-margin-top: calc(var(--header-h, 64px) + 90px); }

.bb-reviews-link {
  font-weight: 500;
  text-underline-offset: 3px;
}
.bb-reviews-link:hover { text-decoration: underline; text-decoration-color: var(--ink); }

.bb-price {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}

/* figma 34590:23503 — Manrope/H5, 24/1.3, no tracking. the inherited 1.5 body
   line-height was making the row 36px tall instead of 31 */
.bb-price strong {
  font-size: 24px;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: 0;
}

.bb-price s { color: var(--gray); font-size: var(--text-body); }

/* figma 34588:68809: four 24px rows on a 36px pitch, so 12px between them */
.bb-bullets {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.bb-bullets li {
  position: relative;
  padding-left: 30px;
  line-height: 1.5;
  /* two of the four bullets wrapped with a lone last word at 390 */
  text-wrap: balance;
}

/* Paul (Aug 23, screenshot): checkmarks, not dots, at every width. Inline SVG
   in the ink colour; 18px glyph centred on the 24px line box. */
.bb-bullets li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 3px;
  width: 18px;
  height: 18px;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230f1010' stroke-width='2.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E") center / contain no-repeat;
}

@media (min-width: 990px) {
  .bb-bullets li::before {
    top: 3px;
  }
}

/* ---------- Social proof strip ---------- */

/* ---------- The Ultimate Summer Bundle ---------- */

.bc-price { font-weight: 700; white-space: nowrap; }
.bc-price s { color: var(--muted); font-weight: 400; margin-right: 4px; }

.bc-total {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  padding-top: 2px;
}

.bc-total strong { font-size: 24px; font-weight: 700; letter-spacing: -0.02em; }
.bc-total s { color: var(--muted); }

/* Membership offer — dark, hi-tech (8Sleep-grade) */

/* iridescent aura along the top edge */

@keyframes orbPulse {
  0%, 100% { box-shadow: 0 0 10px rgba(47, 134, 255, 0.5); }
  50% { box-shadow: 0 0 22px rgba(47, 134, 255, 0.95); }
}

/* Mini accordion in buy box (figma 34588:68896): 480px wide inside the 520px
   column, 24px rows with 16px above and below each rule */
/* 24px above comes from the .buybox column gap, not a margin here */
.bb-acc { padding-inline: 20px; }
.bb-acc .acc-item { border-bottom-color: #e5e6ed; }
.bb-acc .acc-item:last-child { border-bottom: 0; }
.bb-acc .acc-trigger { gap: 12px; font-size: var(--text-body); line-height: 1.5; letter-spacing: 0; padding-block: 16px; }
.bb-acc .acc-item:first-child .acc-trigger { padding-top: 0; }
.bb-acc .acc-item:last-child:not(.open) .acc-trigger { padding-bottom: 0; }
.bb-acc .acc-icon { width: 24px; height: 24px; background: transparent; }
.bb-acc .acc-item.open .acc-icon svg { transform: rotate(180deg); }
.bb-acc .acc-body { font-size: var(--text-body); padding-bottom: 18px; }

/* ---------- Sticky mobile ATC ---------- */
/* one full-width labeled button on a flat white bar (Paul, Aug 23). the old
   gradient band + price card is gone: 126pt of chrome down to 76, no scrim
   over the content being read, and the control is the same button the buy
   box shows so there is nothing new to decode */
.sticky-atc {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 60;
  /* env() resolves to 0 without viewport-fit=cover, so max() keeps the 12px
     floor either way */
  /* Paul (Aug 24): this was a sectioned-off white panel with a hard rule across
     the top. It is a gradient blur now - the page keeps running underneath and
     softens into the bar instead of stopping at a line. The tint is a gradient
     so the button sits on solid paper while the top edge dissolves; the blur
     rides a masked ::before so the frost fades on the same ramp rather than
     cutting off square. Extra top padding is the room that fade needs. */
  /* Paul (Sep 7): the pill sat flush to the screen edge and its corners once
     the iOS toolbar collapsed, because the 12px floor is all that remains when
     env() reports 0. The floor is now 22px and the safe area is ADDED to it
     rather than swapped for it, so the button keeps a real margin on every
     device, with and without a home indicator. Side gutters widen to 20px so
     the capsule's corners clear the screen corners too. */
  padding: 26px 20px calc(22px + env(safe-area-inset-bottom, 0px));
  background: linear-gradient(
    to top,
    var(--paper) 0%,
    var(--paper) 58%,
    rgba(255, 255, 255, 0.86) 78%,
    rgba(255, 255, 255, 0) 100%
  );
  border-top: 0;
  box-shadow: none;
  transform: translateY(100%);
  visibility: hidden;
  transition: transform 0.24s var(--ease-out), visibility 0s linear 0.24s;
}

/* bleed past the layout-viewport edge: while the iOS toolbar collapses or
   expands, the visual viewport extends below the fixed bar and would show a
   strip of raw page under the bar's hard end */
/* the frost itself, faded on the same ramp as the tint above. Masked so the
   blur stops where the gradient does - an unmasked backdrop-filter would frost
   a hard-edged rectangle, which is the sectioned-off look this replaces.
   Sits behind the bar's own content; Safari needs the -webkit- prefixes. */
.sticky-atc::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  -webkit-mask-image: linear-gradient(to top, #000 0%, #000 58%, rgba(0, 0, 0, 0.55) 78%, transparent 100%);
  mask-image: linear-gradient(to top, #000 0%, #000 58%, rgba(0, 0, 0, 0.55) 78%, transparent 100%);
}

.sticky-atc::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: 100%;
  height: 80px;
  background: var(--paper);
}

.sticky-atc.show {
  transform: translateY(0);
  visibility: visible;
  transition: transform 0.24s var(--ease-out), visibility 0s;
}

@media (prefers-reduced-motion: reduce) {
  .sticky-atc {
    transform: none;
    transition: opacity 0.12s, visibility 0s linear 0.12s;
    opacity: 0;
  }
  .sticky-atc.show {
    opacity: 1;
    transition: opacity 0.12s, visibility 0s;
  }
}

/* background-color, not the shorthand: the shorthand would drop the buy
   button's gradient while the thumb is down */
.sticky-atc__solo:active { background-color: #0f76a6; }

@media (min-width: 990px) { .sticky-atc { display: none; } }

/* ---------- Sticky desktop bar ---------- */
.sticky-bar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 60;
  display: none;
  align-items: center;
  gap: 20px;
  /* same gutter as the page above it */
  padding: 8px max(24px, var(--pad-x));
  background: var(--paper);
  border-top: 1px solid var(--line-card);
  box-shadow: 0 -6px 18px rgba(15, 16, 16, 0.08);
  transform: translateY(110%);
  visibility: hidden;
  transition: transform 0.5s var(--ease-out), visibility 0s linear 0.5s;
}

.sticky-bar.show {
  transform: translateY(0);
  visibility: visible;
  transition: transform 0.5s var(--ease-out), visibility 0s;
}

@media (min-width: 990px) { .sticky-bar { display: flex; } }

.sticky-bar .sb-thumb {
  width: 56px;
  height: 56px;
  border-radius: var(--r-sm);
  object-fit: cover;
  background: var(--surface);
}

.sticky-bar .sb-info { display: flex; flex-direction: column; gap: 3px; }
.sticky-bar .sb-info b { font-size: var(--text-body-lg); font-weight: 600; letter-spacing: -0.01em; }
.sticky-bar .sb-stars {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: var(--text-xs);
  color: var(--muted);
  font-weight: 500;
}

.sticky-bar .sb-price {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-left: auto;
}

.sticky-bar .sb-price strong { font-size: 20px; font-weight: 700; }
.sticky-bar .sb-price s { color: var(--muted); font-size: var(--text-sm); }

.sticky-bar .sb-delivery { font-size: var(--text-xs); color: var(--muted); }

.sticky-bar .sb-cta { width: auto; padding-inline: 28px; height: 50px; }

/* ---------- Bento ---------- */
.bento { background: var(--paper); }

.bento-grid {
  display: grid;
  gap: 12px;
  grid-template-columns: 1fr;
}

.bento-grid > * { min-width: 0; }

/* the tripod/mat/app tiles wrap their img in a <picture> to swap in the figma
   artwork on mobile. contents keeps the img as the flex item it was, so the
   layout rules that size these photos are unaffected at every breakpoint.
   contents also promotes <source> into the flex row, where it eats a gap even
   though it paints nothing — hence the explicit none */
.bento-grid picture { display: contents; }
.bento-grid picture > source { display: none; }

@media (min-width: 990px) {
  /* figma — 750 / 227 / 515 columns across the 1520px band */
  .bento-grid { grid-template-columns: 750fr 227fr 515fr; }
  .b-sim { grid-column: 1; grid-row: 1; }
  .b-tripod { grid-column: 2; grid-row: 1; }
  .b-pair--stack { grid-column: 3; grid-row: 1; }
  .b-pair--half { grid-column: 1; grid-row: 2; }
  .b-courses { grid-column: 2 / 4; grid-row: 2; }
  .b-ai-strip { grid-column: 1 / 4; }
}

.b-card {
  position: relative;
  border-radius: 4px;
  background: var(--surface-cool);
  overflow: clip;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 20px 16px;
  min-height: 170px;
}

/* live-site card heights */
@media (min-width: 990px) {
  .b-courses { min-height: 400px; }
  .b-tripod { min-height: 600px; }
  .b-side { min-height: 170px; }
  .b-space, .b-tv { min-height: 390px; }
}

.b-title {
  font-size: 20px;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: -0.01em;
  text-align: center;
}

.b-sub {
  color: var(--ink);
  font-size: var(--text-body);
  text-align: center;
  max-width: 34ch;
  margin-inline: auto;
}
/* "trust." sat alone on line two under Precise Golf Simulation (Ced, Aug 25) */
.b-sim .b-sub { text-wrap: balance; }

/* precise simulation hero */
.b-sim-video {
  display: block;
  width: 100%;
  margin-top: 8px;
  border-radius: var(--r-md);
  aspect-ratio: 16 / 9;
  object-fit: cover;
  flex: 1;
  min-height: 0;
}

/* tripod tall */
.b-tripod { padding-bottom: 0; }

.b-tripod img {
  margin: 12px auto 0;
  max-height: 470px;
  width: auto;
  object-fit: contain;
  object-position: bottom;
  flex: 1;
  min-height: 0;
}

@media (max-width: 989.98px) {
  .b-tripod img { max-height: 280px; }
}

/* pairs */
.b-pair { display: grid; gap: 12px; }
.b-pair--half { grid-template-columns: 1fr; }
.b-pair--stack { grid-template-rows: 1fr 1fr; }

@media (min-width: 750px) {
  .b-pair--half { grid-template-columns: 1fr 1fr; }
}

/* light cards with a device image at the side (live-site pattern) */
.b-side {
  flex-direction: row;
  align-items: center;
  gap: 12px;
  padding: 18px 0 18px 20px;
}

.b-side-text {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.b-side-text .b-title, .b-side-text .b-sub {
  text-align: left;
  margin-inline: 0;
}

.b-side img {
  width: 42%;
  max-height: 150px;
  object-fit: contain;
  object-position: right center;
  flex: none;
}

/* radar */

/* courses strip — figma holds it still; the desktop parity block below parks it
   at the offset figma uses, so no scroll animation */
.course-marquee {
  overflow: hidden;
  margin: 14px -16px -20px;
  flex: 1;
  display: flex;
  align-items: center;
}

.cm-track {
  display: flex;
  width: max-content;
}

.cm-track img {
  height: clamp(150px, 20vw, 260px);
  width: auto;
}

/* space & tv cards */
/* ---------- 7x7 play space: the footprint loop ----------
   Paul (Aug 24) asked for the how-it-works step-3 tape on this tile. It is the
   same loop the overhead gallery slide runs, so the tile shares that slide's
   pdp-floor__* parts and keyframes (line ~546) instead of shipping a second
   copy of them. The <figure class="b-floor"> takes the box the img used to
   hold so the pdp-floor__svg overlay has something to sit on, and the img
   fills it, so every .b-space sizing rule below now targets the figure. */
.b-space .b-floor {
  position: relative;
  margin: 0;
  min-width: 0;
}
.b-space .b-floor img {
  display: block;
  width: 100%;
  height: 100%;
  margin: 0;
  object-fit: cover;
}

.b-space img, .b-tv img {
  width: 100%;
  border-radius: 4px;
  margin-top: 10px;
  aspect-ratio: 4 / 3.4;
  object-fit: cover;
  flex: 1;
  min-height: 0;
}

/* AI strip */
.b-ai-strip {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  text-align: center;
  border-radius: var(--r-card, 12px);
  background: var(--surface);
  padding: 28px 24px;
}

@media (min-width: 750px) {
  .b-ai-strip { flex-direction: row; justify-content: space-between; text-align: left; padding-inline: 40px; }
}

.b-ai-strip p { color: var(--muted); font-size: var(--text-sm); margin-top: 4px; }

/* ---------- Play / Train / Improve tiles ---------- */
.tiles { overflow: clip; }

.tile-rail { padding-block: 8px 16px; }

/* desktop: a static grid that always fits — the swipe rail is mobile-only.
   the rail lives outside .bm-container (full-bleed for the mobile swipe), so
   it needs the same 1520-band cap or a 4k/1x window stretches the four tiles
   across the whole screen */
@media (min-width: 990px) {
  .tile-rail {
    display: grid;
    gap: 16px;
    overflow: visible;
    max-width: calc(1520px + var(--pad-x) * 2);
    margin-inline: auto;
  }
  
  .tile-rail--4 { grid-template-columns: repeat(4, 1fr); }
  .tile-rail .tile, .tile-rail .tile--sm { width: auto; }
  .tiles .rail-nav { display: none; }
}

.tile {
  position: relative;
  border-radius: var(--r-lg);
  overflow: clip;
  background: var(--surface-2);
  width: clamp(270px, 76vw, 410px);
  aspect-ratio: 410 / 470;
}

.tile--sm { width: clamp(240px, 64vw, 306px); aspect-ratio: 306 / 352; }

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

.tile::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, transparent 55%, rgba(9, 10, 11, 0.62));
}

.tile figcaption {
  position: absolute;
  z-index: 2;
  left: 20px;
  right: 20px;
  bottom: 18px;
  color: var(--paper);
  font-size: clamp(20px, 17.6px + 0.7vw, 24px);
  font-weight: 600;
  letter-spacing: -0.01em;
}

/* floating metric chip on train tiles */

/* ---------- FAQ ---------- */

/* ---------- Final CTA (shared look with home) ---------- */

/* ============================================================
   App-capability sections (Four modes, On the Course, Social)
   ============================================================ */

/* Image placeholder slot — shows a labeled hint until the real
   file (named in the label) is dropped into assets/img/app/ */

/* ---------- Four ways to play ---------- */

/* ---------- On the Course ---------- */
.course-sec { background: var(--ink); color: var(--paper); overflow: clip; }
.course-sec .bm-eyebrow { color: #e5b45b; }
.course-sec .section-head h2 { color: var(--paper); }
.course-sec .section-head .bm-sub { color: var(--muted-dark); }

.course-grid {
  display: grid;
  gap: 16px;
  grid-template-columns: 1fr;
  align-items: stretch;
}
@media (min-width: 900px) { .course-grid { grid-template-columns: 1.1fr 1fr; } }

.course-map {
  border-radius: var(--r-lg);
  aspect-ratio: 9 / 12;
  background: var(--dark-2);
}
@media (min-width: 900px) { .course-map { aspect-ratio: auto; min-height: 480px; } }

.course-feats { display: flex; flex-direction: column; gap: 12px; }

.course-feat {
  display: flex;
  gap: 16px;
  padding: 20px;
  border-radius: var(--r-lg);
  background: var(--dark-2);
}
.course-feat .cf-ico {
  flex: none;
  display: grid;
  place-items: center;
  width: 44px; height: 44px;
  border-radius: var(--r-md);
  background: rgba(229,180,91,0.14);
  color: #e5b45b;
}
.course-feat h4 { font-size: var(--text-body-lg); font-weight: 600; margin-bottom: 4px; }
.course-feat p { color: var(--muted-dark); font-size: var(--text-sm); line-height: 1.5; }

/* ---------- Share the game / Guest Pass ---------- */
.share-sec { background: var(--surface); overflow: clip; }

.share-grid {
  display: grid;
  gap: 16px;
  grid-template-columns: 1fr;
  align-items: center;
}
@media (min-width: 900px) { .share-grid { grid-template-columns: 1fr 1fr; } }

.share-text { display: flex; flex-direction: column; gap: 16px; }
/* the heading and the sub live in their own box so they can sit beside the
   phones on mobile; on desktop it just re-supplies the 16px rhythm
   .share-text used to give them directly */
.share-intro { display: flex; flex-direction: column; gap: 16px; }
.share-text .bm-sub { max-width: 44ch; }

.share-points { display: flex; flex-direction: column; gap: 14px; margin-top: 4px; }
.share-point { display: flex; gap: 12px; align-items: flex-start; }
.share-point svg { flex: none; margin-top: 2px; color: var(--blue); }
.share-point b { font-weight: 600; }
.share-point span { color: var(--muted); font-size: var(--text-sm); display: block; }

/* Guest Pass ticket (pure CSS, mirrors the in-app card) */

/* ============================================================
   Plan picker — Benchmark Unlimited (8Sleep-style selector)
   ============================================================ */

/* custom radio */

/* help accordion inside picker */

/* includes line under ATC */

/* ============================================================
   Enhance your setup — accessory quick-add cards (8Sleep-style)
   ============================================================ */

/* ---------- "What you get" included block ---------- */

/* ============================================================
   Mobile buy-box per updated Figma comp (34416:29260)
   ============================================================ */

/* soft combined badge "$299 (SAVE $180)" — mobile only */

@media (max-width: 989.98px) {
  /* order: title -> price -> rating -> ATC -> what-you-get -> the rest */
  .buybox > * { order: 20; }
  .buybox .bb-title { order: 1; }
  .buybox .bb-price { order: 2; }
  .buybox .bb-rating { order: 3; }
  .buybox .bm-btn--buy { order: 4; }
  
  
  
  
  
  
  .buybox .bb-acc { order: 11; }

  /* price badges: sale-magenta 60% OFF on mobile */
  
}

/* "What you get" — surface card, centered title, hairline rows */

/* the " reviews" word shows at every width now the rating has its own row
   (Paul, Aug 23) — the compact form existed to share a row with the delivery
   date, which no longer happens */

/* ============================================================
   Mobile buy-box v3 (Figma 34419:31633): dark bundle promo card
   ============================================================ */

/* soft badge now carries the sale magenta text (design v3) */

/* centered delivery line under the stock note (mobile pattern) */

/* trust line */

/* ---------- Dark bundle card ---------- */

.bd-items { display: flex; flex-direction: column; }

.bd-items li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding-block: 7px;
  font-size: var(--text-sm);
  font-weight: 600;
}

.bd-items .bd-name {
  position: relative;
  padding-left: 24px;
}

.bd-items .bd-name::before {
  content: "";
  position: absolute;
  left: 0;
  top: 50%;
  translate: 0 -50%;
  width: 15px;
  height: 15px;
  background: no-repeat center / contain
    url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%230f1010" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>');
}

.bd-items .bd-sub {
  justify-content: flex-start;
  padding: 2px 0 2px 24px;
  color: var(--muted);
  font-weight: 500;
}

.bd-note {
  text-align: center;
  color: var(--muted);
  font-size: var(--text-xs);
  line-height: 1.5;
}

/* ---------- Mobile order v3: rating under title, WYG before ATC ---------- */
@media (max-width: 989.98px) {
  .buybox .bb-title { order: 1; }
  .buybox .bb-rating { order: 2; }
  .buybox .bb-price { order: 3; }
  
  .buybox .bm-btn--buy { order: 5; }
  
  
  
  
  .buybox .bb-acc { order: 11; }

  /* the bundle carries Unlimited on mobile — hide the standalone picker */
  
}

/* v3.1 refinements per updated PDF comp */

.bd-info { vertical-align: -2px; margin-left: 2px; }

/* ============================================================
   v3.2: desktop buy column matches the mobile comp 1:1
   ============================================================ */

/* the bundle now carries Unlimited on every viewport */

/* delivery lives under the stock line everywhere */

/* sale badges are magenta on all viewports */

/* desktop buy column rhythm (figma 34812:114466): 20px blocks,
   12px title-to-rating, 16px button-to-delivery, 40px above the title */
@media (min-width: 990px) {
  .buybox { gap: 20px; padding-top: 40px; }
  .bb-rating { margin-top: -8px; }
  .bb-getit { margin-top: -4px; }
  /* bullets sit on a 32px pitch: 24px rows with 8px between */
  .bb-bullets { gap: 8px; }
}

/* ============================================================
   Founding Sale pass: collapsible "What you get" below ATC
   ============================================================ */

/* mobile order: WYG sits below ATC/stock/delivery (per client) */
@media (max-width: 989.98px) {
  .buybox .bm-btn--buy { order: 4; }
  
  
  
}

/* enhance: 4 upsell cards; phone media; tighter grid on desktop */

/* ============================================================
   "What you get" — 1:1 with the design comp
   (cool blue-grey header band, white rows, large grey tiles)
   ============================================================ */

/* product cutouts sit inside the tile, not cover-cropped */

/* tripod: show the head (top of the cutout) */

/* empty phone outline (per comp) */

/* WYG polish: clean plus/minus icon, larger mat cutout */

/* ============================================================
   Bundle card v3.2 polish + in-column Enhance
   ============================================================ */

/* thumbs stretch the full card width (proportionally larger) */

/* info icons flow inline right after the item text */
.bd-info { display: inline-block; }

/* bundle total centered */

/* Enhance in the buy column: stacked full-width cards */

/* mobile order: enhance after the accordion */
@media (max-width: 989.98px) {
  .buybox .bb-acc { order: 11; }
  
}

/* ============================================================
   WYG compact (exact Figma spec: 56px tiles, 14/12px type,
   #e5edf1 tiles & pills) + Enhance slider
   ============================================================ */

/* tripod: exact Figma crop (head), source image 2:3 */

/* phone tile: black frame + green screen image */

/* ---------- Enhance slider ---------- */

/* ============================================================
   Real-imagery tiles (Figma 34480:11379)
   ============================================================ */

/* ============================================================
   Mobile "Golf, but Smarter" bento — live-site grid mechanics
   (6-track grid, span classes, L-shaped tripod block)
   ============================================================ */
@media (max-width: 989.98px) {
  .bento-grid {
    grid-template-columns: repeat(6, 1fr);
    gap: 6px;
    grid-auto-flow: dense;
  }
  .b-sim { grid-column: span 6; order: 1; }
  .b-tripod { grid-column: span 2; grid-row: span 2; order: 2; min-height: 214px; padding: 16px 3px 0; }
  .b-tripod img { max-height: none; flex: 1; min-height: 0; object-fit: contain; }
  .b-pair--stack { display: contents; }
  /* the tripod spans both rows, so its height sets the mat/app rows - a
     min-height here would push that span past the figma card */
  .b-mat { grid-column: span 4; order: 3; min-height: 0; }
  .b-app { grid-column: span 4; order: 4; min-height: 0; }
  /* figma mobile runs the 7x7 / cast pair straight after the tripod block, with
     the courses card below it - desktop keeps courses first */
  .b-pair--half { grid-column: span 6; order: 5; display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
  .b-courses { grid-column: span 6; order: 6; min-height: 220px; }
  .b-space, .b-tv { min-height: 236px; }
  .b-ai-strip { grid-column: span 6; order: 7; flex-direction: row; justify-content: space-between; text-align: left; padding: 15px 16px; }
  .b-ai-strip .ai-badge { height: 44px; }

  /* live-site mobile card compaction */
  .b-card { padding: 12px 8px; gap: 8px; min-height: 0; }
  .b-title { font-size: 16px; line-height: 1.4; }
  .b-sub { font-size: 12px; line-height: 1.3; }
}

/* min-heights must survive the .b-card mobile reset (higher specificity) */
@media (max-width: 989.98px) {
  .bento-grid .b-courses { min-height: 220px; }
  /* figma mobile: 214 tripod (two 104 rows plus the 6px gap), 236 play/cast */
  .bento-grid .b-tripod { min-height: 214px; }
  .bento-grid .b-mat, .bento-grid .b-app { min-height: 0; }
  .bento-grid .b-space, .bento-grid .b-tv { min-height: 236px; }

  /* the tripod art is 470x1288, and an auto grid row sizes to max-content - so
     the raw image height, not min-height, was setting both stacked rows. a zero
     flex-basis drops it out of intrinsic sizing and lets it fill instead */
  .bento-grid .b-tripod img {
    height: 0;
    flex: 1 1 0;
    min-height: 0;
  }

  /* 84px keeps the mat/app cards at figma's 104 without a forced card height */
  .bento-grid .b-side img {
    height: 84px;
  }
}

/* WYG phone tile: blank white screen (per the user's reference tiles) */

/* ============================================================
   Bento quality pass (per golfdaddy reference)
   ============================================================ */

/* Tripod: much bigger, base anchored to the card bottom */
.b-tripod { padding-bottom: 0; }
.b-tripod img {
  margin: 6px auto 0;
  max-height: none;
  width: 62%;
  flex: 1;
  min-height: 0;
  object-fit: cover;
  object-position: top center;
}

/* AI strip: glowing dark pill backing (like the reference badge) */

/* Play at Home: game-mode media are wide app renders */

/* Lesson modules rail */

/* Upgrade your experience: two products at once, quick add */

/* ============================================================
   Lesson module cards (.lm-card) — dark cards carrying the app's
   line-drawn module figures + measurement overlays.
   Pairs with partials/lesson-modules.html; tokens from base.css.
   Overlay inks are the app's fixed viz palette (not themed):
   ZONE #00BC82 · MEAS #2FD49D · GOLD #F5C542.
   No hover motion — these cards are not clickable.
   ============================================================ */

/* Figure art: fixed-height stage, centered; each SVG keeps its authored
   viewBox (0..w x 0..300) and clips to it, like the app's tiles. */

/* Meta row: small chips — camera view + tracker count. */

/* Desktop buy column: ATC + stock + delivery move BELOW "What you get".
   Mobile keeps its own order (rules in the max-width block). */
@media (min-width: 990px) {
  .buybox > * { order: 20; }
  .buybox .bb-title { order: 1; }
  .buybox .bb-rating { order: 2; }
  .buybox .bb-price { order: 3; }
  
  .buybox .bm-btn--buy { order: 5; }
  
  
  
  
  .buybox .bb-acc { order: 10; }
  
}

/* Upgrade your experience: the two hero add-ons (tripod head crop, layered pads) */

/* ============================================================
   Fix pass: tripod uncropped, range photo space, marquee ratio,
   light lesson cards, light At-the-Range, social photo slot
   ============================================================ */

/* Upgrade block: tripod fully visible */

/* 35 Courses marquee: natural phone proportions, no squeeze */
.course-marquee { overflow: hidden; }
.cm-track { display: flex; width: max-content; gap: 0; }
.cm-track img {
  height: 240px;
  width: auto;
  max-width: none;
  flex: none;
}
@media (max-width: 749.98px) { .cm-track img { height: 150px; } }

/* AI strip badge (real asset with baked glow) */
.b-ai-strip .ai-badge { height: 76px; width: auto; }

/* Lesson module cards: light, grey illustration backing, dark figures */

/* recolor the ported white figure art for light backing */

255, 255, 0.08)"] { fill: rgba(15, 16, 16, 0.05); }
255, 255, 0.6)"] { stroke: rgba(15, 16, 16, 0.4); }
255, 255, 0.6)"] { fill: rgba(15, 16, 16, 0.4); }

/* At the Range: light section (no dark background) */
.course-sec { background: var(--paper); color: var(--ink); }
.course-sec .section-head h2 { color: var(--ink); }
.course-sec .section-head .bm-sub { color: var(--muted); }
.course-sec .bm-eyebrow { color: var(--blue); }
.course-feat { background: var(--surface); }
.course-feat p { color: var(--muted); }
.course-feat .cf-ico { background: var(--blue-tint); color: var(--blue); }
.course-map { background: var(--surface); }

/* Play tiles: two-line captions */
.tile figcaption span {
  display: block;
  font-size: var(--text-sm);
  font-weight: 500;
  opacity: 0.85;
  margin-top: 2px;
}

/* Social photo slot (replaces the guest pass) */

/* Bundle thumbs stretch wider now that there are two */

/* Upsell tripod: contained head shot, equal height with the pads */

/* Sale bar: FOUNDING SALE white, only 60% OFF yellow */

/* Shop dropdown is a 3-card row now */

/* v5 polish: black stock line, hairline before gift, WYG bottom border,
   taller first-screen stage, sticky sale bar */

/* Unlimited Bundle Offer: compact landscape thumbs — grey panel shows either side */

/* Play at Home: Figma flat tiles (captions baked into art) */
.tile--sm { aspect-ratio: 362 / 420; }
@media (min-width: 990px) {
  .tile-rail--4 { gap: 24px; }
}

/* Upgrade your experience: two flat cards per Figma 34516:92738 */

/* Unlimited Bundle Offer per Figma 34516:174705: taller thumbs (226x178), big timer, 56px CTA */

/* Play at Home tiles rebuilt in layers (Figma 34543): photo + phone + gradient + HTML caption */
.tile--mode { border-radius: 16px; }
.tile--mode .tm-photo {
  position: absolute;
  inset: 0;
  overflow: hidden;
}
.tile--mode .tm-photo img {
  position: absolute;
  inset: auto;
  max-width: none;
}
.tile--mode::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom, rgba(9, 10, 11, 0) 55%, rgba(9, 10, 11, 0.62) 100%);
  pointer-events: none;
  z-index: 1;
}
.tile--mode .tm-phone {
  position: absolute;
  top: 11.9%;
  right: 4.14%;
  width: 46.98%;
  height: auto;
  z-index: 2;
}
.tile--mode figcaption {
  position: absolute;
  left: 24px;
  right: 24px;
  bottom: 24px;
  z-index: 3;
  display: flex;
  flex-direction: column;
  gap: 8px;
  color: #fff;
  font-size: 24px;
  font-weight: 600;
  line-height: 1.3;
  text-align: left;
}
.tile--mode figcaption span {
  font-size: 14px;
  font-weight: 400;
  line-height: 1.4;
}

/* WYG thumbs: flat Figma tiles (bg + radius baked into the art) */


/* phone overlay: kill the inherited left:0 from the base .tile img inset */
.tile--mode .tm-phone { left: auto; bottom: auto; }

/* full-length phone overlay (design 156x384 at 362x420 — extends past the tile bottom) */
.tile--mode .tm-phone { display: block; overflow: visible; }
.tile--mode .tm-phone img {
  position: static;
  display: block;
  width: 100%;
  height: auto;
  max-width: none;
}
.tile--mode .tm-phone .tmp-screen {
  position: absolute;
  left: 2.3%;
  top: 1.07%;
  width: 88.69%;
  height: auto;
}

/* Ranked Match tile: champion-badge trail per Figma 34812:114746 */
.tile--mode .tm-rank {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
}
.tm-rank .tmr-trail {
  position: absolute;
  display: block;
}

/* Bento v3 per Figma 34516:91284 (July 21) */
.b-space .b-floor {
  width: min(279px, 82%);
  margin-inline: auto;
}
.b-space img, .b-tv img {
  width: min(279px, 82%);
  margin-inline: auto;
  aspect-ratio: auto;
  object-fit: contain;
  border-radius: 0;
  display: block;
}
.cm-track img { height: clamp(160px, 22vw, 277px); }
.b-ai-strip .ai-badge { height: 112px; }

/* At the Range: real Figma composition (716x480 landscape) replaces the portrait slot */

/* At the Range: dark feature cards per July-21 mock */
.course-feat { background: #0f1010; }
.course-feat h4 { color: var(--paper); font-size: 20px; }
.course-feat p { color: rgba(255, 255, 255, 0.66); }
.course-feat .cf-ico { background: rgba(255, 255, 255, 0.12); color: var(--paper); }
.course-feats { justify-content: center; }

/* July-21 feedback batch */
/* Upgrade your experience: more air between title and sub */

/* AI strip: text + badge as one centered cluster; badge runs edge to edge vertically */
@media (min-width: 750px) {
  .b-ai-strip {
    justify-content: center;
    gap: 40px;
    padding-block: 0;
    min-height: 122px;
  }
}
.b-ai-strip .ai-badge { height: 122px; }
@media (max-width: 749.98px) { .b-ai-strip .ai-badge { height: 88px; } }

/* Train at Home: flat Figma tiles (photo + metric card + caption baked), 366x351 */

/* Improve at Home: stacked module deck (one card in focus, next ones peeking behind) */

/* ===== July-21 evening batch ===== */
/* FAQ inherits the standard .bm-container width (no extra cap) */

/* Share every milestone: photo card + 2x2 point cards */

.share-points { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-top: 12px; }
.share-point {
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
  padding: 20px;
  border-radius: 14px;
  background: var(--paper);
  border: 1px solid #ececec;
}
.share-point svg { color: var(--ink); margin-top: 0; }
@media (max-width: 599.98px) { .share-points { grid-template-columns: 1fr; } }

/* Final CTA: packshot sits flush with the section's top and bottom edges */

/* Improve at Home: three flat cards per Figma 34555:59875 */
.improve-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(16px, 2.5vw, 36px);
}
@media (min-width: 750px) { .improve-grid { grid-template-columns: repeat(3, 1fr); } }
.imp-card {
  position: relative;
  margin: 0;
  aspect-ratio: 402 / 460;
  border-radius: 16px;
  overflow: clip;
  background: var(--surface);
}
.imp-card img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.imp-card--overlay::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom, rgba(9, 10, 11, 0) 55%, rgba(9, 10, 11, 0.62) 100%);
  pointer-events: none;
}
.imp-card--overlay figcaption {
  position: absolute;
  left: 16px;
  right: 16px;
  bottom: 25px;
  z-index: 2;
  text-align: center;
  color: #fff;
  font-size: 28px;
  font-weight: 600;
  line-height: 1.4;
}

/* Upgrade cards must never outgrow the buy column */

/* Founding Members Bundle — compact teaser row above Add to Cart. sizes come
   off the figma comp: 60px thumb inside 16px padding, so the row is 92 tall */
.fm-bundle {
  display: flex;
  align-items: center;
  gap: 20px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 16px;
  color: var(--ink);
  text-decoration: none;
}

.fm-bundle__thumb {
  flex-shrink: 0;
  width: 60px;
  height: 60px;
  border-radius: 8px;
  background: #f1f1f2;
  overflow: clip;
}

.fm-bundle__thumb img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}

.fm-bundle__text {
  flex: 1 0 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.fm-bundle__title {
  font-size: 18px;
  font-weight: 600;
  line-height: 1.3;
}

.fm-bundle__timer {
  font-size: 14px;
  font-weight: 500;
  line-height: 1.3;
  color: #a2215e;
}

.fm-bundle__timer b {
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

/* figma fills the disc off-white with no ring - sampled #f1f1f2 edge to edge */
.fm-bundle__go {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  background: #f1f1f2;
  border-radius: 50%;
}

/* Unlimited Bundle Offer — light in-column card */
.bundle-light {
  display: flex;
  flex-direction: column;
  align-items: center;
  background: var(--paper);
  border: 1px solid #d4d4d4;
  border-radius: 16px;
  padding: 24px 12px 24px;
  text-align: center;
}
.bl-pill {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  height: 36px;
  padding: 0 24px;
  border-radius: 24px;
  background: linear-gradient(90deg, #6d1943 0%, #b0356b 49.52%, #6d1943 100%);
  color: #fff;
  font-size: 14px;
  font-weight: 600;
}
.bl-pill .bl-sun { font-style: normal; font-size: 15px; line-height: 1; }
.bl-head { margin-top: 16px; font-size: 20px; font-weight: 600; line-height: 1.3; letter-spacing: normal; }
.bl-timer { margin-top: 8px; font-size: 16px; font-weight: 500; color: #ad3469; }
.bl-timer b { font-weight: 500; font-variant-numeric: tabular-nums; }
.bl-thumbs {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 16px;
  width: 100%;
}
.bl-thumbs span { flex: 1; border-radius: 12px; overflow: clip; }
.bl-thumbs img { width: 100%; height: auto; display: block; }
.bl-thumbs i { font-style: normal; font-weight: 600; color: var(--ink); }
.bundle-light .bd-items { width: 100%; margin-top: 24px; padding-inline: 12px; text-align: left; }
.bundle-light .bd-items li { display: flex; align-items: center; justify-content: space-between; padding-block: 5px; font-size: 12px; }
/* figma 34599:24432: 8px check-to-label, 4px label-to-info */
.bundle-light .bd-name { display: inline-flex; align-items: center; gap: 0; font-weight: 600; color: var(--ink); }
.bundle-light .bd-name .li-check { margin-right: 8px; }
.bundle-light .bd-name .bd-info { margin-left: 4px; }
.bundle-light .bc-price { color: var(--ink); font-weight: 700; }
.bundle-light .bc-price s { color: #6d6a67; font-weight: 400; margin-right: 9px; }
/* sub rows sit in the label column, not the checkmark column (figma 34599:24455) */
.bundle-light .bd-items li.bd-sub { justify-content: flex-start; padding: 2px 0 2px 23px; color: #6d6a67; font-weight: 500; }
.bl-divider { width: 100%; height: 1px; background: #f2f2f6; margin-top: 16px; }
.bundle-light .bc-total { display: flex; align-items: center; justify-content: center; gap: 10px; margin-top: 16px; }
.bundle-light .bc-total strong { font-size: 25.6px; font-weight: 700; letter-spacing: -0.5px; }
.bundle-light .bc-total s { font-size: 18px; color: #6d6a67; }
.bl-btn {
  width: 100%;
  margin-top: 16px;
  min-height: 56px;
  border-radius: 8px;
  background: var(--ink);
  color: #fff;
  font-size: 16px;
  font-weight: 600;
}
.bl-btn:hover { background: #2a2b2b; }
/* figma 34616:15601: 417px measure (40px inset), 12/18 Manrope, wraps on its own */
.bundle-light .bd-note { margin-top: 16px; padding-inline: 40px; font-size: 12px; line-height: 18px; color: #6d6a67; }

/* single-row upsell */

/* sale bar: solid #2a2a2a, no separators */

/* gallery arrows: 48px white circles */
.pdp-stage .rail-nav {
  width: 48px;
  height: 48px;
  background: #fff;
  color: var(--gray);
  border-radius: 50%;
}
/* active thumb: dark ring */
.pdp-thumb.is-active { outline: 1.5px solid #0f1010; outline-offset: 1px; }

/* Improve at Home v3: four cards */
@media (min-width: 750px) { .improve-grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

/* Share every milestone v3: white point cards + parallax phones */
.share-grid { align-items: start; }
@media (min-width: 900px) { .share-grid { grid-template-columns: 1.06fr 1fr; gap: 48px; } }
/* figma runs this sub grey at 20/27, not the black body size the shared
   .bm-sub--muted rule gives every other section */
.share-text .bm-sub { color: var(--muted); }
/* mobile figma runs this sub a shade darker than the desktop grey */
@media (max-width: 989.98px) {
  .share-text .bm-sub { color: #2e2c2b; }
}
@media (min-width: 990px) {
  .share-text .bm-sub { font-size: 20px; line-height: 27px; }
}
.share-points { grid-template-columns: 1fr 1fr; gap: 16px; }
.share-point {
  background: var(--paper);
  border: 0;
  border-radius: 8px;
  padding: 24px;
  gap: 12px;
}
.sp-ico {
  flex: none;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: 4px;
  background: var(--ink);
  color: #fff;
}
.share-point b { display: block; margin-bottom: 4px; }
.share-phones {
  position: relative;
  display: grid;
  place-items: center;
  min-height: 480px;
}
/* figma 34855:49695: the phones fill the full 716px column, landing on its
   515px panel height at the 1520 band */
.shp-duo { width: 100%; max-width: none; height: auto; display: block; }
@media (min-width: 900px) {
  /* the phones scale with their grid column instead of a fixed 515px height:
     a fixed height forced ~713px of min-content width and crushed the cards
     column at 1280. at the 1520 band the column is 716px wide, which lands the
     export on the same 515px panel the figma frame shows. */
  .share-phones { min-height: 0; height: auto; }
  .shp-duo { width: 100%; max-width: 716px; height: auto; }
  .share-grid > * { min-width: 0; }
}
@media (max-width: 899.98px) {
  /* Paul (Aug 22 POV @1:09): the heading and the intro sit BESIDE the phones
     on mobile instead of stacked above them, so the block opens in one screen
     instead of a full band of text before anything visual.
     .share-text still dissolves, so .share-intro, .share-points and
     .share-phones are all direct grid items of .share-grid. */
  .share-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.35fr);
    align-items: center;
    column-gap: 12px;
    row-gap: 16px;
  }
  .share-text { display: contents; }
  .share-intro {
    grid-column: 1;
    grid-row: 1;
    gap: 8px;
    text-align: left;
  }
  .share-intro > h2 { font-size: 28px; line-height: 1.25; }
  .share-intro > .bm-sub { font-size: 13px; line-height: 1.4; margin-inline: 0; max-width: none; }
  .share-phones {
    grid-column: 2;
    grid-row: 1;
    min-height: 0;
    height: auto;
    margin-top: 0;
    /* bleed to the screen edge so the two phones keep a readable size in the
       narrower column: buys back one full page gutter */
    margin-right: calc(var(--pad-x) * -1);
  }
  .share-points { grid-column: 1 / -1; grid-row: 2; }
    /* Paul (Sep 4): back to the full export - both phones, uncropped, exactly
       as live has shipped it.

       Two passes tried to crop this frame to the right-hand phone after Daniel
       (Aug 31) said "images are hard to see": first aimed at that phone's
       centre, which left a 7%-wide slice of the LEFT device against the frame
       edge, then re-aimed at the gap between them, which was clean but grew the
       section ~118px taller. Paul rejected both. The crop is the wrong lever
       here - if the phones need to read larger, change the column or the export,
       not the window onto it. */
  .shp-duo { width: 100%; max-width: none; }
  /* the mockup is only ~175px tall in this column, and a +/-42px parallax
     drift at that size reads as a wobble, so pin it. !important beats the
     inline transform benchmark-pdp.js writes on every scroll frame. */
  .shp-duo { transform: none !important; }

  /* figma's point cards: 10px gutter and 16px padding, which lands the copy
     column on ~138px — the width that gives every figma line break below */
  /* Paul (Aug 23): inline chip tiles. Icon and label share one line, which
     drops the block from ~229px to ~116px and removes the ragged-row defect
     by construction: at 440 the old 2x2 sized row 1 from the one title that
     wrapped (119px) and row 2 from the ones that did not (100px), so the two
     rows never lined up. Short labels come from .sp-short in the markup; the
     full titles wrap at this width and would defeat the layout. */
  .share-points { gap: 8px; }
  .share-point {
    flex-direction: row;
    align-items: center;
    gap: 10px;
    padding: 11px 12px;
    border-radius: 10px;
  }
  /* three classes, not two: the global .share-point .sp-ico rule further down
     this file sets 40px and would otherwise win on source order */
  .share-points .share-point .sp-ico { width: 28px; height: 28px; border-radius: 6px; }
  .share-points .share-point .sp-ico svg { width: 16px; height: 16px; }
  /* Paul (Aug 21 POV @4:50): drop the card descriptions. div > span skips the
     .sp-ico chip and the label spans, which sit inside <b> */
  .share-point b { font-size: 13px; line-height: 1.25; margin-bottom: 0; }
  .share-point div > span { display: none; }
  /* same source-order problem as .sp-ico: the .sp-short base rule lives
     further down the file, so this needs the extra class to win */
  .share-points .share-point .sp-short { display: inline; }
  .share-points .share-point .sp-full { display: none; }
}

/* Courses tile v3: marquee of 8 phone course cards */
.cm-set { display: flex; gap: 10px; padding-right: 10px; flex: none; }
.cm-set img { width: auto; height: clamp(170px, 15vw, 220px); border-radius: 12px; }
/* flex: none keeps max-content authoritative. as a shrinkable flex item the
   track's width is only held up by min-width:auto, and the -50% keyframe
   resolves against the track's own border box — so any shrink shortens the
   travel instead of landing on the seam. */
.cm-track { align-items: center; flex: none; }

/* the strip scrolls itself: the track holds two identical sets, so -50% lands
   exactly on a seam and the loop is invisible. prefers-reduced-motion kills it
   in the block near the end of this file.

   ios safari specifics: translate3d (not translateX) and an explicit from
   keyframe, because webkit only promotes and pre-resolves the keyframe values
   for a 3d transform — a 2d one on a track this wide gets left on the main
   thread and can sit frozen behind the page's own load work. the static
   translate3d + backface-visibility below build the layer before the animation
   starts so the first frame has somewhere to composite into. */
.cm-track {
  transform: translate3d(0, 0, 0);
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  animation: bm-course-marquee 40s linear infinite;
  will-change: transform;
}

@keyframes bm-course-marquee {
  from { transform: translate3d(0, 0, 0); }
  to { transform: translate3d(-50%, 0, 0); }
}

/* At the Range v3: light warm feature rows (44px dark icon tiles stay) */
.course-feat {
  background: #f4f3f1;
  border-radius: 16px;
  padding: 20px 32px;
  min-height: 111px;
  align-items: center;
}
.course-feat h4 { color: var(--ink); font-size: 18px; font-weight: 500; margin-bottom: 4px; }
.course-feat p { color: var(--gray); font-size: 14px; }
.course-feat .cf-ico { background: var(--ink); color: #fff; border-radius: 4px; }
.course-map img { border-radius: 8px; width: 100%; height: 100%; object-fit: cover; }
.course-map { aspect-ratio: 716 / 480; border-radius: 8px; }

/* FAQ v3: two-line centered heading, square toggles, outline Show More */

/* Get-it-by line under the ATC */
.bb-getit { text-align: center; font-size: 14px; font-weight: 600; line-height: 1.4; color: var(--gray); }
.bb-getit b { font-weight: 800; color: var(--ink); }

/* Buy box v3: the DOM order IS the design order — kill all legacy reordering (all breakpoints) */
.buybox > * { order: 0 !important; }

/* Founding popup v3: mirrors the light bundle card */

/* CTA packshot: right edge fades out instead of cutting the shadow */

/* sale bar: unified black (overrides the earlier #2a2a2a) */


/* ============================================================
   Figma sync — 34516-35407 (mobile) / 34516-90746 (desktop)
   ============================================================ */

/* per-breakpoint copy swaps (figma uses different copy per frame).
   Aug 24: no markup uses this pair any more. The bento tiles and the two buy
   boxes were the last holdouts and they now ship one line at every width, so
   the utility stays available but nothing should reach for it without a
   reason a reader could not guess from the page itself. */
.bm-mobile-copy { display: none; }

/* figma breaks the courses subtitle before "levels"; keeping the tail as one
   unwrappable run drops it whole instead of hard-coding a <br> that would
   strand a word on narrower phones. mobile-only - the span it sits in is
   display:none above the breakpoint */
.b-sub-keep { white-space: nowrap; }

/* Paul (Aug 23): the Cast tile shows AirPlay and Chromecast as glyph pills
   instead of a sentence. Generic glyphs, not the official brand marks.
   Aug 24: at every width, not just mobile. */
.bm-pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 12px;
  font-weight: 700;
  line-height: 1;
  padding: 6px 10px;
  border-radius: var(--r-pill);
  background: var(--chip);
  color: var(--ink);
  white-space: nowrap;
}
.bm-pill svg { width: 13px; height: 13px; display: block; flex: none; }
/* `display` used to live in the mobile block below, because this class sat on
   a .bm-mobile-copy span and a bare `display: flex` here would have outranked
   `.bm-mobile-copy { display: none }` on source order. The pills ARE the sub
   now, so the span is gone and the rule belongs with the rest of the base.
   Centered because the tile's title is centered (Paul, Aug 23 screenshot). */
.b-sub-pills { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px; }


@media (max-width: 989.98px) {
  .bm-mobile-copy { display: inline; }
  .bm-desktop-copy { display: none; }

  /* Paul (Aug 23, screenshot): bullets directly under the price, ATC and
     delivery after them — the same stack desktop runs. This block outranks
     the three older order layers above, so it is the single source of truth. */
  .buybox > * { order: 20 !important; }
  .buybox .bb-title { order: 1 !important; }
  .buybox .bb-rating { order: 2 !important; }
  .buybox .bb-price { order: 3 !important; }
  .buybox .bb-bullets { order: 4 !important; }
  .buybox .fm-bundle { order: 5 !important; }
  .buybox .bb-atc { order: 6 !important; }
  .buybox .bb-getit { order: 7 !important; }
  .buybox .bb-acc { order: 8 !important; }
}

/* share cards: white glyph centred on the black icon chip. the display + colour
   here outrank .share-point span (display:block) and .share-point svg (ink),
   which otherwise pin the glyph to the top of the chip and paint it black. */
.share-point .sp-ico {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  color: #fff;
}
.share-point .sp-ico svg { color: inherit; display: block; }

/* desktop keeps the full titles and their descriptions; only the chip layout
   below 900 uses the short forms */
.share-point .sp-short { display: none; }

/* at-the-range: light theme, no eyebrow (both figma frames) */
.course-sec { background: var(--paper); color: var(--ink); }
.course-sec .bm-eyebrow { display: none; }
.course-sec .section-head h2 { color: var(--ink); }
.course-sec .section-head .bm-sub { color: var(--muted); }
.course-feat { background: var(--surface); }
.course-feat h4 { color: var(--ink); }
.course-feat p { color: var(--muted); }
.course-feat .cf-ico { background: var(--ink); color: #fff; }

/* bento AI strip: mobile ships figma's gradient panel (node 34812:99762) as one
   baked image — the colour wheel, its ellipse mask and the 25px backdrop blur
   are all in the export, so nothing blurs at paint time — with the pill svg on
   top and the copy left as live text */
.ai-badge-mobile { display: none; }
@media (max-width: 989.98px) {
  .ai-badge { display: none; }
  .ai-badge-mobile {
    display: block;
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    /* figma runs the panel 187.5 of the 351 card, bled to the card edge */
    width: 187.5px;
    max-width: 100%;
    pointer-events: none;
  }
  .ai-badge-mobile__bg {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: right center;
  }
  .ai-badge-mobile__pill {
    position: absolute;
    top: 50%;
    /* figma centres the pill 86.5 off the panel's right edge, and the svg
       carries 6.8 of baked shadow margin either side of the 120 pill */
    right: 19.5px;
    /* the baked drop shadow only hangs below the pill, so the svg box centres
       ~4px higher than the pill does — nudge it back down */
    translate: 0 calc(-50% + 4.2px);
    display: block;
    width: 134px;
    height: auto;
  }
}

/* gallery on mobile: full-bleed square with white overlay dots (figma 34516:35431) */
@media (max-width: 989.98px) {
  /* Paul (Aug 24, round 2): the bottom scrim is gone. It was added to keep the
     white dots legible on the lighter slides, but it sat on .pdp-stage - the
     fixed frame - not on the slides, so it painted one 96px band across
     everything the rail scrolled past. On a dark photo it was invisible; on
     the near-white studio and "in the box" slides it read as a grey rectangle
     with hard edges at the slide seams, appearing and disappearing as you
     swiped. That is what Paul saw as "a rectangular gradient between images".

     A scrim can only work here if it travels WITH each slide, and the slides
     are bare <img>/<video> inside a display:contents <picture>, so there is
     nothing to hang a per-slide pseudo-element on without restructuring the
     rail the wrap-around and snap maths depend on.

     The dots carry their own contrast instead, which is what the ring was
     already there for - it just needed to be strong enough to work alone.
     Verified against the lightest slide in the deck. */
  /* figma 34516:35431 sits the dots 12px off a 375-wide square stage; scale the
     offset with the stage so the mat line holds from 375 through 430 */
  .pdp-dots { bottom: clamp(12px, 3.2vw, 14px); gap: 8px; }
  .pdp-dots span {
    width: 8px;
    height: 8px;
    border: 0;
    background: rgba(255, 255, 255, 0.62);
    /* ring 0.18 -> 0.42 and a deeper drop: with no scrim under them these have
       to hold on a near-white photo by themselves */
    box-shadow: 0 0 0 1px rgba(9, 10, 11, 0.42), 0 1px 3px rgba(9, 10, 11, 0.38);
  }
  .pdp-dots span.is-active {
    background: #fff;
    box-shadow: 0 0 0 1px rgba(9, 10, 11, 0.38), 0 1px 4px rgba(9, 10, 11, 0.42);
  }

  /* mobile buy box rhythm (figma 34588:79239): 12px page gutter, 16px blocks,
     8px title-to-rating and button-to-delivery, 8px bullet rows, 28px title,
     18px bundle heading */
  .bm-pdp { --pad-x: 12px; }
  /* figma runs the buy box straight into the bundle band (34812:95149 closes at
     1035.5, 34947:40599 opens there); the band's own 8px is half of its 16 */
  .pdp { padding-bottom: 16px; }
  .section-benchmark-pdp-main .pdp { padding-bottom: 8px; }
  /* figma's mobile content band is 16/16 (34812:99668); set once above */
  .bb-title { font-size: 32px; line-height: 1.2; }
  .bb-rating { margin-top: -8px; }
  .bb-rating .stars { width: 92px; }
  .bb-getit { margin-top: -8px; }
  /* figma runs the bullets straight into the bundle card on mobile - neither
     the bundle teaser row nor the buy-box faq appears between them */
  .buybox .fm-bundle,
  .buybox .bb-acc { display: none; }
  /* figma breaks Play at Home's sub after the em dash. the line needs 364.7px
     to hold "from", so a 390px+ phone pulls it up without this cap */
  .tiles .section-head .bm-sub { max-width: 348px; }
  .bl-head { font-size: 18px; font-weight: 500; }
}

/* bundle rows: single checkmark — the inline icon, not the legacy ::before */
.bundle-light .bd-name { padding-left: 0; }
.bundle-light .bd-name::before { content: none; }
.bundle-light .bd-items li { gap: 8px; }
.bundle-light .bd-name { font-weight: 500; }

/* bento mobile density per figma 34584:42869 (titles 12-14px, subs 10px, compact rows) */
@media (max-width: 989.98px) {
  .bento .section-head { margin-bottom: 16px; }
  /* figma: 14px card titles across the bento */
  .bento .b-title { font-size: 14px; line-height: 1.4; }
  /* Paul (Aug 23): subs were 10px, below the buy-box bullets and under the
     smallest size anything else on this page runs at. Figma set 10px because
     the copy was long enough to need the room; the copy is now one short
     clause per tile, so the space it freed goes back into the type. */
  .bento .b-sub { font-size: 13px; line-height: 1.35; }
  .b-pair--half .b-sub { font-size: 13px; line-height: 1.35; }
  .b-mat, .b-app { padding: 10px 12px; align-items: center; }
  .b-side .b-side-text { max-width: calc(100% - 92px); flex: 1; min-width: 0; }
  .b-side img { width: 84px; height: 100%; object-fit: contain; }
  /* tripod art: near-full column width, top-anchored, cropped at the card bottom */
  .b-tripod img {
    flex: 1;
    min-height: 0;
    width: 94%;
    margin-inline: auto;
    object-fit: cover;
    object-position: top center;
  }
  /* course phones: 180px tall per figma */
  .cm-set img { height: 180px; }
  /* figma mobile opens the marquee on Malibu Ranch, so the sedona sliver and
     matterhorn drop out of both sets and the loop stays seamless */
  .cm-set > img:nth-child(-n + 2) { display: none; }
  /* figma clips that opening card by 16% of its width rather than starting it
     flush, which also sets where the row cuts off on the right */
  .b-courses .cm-track { margin-left: -14px; }
  /* 7x7 / cast tiles: media runs edge to edge and hugs the card bottom */
  .b-space, .b-tv { padding-bottom: 0; }
  .b-space .b-floor {
    width: calc(100% + 16px);
    max-width: none;
    margin: auto -8px 0;
    flex: none;
  }
  .b-space img, .b-tv img {
    width: calc(100% + 16px);
    max-width: none;
    margin: auto -8px 0;
    flex: none;
    object-fit: cover;
    border-radius: 0;
  }
  /* figma runs both tiles at 236 tall; the copy above the art is fixed, so the
     media carries the difference (space had a square crop, cast a 172/164) */
  .b-space .b-floor { aspect-ratio: 10 / 9; }
  .b-space img { aspect-ratio: 10 / 9; }
  .b-tv img { aspect-ratio: 172 / 146; }
  .b-ai-strip {
    position: relative;
    background: var(--surface-cool);
    overflow: clip;
    min-height: 86px;
    padding: 12px 18px 12px 20px;
    gap: 8px;
  }
  .b-ai-strip h3 { font-size: 14px; line-height: 1.4; }
  .b-ai-strip p { font-size: 13px; line-height: 1.35; margin-top: 6px; color: var(--ink); }
}

/* play + improve rails on mobile: ~218px tiles like the figma frame */
@media (max-width: 989.98px) {
  /* figma: mobile section titles = H4 28/500/1.3, subs = 14/400/1.4.
     section h2/subs carry .bm-h1/.bm-sub, so the general rules cover tiles + bento too */
  .bm-h1 { font-size: 28px; font-weight: 500; line-height: 1.3; }
  .bm-sub { font-size: var(--text-sm); line-height: 1.4; }
  .tiles .section-head { align-items: flex-start; text-align: left; }
  /* figma's mobile mode cards run 269 of the 375 frame (71.5%) with a 16px
     rail gap, and the caption scales with them: 20/600 over 14/400 */
  /* Paul (Aug 24): back to figma's left-to-right swipe. The Aug 23 2x2 grid
     was the fix for "at 390 the rail showed Solo Play, 30% of Local Party,
     and nothing of Ranked Match or Virtual Range, with no dots" - but the
     part that was actually missing was the dots. .tile-dots below the rail
     now says how many modes there are and which one you are on, so the cards
     go back to figma's 269-of-375 (71.5%) width. That leaves 20-26% of the
     next card showing at 375-440, which reads as "there is more here".
     Desktop is untouched: it keeps the static four-across grid at line 1053. */
  .tile--sm { width: clamp(240px, 71.5vw, 288px); }
  .tiles .rail-nav { display: none; }
  .tile-rail { gap: 16px; }
  .tile figcaption { font-size: 16px; left: 14px; right: 14px; bottom: 12px; }
  .tile figcaption span { font-size: 11px; }
  .tile--mode figcaption { font-size: 20px; left: 16px; right: 16px; bottom: 20px; }
  .tile--mode figcaption span { font-size: 14px; }

  .improve-grid,
  .improve-grid--4 {
    display: flex;
    gap: 8px;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  .improve-grid::-webkit-scrollbar { display: none; }
  .improve-grid .imp-card {
    flex: none;
    width: clamp(190px, 56vw, 218px);
    scroll-snap-align: center;
  }
  .imp-card figcaption { font-size: 16px; }

  /* the gradient panel is out of flow now, so the copy holds figma's 171 box
     (which is what wraps the title onto two lines) and stacks above the glow */
  .b-ai-strip > div {
    position: relative;
    z-index: 1;
    flex: none;
    width: 171px;
    max-width: 100%;
  }
}

/* mobile section rhythm: 72px + 72px between sections reads as a hole
   on a phone — tighten to 40px each side */
@media (max-width: 989.98px) {
  .bm-pdp { --section-y: 40px; }
}

/* courses card matches the figma collection card (node 34584:42937):
   14px title, 10px sub, 11px top padding, marquee row 223px tall with
   the 180px phones centered — card height comes from content, not min-height */
@media (max-width: 989.98px) {
  .bento-grid .b-courses {
    min-height: 0;
    padding: 11px 0 0;
    gap: 7px;
  }
  .b-courses .b-title {
    font-size: 14px;
    padding-inline: 13px;
  }
  .b-courses .b-sub {
    max-width: none;
    padding-inline: 13px;
  }
  .b-courses .course-marquee {
    flex: none;
    margin: 2px 0 0;
    padding: 21px 0 22px;
  }
}

/* mobile type + wraps measured off the figma 375 frame. the hero tile is the
   one card figma keeps at the full scale (20 / 16); every other card stays at
   the 14 / 10 density set above. */
@media (max-width: 989.98px) {
  .bento-grid .b-sim .b-title { font-size: 28px; font-weight: 500; line-height: 1.3; }
  .bento-grid .b-sim .b-sub {
    font-size: 16px;
    line-height: 1.5;
    /* figma's four lines need 302-314px of measured column; 308 is mid-window */
    max-width: 308px;
  }

  /* figma runs the mat/app copy narrower than the card allows, which is what
     breaks the mat after "Mat gives you a". the measured window that also keeps
     the app copy on its three figma lines is 102.3-108.8px; min() keeps the
     column inside the card on phones narrower than the figma frame */
  /* Paul (Aug 23): the 105px cap was tuned for the old 10px copy and its figma
     line breaks; at 13px it strands single words ("out") on their own line.
     The image columns run ~119px wide, so the text takes what is left instead
     of a hard cap, and balance keeps the remaining wraps even. */
  .bento-grid .b-side .b-side-text { max-width: calc(100% - 132px); }
  .bento-grid .b-side .b-sub { text-wrap: balance; }

  /* the tripod art was running ~28% oversized against figma. 73.7% of the card
     puts the head at 25.6% of the card width and the pole at 16.6%, which are
     figma's two measurements — object-fit is cover and width-driven, so the box
     width is what sets the art's scale */
  .bento-grid .b-tripod img { width: 73.7%; }

  /* figma bleeds the mat/app photo to the card's top, right and bottom edges
     the same way the desktop tiles do — it was sitting contained at 84px with
     air on every side. the card keeps its left padding for the copy and drops
     the right one so the photo can run to the edge */
  .bento-grid .b-mat,
  .bento-grid .b-app { padding-right: 0; }
  .bento-grid .b-side img {
    width: 45%;
    /* +20 / -10 cancels the card's vertical padding so the photo runs edge to
       edge, and auto-left pins it to the right edge like figma */
    height: calc(100% + 20px);
    max-height: none;
    margin-block: -10px;
    margin-left: auto;
    object-fit: cover;
    object-position: right center;
  }
  /* the app shot is a portrait phone, so as a flex item its intrinsic height
     set the row and pushed the tripod's two-row span past 214. taking it out of
     flow leaves the copy to size the card and lets the clip crop the wrist */
  .bento-grid .b-app img {
    position: absolute;
    top: 0;
    right: 0;
    width: 42%;
    height: auto;
    margin: 0;
    object-fit: contain;
    object-position: right top;
  }
}

/* desktop section rhythm, measured off the figma page frame (34812:114437) at
   1920: the hero closes at 913 and the bundle card opens at 1013, the bundle
   card closes at 1485 and the bento opens at 1618, the bento closes at 2744 and
   Play at Home opens at 2844, its cards close at 3413 and the share band opens
   at 3513. The bundle band carries 24px of its own padding, so the two gaps it
   touches are split 76 + 24 and 24 + 109. --section-y (128) is left alone: the
   share band and the reviews/FAQ/CTA below own their padding already. */
@media (min-width: 990px) {
  /* the pad PDP shares this stylesheet, so it keeps the old seam and only the
     Golf At Home frame takes figma's 76 + the bundle band's own 24 */
  .pdp { padding-block-end: clamp(32px, 3vw, 48px); }
  .section-benchmark-pdp-main .pdp { padding-block-end: 76px; }
  .bento { padding-block-start: 109px; padding-block-end: 0; }
  .tiles { padding-block: 100px; }
}

/* ============================================================
   Bento desktop parity — figma 34516:91286, authored on the 1520px band.
   Widths are a share of their figma column (750 / 227 / 515); everything
   else is calc(N * var(--bento-u)) where N is the raw figma px. Both track
   the container, so the tiles stay proportional below the 1524px cap.
   This block is last on purpose — it supersedes the earlier bento passes.
   ============================================================ */
@media (min-width: 990px) {
  /* --bento-u is one figma pixel: 1px once the container reaches its 1520px
     band, shrinking with the container below it. Type, padding and gaps are
     all written as calc(N * var(--bento-u)) so the tiles keep figma's line
     breaks instead of re-wrapping on narrower desktops. */
  .bento-grid {
    --bento-u: min(1px, calc(0.06579vw - 0.0632px));
    gap: calc(12 * var(--bento-u));
  }

  /* row proportions: 518 / 454 tall against the 750 left column (34812:119668) */
  .bento-grid .b-sim { aspect-ratio: 750 / 518; }
  /* stack matches the hero beside it so row 1 can't grow past figma */
  .bento-grid .b-pair--stack { aspect-ratio: 515 / 518; }
  .bento-grid .b-pair--half { aspect-ratio: 750 / 454; }
  /* courses spans the 227 + 12 + 515 columns */
  .bento-grid .b-courses { aspect-ratio: 754 / 454; }
  .bento-grid .b-pair { gap: calc(12 * var(--bento-u)); }

  /* cards fill their row; the figma min-heights fought the ratios above */
  .bento-grid .b-sim,
  .bento-grid .b-tripod,
  .bento-grid .b-side,
  .bento-grid .b-courses,
  .bento-grid .b-space,
  .bento-grid .b-tv { min-height: 0; }

  /* shared shell: 12px pad, 8px title-box gap, media adds the rest */
  .bento-grid .b-card { padding: calc(12 * var(--bento-u)); gap: calc(8 * var(--bento-u)); }
  .bento .b-title {
    font-size: calc(20 * var(--bento-u));
    font-weight: 600;
    line-height: 1.3;
    letter-spacing: 0;
  }
  .bento .b-sub {
    font-size: calc(16 * var(--bento-u));
    line-height: 1.5;
    max-width: none;
    margin-inline: 0;
  }

  /* ---- Precise Golf Simulation (750x518) ---- */
  .bento-grid .b-sim {
    align-items: center;
    padding: calc(24 * var(--bento-u)) calc(12 * var(--bento-u)) calc(12 * var(--bento-u));
  }
  .bento-grid .b-sim .b-title,
  .bento-grid .b-sim .b-sub { text-align: center; }
  /* the 620u cap here was measured so figma's line one could end on
     "AI-powered golf". That clause is gone (Aug 24) and the sub is a single
     short line, so it just centres in the card. */
  .bento-grid .b-sim .b-sub { margin-inline: auto; }
  .bento-grid .b-sim-video {
    width: 100%;
    margin: calc(8 * var(--bento-u)) 0 0;
    flex: 1;
    min-height: 0;
    aspect-ratio: auto;
    border-radius: calc(8 * var(--bento-u));
    object-fit: cover;
  }

  /* ---- Magnetic Tripod (226x515, figma 34812:119648) — the art runs the
     full card width and hugs the bottom edge, so the corners carry no gap */
  .bento-grid .b-tripod {
    align-items: center;
    padding: calc(42 * var(--bento-u)) 0 0;
    /* the art's intrinsic height must not size row 1 — the hero and the
       mat/app stack own the row; the tripod just fills it */
    contain: size;
  }
  .bento-grid .b-tripod img {
    width: 100%;
    margin: calc(32 * var(--bento-u)) 0 0;
    flex: 1;
    min-height: 0;
    object-fit: cover;
    object-position: top center;
  }

  /* ---- Benchmark Mat / App access (515x253) ---- */
  .bento-grid .b-side {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: calc(12 * var(--bento-u));
    padding: 0 0 0 calc(42 * var(--bento-u));
  }
  /* figma insets the copy further and runs it in a narrow column, which is what
     breaks the mat text after "consistent" / "designed for" and the app text
     after "access". the measured window that gives every one of those breaks is
     219.1-223.5px, so 221 sits in the middle of it */
  .bento-grid .b-side .b-side-text {
    flex: none;
    min-width: 0;
    max-width: calc(221 * var(--bento-u));
    gap: calc(8 * var(--bento-u));
  }
  /* floating product shot with transparent margins — show it whole in the
     space left of the copy instead of bleeding past the card edge */
  .bento-grid .b-mat img {
    flex: 1 1 auto;
    width: auto;
    min-width: 0;
    max-width: none;
    height: 100%;
    max-height: none;
    margin: 0;
    object-fit: contain;
    object-position: center;
  }
  /* hand-held phone sits against the right edge */
  .bento-grid .b-app img {
    flex: none;
    width: 45%;
    max-width: none;
    height: 92%;
    max-height: none;
    margin: 0;
    align-self: flex-end;
    object-fit: contain;
    object-position: right bottom;
  }

  /* ---- 35 Unique Courses (754x454) ---- */
  .bento-grid .b-courses {
    align-items: center;
    justify-content: center;
    padding: calc(20 * var(--bento-u)) 0 calc(20 * var(--bento-u));
  }
  .bento-grid .b-courses .b-title,
  .bento-grid .b-courses .b-sub { width: 100%; padding-inline: calc(16 * var(--bento-u)); }
  .bento-grid .b-courses .b-sub { margin-top: calc(8 * var(--bento-u)); }
  .bento-grid .course-marquee {
    margin: calc(8 * var(--bento-u)) 0 0;
    /* below the 1520 band the bento unit outruns the card's own width, so a
       fixed 277 row swallows the bottom padding — let the row shrink instead */
    flex: 0 1 auto;
    height: calc(277 * var(--bento-u));
    min-height: 0;
    width: 100%;
    align-self: stretch;
    overflow: hidden;
    display: flex;
    align-items: center;
  }
  .bento-grid .cm-track,
  .bento-grid .cm-set { align-items: center; }
  /* the spacing lives inside a set, never on the track: a gap between the two
     sets would put the -50% keyframe short of the seam */
  .bento-grid .cm-set {
    gap: calc(10 * var(--bento-u));
    padding-right: calc(10 * var(--bento-u));
  }
  /* phones fill the row exactly; anything taller gets its bezels clipped by
     the marquee's overflow */
  .bento-grid .cm-track,
  .bento-grid .cm-set { height: 100%; }
  .bento-grid .cm-track img { height: 100%; width: auto; }
  /* start position for the scroll: 209 lands the crop inside Matterhorn on the
     left and inside Cozy Meadows on the right, the pair figma shows cut */
  .bento-grid .cm-track { margin-left: calc(-209 * var(--bento-u)); }

  /* ---- 7x7 ft Play Space / Cast to Your TV (369x454, figma 34812:119668) ---- */
  .bento-grid .b-space,
  .bento-grid .b-tv {
    align-items: center;
    justify-content: flex-start;
    padding: calc(20 * var(--bento-u)) 0 0;
  }
  .bento-grid .b-space .b-title,
  .bento-grid .b-space .b-sub { width: 100%; padding-inline: calc(16 * var(--bento-u)); }
  .bento-grid .b-tv .b-title,
  .bento-grid .b-tv .b-sub { width: 100%; padding-inline: calc(24 * var(--bento-u)); }
  .bento-grid .b-space .b-sub { margin-top: calc(8 * var(--bento-u)); }
  .bento-grid .b-tv .b-sub { margin-top: calc(4 * var(--bento-u)); }
  /* the AirPlay / Chromecast pills are this tile's sub at every width now.
     They were sized against the 13px mobile sub, so on desktop they have to
     join the figma-pixel system like everything else in this block - a fixed
     14px would be right at the 1520 band and a third too big at 990. */
  .bento-grid .b-tv .b-sub-pills {
    gap: calc(6 * var(--bento-u));
    margin-top: calc(8 * var(--bento-u));
  }
  .bento-grid .b-tv .bm-pill {
    font-size: calc(14 * var(--bento-u));
    gap: calc(6 * var(--bento-u));
    padding: calc(8 * var(--bento-u)) calc(13 * var(--bento-u));
  }
  .bento-grid .b-tv .bm-pill svg {
    width: calc(15 * var(--bento-u));
    height: calc(15 * var(--bento-u));
  }
  /* the art hugs the card's bottom edge, so the corners carry no gap */
  .bento-grid .b-space img,
  .bento-grid .b-tv img {
    height: auto;
    margin: auto 0 0;
    flex: none;
    border-radius: 0;
    object-fit: cover;
  }
  .bento-grid .b-space img { width: 100%; aspect-ratio: 738 / 651; }
  .bento-grid .b-space .b-floor { width: 100%; margin: auto 0 0; flex: none; }
  /* tv art bakes in its own card-grey backdrop and runs 349 of the 369 card */
  .bento-grid .b-tv img { width: 94.58%; aspect-ratio: 350 / 332; }

  /* ---- Accuracy Powered by Benchmark Motion (1519x126) ---- */
  .bento-grid .b-ai-strip {
    flex-direction: row;
    align-items: center;
    justify-content: center;
    gap: calc(24 * var(--bento-u));
    height: calc(126 * var(--bento-u));
    min-height: 0;
    padding: 0;
    border-radius: 4px;
    background: var(--surface-cool);
    text-align: left;
  }
  .bento-grid .b-ai-strip > div {
    flex: none;
    width: calc(405 * var(--bento-u));
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: calc(2 * var(--bento-u));
    text-align: left;
  }
  .bento-grid .b-ai-strip h3 {
    width: 100%;
    font-size: calc(20 * var(--bento-u));
    font-weight: 600;
    line-height: 1.3;
    letter-spacing: 0;
  }
  .bento-grid .b-ai-strip p {
    margin-top: 0;
    font-size: calc(16 * var(--bento-u));
    line-height: 1.5;
    color: var(--ink);
  }
  .bento-grid .b-ai-strip .ai-badge {
    flex: none;
    height: calc(126 * var(--bento-u));
    width: auto;
  }
}

/* ---- Simulation Mat: the scan pass over the mat art ----
   Paul (Aug 24): "maybe this image should have a scan effect ... take context
   from the how-it-works page". This is the step-4 scan pass from the
   story-scroll /pages/app build (hw-scan-sweep / hw-scan-slide / hw-mat-outline
   / hw-mat-dot), retimed to one 4s loop and re-traced in the bento art's own
   252x252 space: the mat body is the quad M28 56H209L233 251H4Z and the chalk
   strike patch measures x92-145 y78-150 with its ball down to y160.

   The <img> used to be the flex item. It is now wrapped in .b-mat-media, which
   takes the img's exact box at every breakpoint so the overlay has something to
   sit on - the rules below are the old .b-side img / .bento-grid .b-mat img
   values moved onto the wrapper and scoped to .b-mat, so the app tile keeps
   every rule it had. The svg mirrors the photo's object-fit with one
   xMaxYMid slice: below 990 the photo is cover from the right, and at 990+ the
   wrapper is the square the contained art already occupied, where slice and
   meet agree. Blue is the site --blue, not the how-it-works yellow (a net-new
   palette colour there - open question for Paul). */
.bento-grid .b-mat .b-mat-media {
  position: relative;
  display: block;
  min-width: 0;
}
.bento-grid .b-mat .b-mat-media img {
  display: block;
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  margin: 0;
}
.b-mat-scan {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

@media (max-width: 989.98px) {
  /* the old .bento-grid .b-side img box: figma bleeds the photo to the card's
     top, right and bottom edges, so +20/-10 cancels the card's vertical padding
     and auto-left pins it to the right edge */
  .bento-grid .b-mat .b-mat-media {
    width: 45%;
    height: calc(100% + 20px);
    margin-block: -10px;
    margin-left: auto;
    flex: none;
  }
  /* Paul (Aug 24): the mat art must never be cut off. It used to be cover from
     the right, which bled the mat's right edge off the tile; contain shows the
     whole graphic. The scan svg switches with it (xMidYMid meet below), so the
     overlay still lands on the same pixels. */
  .bento-grid .b-mat .b-mat-media img {
    object-fit: contain;
    object-position: center;
  }
}

@media (min-width: 990px) {
  /* the old .bento-grid .b-mat img box: the art is a square floating on
     transparency, contained in the space left of the copy and centred. The
     wrapper is that square (the flex width, which is the short side), so the
     img renders exactly as it did and the svg lands 1:1 on it. */
  .bento-grid .b-mat .b-mat-media {
    flex: 1 1 auto;
    width: auto;
    max-width: none;
    height: auto;
    max-height: 100%;
    aspect-ratio: 1 / 1;
    align-self: center;
    margin: 0;
  }
  .bento-grid .b-mat .b-mat-media img {
    object-fit: contain;
    object-position: center;
  }
}

/* rest state: nothing paints until .is-scanning, so a blocked script leaves the
   plain photo exactly as it is today */
.b-mat-tint {
  fill: var(--blue);
  fill-opacity: 0.12;
  transform: translateY(56px);
  opacity: 0;
}
.b-mat-sweep {
  transform: translateY(56px);
  opacity: 0;
}
.b-mat-lock-fill {
  fill: var(--blue);
  fill-opacity: 0.12;
  opacity: 0;
}
.b-mat-lock {
  fill: none;
  stroke: var(--blue);
  stroke-width: 2;
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  opacity: 0;
}
.b-mat-dots {
  fill: var(--blue);
  stroke: #ffffff;
  stroke-width: 1.2;
}
.b-mat-dot {
  transform-box: fill-box;
  transform-origin: center;
  transform: scale(0);
  opacity: 0;
}

/* one 4s cycle: the bar leaves the mat's top edge at 8%, clears the bottom at
   44% (it crosses the strike patch between 12% and 26%) with the tint welded to
   its trailing edge, the strike area locks on behind it - corners at 30-36%,
   outline drawn by 50% - everything holds to 78% and fades by 88%. Only the bar
   and the dots move, and both move on transform, so the loop is composited. */
.b-mat.is-scanning .b-mat-sweep { animation: bm-mat-sweep 4s linear infinite; }
.b-mat.is-scanning .b-mat-tint { animation: bm-mat-tint 4s linear infinite; }
.b-mat.is-scanning .b-mat-dot { animation: bm-mat-dot 4s var(--bm-ease, cubic-bezier(0.22, 1, 0.36, 1)) var(--d, 0s) infinite; }
.b-mat.is-scanning .b-mat-lock { animation: bm-mat-lock 4s var(--bm-ease, cubic-bezier(0.22, 1, 0.36, 1)) infinite; }
.b-mat.is-scanning .b-mat-lock-fill { animation: bm-mat-lock-fill 4s ease-in-out infinite; }

@keyframes bm-mat-sweep {
  0%, 8% { transform: translateY(56px); opacity: 0; }
  12% { opacity: 1; }
  44% { transform: translateY(252px); opacity: 1; }
  50%, 100% { transform: translateY(252px); opacity: 0; }
}

@keyframes bm-mat-tint {
  0%, 8% { transform: translateY(56px); opacity: 0; }
  12% { opacity: 1; }
  44%, 78% { transform: translateY(252px); opacity: 1; }
  88%, 100% { transform: translateY(252px); opacity: 0; }
}

@keyframes bm-mat-dot {
  0%, 30% { transform: scale(0); opacity: 0; }
  34% { transform: scale(1.3); opacity: 1; }
  36%, 78% { transform: scale(1); opacity: 1; }
  88%, 100% { transform: scale(0.6); opacity: 0; }
}

@keyframes bm-mat-lock {
  0%, 36% { stroke-dashoffset: 1; opacity: 0; }
  38% { opacity: 0.85; animation-timing-function: linear; }
  50%, 78% { stroke-dashoffset: 0; opacity: 0.85; }
  88%, 100% { stroke-dashoffset: 0; opacity: 0; }
}

@keyframes bm-mat-lock-fill {
  0%, 44% { opacity: 0; }
  52%, 78% { opacity: 1; }
  88%, 100% { opacity: 0; }
}

/* motion opt-out: the driver still adds .is-scanning, so kill the loops and pin
   the overlay on its landed frame instead of leaving the photo bare - the same
   contract the how-it-works overlays use */
@media (prefers-reduced-motion: reduce) {
  .b-mat.is-scanning .b-mat-sweep,
  .b-mat.is-scanning .b-mat-tint,
  .b-mat.is-scanning .b-mat-dot,
  .b-mat.is-scanning .b-mat-lock,
  .b-mat.is-scanning .b-mat-lock-fill { animation: none; }
  .b-mat.is-scanning .b-mat-tint { transform: translateY(252px); opacity: 1; }
  .b-mat.is-scanning .b-mat-lock { stroke-dashoffset: 0; opacity: 0.85; }
  .b-mat.is-scanning .b-mat-lock-fill { opacity: 1; }
  .b-mat.is-scanning .b-mat-dot { transform: none; opacity: 1; }
}

/* Play at Home runs on the same band as the bento in figma, but .rail insets it
   to --container — put its first card back on the page gutter. */
.tile-rail { padding-inline: var(--pad-x); }

/* swipe position dots. Desktop lays all four modes out at once, so they only
   exist below the breakpoint. Same 6 -> 8px geometry as the gallery's
   .pdp-dots, repainted for a light background: those sit on a photo and get
   their contrast from a white ring, these sit on --paper. */
.tile-dots { display: none; }

@media (max-width: 989.98px) {
  .tile-dots {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    margin-top: 18px;
  }
  .tile-dots span {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: rgba(15, 16, 16, 0.22);
    transition: width var(--dur-1) var(--ease-out), height var(--dur-1) var(--ease-out), background-color var(--dur-1);
  }
  .tile-dots span.is-active { width: 8px; height: 8px; background: var(--ink); }
}

/* ---------- Coaching at Home: the Play at Home band, mirrored ----------
   Paul (Aug 24): "below solo play, local party, ranked match, virtual match,
   you could do a duplicate section, one with the background color, which
   talked about coaching. Maybe flip the graphics for coaching."
   The band reuses .tiles / .tile / .tile--sm / .tile--mode / .tile-rail--4
   verbatim, so it inherits the 71.5vw mobile swipe, the four-across desktop
   grid and the dots above without a single shared rule being touched. Play at
   Home has to stay byte-identical, so everything here is scoped to .coach-sec
   or to the .tile--flip modifier, which nothing else in the theme uses. */
.coach-sec { background: var(--surface-cool); }

/* Share the game is --surface (#f4f3f1) and follows this band directly, so two
   tinted bands would touch and read as one grey block. The sibling selector
   only fires when the coaching band is actually rendered, which puts the page
   back on white / grey / white; switch the band off in the section settings
   and Share keeps the colour it has today. */
.coach-sec ~ .share-sec { background: var(--paper); }
/* Paul (Aug 24): flipping Share to white so the page alternates left its four
   point cards white on white - they are var(--paper) with border:0 from 990 up,
   which only ever read as cards because the section behind them was the warm
   --surface. Give them the cool grey the bento tiles use, so each point is its
   own block again wherever the flip applies. */
.coach-sec ~ .share-sec .share-point {
  background: var(--surface-cool);
  border-color: transparent;
}

/* the flip itself: Play at Home hangs its phone off the right edge and sets
   the caption bottom-left, so coaching does the mirror of both. Photographs
   are not mirrored, which would hand every golfer the wrong hand. */
.tile--flip .tm-phone { left: 4.14%; right: auto; }
.tile--flip figcaption { text-align: right; align-items: flex-end; }

/* Improve at Home sits on the same band and the same 363x420 card as Play at
   Home in figma — it was running a 36px gutter and a slightly wider card. */
@media (min-width: 750px) {
  .improve-grid--4 { gap: 24px; }
}
.imp-card { aspect-ratio: 362 / 420; }

/* Ranked Match ships from figma as one flat tile — phone overlay, gradient and
   caption are all baked into the art, so the layered versions would double up.
   The caption text lives in the img alt instead. */
.tile--flat::after { content: none; }

/* At the Range: same 1520px band as the sections above (was --container), and
   figma splits it 429 photo / 28 gutter / 454 feature list, not 1.1fr / 1fr. */
@media (min-width: 900px) {
  .course-grid { grid-template-columns: 429fr 454fr; column-gap: 3.07%; }
  /* the map's aspect-ratio was sizing it off its own height, flooring column 1
     and then overflowing into the feature list — figma just fills the cell, and
     the photo's own object-fit: cover handles the crop */
  .course-grid > .course-map {
    min-width: 0;
    aspect-ratio: auto;
    width: 100%;
    height: 100%;
  }
}
/* figma runs this sub at Colors/Black like every other section sub */
.course-sec .section-head .bm-sub { color: var(--ink); }

/* Ratings & Reviews ships on its own 1304px band, which left its heading and
   cards inside every other section on the page. Put it on the same 1520 band
   the bento, tiles and At the Range sections run (.bm-container--wide) so the
   whole page shares one left edge. Scoped to this stylesheet, which only loads
   on the benchmark PDP template. */
.jm-reviews-section .jm-reviews-wrap {
  --jm-pad-x: clamp(16px, 4vw, 48px);
  max-width: calc(1520px + var(--jm-pad-x) * 2);
  padding-inline: var(--jm-pad-x);
}
@media (min-width: 990px) {
  .jm-reviews-section .jm-reviews-wrap {
    --jm-pad-x: var(--pad-x);
    /* follow the shared 1520 band, capped like .bm-container so 4k/1x
       centres the masonry instead of running four giant columns */
    max-width: calc(1520px + var(--jm-pad-x) * 2);
  }
}
@media (max-width: 989.98px) {
  .jm-reviews-section .jm-reviews-wrap { --jm-pad-x: 12px; }
}

/* the footer holds a 1520px band against a 16px gutter, so it only lands on the
   page's 200px line at exactly 1920 and runs wider than every section above it
   below that. Put it on the same gutter instead — identical at 1920, aligned
   everywhere else. Two classes deep because footer-benchmark.css loads after
   this file, and scoped to this stylesheet, which is PDP-only. */
@media (min-width: 990px) {
  .footer-benchmark.footer-benchmark { padding-inline: var(--pad-x); }
  .footer-benchmark .footer-benchmark__top,
  .footer-benchmark .footer-benchmark__divider,
  .footer-benchmark .footer-benchmark__bottom { max-width: none; }
}

/* the fixed ATC bars sit over the end of the page, which buried the footer's
   copyright + payment row. Reserve their height under the footer so that row
   stays visible like figma. Scoped to this stylesheet (benchmark PDP only). */
/* figma closes the footer 32px under the copyright row (34814:13705). The bars
   used to be cleared with padding, which added ~64px to the footer; they now
   retract while the footer's last row is on screen (benchmark-pdp.js), so the
   row stays readable on figma's spacing. */
body:has(.bm-pdp) .footer-benchmark {
  padding-bottom: 32px;
}

/* ============================================================
   Motion
   ============================================================ */

/* The PDP runs without entrance motion: the gallery, buy box and every
   [data-reveal] section land in their final state immediately. The shared
   benchmark-reveal.css still animates the other benchmark pages. */
.bm-pdp [data-reveal] {
  transition: none;
}
.bm-pdp [data-reveal].pre-reveal:not(.in-view) {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  .cm-track {
    animation: none !important;
  }
}

/* ============================================================
   Founding Members upsell modal (figma 35026:23750)
   ============================================================ */

.fm-modal {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
}

.fm-modal[hidden] { display: none; }

/* figma 35026:23748: black at 24% with a 1px blur over the page */
.fm-modal__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.24);
  backdrop-filter: blur(1px);
  opacity: 0;
  transition: opacity var(--dur-1) var(--ease-out);
}

.fm-modal.is-open .fm-modal__backdrop { opacity: 1; }

.fm-modal__card {
  position: relative;
  width: 480px;
  max-width: 100%;
  max-height: calc(100dvh - 32px);
  overflow: auto;
  background: #fff;
  border-radius: 24px;
  /* the extra top padding is headroom for .fm-modal__close, which floats in
     the card's top-right corner above the full-width trust bar */
  padding: 44px 32px 32px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  text-align: left;
  opacity: 0;
  transform: translateY(12px) scale(0.98);
  transition: opacity var(--dur-1) var(--ease-out), transform var(--dur-1) var(--ease-out);
}

.fm-modal.is-open .fm-modal__card {
  opacity: 1;
  transform: none;
}

.fm-modal__card:focus { outline: none; }

/* desktop keeps the flat card layout; the wrapper only exists for the sheet */
.fm-modal__body { display: contents; }

/* mobile-only sheet affordance; the mobile block below switches it on */
.fm-modal__handle { display: none; }

/* Paul (Aug 22 POV @2:07): a pop-up needs a real close control. It reads as
   "close", but dismissing the upsell adds just the simulator - see
   dismissFmModal in benchmark-pdp.js. */
.fm-modal__close {
  position: absolute;
  top: 8px;
  right: 8px;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: #f3f3f4;
  color: var(--ink);
  cursor: pointer;
}

.fm-modal__close svg { display: block; }

.fm-modal__trust {
  margin: 0;
  width: 100%;
  padding: 6px 24px;
  border-radius: 24px;
  background: linear-gradient(90deg, #6d1943 0%, #b0356b 49.519%, #6d1943 100%);
  color: #fff;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.3;
  text-align: center;
}

.fm-modal__meta {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.fm-modal__tag {
  padding: 6px 12px;
  border-radius: 4px;
  background: linear-gradient(90deg, #6d1943 0%, #b0356b 49.519%, #6d1943 100%);
  color: #fff;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.3;
}

.fm-modal__expiry {
  color: #ad3469;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.3;
}

.fm-modal__title {
  margin: 0;
  width: 100%;
  color: var(--ink);
  font-size: 16px;
  font-weight: 600;
  line-height: 1.5;
}

.fm-modal__media {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 8px;
}

.fm-modal__plus { flex: none; }

.fm-modal__tile {
  position: relative;
  flex: 1;
  min-width: 0;
  aspect-ratio: 1;
  border-radius: 4px;
  overflow: hidden;
  background: #f3f3f4;
}

/* the bundle assets are square and already framed like the figma tiles */
.fm-modal__tile img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.fm-modal__off {
  position: absolute;
  left: 8px;
  top: 7.5px;
  padding: 2px 4px;
  border-radius: 2.5px;
  background: #ffc32c;
  color: var(--ink);
  font-size: 10px;
  font-weight: 600;
  line-height: 1.3;
}

.fm-modal__list {
  list-style: none;
  margin: 0;
  padding: 0;
  width: 100%;
}

.fm-modal__list li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 6px 0;
}

.fm-modal__item-label {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: var(--ink);
  font-size: 12px;
  font-weight: 600;
  line-height: 1.3;
}

.fm-modal__check { flex: none; }

.fm-modal__info {
  position: relative;
  display: inline-flex;
  width: 14px;
  height: 14px;
  cursor: help;
}

.fm-modal__info svg { width: 14px; height: 14px; }

.fm-modal__tip {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  translate: -50% 0;
  z-index: 2;
  width: max-content;
  max-width: 220px;
  padding: 8px 10px;
  border-radius: 6px;
  background: var(--ink);
  color: var(--paper);
  font-size: 12px;
  font-weight: 400;
  line-height: 1.4;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--dur-1);
}

.fm-modal__info:hover .fm-modal__tip,
.fm-modal__info:focus-visible .fm-modal__tip {
  opacity: 1;
  visibility: visible;
}

.fm-modal__price {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  white-space: nowrap;
  line-height: 1.3;
}

.fm-modal__price s {
  color: #6d6a67;
  font-size: 12px;
  font-weight: 400;
}

.fm-modal__price b {
  color: var(--ink);
  font-size: 12px;
  font-weight: 700;
}

.fm-modal__rule {
  width: 100%;
  height: 1px;
  margin: 0;
  border: 0;
  background: #e5e6ed;
}

.fm-modal__total {
  display: flex;
  align-items: center;
  gap: 10px;
  padding-top: 2px;
}

.fm-modal__total strong {
  color: var(--ink);
  font-size: 20px;
  font-weight: 600;
  line-height: 1.3;
}

.fm-modal__total s {
  color: #6d6d6d;
  font-size: 16px;
  font-weight: 400;
  line-height: 1.5;
}

.fm-modal__save {
  padding: 4px 8px;
  border-radius: 4px;
  background: #ffc32c;
  color: var(--ink);
  font-size: 14px;
  font-weight: 600;
  line-height: 1.4;
  white-space: nowrap;
}

/* the coaching infographic is flat artwork, not a box shot — keep it whole */
.fm-modal__tile--coaching img { object-fit: contain; }

.fm-modal__terms {
  margin: 0;
  width: 100%;
  color: #6d6a67;
  font-size: 11px;
  font-weight: 400;
  line-height: 1.4;
}

.fm-modal__getit {
  margin: 0;
  padding: 0 40px;
  color: #6d6d6d;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.4;
  text-align: center;
}

.fm-modal__decline {
  width: 100%;
  height: 56px;
  padding: 0 32px;
  border: 0;
  border-radius: 10px;
  background: #f3f3f4;
  color: var(--ink);
  font-size: 14px;
  font-weight: 600;
  line-height: 21px;
  text-decoration: underline;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

/* ------------------------------------------------------------
   Mobile: the upsell is a native-style bottom sheet again.
   Paul (Aug 24 design review): "Previously the popup extended to the
   sides and bottom of the screen. It extended from the bottom up.
   Which is better than a popup like this... popups like this are more
   ignored... we've been trained for 10 years: this means like an ad."
   A centred card gets rejected on instinct; anchored to the bottom
   edge, edge to edge, sliding up, it reads as part of the page.
   Do NOT flip this back to a centred card (that was the Aug 22 POV
   @2:07 call, reversed on Aug 24).
   Dismiss semantics are unchanged: backdrop, Escape, the decline line
   and a drag-away all complete the plain simulator add - see
   dismissFmModal in benchmark-pdp.js.
   Same breakpoint as the rest of the mobile PDP (sticky ATC).
   ------------------------------------------------------------ */
@media (max-width: 989.98px) {
  .fm-modal {
    align-items: flex-end;
    padding: 0;
  }

  .fm-modal__card {
    width: 100%;
    max-width: none;
    max-height: 92dvh;
    border-radius: 20px 20px 0 0;
    padding: 0 20px calc(20px + env(safe-area-inset-bottom));
    gap: 0;
    overflow: hidden;
    box-shadow: 0 -8px 30px rgba(0, 0, 0, 0.18);
    /* the desktop base fades in with a 12px rise, so BOTH its opacity and
       its transform have to be overridden or the sheet fades in place
       instead of sliding. 0.42s must stay <= the 450ms closeTimer in
       benchmark-pdp.js, which holds the scroll lock until the slide is
       fully off screen; move the two together or not at all. */
    opacity: 1;
    transform: translateY(100%);
    transition: transform 0.42s var(--ease-out);
    will-change: transform;
  }

  .fm-modal.is-open .fm-modal__card { transform: translateY(0); }

  /* same toolbar-transition bleed as .sticky-atc::after: continue the
     sheet's white past the layout-viewport edge so an iOS toolbar collapse
     never shows a strip of raw page under its hard bottom edge. Lives on
     .fm-modal, not the card, because the card is overflow: hidden; gone
     entirely while [hidden] because .fm-modal[hidden] { display: none }. */
  .fm-modal::after {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    top: 100%;
    height: 120px;
    background: #fff;
  }

  /* no transition while the finger owns the sheet */
  .fm-modal.is-dragging .fm-modal__card,
  .fm-modal.is-dragging .fm-modal__backdrop { transition: none; }

  /* the standard sheet affordance, and the drag-to-dismiss hit area:
     dragging it away is the same resolution as a backdrop tap (adds just
     the simulator) - see the sheet drag block in benchmark-pdp.js */
  .fm-modal__handle {
    display: block;
    flex: none;
    width: 44px;
    height: 4px;
    margin: 10px auto 12px;
    border-radius: 999px;
    background: #d5d7dd;
    touch-action: none;
    cursor: grab;
  }

  /* generous drag target around the 4px pill; absolute against the card,
     which is the nearest positioned ancestor */
  .fm-modal__handle::before {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    height: 32px;
  }

  /* the card itself stays put; only the offer scrolls. benchmark-scroll-lock.js
     names .fm-modal__body as the one scroller touch may move while the lock
     is on, so this has to stay a real scroller. */
  .fm-modal__body {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    width: 100%;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    padding-bottom: 2px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .fm-modal__backdrop,
  .fm-modal__card {
    transition: none;
  }
}

/* ============================================================
   Aug 24 Intelligems split tests — GAH PDP Add to Cart
   (lane pdp-atc-split-tests)

   Every rule below is inert until <html> carries a flag class that
   layout/theme.liquid writes synchronously from window.GD_FLAGS, so the
   default page is byte-for-byte the page that shipped before this block.
     .gd-atc-price      TEST 1  price inside the Add to Cart label
     .gd-atc-fold       TEST 2  arm B, mobile Add to Cart under the price
     .gd-atc-fold-tight TEST 2  arm B + 4:3 hero stage on short viewports
     .gd-atc-sticky     TEST 2  arm C, mobile sticky bar shown from load
   ============================================================ */

/* TEST 1 — the price span ships in the markup on every load so Intelligems
   has something tagged to rewrite whichever arm the visitor lands in; only
   the flag class reveals it. Weight 500 and nowrap match the legacy
   .product-form__submit-price that golfdaddy.com still runs
   (assets/section-main-product-custom.css:332). */
.bm-pdp .bb-atc__price { display: none; font-weight: 500; white-space: nowrap; }
html.gd-atc-price .bm-pdp .bb-atc__price { display: inline; }

@media (max-width: 989.98px) {
  /* TEST 2 arm B — Paul (Aug 24): "when you first jump on this page, do you
     see the add to cart button? It's cut off." The four bullets are 148px of
     the reason: the base order layer at line 2166 puts them between the price
     and the button. This arm lifts the button (and its delivery line) above
     them for the test group only. It must outrank that block, which is
     !important at 0,2,0, hence html.gd-atc-fold .bm-pdp .buybox (0,4,0). */
  /* Aug 28, Paul: TEST 2 arm B declared the WINNER — above-the-fold ATC is
     now the permanent default for everyone (selector no longer gated on the
     arm class; the flag/QA param can no longer revert it). */
  .bm-pdp .buybox .bb-atc { order: 4 !important; }
  .bm-pdp .buybox .bb-getit { order: 5 !important; }
  .bm-pdp .buybox .bb-bullets { order: 6 !important; }

  /* TEST 2 arm C — mirror of the .show class benchmark-pdp.js toggles once the
     buy box scrolls off, without touching that observer: the bar is simply up
     from load. Above the fold at any viewport height by construction, at the
     cost of 76px of bottom chrome. */
  html.gd-atc-sticky .bm-pdp .sticky-atc { transform: none; visibility: visible; opacity: 1; } /* reduced-motion path hides via opacity */
}

/* TEST 2 arm B, "tight" variant — the order swap alone still leaves the button
   a few px under the fold on 390x844 and 375x667 phones, where Safari's first
   paint is only ~664px tall. Cropping the hero stage from the figma 1:1 to 4:3
   on short viewports buys ~90px more. Changes the hero video framing, so it is
   a separate arm and needs Paul's sign-off before it runs. */
@media (max-width: 989.98px) and (max-height: 700px) {
  html.gd-atc-fold-tight .bm-pdp .pdp-rail img,
  html.gd-atc-fold-tight .bm-pdp .pdp-rail video.pdp-hero-video { aspect-ratio: 4 / 3; }
}

/* ---------------------------------------------------------------------------
   GAH-BUNDLE-01, arm A: no bundle surfaces on the Golf At Home PDP.

   These rules only paint the first frame. benchmark-pdp.js then REMOVES the
   nodes, because both cards run live countdown timers and the upsell modal
   must not merely be hidden (the ATC wiring is an element-existence check).
   The .gd-no-bundle class is written in <head> and is scoped in theme.liquid
   to this one template, so /products/benchmarkgolf-launch-bundle keeps its
   own .lb-card.

   Assets are deliberately NOT gated: both arms load identical bytes, or the
   test would measure page weight rather than the bundle.
   --------------------------------------------------------------------------- */
.gd-no-bundle .section-launch-bundle-benchmark,
.gd-no-bundle .lb-card,
.gd-no-bundle .fm-modal {
  display: none !important;
}

/* ---------------------------------------------------------------------------
   GAH-HERO-01, arm A: the living-room loop is removed entirely.

   No replacement slide is inserted. The gallery already carries the studio
   follow-through as slide 1, so hiding the video simply promotes it to first.
   An inserted slide would have shifted every data-slide-to index and pointed
   the thumbnails at the wrong photos.

   The video's own thumbnail goes with it (Paul: "just don't have that image
   show, even at bottom"). display:none keeps DOM order intact, so the
   remaining data-slide-to indices stay correct.
   --------------------------------------------------------------------------- */
html.gd-hero-still .bm-pdp video.pdp-hero-video { display: none !important; }
html.gd-hero-still .bm-pdp .pdp-thumb--video { display: none !important; }

/* ---------------------------------------------------------------------------
   GAH-DROP-01: the buy-box price rolls $299 -> $119 on first paint (arm B).

   Two jobs here, and NOTHING is CSS-animated - the control arm has no rule at
   all, and arm B's motion is a rAF tween in assets/benchmark-price-drop.js.

   1. The first-paint gate. layout/theme.liquid adds html.gd-drop-pending in
      <head> on the GAH template and lifts it when the arm is known (or on
      ig:ready / a 3000ms cap). This file is a blocking stylesheet_tag at the
      top of benchmark-pdp-main, ahead of the buy box in DOM order, so the
      rule is in force before the price can ever paint. visibility, not
      display: the row keeps its box, so lifting the gate moves nothing.
      ONE gate rule, in ONE file, anchored at html - the
      benchmark-labor-day.css lesson: a second copy in a later stylesheet is
      how two arms end up stacked.

   2. The roll overlay. The stamped <strong> is owned by the DEAL-5 follower
      (assets/benchmark-deal-price.js rewrites its textContent whenever it
      differs), so the tween never writes into it: it paints a sibling
      .bb-price__roll positioned over the <strong> while the <strong> itself
      goes color:transparent (its box, and so the struck price and badge
      beside it, stay exactly where they are - no CLS). Same 24/600/1.3 as
      .bb-price strong above, tabular digits so the frames do not jitter.
      The <strong> gets tabular digits too, but ONLY under the arm class:
      the roll's last frame hands off to the <strong>'s own $119, and the
      glyphs must not shift at that instant - yet arm A, the pad PDP and the
      bundle PDP (both load this file and render a .bb-price) have no roll,
      and the A/B comparison must not carry an A-side rendering change that
      is not the thing being measured. The class is written before the gate
      lifts (theme.liquid refuses it after a static release), so it never
      toggles on a price the visitor can already see.
      Reduced motion and forced colors (Windows High Contrast repaints author
      colours, so the transparent <strong> would print through the overlay)
      hide the overlay outright; the script also bails for both, and apply()
      withholds the arm class, so those visitors get the Liquid $119
      untouched and count as a_static.
   --------------------------------------------------------------------------- */
html.gd-drop-pending .bm-pdp .buybox .bb-price { visibility: hidden; }

html.gd-price-drop .bb-price strong { font-variant-numeric: tabular-nums; }

.bb-price { position: relative; }

.bb-price__roll {
  position: absolute;
  font-size: 24px;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: 0;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .bb-price__roll { display: none; }
}

@media (forced-colors: active) {
  .bb-price__roll { display: none; }
}

/* ---------------------------------------------------------------------------
   GAH-PHOTO-01: the Local Party slide, thumb and dot ship in the markup; the
   arm class is the only thing that shows them. Negated so the elements keep
   their natural display when the class is on (picture: contents, thumb: the
   .pdp-thumbs flex item, dot: the .pdp-dots flex item). Every selector in
   this block carries the gate. The hero-still rules above are untouched.
   --------------------------------------------------------------------------- */
html:not(.gd-party-photo) .bm-pdp [data-gd-party] { display: none !important; }
