/* Ball Anatomy — scroll section on a PolaraDS dark surface.
   Tokens only (--pg-*); the one red in view is the spin-axis line. */
.ba {
  --ba-ink: var(--pg-color-white);
  --ba-dim: rgb(255 255 255 / 0.66);
  --ba-rule: rgb(255 255 255 / 0.22);
  background: var(--pg-bg-dark);
  color: var(--ba-ink);
}
.ba h2,
.ba h3 { color: inherit; }

.ba__intro {
  padding-block: var(--pg-space-8) var(--pg-space-7);
  text-align: center;
}
/* Desktop: the intro lies over the top of the first stop instead of pushing the stage down,
   so the page opens on the whole ball, centred, with the heading above it (v2 note 1). It
   scrolls away with the move to stop 1. On a phone the ball already sits right under it. */
@media (min-width: 900px) {
  .ba { position: relative; }
  .ba__intro {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    z-index: 2;
    padding-block: var(--pg-space-6) 0;
    pointer-events: none;
    transition: opacity var(--pg-duration-fast) var(--pg-ease);
  }
  /* Only while we are still on it. See updateNav: clicking through never scrolls the page, so
     without this the heading sits over the ball for the whole film. On a phone the intro is in
     the flow and pushes the stage down, so there is nothing to hide and this does not apply. */
  .ba--past-opening .ba__intro { opacity: 0; }
}
.ba__intro .pg-section-heading { margin-bottom: var(--pg-space-4); }
/* 52ch, not 44: at 44 the lead set in four lines with "happens" alone on the last
   (Jake, 2026-09-28 and again 2026-09-30). Measured against a render, not guessed. */
.ba__lead {
  max-width: 52ch;
  margin-inline: auto;
  font-size: var(--pg-text-lead);
  line-height: 1.5;
  color: var(--ba-dim);
}
/* The payoff, on its own line so it is not the tail of the explanation (Jake, 2026-09-26). */
.ba__lead--payoff { margin-top: var(--pg-space-3); color: var(--ba-ink); }

.ba__track { position: relative; height: 800vh; }   /* one viewport per stop; JS sets the exact height */
.ba__stage {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100svh;
  overflow: hidden;
}
.ba__canvas { position: absolute; top: 0; left: 0; }
.ba__lines {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}

/* ── Leaders: a black under-stroke keeps the white line legible over the white ball ── */
.ba-leader__under,
.ba-leader__over {
  fill: none;
  stroke-dasharray: 1;
  stroke-linejoin: round;
}
.ba-leader__under { stroke: var(--pg-color-black); stroke-width: 3; }
.ba-leader__over { stroke: var(--pg-color-white); stroke-width: 1; }
.ba-leader__dot { fill: var(--pg-color-black); stroke: var(--pg-color-white); stroke-width: 1.5; }

.ba-axis__under { stroke: var(--pg-color-black); stroke-width: 5; stroke-linecap: round; }
.ba-axis__over { stroke: var(--pg-accent); stroke-width: 2; stroke-linecap: round; }

/* ── Captions ── */
.ba__captions { margin: 0; padding: 0; list-style: none; }
.ba-caption {
  position: absolute;
  top: 0;
  left: 0;
  width: clamp(13rem, 19vw, 17rem);
  opacity: 0;
  will-change: transform, opacity;
}
.ba-caption[data-side='left'] { text-align: right; }
.ba-caption__index {
  display: block;
  margin-bottom: var(--pg-space-2);
  font-size: var(--pg-text-caption);
  color: var(--ba-dim);
}
.ba-caption__title { margin-bottom: var(--pg-space-2); line-height: 20px; }
.ba-caption__body { margin: 0; color: var(--ba-dim); }
.ba-caption[data-side='dock'] {
  padding-top: var(--pg-space-3);
  border-top: var(--pg-border-width) solid var(--ba-rule);
}

/* ── Robot-test stat ── */
.ba-stat {
  position: absolute;
  top: 0;
  left: 0;
  width: min(24rem, calc(100vw - 40px));
  margin: 0;
  opacity: 0;
}
.ba-stat__ratio {
  margin: 0 0 var(--pg-space-1);
  font-size: var(--pg-text-h2, var(--pg-text-h1));
  line-height: 1.1;
  font-weight: 700;
  color: var(--pg-color-white, #fff);
}
.ba-stat__label {
  margin-bottom: var(--pg-space-2);
  font-size: var(--pg-text-caption);
  text-transform: uppercase;
  color: var(--ba-dim);
}
.ba-stat__rows { display: grid; gap: var(--pg-space-2); margin: 0; }
.ba-stat__row { display: grid; grid-template-columns: 8rem 1fr; align-items: center; gap: var(--pg-space-2); }
.ba-stat__row dt { color: var(--ba-dim); }
/* A fixed value column, not `auto`: with flex the value sized itself and "27 yards" wrapped
   onto two lines in the 22rem card. A shared, fixed width also keeps both rows' bar tracks
   identical, which an `auto` column would not -- "27 yards" is wider than "7 yards", so the
   two bars would sit in tracks of different lengths and the ratio they exist to show would
   be wrong. */
.ba-stat__row dd { display: grid; grid-template-columns: 1fr 9.5rem; align-items: center;
  gap: var(--pg-space-2); margin: 0; }
.ba-stat__bar {
  height: 6px;
  width: calc(100% * var(--ba-bar));
  background: var(--pg-color-gray-500);
  transform: scaleX(var(--ba-reveal, 0));
  transform-origin: left;
}
.ba-stat__row--polara dt,
.ba-stat__row--polara .ba-stat__value { color: var(--ba-ink); }
.ba-stat__row--polara .ba-stat__bar { background: var(--pg-color-white); }
.ba-stat__value { font-size: var(--pg-text-card-title); color: var(--ba-dim); white-space: nowrap; }
.ba-stat__takeaway {
  margin: var(--pg-space-3) 0 0; color: var(--ba-dim); }
.ba-stat__takeaway strong { font-weight: 700; color: var(--ba-ink); }

/* ── Slogan ring (Polara's badge artwork, fitted to the resting ball) ── */
.ba-slogan {
  position: absolute;
  top: 0;
  left: 0;
  max-width: none;
  opacity: 0;
  pointer-events: none;
  will-change: opacity;
}

/* ── Spec strip + CTA ── */
.ba-specs {
  position: absolute;
  top: 0;
  left: 0;
  display: flex;
  align-items: center;
  gap: var(--pg-space-6);
  opacity: 0;
}
.ba-specs__heading { margin: 0 0 var(--pg-space-2); font-size: var(--pg-text-caption); text-transform: uppercase; color: var(--ba-ink); }
.ba-specs__list { display: flex; margin: 0; }
.ba-specs__list > div { padding-inline: var(--pg-space-6); border-left: var(--pg-border-width) solid var(--ba-rule); }
.ba-specs__list > div:first-child { padding-left: 0; border-left: 0; }
.ba-specs__list dt { font-size: var(--pg-text-caption); text-transform: uppercase; color: var(--ba-dim); }
.ba-specs__list dd { margin: var(--pg-space-1) 0 0; font-size: var(--pg-text-h1); white-space: nowrap; }
.ba-specs__note { max-width: 28ch; margin: 0; color: var(--ba-dim); }
/* Find Your Fit: Polara's own fitting assessment. The code is here to be scanned off a screen
   somebody else is holding, so the whole block is a link too and a reader on their own phone
   can just tap it. White tile and a wide quiet zone: scanners want dark-on-light. */
.ba-fit {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: var(--pg-space-2);
  margin-top: var(--pg-space-4);
  text-decoration: none;
}
.ba-fit__label {
  font-size: var(--pg-text-caption);
  text-transform: uppercase;
  color: var(--ba-dim);
}
.ba-fit:hover .ba-fit__label { color: var(--ba-ink); }
.ba-fit__qr {
  width: 88px;
  height: 88px;
  padding: 6px;
  background: var(--pg-color-white);
}
/* Desktop finale: a column beside the tee lockup. */
.ba-specs--column { flex-direction: column; align-items: flex-start; }
.ba-specs--column .ba-specs__list { flex-direction: column; gap: var(--pg-space-6); }
.ba-specs--column .ba-specs__list > div { padding: 0; border-left: 0; }

.ba__progress {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: var(--ba-rule);
}
.ba__progress span {
  display: block;
  height: 100%;
  background: var(--pg-color-white);
  transform: scaleX(0);
  transform-origin: left;
}
/* A quiet nudge at the foot of the stage, half a second after the ball settles on a caption:
   the page takes over the scroll, so a reader who stops reading needs telling it goes on. */
.ba__hint {
  position: absolute;
  left: 0;
  right: 0;
  bottom: var(--pg-space-5);
  z-index: 1;
  margin: 0;
  font-size: var(--pg-text-caption);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-align: center;
  color: var(--ba-dim);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.5s var(--pg-ease);
}
.ba__hint--on { opacity: 1; }
/* On a phone the hint sits under the dimple strip, which reserves room for it. */
@media (width <= 899px) { .ba__hint { bottom: 16px; } }

/* Chevrons at the bottom right: the same steps a scroll takes, for a reader who would rather
   click (Jake, 2026-09-24). Up goes back a caption, down goes on; during a move either one cuts
   it short and lands. Each is 44px, the smallest comfortable touch target. */
.ba__nav {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  transition: opacity var(--pg-duration-fast) var(--pg-ease);
}
/* The end card fills the stage top to bottom: the slogan ring reaches within a few pixels of
   the top and the specs panel runs to the bottom, so there is no room left for a 44px chevron
   at any screen size. They step aside for it and return on the way back out (see updateNav). */
.ba--finale .ba__nav {
  opacity: 0;
  pointer-events: none;
}
.ba__nav-btn {
  position: absolute;
  top: 0;
  left: 0;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  padding: 0;
  pointer-events: auto;
  --_bd: var(--ba-rule);
  --_bd-hover: var(--pg-color-white);
}
/* Hidden, not dimmed. At stop 0 there is nowhere to go back to, and on desktop the intro
   lies over the top of the stage rather than pushing it down -- so a dimmed-but-drawn back
   chevron opened the page sitting on the eyebrow and the heading (Jake, 2026-09-26). It
   keeps its 44px of space, so nothing below it moves when it returns at stop 1. */
.ba__nav-btn[disabled] { opacity: 0; pointer-events: none; }
/* A move is waiting on frames: the progress rail breathes instead of the ball stuttering. */
.ba--loading .ba__progress { animation: ba-wait 1.2s var(--pg-ease) infinite alternate; }
@keyframes ba-wait { from { opacity: 1; } to { opacity: 0.25; } }

@media (width <= 899px) {
  /* The end card: the spec rows sat side by side, 485px of them against a 360-430px screen, so
     the block ran off the left edge of every phone (Jake, 2026-09-24). They stack instead, and
     the block is held inside the screen. */
  .ba-specs { flex-direction: column; gap: var(--pg-space-4); width: min(calc(100vw - 32px), 24rem); }
  .ba-specs__list { flex-direction: column; gap: var(--pg-space-3); }
  .ba-specs__list > div { padding-inline: 0; border-left: 0; }
  .ba-specs__list dd { font-size: var(--pg-text-card-title); }
  .ba-specs__note { max-width: none; }
  .ba-fit__qr { width: 72px; height: 72px; padding: 5px; }
  .ba-fit { margin-top: var(--pg-space-3); }
}
.ba-map--gone { display: none; }   /* no room for the dimple strip under the captions */

/* ── ?static (QA): stacked key frames, nothing moves ── */
.ba--static .ba__track { height: auto; }
.ba--static .ba__stage { position: static; height: auto; overflow: visible; }
.ba--static .ba__canvas,
.ba--static .ba-slogan,
.ba--static .ba__lines,
.ba--static .ba__progress,
.ba--static .ba__nav { display: none; }
.ba--static .ba__captions {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: var(--pg-space-7) var(--pg-space-6);
  max-width: var(--pg-page-width);
  margin-inline: auto;
  padding: 0 var(--pg-page-gutter) var(--pg-space-7);
}
.ba--static .ba-caption,
.ba--static .ba-stat,
.ba--static .ba-result,
.ba--static .ba-specs { position: static; width: auto; opacity: 1; transform: none; }
.ba--static .ba-stat,
.ba--static .ba-specs { max-width: var(--pg-page-width); margin: 0 auto var(--pg-space-7); padding-inline: var(--pg-page-gutter); --ba-reveal: 1; }
.ba--static .ba-specs { flex-wrap: wrap; }
.ba--static .ba-specs__heading { flex-basis: 100%; }
.ba--static .ba-static__frame { width: 100%; height: auto; margin-bottom: var(--pg-space-4); }
.ba--static .ba__intro { position: static; padding-block: var(--pg-space-8) var(--pg-space-7); }

/* ── Flattened dimple map (stops 02-04; tools/make_dimple_map.py draws the SVG) ──
   The strip lights the zone the current captions talk about and veils the rest. */
.ba-map {
  position: absolute;
  top: 0;
  left: 0;
  margin: 0;
  opacity: 0;
  pointer-events: none;
  will-change: opacity;
}
.ba-map__svg { display: block; width: 100%; height: auto; overflow: visible; }
.ba-map__cover,
.ba-map__section { fill: #e6e6e2; }
.ba-map__d--shallow { fill: #d4d4cf; stroke: #9a9a95; stroke-width: 1; }
.ba-map__floor { fill: #dcdcd7; }
.ba-map__d--deep,
.ba-map__d--small { stroke: #5f5f5b; stroke-width: 0.6; }
.ba-map__edge { fill: none; stroke: var(--ba-rule); }
.ba-map__rule { stroke: var(--ba-dim); stroke-width: 1; stroke-dasharray: 3 3; }
.ba-map__tick { stroke: var(--ba-dim); }
.ba-map__veil { fill: var(--pg-bg-dark); opacity: 0; transition: opacity 0.45s var(--pg-ease); }
.ba-map__label {
  font-size: 13px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  fill: var(--ba-ink);
  transition: opacity 0.45s var(--pg-ease);
}
.ba-map__idx { fill: var(--ba-dim); }
.ba-map__foot { font-size: 12px; fill: var(--ba-dim); }
.ba-map[data-focus='band'] :is(.ba-map__veil, .ba-map__label)[data-zone='poles'],
.ba-map[data-focus='poles'] :is(.ba-map__veil, .ba-map__label)[data-zone='band'] { opacity: 0.62; }
.ba-map[data-focus='band'] .ba-map__label[data-zone='poles'],
.ba-map[data-focus='poles'] .ba-map__label[data-zone='band'] { opacity: 0.4; }
/* Desktop draws the standing strip, phones the lying one. --ba-map-k undoes the drawing's scale
   so the labels stay a fixed size; phones show a half strip drawn smaller, so type steps up. */
.ba-map__svg--v { display: none; width: 100%; }
.ba-map:not(.ba-map--half) .ba-map__svg--v { display: block; }
.ba-map:not(.ba-map--half) .ba-map__svg--h { display: none; }
.ba-map__svg--v .ba-map__label { font-size: calc(13px * var(--ba-map-k, 1)); }
.ba-map__svg--v .ba-map__foot { font-size: calc(12px * var(--ba-map-k, 1)); }
.ba-map--half .ba-map__label { font-size: 19px; }
.ba-map--half .ba-map__foot { font-size: 17px; }
.ba-map--half [data-half='south'] { display: none; }
.ba--static .ba-map { display: none; }
