/* ============================================================
   Decode to Recode / The Longevity Network
   pages.css: the components added on 24 Sep 2026 for Home,
   Bootcamp, Workshops and Apply. Loads right after site.css and
   uses only its tokens: no hex values here. Every block is
   complete and readable with JavaScript off; scripts only add
   motion and the live text. Phone breakpoints: 767px and 1023px.
   ============================================================ */

/* ---------- 1. Sticky bar (data-stickybar) ----------
   Fixed to the bottom of the viewport, 56px, ink on paper text.
   Hidden until pages.js adds .is-on (after .hero has scrolled out),
   and off again while any [data-stickybar-stop] element is in view. */
.stickybar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 80;
  min-height: 56px; padding-bottom: env(safe-area-inset-bottom, 0px);
  background: var(--ink); color: var(--paper);
  border-top: 1px solid var(--ink-2);
  transform: translateY(100%); visibility: hidden;
  transition: transform var(--t-fast) var(--ease), visibility 0s linear var(--t-fast);
}
.stickybar.is-on {
  transform: none; visibility: visible;
  transition: transform var(--t-fast) var(--ease), visibility 0s;
}
body[data-menu-open="true"] .stickybar { transform: translateY(100%); visibility: hidden; }
.stickybar-inner { height: 56px; display: flex; align-items: center; justify-content: space-between; gap: var(--s4); }
.stickybar-text {
  margin: 0; min-width: 0; max-width: none; flex: 1 1 auto;
  font-family: var(--font-mono); font-weight: 500; font-size: var(--label);
  letter-spacing: var(--track); text-transform: uppercase; line-height: 1.4;
  color: var(--paper-70);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.stickybar-text b, .stickybar-text strong { color: var(--paper); font-weight: 500; }
.stickybar .btn { flex: none; min-height: 40px; padding: 0 20px; font-size: 14px; }
.stickybar .btn-primary { --btn-bg: var(--brand-accent); --btn-fg: var(--ink); --btn-bd: var(--brand-accent); }
.stickybar .btn-primary:hover { --btn-bg: var(--paper); --btn-bd: var(--paper); }
.stickybar :focus-visible { outline-color: var(--brand-accent); }
@media (max-width: 480px) {
  .stickybar-text { display: none; }
  .stickybar .btn { width: 100%; }
}
/* Keyboard focus never lands under the bar (WCAG 2.4.11): when the browser
   scrolls a focused element into view it leaves room for the bar. :has() where
   supported; pages.js adds html.has-stickybar for the rest. 2 separate rules,
   because an unsupported :has() would drop a shared selector list. */
html:has([data-stickybar]) { scroll-padding-bottom: calc(56px + env(safe-area-inset-bottom, 0px) + 16px); }
html.has-stickybar { scroll-padding-bottom: calc(56px + env(safe-area-inset-bottom, 0px) + 16px); }

/* ---------- 2. Hour cards (.hours > .hour) ----------
   4 hairline cells like .hgrid: a mono time stamp, a body, 1 bold phrase.
   .hour-role is the same card with a mono label instead of a clock time. */
.hours {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 1px; background: var(--hairline); border: 1px solid var(--hairline);
}
.hour {
  margin: 0; min-width: 0; background: var(--surface); padding: var(--s6);
  display: grid; gap: var(--s4); align-content: start;
}
.hour-stamp {
  margin: 0; max-width: none;
  font-family: var(--font-mono); font-weight: 500; font-size: clamp(28px, 3vw, 40px);
  line-height: 1; letter-spacing: -0.03em; color: var(--ink); font-variant-numeric: tabular-nums;
}
.hour-role {
  margin: 0; max-width: none; padding-top: 6px;
  font-family: var(--font-mono); font-weight: 500; font-size: var(--label);
  letter-spacing: var(--track); text-transform: uppercase; line-height: 1.5; color: var(--mute);
}
.hour-body { margin: 0; max-width: none; color: var(--text); }
.hour-body strong { display: block; margin-top: var(--s3); color: var(--ink); font-weight: 600; }
.band-ink .hours { background: var(--ink-2); border-color: var(--ink-2); }
.band-ink .hour { background: var(--ink); }
.band-ink .hour-stamp, .band-ink .hour-body strong { color: var(--paper); }
.band-ink .hour-role { color: var(--mute-on-ink); }
.band-ink .hour-body { color: var(--paper-70); }
@media (max-width: 1023px) { .hours { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 767px) { .hours { grid-template-columns: minmax(0, 1fr); } }

/* ---------- 3. Count-up numerals ([data-countup]) ----------
   The static text is the final value and the fallback. pages.js counts
   from 0 once, when the numeral scrolls in; reduced motion shows the
   value at once. Tabular figures keep the width steady while counting. */
[data-countup] { display: inline-block; font-variant-numeric: tabular-nums; }
.stat > .numeral[data-countup] { margin-bottom: var(--s3); }

/* ---------- 4. Evidence tiles (.evidence > .ev) ----------
   3 hairline cells (figure in mono, finding, citation as a label) and
   one wide cell (.ev-wide) that spans the row, for "The honest bit". */
.evidence {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1px; background: var(--hairline); border: 1px solid var(--hairline);
}
.ev {
  margin: 0; min-width: 0; background: var(--surface); padding: var(--s6);
  display: grid; gap: var(--s4); align-content: start;
}
.ev-wide { grid-column: 1 / -1; }
.ev-fig {
  margin: 0; max-width: none;
  font-family: var(--font-mono); font-weight: 500; font-size: clamp(36px, 4vw, 56px);
  line-height: 0.9; letter-spacing: -0.04em; color: var(--ink); font-variant-numeric: tabular-nums;
}
.ev-find { margin: 0; max-width: none; color: var(--text); }
.ev-cite {
  margin: 0; max-width: none;
  font-family: var(--font-mono); font-weight: 500; font-size: var(--label);
  letter-spacing: var(--track); text-transform: uppercase; line-height: 1.5; color: var(--mute);
}
.ev-wide .h3 { margin: 0; }
.ev-wide p { max-width: 80ch; }
.band-ink .evidence { background: var(--ink-2); border-color: var(--ink-2); }
.band-ink .ev { background: var(--ink); }
.band-ink .ev-fig { color: var(--paper); }
.band-ink .ev-find { color: var(--paper-70); }
.band-ink .ev-cite { color: var(--mute-on-ink); }
@media (max-width: 1023px) {
  .evidence { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* an odd last tile spans the row so no hairline cell is left empty */
  .evidence > .ev:nth-child(odd):nth-last-child(2), .evidence > .ev:nth-child(odd):last-child { grid-column: 1 / -1; }
}
@media (max-width: 767px) { .evidence { grid-template-columns: minmax(0, 1fr); } }

/* ---------- 5. Pinned sequence (.pinseq, data-pinseq) ----------
   Static by default: head left, panels stacked in flow, all visible.
   Pinned only under html.gsap (set by pages.js when GSAP is present and
   motion is allowed) and only above 767px: the stage sticks below the
   header for 1 screen per panel and pages.js toggles .is-on by scroll
   progress. On phones the fallback layout holds even if html.gsap is set
   (site.js sets it for .basics on the same page). */
.pinseq { position: relative; }
.pinseq-stage { padding: var(--section-y) 0; }
.pinseq-grid {
  display: grid; grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: var(--s7) var(--s5); align-items: start;
}
.pinseq-head { grid-column: span 5; min-width: 0; }
.pinseq-panels { grid-column: 7 / span 6; min-width: 0; display: grid; gap: var(--s7); }
.pinseq-panels > .panel { min-width: 0; }
@media (max-width: 1023px) { .pinseq-head, .pinseq-panels { grid-column: span 12; } }

html.gsap .pinseq { min-height: 200vh; }
html.gsap .pinseq-stage {
  position: sticky; top: var(--header-h);
  min-height: calc(100vh - var(--header-h));
  display: flex; align-items: center; padding: var(--s8) 0;
}
html.gsap .pinseq-grid { width: 100%; align-items: center; }
html.gsap .pinseq-panels { gap: 0; }
html.gsap .pinseq-panels > .panel {
  grid-area: 1 / 1 / 2 / 2;
  opacity: 0; pointer-events: none;
  transition: opacity 400ms var(--ease);
}
html.gsap .pinseq-panels > .panel.is-on { opacity: 1; pointer-events: auto; }
@media (max-width: 767px) {
  html.gsap .pinseq { min-height: 0; }
  html.gsap .pinseq-stage { position: static; top: auto; min-height: 0; display: block; padding: var(--section-y) 0; }
  html.gsap .pinseq-grid { align-items: start; }
  html.gsap .pinseq-panels { gap: var(--s7); }
  html.gsap .pinseq-panels > .panel { grid-area: auto; opacity: 1; pointer-events: auto; transition: none; }
}

/* ---------- 6. Countdown and places (.meta.places, data-countdown) ----------
   A metadata row under the hero facts. The text inside [data-cd-text]
   is replaced by pages.js only between the open and close dates. */
.places {
  display: block; margin-top: var(--s5); padding-top: var(--s3);
  border-top: 1px solid var(--hairline); max-width: 720px;
  font-variant-numeric: tabular-nums;
}
.places [data-cd-text] { display: inline; }
.band-ink .places { border-color: var(--ink-2); }
.band-teal .places { border-color: var(--teal-mid); }

/* ---------- 7. Format toggle (.toggle, data-formats-toggle) ----------
   2 buttons with aria-pressed. The container [data-formats] carries
   data-format="inperson" or "online"; elements marked data-fmt show only
   when they match, elements without data-fmt always show. With JavaScript
   off the toggle is hidden and both formats are shown. */
.toggle {
  display: inline-flex; align-items: center; gap: 2px; padding: 2px;
  border: 1px solid var(--field-border); border-radius: var(--r-pill); background: transparent;
}
.toggle-btn {
  min-height: 40px; padding: 0 18px; border: 0; border-radius: var(--r-pill);
  background: transparent; color: var(--mute); cursor: pointer; white-space: nowrap;
  font-family: var(--font-mono); font-weight: 500; font-size: var(--label-lg);
  letter-spacing: var(--track); text-transform: uppercase;
  transition: background-color var(--t-fast) ease, color var(--t-fast) ease;
}
.toggle-btn:hover { color: var(--ink); }
.toggle-btn[aria-pressed="true"] { background: var(--ink); color: var(--paper); }
.band-ink .toggle { border-color: var(--mute-on-ink); }
.band-ink .toggle-btn { color: var(--mute-on-ink); }
.band-ink .toggle-btn:hover { color: var(--paper); }
.band-ink .toggle-btn[aria-pressed="true"] { background: var(--brand-accent); color: var(--ink); }
html:not(.js) .toggle { display: none; }
html.js [data-formats][data-format="inperson"] [data-fmt="online"] { display: none; }
html.js [data-formats][data-format="online"] [data-fmt="inperson"] { display: none; }
@media (max-width: 480px) {
  .toggle { display: flex; width: 100%; }
  .toggle-btn { flex: 1 1 0; }
}

/* ---------- 8. Proof strip (.proof > .proof-item) ----------
   Mono, mute, items separated by a middle dot drawn here; stacks on phone. */
.proof {
  display: flex; flex-wrap: wrap; gap: 6px 0; max-width: none;
  font-family: var(--font-mono); font-weight: 500; font-size: var(--label);
  letter-spacing: var(--track); text-transform: uppercase; line-height: 1.6; color: var(--mute);
}
.proof-item { display: inline; }
.proof-item + .proof-item::before { content: "\00B7"; margin: 0 10px; color: var(--hairline); }
.band-ink .proof { color: var(--mute-on-ink); }
.band-ink .proof-item + .proof-item::before { color: var(--ink-2); }
.band-teal .proof { color: var(--on-teal-2); }
.band-teal .proof-item + .proof-item::before { color: var(--teal-mid); }
@media (max-width: 767px) {
  .proof { flex-direction: column; gap: 8px; }
  .proof-item + .proof-item::before { content: none; }
}

/* ---------- 9. Big words close (.bigwords > .bigword) ----------
   Display font, uppercase, 1 word per line; aria-hidden in the markup,
   with a visually hidden h2 and the button row after it. */
.bigwords {
  display: grid; justify-items: start; margin: 0 0 var(--s7);
  font-family: var(--font-sans); font-weight: 800; text-transform: uppercase;
  letter-spacing: -0.03em; font-size: clamp(56px, 12vw, 180px); line-height: 0.85;
  color: var(--ink); overflow-wrap: anywhere;
}
.bigword { display: block; }
.bigwords-sub { font-size: var(--lead); line-height: 1.5; max-width: 44ch; margin: 0 0 var(--s6); }
.band-ink .bigwords, .band-teal .bigwords { color: var(--paper); }

/* ---------- 10. Apply form (.apply-grid, .apply-form, .apply-aside) ----------
   The form reuses .form, .field, .input, .check, .form-2, .radios and
   .form-status from site.css. .apply-grid puts the form left and a short
   reassurance column right; the status line stays the form's next sibling. */
.apply-grid {
  display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 4fr);
  column-gap: var(--s8); row-gap: var(--s5); align-items: start;
}
.apply-grid > .form, .apply-grid > .form-status { grid-column: 1; }
.apply-grid > .apply-aside { grid-column: 2; grid-row: 1 / span 2; }
.apply-aside {
  display: grid; gap: var(--s4); align-content: start;
  border-top: 1px solid var(--hairline); padding-top: var(--s5);
}
.apply-aside p { font-size: var(--small); color: var(--mute); max-width: 40ch; }
.apply-aside .label { margin: 0; }
.apply-form { max-width: 720px; gap: var(--s5); }
.apply-form .form-2 { gap: var(--s5); }
.apply-form .field-help { margin: 0; font-size: var(--small); color: var(--mute); }
.apply-form fieldset.field { gap: 10px; }
.apply-form .radios { gap: 10px; }
.apply-form .check { max-width: 60ch; }
.apply-form .btn { margin-top: var(--s2); }
.band-ink .apply-aside { border-color: var(--ink-2); }
.band-ink .apply-aside p, .band-ink .apply-form .field-help { color: var(--mute-on-ink); }
@media (max-width: 1023px) {
  .apply-grid { grid-template-columns: minmax(0, 1fr); }
  .apply-grid > .apply-aside { grid-column: 1; grid-row: auto; }
}

/* ---------- 11. Reduced motion: static and visible, no transitions ---------- */
@media (prefers-reduced-motion: reduce) {
  .stickybar, .stickybar.is-on { transition: none; }
  .toggle-btn { transition: none; }
  html.gsap .pinseq { min-height: auto; }
  html.gsap .pinseq-stage { position: static; min-height: auto; display: block; padding: var(--section-y) 0; }
  html.gsap .pinseq-grid { align-items: start; }
  html.gsap .pinseq-panels { gap: var(--s7); }
  html.gsap .pinseq-panels > .panel { grid-area: auto; opacity: 1; pointer-events: auto; transition: none; }
}

/* ---------- 12. Integration additions (24 Sep 2026) ----------
   Rules the page builds needed that the component contract did not name. */

/* Bootcamp § 01: the centred closing line under the stat tiles */
.closer { text-align: center; margin-left: auto; margin-right: auto; max-width: 40ch; font-size: clamp(20px, 1.8vw, 24px); }

/* Hero facts grid on ink and teal: the hairlines match the band, as .places does */
.band-ink .meta-cols > span { border-top-color: var(--ink-2); }
.band-teal .meta-cols > span { border-top-color: var(--teal-mid); }

/* Big words as navigation (Home): each word is a link with a mono label under it.
   The word keeps the .bigwords display style; hover and focus shift it to mute. */
.bigwords-nav { gap: var(--s6); }
.bigword-row { display: grid; justify-items: start; gap: var(--s3); }
.bigword-link { display: inline-block; color: inherit; text-decoration: none; }
.bigword-link .bigword { transition: color var(--t-fast) ease; }
.bigword-link:hover .bigword, .bigword-link:focus-visible .bigword { color: var(--mute); }
.bigword-link:focus-visible { outline-offset: 8px; }
.bigwords-nav .label { margin: 0; }
.band-ink .bigword-link:hover .bigword, .band-ink .bigword-link:focus-visible .bigword,
.band-teal .bigword-link:hover .bigword, .band-teal .bigword-link:focus-visible .bigword { color: var(--mute-on-ink); }

/* Start page: the rules that were inline style attributes, now classes */
.hero-tight { padding-bottom: var(--s7); }
.qgroup-note { font-size: 0.5em; letter-spacing: 0; }
.question-flush { border-top: 0; padding-top: 0; }
.result-totals-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }

/* Bootcamp hero on phones: the Book a call button sits right under the tagline,
   above the lead and the facts, so the primary action shows on a short first
   screen. DOM and focus order are unchanged; the lead has no links. Scoped with
   .hero-cta-first so the other heroes keep their order. */
@media (max-width: 767px) {
  .hero-cta-first { display: flex; flex-direction: column; }
  .hero-cta-first > .lead { order: 1; }
  .hero-cta-first > .meta { order: 2; }
}
.result-totals .v-word { font-family: var(--font-sans); font-weight: 800; text-transform: uppercase; }

@media (prefers-reduced-motion: reduce) {
  .bigword-link .bigword { transition: none; }
}

/* ---------- 13. Form success without JavaScript (25 Sep 2026) ----------
   Netlify redirects to the page with #sent; the status line carries id="sent",
   so it shows even when site.js has not run. */
#sent:target { display: block; }
[data-sent-status]#sent:target { display: block !important; }

/* ---------- 14. Marquee pause (WCAG 2.2.2) ----------
   pages.js puts a .marquee-toggle button right after every .marquee. It sits
   at the right edge of the container line, in the mono label style. Under
   reduced motion the track is already still, so the button is hidden. */
.marquee.is-paused .marquee-track { animation-play-state: paused; }
/* Without JavaScript there is no Pause motion button, so the line stays still */
html:not(.js) .marquee-track { animation: none; }
.marquee-toggle {
  display: block; width: fit-content; min-height: 32px;
  margin: var(--s2) max(var(--gutter), calc((100% - var(--container)) / 2 + var(--gutter))) 0 auto;
  padding: 0 2px; border: 0; background: transparent; cursor: pointer;
  font-family: var(--font-mono); font-weight: 500; font-size: var(--label);
  letter-spacing: var(--track); text-transform: uppercase; line-height: 1.5;
  color: var(--mute); text-decoration: none;
}
.marquee-toggle:hover { color: var(--ink); }
.marquee-toggle:focus-visible { color: var(--ink); text-decoration: underline; text-underline-offset: 0.3em; text-decoration-thickness: 1px; }
.band-ink .marquee-toggle, .band-teal .marquee-toggle { color: var(--mute-on-ink); }
.band-ink .marquee-toggle:hover, .band-ink .marquee-toggle:focus-visible,
.band-teal .marquee-toggle:hover, .band-teal .marquee-toggle:focus-visible { color: var(--paper); }
@media (prefers-reduced-motion: reduce) {
  .marquee-toggle { display: none; }
}

/* ---------- 15. Start page quiz count on phones ----------
   The count reads "Answered 0 of 9 (8 questions and your stage)": on phones it
   takes the first line and the track and "Stored nowhere" share the second. */
@media (max-width: 767px) {
  .quiz-progress-inner { height: auto; min-height: 44px; flex-wrap: wrap; row-gap: 6px; padding-top: var(--s2); padding-bottom: var(--s2); }
  .quiz-progress-inner > .count:first-child { flex: 1 1 100%; white-space: normal; }
  .quiz-progress .track { min-width: 48px; }
}

/* ---------- 13. Picker (tap to reveal, [data-picker]) ----------
   Reuses the .toggle pill look. Wraps on narrow screens. JS sets [hidden]
   on the panels that are not chosen; without JS every panel shows. */
.picker { min-width: 0; }
.picker-btns { flex-wrap: wrap; border-radius: var(--r-card); }
.picker-btns .toggle-btn { padding: 0 14px; }
.picker-panel { margin-top: var(--s5); padding-top: var(--s5); border-top: 1px solid var(--hairline); }
.picker-panel[hidden] { display: none; }
/* Each panel's first child names it: shown without JavaScript (where the buttons
   are hidden and every panel shows), visually hidden once the buttons run, so it
   still labels the panel for screen readers. */
.picker-name { margin: 0 0 var(--s4); }
html.js .picker-name {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.band-ink .picker-panel { border-color: var(--ink-2); }
.band-teal .picker-panel { border-color: var(--teal-mid); }
@media (max-width: 480px) {
  .picker-btns { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); width: 100%; }
  .picker-btns .toggle-btn { min-width: 0; padding: 4px; white-space: normal; line-height: 1.2; }
}

/* ---------- 14. Phone: no separator dot at the start of a wrapped line ----------
   On narrow screens the dots between .meta and .proof items are dropped and a
   plain gap separates the items instead. */
@media (max-width: 767px) {
  .meta:not(.meta-stack):not(.meta-cols) { gap: 4px 16px; }
  .meta:not(.meta-stack):not(.meta-cols) > span + span::before { content: none; }
  .proof { gap: 4px 16px; }
  .proof-item + .proof-item::before { content: none; }
}

/* ============================================================
   25 Sep 2026: the shared motion and media layer, M1 to M8.
   Hooks, exactly as pages use them:
     M1 .hero-film[data-herofilm] > .hero-film-media > img, .hero-film-body
     M2 .rise > .rise-line > span
     M3 .scrub[data-scrub]
     M4 .hscroll[data-hscroll] > .hscroll-track > .hscroll-item
     M5 .logos[data-logos] > .logos-track > .logo (.logo-text)
     M6 .stackcards > .stackcard
     M7 .wipe on an .img-frame or a figure
     M8 .seal > .seal-kicker, .h3, p (pages.js adds the ring)
   Tokens only. Every block is complete and still with JavaScript
   off, without GSAP and under reduced motion (section 24).
   ============================================================ */

/* ---------- 16. Film hero (M1: .hero-film, data-herofilm) ----------
   Full-bleed key art under a constant ink scrim (::before) and an ink
   gradient (::after), paper text on top. The scrim keeps body text readable
   on the light key art; the gradient reads --hf-shade, which pages.js scrubs
   from 1 to 0.35 while the image scales from 1.12 to 1 as the hero scrolls
   out. The 1.12 start is set here so the first paint does not jump; without
   GSAP pages.js adds .is-static and the image sits at 1, still. */
.hero-film {
  position: relative; isolation: isolate; overflow: hidden;
  display: flex; flex-direction: column; justify-content: flex-end;
  min-height: min(calc(100vh - var(--header-h)), 1080px);
  background: var(--ink); color: var(--paper);
}
@supports (height: 100svh) {
  .hero-film { min-height: min(calc(100svh - var(--header-h)), 1080px); }
}
.hero.hero-film { padding-top: 0; padding-bottom: 0; }
.hero-film-media { position: absolute; inset: 0; z-index: -1; overflow: hidden; background: var(--ink); }
.hero-film-media img {
  width: 100%; height: 100%; max-width: none; object-fit: cover; object-position: center;
  transform-origin: 50% 40%; background: var(--ink);
}
/* z-index 1 on both layers: once the img has a transform (the 1.12 start or the
   GSAP scale) it paints in the positioned layer in tree order, so without it the
   img would cover ::before and the scrim would vanish while motion is on. */
.hero-film-media::before, .hero-film-media::after {
  content: ""; position: absolute; inset: 0; pointer-events: none; z-index: 1;
}
.hero-film-media::before { background: var(--ink); opacity: 0.55; }
.hero-film-media::after {
  background:
    linear-gradient(to top, var(--ink) 0%, transparent 72%),
    linear-gradient(to right, var(--ink) 0%, transparent 62%);
  opacity: var(--hf-shade, 1);
}
.hero-film-body { position: relative; z-index: 1; padding-top: var(--hero-y); padding-bottom: var(--s9); }
@media (prefers-reduced-motion: no-preference) {
  html.js .hero-film[data-herofilm]:not(.is-static) .hero-film-media img { transform: scale(1.12); }
}
.hero-film .display { margin: var(--s5) 0 var(--s6); }
.hero-film h1, .hero-film h2, .hero-film h3, .hero-film .h4, .hero-film p { color: var(--paper); }
.hero-film .label, .hero-film .meta, .hero-film .marker { color: var(--paper-70); }
/* Over the photo --mute-on-ink loses contrast as --hf-shade fades: paper-70 here */
.hero-film .proof, .hero-film .marquee-toggle { color: var(--paper-70); }
.hero-film .marquee-toggle:hover, .hero-film .marquee-toggle:focus-visible { color: var(--paper); }
.hero-film .label strong, .hero-film .meta b, .hero-film .meta strong { color: var(--paper); }
.hero-film .meta > span + span::before { color: var(--paper-60); }
.hero-film .marker::after { background: var(--paper-60); }
.hero-film .places { border-color: var(--paper-60); }
.hero-film .textlink { color: var(--paper); }
.hero-film .btn-primary { --btn-bg: var(--brand-accent); --btn-fg: var(--ink); --btn-bd: var(--brand-accent); }
.hero-film .btn-primary:hover { --btn-bg: var(--paper); --btn-bd: var(--paper); }
.hero-film .btn-outline { --btn-fg: var(--paper); --btn-bd: var(--paper-60); }
.hero-film .btn-outline:hover { --btn-bd: var(--paper); }
.hero-film :focus-visible { outline-color: var(--brand-accent); }
/* .hero-seq children rise on load here too (pages.js adds .is-loaded, as site.js does for .hero) */
html.js .hero-film.is-loaded .hero-seq { transform: none; transition: transform var(--t-hero) var(--ease); }
html.js .hero-film.is-loaded .hero-seq:nth-child(1) { transition-delay: 50ms; }
html.js .hero-film.is-loaded .hero-seq:nth-child(2) { transition-delay: 120ms; }
html.js .hero-film.is-loaded .hero-seq:nth-child(3) { transition-delay: 190ms; }
html.js .hero-film.is-loaded .hero-seq:nth-child(4) { transition-delay: 260ms; }
html.js .hero-film.is-loaded .hero-seq:nth-child(5) { transition-delay: 330ms; }
@media (max-width: 767px) {
  .hero-film-body { padding-bottom: var(--s8); }
  /* on a phone the text runs the full width, over the light sky on the right: a deeper scrim */
  .hero-film-media::before { opacity: 0.72; }
  /* the key art's own title sits right of centre: on a phone crop keep the profile instead */
  .hero-film-media img { object-position: 35% 50%; }
}

/* ---------- 17. Line rise (M2: .rise > .rise-line > span) ----------
   Each line is a clipping box; its inner span rises from 100% to 0 once, on
   load, 90ms apart. The start position lives only in the keyframes, so with
   the animation off (reduced motion, no JavaScript, .is-static for full-page
   captures) every line simply sits in place. The text is always in the DOM.
   The 0.1em padding and matching negative margin keep accents and commas
   inside the clip without changing the line spacing. */
.rise-line { display: block; overflow: hidden; padding: 0.1em 0; margin: -0.1em 0; }
.rise-line > span { display: block; }
@keyframes rise-in { from { transform: translateY(100%); } to { transform: translateY(0); } }
@media (prefers-reduced-motion: no-preference) {
  html.js .rise:not(.is-static) .rise-line > span { animation: rise-in 1000ms var(--ease) both; }
  html.js .rise:not(.is-static) .rise-line:nth-child(2) > span { animation-delay: 90ms; }
  html.js .rise:not(.is-static) .rise-line:nth-child(3) > span { animation-delay: 180ms; }
  html.js .rise:not(.is-static) .rise-line:nth-child(4) > span { animation-delay: 270ms; }
  html.js .rise:not(.is-static) .rise-line:nth-child(5) > span { animation-delay: 360ms; }
  html.js .rise:not(.is-static) .rise-line:nth-child(6) > span { animation-delay: 450ms; }
}

/* ---------- 18. Scrub words (M3: .scrub, data-scrub) ----------
   A statement paragraph. pages.js wraps the words (.scrub-word) only when
   GSAP runs, then scrubs each from 0.18 to 1 opacity as the paragraph moves
   through the viewport; screen readers get the untouched sentence from a
   visually hidden copy. Otherwise the paragraph is plain text at full opacity. */
.scrub {
  font-family: var(--font-sans); font-weight: 600;
  font-size: clamp(24px, 3.2vw, 44px); line-height: 1.2; letter-spacing: -0.02em;
  color: var(--ink); max-width: 32ch; text-wrap: pretty;
}
.band-ink .scrub, .band-teal .scrub, .hero-film .scrub { color: var(--paper); }
.scrub-word { display: inline; }

/* ---------- 19. Horizontal gallery (M4: .hscroll, data-hscroll) ----------
   Default (phone, tablet, no GSAP, reduced motion): a native horizontal
   scroller with scroll-snap, a visible thin scrollbar and the next item
   peeking in; the track is focusable so arrow keys scroll it. Place the
   wrapper outside .container: the track pads itself to the container line.
   Every image in a row shares one height (--hs-h) and keeps its own ratio,
   so stills and a poster sit on one line; captions wrap to the image width.
   Desktop with GSAP: pages.js adds .is-pinned, the wrapper fills the viewport
   below the header, pins, and vertical scroll moves the track sideways. */
.hscroll {
  position: relative;
  --hs-pad: max(var(--gutter), calc((100% - var(--container)) / 2 + var(--gutter)));
  --hs-h: 48vw;
}
.hscroll-track {
  display: flex; align-items: flex-start; gap: var(--s5);
  overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory; scroll-padding-inline: var(--hs-pad);
  padding: 0 var(--hs-pad) var(--s5);
  scrollbar-width: thin; scrollbar-color: var(--field-border) var(--hairline);
  -webkit-overflow-scrolling: touch;
}
.hscroll-track::after { content: ""; flex: 0 0 1px; }
.hscroll-track::-webkit-scrollbar { height: 6px; }
.hscroll-track::-webkit-scrollbar-track { background: var(--hairline); border-radius: var(--r-pill); }
.hscroll-track::-webkit-scrollbar-thumb { background: var(--field-border); border-radius: var(--r-pill); }
.hscroll-track:focus-visible { outline-offset: -2px; }
.hscroll-item { flex: 0 0 auto; width: min-content; min-width: 0; margin: 0; scroll-snap-align: start; }
.hscroll-item img {
  height: var(--hs-h); width: auto; max-width: calc(100vw - 2 * var(--gutter));
  object-fit: cover; border-radius: 16px;
}
.hscroll-item figcaption { margin-top: var(--s3); }
.band-ink .hscroll-track { scrollbar-color: var(--mute-on-ink) var(--ink-2); }
.band-ink .hscroll-track::-webkit-scrollbar-track { background: var(--ink-2); }
.band-ink .hscroll-track::-webkit-scrollbar-thumb { background: var(--mute-on-ink); }
@media (min-width: 768px) { .hscroll { --hs-h: 32vw; } }
@media (min-width: 1024px) { .hscroll { --hs-h: clamp(240px, 24vw, 400px); } }
/* Pinned (desktop, GSAP): no native scroll, one long row moved by transform */
.hscroll.is-pinned {
  --hs-h: min(calc(100vh - var(--header-h) - 200px), 560px);
  height: calc(100vh - var(--header-h)); overflow: hidden;
  display: flex; flex-direction: column; justify-content: center;
}
.hscroll.is-pinned .hscroll-track {
  width: max-content; overflow: visible; scroll-snap-type: none; padding-bottom: 0;
  will-change: transform;
}
.hscroll.is-pinned .hscroll-track::after { content: none; }
.hscroll.is-pinned .hscroll-item img { max-width: none; }

/* ---------- 20. Logo strip (M5: .logos, data-logos) ----------
   Greyscale marks 28 to 36px tall in a static row that wraps. When the row is
   wider than its box, pages.js duplicates the items (aria-hidden), adds
   .is-marquee and a Pause motion button (.marquee-toggle, as for .marquee):
   the track then loops by -50%, paused on hover and by the button. Spacing is
   padding on each item, so the duplicated half is exactly half the track. */
.logos { position: relative; overflow: hidden; padding: var(--s4) 0; }
.logos-track {
  display: flex; flex-wrap: wrap; align-items: center; row-gap: var(--s5);
  margin: 0; padding: 0; list-style: none;
}
.logo {
  flex: none; display: flex; align-items: center;
  height: clamp(28px, 2.6vw, 36px); padding-right: clamp(40px, 5vw, 72px);
}
.logo img {
  height: 100%; width: auto; max-width: none; background: transparent;
  filter: grayscale(1); opacity: 0.72;
}
.logo-text span {
  font-family: var(--font-sans); font-weight: 800; text-transform: uppercase;
  letter-spacing: -0.01em; font-size: clamp(15px, 1.5vw, 20px); line-height: 1;
  white-space: nowrap; color: var(--mute);
}
.band-ink .logo img, .band-teal .logo img, .hero-film .logo img { filter: grayscale(1) brightness(0) invert(1); opacity: 0.7; }
.band-ink .logo-text span, .hero-film .logo-text span { color: var(--mute-on-ink); }
.band-teal .logo-text span { color: var(--on-teal-2); }
@keyframes logos-loop { from { transform: translateX(0); } to { transform: translateX(-50%); } }
.logos.is-marquee .logos-track {
  flex-wrap: nowrap; width: max-content;
  animation: logos-loop var(--logos-dur, 40s) linear infinite; will-change: transform;
}
.logos.is-marquee:hover .logos-track, .logos.is-paused .logos-track { animation-play-state: paused; }
.marquee-toggle[hidden] { display: none; }

/* ---------- 21. Stack cards (M6: .stackcards > .stackcard) ----------
   Phone: a normal list. From 768px each card is sticky, 16px lower than the
   one before, so the next card slides over it as you scroll. pages.js adds
   .is-static to a stack whose tallest card would not fit under its offset
   (so no text is ever hidden under the next card). */
.stackcards { display: grid; gap: var(--s5); }
.stackcard {
  min-width: 0; background: var(--surface); color: var(--text);
  border: 1px solid var(--hairline); border-radius: var(--r-card); padding: var(--s6);
}
.band-ink .stackcard { background: var(--ink); border-color: var(--mute-on-ink); }
.band-teal .stackcard { background: var(--teal); border-color: var(--teal-mid); }
@media (min-width: 768px) {
  .stackcards { gap: var(--s8); }
  .stackcard {
    position: sticky; top: calc(var(--header-h) + var(--s5) + var(--stack-i, 0) * var(--s4));
    min-height: min(52vh, 480px); padding: var(--s7);
  }
  .stackcard:nth-child(2) { --stack-i: 1; }
  .stackcard:nth-child(3) { --stack-i: 2; }
  .stackcard:nth-child(4) { --stack-i: 3; }
  .stackcard:nth-child(5) { --stack-i: 4; }
  .stackcard:nth-child(6) { --stack-i: 5; }
  .stackcard:nth-child(7) { --stack-i: 6; }
  .stackcard:nth-child(8) { --stack-i: 7; }
  .stackcards.is-static { gap: var(--s5); }
  .stackcards.is-static .stackcard { position: static; min-height: 0; }
}

/* ---------- 22. Wipe reveal (M7: .wipe on an .img-frame or a figure) ----------
   Same pattern as .reveal: visible at rest; only once pages.js has started
   its observer (html.reveal-on) is an un-revealed .wipe clipped, and it wipes
   open left to right when it scrolls in. Anything in the first viewport is
   shown at once. The clip sits on the direct children (the image, the
   caption, the crosshair marks), never on .wipe itself: Chromium measures an
   observed element through its own clip-path, so a fully clipped .wipe would
   never report itself as in view. The frame's placeholder fill is dropped so
   no dark box shows before the image wipes in (the img keeps its own). */
.img-frame.wipe { background: transparent; }
html.reveal-on .wipe:not(.is-in) > * { clip-path: inset(0 100% 0 0); }
html.reveal-on .wipe.is-in > * {
  clip-path: inset(0 0 0 0);
  transition: clip-path 1100ms var(--ease), transform 300ms ease-in-out;
}
html.reveal-on figure.wipe.is-in > figcaption { transition-delay: 120ms, 0ms; }
html.reveal-on .wipe.is-in.no-anim > * { transition: transform 300ms ease-in-out; }

/* ---------- 23. Guarantee seal (M8: .seal) ----------
   An accent block with an ink rule. pages.js prepends a decorative ring
   (.seal-ring, aria-hidden): the kicker text set around a circle, turning
   once every 30s, paused on hover. Without JavaScript there is no ring and
   the block reads the same. */
.seal {
  position: relative; display: grid; gap: var(--s4); align-content: start;
  background: var(--brand-accent); color: var(--ink);
  border: 1px solid var(--ink); border-radius: var(--r-card);
  padding: var(--s7); max-width: 880px;
}
.seal .seal-kicker, .seal .h3, .seal p,
.band-ink .seal .seal-kicker, .band-ink .seal .h3, .band-ink .seal p,
.band-teal .seal .seal-kicker, .band-teal .seal .h3, .band-teal .seal p { color: var(--ink); margin: 0; }
.seal .h3 { max-width: 24ch; }
.seal p { max-width: 60ch; }
.seal a { color: var(--ink); }
.seal :focus-visible, .band-ink .seal :focus-visible, .band-teal .seal :focus-visible { outline-color: var(--ink); }
.band-ink .seal, .band-teal .seal { border-color: var(--brand-accent); }
.seal-ring {
  display: block; width: 104px; height: 104px; color: var(--ink); pointer-events: none;
}
.seal-ring svg { display: block; width: 100%; height: 100%; overflow: visible; background: transparent; }
.seal-ring text {
  fill: currentColor; font-family: var(--font-mono); font-weight: 500;
  font-size: 8.6px; letter-spacing: 0.12em; text-transform: uppercase;
}
.seal-ring circle { fill: none; stroke: currentColor; stroke-width: 0.75; }
.seal-ring .seal-ring-dot { fill: currentColor; stroke: none; }
@keyframes seal-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: no-preference) {
  .seal-ring svg { animation: seal-spin 30s linear infinite; }
  .seal:hover .seal-ring svg { animation-play-state: paused; }
}
@media (max-width: 767px) {
  .seal { padding: var(--s6) var(--s5); }
  .seal-ring { width: 96px; height: 96px; }
}
@media (min-width: 768px) {
  .seal.has-ring { padding-right: calc(var(--s7) + 128px + var(--s5)); }
  .seal.has-ring .seal-ring { position: absolute; top: var(--s6); right: var(--s6); width: 128px; height: 128px; }
}

/* ---------- 24. Reduced motion for 16 to 23: static, complete, visible ---------- */
@media (prefers-reduced-motion: reduce) {
  .hero-film-media img { transform: none !important; }
  .hero-film-media::after { opacity: 1; }
  .rise-line > span { animation: none; transform: none; }
  .scrub-word { opacity: 1 !important; }
  .logos .logos-track { animation: none; flex-wrap: wrap; width: auto; transform: none; }
  .logos .logo[data-logo-dup] { display: none; }
  html.reveal-on .wipe > *, html.reveal-on .wipe:not(.is-in) > * { clip-path: none; transition: none; }
  .seal-ring svg { animation: none; }
}
/* Full-page captures and a script that never ran leave the hero image at rest */
.hero-film.is-static .hero-film-media img { transform: none; }

/* ---------- 15. Apply: short hero so the first form fields reach the first phone screen (APPLY-SJ-1) ---------- */
@media (max-width: 767px) {
  .hero-short { padding-bottom: var(--s6); }
  #application { padding-top: var(--s6); }
  #application .mb-5 { margin-bottom: var(--s4); }
  .hero-short .crosshair-mark.bl, .hero-short .crosshair-mark.br { display: none; }
}

/* ---------- 25. Tap check (Home, gamified, stored nowhere) ----------
   4 toggle buttons fill a ring. Hidden without JavaScript. */
.tapcheck { border: 1px solid var(--hairline); border-radius: var(--r-card); padding: var(--s5); background: var(--surface); }
html:not(.js) .tapcheck { display: none; }
.tapcheck-q { font-weight: 700; font-size: 18px; line-height: 1.3; margin: var(--s2) 0 var(--s4); color: var(--ink); }
.tapcheck-btns { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s2); }
.tap {
  display: flex; flex-direction: column; gap: 4px; text-align: left; cursor: pointer;
  border: 1px solid var(--field-border); border-radius: 12px; background: transparent; padding: 10px 12px;
  font: 700 15px/1.2 var(--font-sans); color: var(--ink);
  transition: background-color var(--t-fast) ease, border-color var(--t-fast) ease, transform var(--t-fast) var(--ease);
}
.tap-hint { font: 500 var(--label)/1.4 var(--font-mono); letter-spacing: var(--track); text-transform: uppercase; color: var(--mute); }
@media (hover: hover) { .tap:hover { border-color: var(--ink); } }
.tap:active { transform: scale(0.97); }
.tap[aria-pressed="true"] { background: var(--brand-accent); border-color: var(--brand-accent); }
.tap[aria-pressed="true"] .tap-hint { color: var(--text); }
.tapcheck-out { display: flex; align-items: center; gap: var(--s4); margin: var(--s5) 0 var(--s3); }
.tapcheck-ring { width: 52px; height: 52px; flex: 0 0 auto; transform: rotate(-90deg); }
.ring-bg { fill: none; stroke: var(--hairline); stroke-width: 5; }
.ring-fg { fill: none; stroke: var(--ink); stroke-width: 5; stroke-linecap: round; stroke-dasharray: 100; stroke-dashoffset: 100; transition: stroke-dashoffset 500ms var(--ease); }
.tapcheck-msg { margin: 0; }
.tapcheck.is-full .tapcheck-ring { animation: tap-pop 600ms var(--ease) 1; }
@keyframes tap-pop { 50% { transform: rotate(-90deg) scale(1.15); } }
@media (max-width: 380px) { .tapcheck-btns { grid-template-columns: minmax(0, 1fr); } }

/* ---------- 26. Badges (Bootcamp levels, Start, Workshops milestones) ----------
   A mono pill with a dot. .is-on, or a .basic lit by the scroll timeline, shows it earned. */
.badge {
  display: inline-flex; align-items: center; gap: 8px; vertical-align: middle;
  font: 500 var(--label)/1 var(--font-mono); letter-spacing: var(--track); text-transform: uppercase;
  padding: 6px 10px 6px 8px; border-radius: var(--r-pill); border: 1px solid var(--hairline); color: var(--mute);
  transition: color 600ms var(--ease), border-color 600ms var(--ease);
}
.badge::before { content: ""; width: 10px; height: 10px; border-radius: 50%; border: 1.5px solid currentColor; transition: background-color 600ms var(--ease); }
.badge.is-on, html.gsap .basic.is-on .badge, html:not(.gsap) .basic .badge { color: var(--ink); border-color: var(--ink); }
.badge.is-on::before, html.gsap .basic.is-on .badge::before, html:not(.gsap) .basic .badge::before { background: var(--brand-accent); border-color: var(--ink); }
.basic-meta .badge { display: flex; width: fit-content; margin: var(--s2) 0 0; }
.band-ink .badge { border-color: var(--ink-2); color: var(--mute-on-ink); }
.band-ink .badge.is-on { color: var(--paper); border-color: var(--paper); }
.badges { display: flex; flex-wrap: wrap; gap: var(--s2); }

/* ---------- 27. Form progress (Apply) ----------
   Sticky under the header while the form is on screen. Hidden without JavaScript. */
.formprogress { position: sticky; top: var(--header-h); z-index: 5; background: var(--paper); padding: var(--s3) 0; margin-bottom: var(--s4); border-bottom: 1px solid var(--hairline); }
html:not(.js) .formprogress { display: none; }
/* A field the browser scrolls to on a failed submit lands below the bar, not under it */
html.js:has(.formprogress:not([hidden])) { scroll-padding-top: calc(var(--header-h) + 96px); }
.formprogress-label { display: flex; justify-content: space-between; gap: var(--s3); max-width: none; margin-bottom: 6px; font: 500 var(--label)/1.4 var(--font-mono); letter-spacing: var(--track); text-transform: uppercase; color: var(--mute); }
.formprogress-label b { color: var(--ink); font-weight: 500; }
.formprogress-track { height: 6px; border-radius: var(--r-pill); background: var(--hairline); overflow: hidden; }
.formprogress-fill { height: 100%; width: 0; background: var(--ink); transition: width 300ms var(--ease); }
.formprogress.is-done .formprogress-fill { background: var(--brand-accent); }
@media (prefers-reduced-motion: reduce) { .ring-fg, .tap, .formprogress-fill, .badge, .badge::before { transition: none; } .tapcheck.is-full .tapcheck-ring { animation: none; } }

/* ---------- 28. Founder cut-out (Home) ----------
   The cut-out portrait stands on an accent panel with 1 big word behind it; the head
   rises out of the panel. js/pages.js moves the portrait slightly with the scroll ([data-parallax]),
   downward only, and the panel clips the bottom so the straight crop line always sits flush with
   the panel edge. The clip is open 40% above the panel, so it never clips the panel's own box and
   the wipe observer still sees it. The wipe's 300ms transform transition is dropped on the portrait,
   because GSAP scrubs that same transform. */
.founder-cut { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); gap: var(--s8); align-items: center; }
.cutout-panel { position: relative; aspect-ratio: 4 / 4.6; margin-top: var(--s7); background: var(--brand-accent); border-radius: var(--r-card); overflow: visible; clip-path: inset(-40% 0 0 0 round var(--r-card)); }
.cutout-word {
  position: absolute; left: 3%; bottom: 5%; z-index: 0; writing-mode: vertical-rl; transform: rotate(180deg);
  font: 800 clamp(40px, 5.2vw, 84px)/0.85 var(--font-sans); letter-spacing: -0.02em; text-transform: uppercase; color: var(--ink); white-space: nowrap;
}
.cutout-panel img { position: absolute; right: 0; bottom: 0; z-index: 1; width: 86%; height: auto; background: transparent; will-change: transform; }
html.reveal-on .cutout-panel.wipe.is-in > img[data-parallax] { transition: clip-path 1100ms var(--ease); }
html.reveal-on .cutout-panel.wipe.is-in.no-anim > img[data-parallax] { transition: none; }
@media (max-width: 1023px) {
  .founder-cut { grid-template-columns: minmax(0, 1fr); gap: var(--s6); }
  .cutout-panel { width: 100%; max-width: 420px; margin-inline: auto; }
}

/* ============================================================
   28 Sep 2026: Home rebuild. The visual pieces borrowed from the
   Diary of a CEO shop (review cards, tabbed module, bundle picture
   with labelled lines, big countdown, film pop-up, side tab), drawn
   in this site's own look. Blocks 29 to 35. Append only.
   ============================================================ */

/* ---------- 29. Hero film title (Home) ---------- */
.hero-filmtitle { margin: var(--s2) 0 0; font-weight: 700; font-size: clamp(18px, 1.9vw, 26px); line-height: 1.2; letter-spacing: -0.01em; max-width: 30ch; }

/* ---------- 30. Viewer reviews (.reviews > .review) ----------
   White cards on ink, 3 across. Below 900px a swipeable row that snaps card by card. No stars. */
/* From 900px a 3-column wall: each card keeps its own height (break-inside: avoid), so the tall
   "honest one" card never stretches the short ones into empty boxes. */
.reviews { list-style: none; padding: 0; columns: 3; column-gap: var(--s5); }
.review { display: flex; flex-direction: column; gap: var(--s4); background: var(--surface); border-radius: var(--r-card); padding: var(--s6); break-inside: avoid; margin-bottom: var(--s5); }
.band-ink .review p { color: var(--text); }
.band-ink .review .review-title { color: var(--ink); }
.review-title { margin: 0; font-weight: 700; font-size: 18px; line-height: 1.3; }
.review-quote { margin: 0; }
.review-quote p { margin: 0; font-size: 17px; line-height: 1.6; max-width: none; }
.band-ink .review .review-by { margin: 0; font: 500 var(--label)/1.5 var(--font-mono); letter-spacing: var(--track); text-transform: uppercase; color: var(--ink); }
.band-ink .review .review-by span { color: var(--mute); }
.review-reply { background: var(--brand-accent); border-radius: 8px; padding: var(--s4); }
.band-ink .review-reply .label { color: var(--ink); }
.band-ink .review-reply .label strong { color: var(--ink); }
.review-reply p:last-child { margin: var(--s1) 0 0; font-weight: 600; }
.reviews:focus-visible { outline: 2px solid var(--brand-accent); outline-offset: 6px; border-radius: var(--r-card); }
@media (max-width: 899px) {
  .reviews {
    columns: auto; display: grid; grid-template-columns: none; grid-auto-flow: column; grid-auto-columns: minmax(260px, 84%); gap: var(--s5);
    overflow-x: auto; scroll-snap-type: x mandatory; overscroll-behavior-x: contain;
    margin-inline: calc(var(--gutter) * -1); padding: 0 var(--gutter) var(--s3); scroll-padding-inline: var(--gutter);
  }
  .reviews { align-items: start; }
  .review { scroll-snap-align: start; padding: var(--s5); margin-bottom: 0; }
}

/* ---------- 31. Struck-out list (Home, The quest) ----------
   Big words; a line draws through the first 3 as the list scrolls in. The last one stands. */
.strikes { list-style: none; padding: 0; margin-bottom: 0; display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s2) var(--s6); }
.strike { font-weight: 800; font-size: clamp(30px, 4.6vw, 64px); line-height: 1.05; letter-spacing: -0.03em; color: var(--mute); }
.strike s { position: relative; text-decoration: none; }
.strike s::after { content: ""; position: absolute; left: -3%; right: -3%; top: 54%; height: 0.09em; background: var(--ink); transform-origin: left center; }
html.reveal-on .strikes:not(.is-in) s::after { transform: scaleX(0); }
html.reveal-on .strikes.is-in s::after { transition: transform 700ms var(--ease) 300ms; }
html.reveal-on .strikes.is-in .strike:nth-child(2) s::after { transition-delay: 550ms; }
html.reveal-on .strikes.is-in .strike:nth-child(3) s::after { transition-delay: 800ms; }
.strike-end { color: var(--ink); background: linear-gradient(transparent 62%, var(--brand-accent) 62%, var(--brand-accent) 92%, transparent 92%); }

/* ---------- 32. The way (Home): 4 tabs on the picker, copy left and picture right ---------- */
.way-tabs .toggle-btn { padding: 0 18px; }
.way-panel { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); gap: var(--s8); align-items: center; }
.way-copy { display: flex; flex-direction: column; align-items: flex-start; gap: var(--s4); }
.way-copy > * { margin: 0; }
.way-for { font-size: var(--lead); line-height: 1.45; font-weight: 500; color: var(--ink); }
.way-lenses { display: flex; flex-wrap: wrap; gap: 6px; }
.way-lenses span { font: 500 var(--label)/1 var(--font-mono); letter-spacing: var(--track); text-transform: uppercase; color: var(--ink); background: var(--brand-accent); border-radius: var(--r-pill); padding: 7px 10px; }
.ticks { list-style: none; padding: 0; margin: 0; display: grid; gap: 10px; }
.ticks li { position: relative; padding-left: 30px; line-height: 1.5; }
.ticks li::before { content: ""; position: absolute; left: 0; top: 0.2em; width: 19px; height: 19px; border-radius: 50%; background: var(--brand-accent); }
.ticks li::after { content: ""; position: absolute; left: 6px; top: calc(0.2em + 5px); width: 7px; height: 4px; border-left: 2px solid var(--ink); border-bottom: 2px solid var(--ink); transform: rotate(-45deg); }
.ticks b { color: var(--ink); }
.way-media { margin: 0; position: relative; border-radius: var(--r-card); overflow: hidden; aspect-ratio: 4 / 3.4; background: var(--paper); }
.way-media img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 30%; }
.way-chat, .way-phone { aspect-ratio: auto; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--s3); padding: var(--s6) var(--s4); }
.way-phone { background: var(--brand-accent); }
.way-chat figcaption, .way-phone figcaption { text-align: center; }
.way-phone figcaption { color: var(--ink); }
.chat { width: min(100%, 380px); display: flex; flex-direction: column; gap: 8px; background: var(--surface); border: 1px solid var(--hairline); border-radius: 18px; padding: var(--s4); box-shadow: 0 18px 40px rgba(10, 10, 10, 0.08); }
.chat-head { margin: 0 0 4px; font: 500 var(--label)/1.4 var(--font-mono); letter-spacing: var(--track); text-transform: uppercase; color: var(--mute); }
.chat-head b { color: var(--ink); font-weight: 500; }
.bubble { margin: 0; max-width: 86%; padding: 8px 12px; border-radius: 14px 14px 14px 4px; background: var(--paper); font-size: 14px; line-height: 1.4; color: var(--text); }
.bubble-me { align-self: flex-end; border-radius: 14px 14px 4px 14px; background: var(--brand-accent); color: var(--ink); }
.bubble-coach { background: var(--ink); color: var(--paper); }
.phone { width: min(100%, 300px); background: var(--ink); border-radius: 38px; padding: 10px; box-shadow: 0 24px 50px rgba(10, 10, 10, 0.25); }
.phone-screen { background: var(--surface); border-radius: 30px; padding: 18px 14px 16px; }
.phone-top { display: flex; justify-content: space-between; align-items: center; gap: var(--s2); margin: 0 0 var(--s3); font-weight: 700; font-size: 14px; color: var(--ink); }
.tapcheck-phone { border: 0; padding: 0; background: transparent; }
.tapcheck-phone .tapcheck-q { font-size: 16px; margin-bottom: var(--s3); }
.tapcheck-phone .tap { padding: 8px 10px; font-size: 14px; }
.tapcheck-phone .tap-hint { font-size: 9px; letter-spacing: 0.06em; }
.tapcheck-phone .tapcheck-out { margin: var(--s4) 0 0; gap: var(--s3); }
.tapcheck-phone .tapcheck-ring { width: 44px; height: 44px; }
.tapcheck-phone .tapcheck-msg { font-size: 13px; line-height: 1.4; }
@media (max-width: 1023px) {
  .way-panel { grid-template-columns: minmax(0, 1fr); gap: var(--s6); }
}
@media (max-width: 700px) {
  .picker-btns.way-tabs { display: grid; grid-auto-flow: row; grid-template-columns: repeat(2, minmax(0, 1fr)); grid-auto-columns: auto; width: 100%; }
  .picker-btns.way-tabs .toggle-btn { min-height: 44px; padding: 6px 8px; white-space: normal; line-height: 1.2; }
}

/* ---------- 33. The bundle picture and the free first steps (Home) ----------
   .bf-stage is a 600 x 500 drawing in percentages: every item and label sits at its
   x / 6 and y / 5 per cent, and the SVG lines use the same 600 x 500 viewBox, so lines
   and items stay joined at every width. Sizes inside use cqw (1% of the picture's width). */
.bundle { display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: var(--s7); align-items: center; background: var(--surface); border: 1px solid var(--hairline); border-radius: var(--r-card); padding: var(--s6); }
.bundle-body { display: flex; flex-direction: column; align-items: flex-start; gap: var(--s4); }
.bundle-body > * { margin: 0; }
.bundle-fig { margin: 0; container-type: inline-size; }
.bf-stage { position: relative; aspect-ratio: 6 / 5; background: var(--paper); border-radius: var(--r-card); overflow: hidden; }
.bf-lines { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 0; }
.bf-lines line { stroke: var(--ink); stroke-width: 1; vector-effect: non-scaling-stroke; }
.bf-call {
  position: absolute; z-index: 3; left: calc(var(--x) / 6 * 1%); top: calc(var(--y) / 5 * 1%); transform: translate(-50%, -50%);
  font: 500 clamp(8px, 1.9cqw, 11px)/1.2 var(--font-mono); letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink); white-space: nowrap;
}
@container (max-width: 300px) { .bf-call { letter-spacing: 0.02em; } }
.bf-live, .bf-doc, .bf-cards, .bf-phone, .bf-chat { position: absolute; }
.bf-live {
  left: 5%; top: 15.2%; width: 43.34%; aspect-ratio: 16 / 10; z-index: 1;
  display: grid; grid-template-columns: 3fr 1fr; gap: 0.7cqw; padding: 0.7cqw;
  background: var(--ink); border-radius: 1.6cqw; box-shadow: 0 2cqw 4cqw rgba(10, 10, 10, 0.18);
}
.bf-live img { width: 100%; height: 100%; object-fit: cover; border-radius: 1cqw; }
.bf-live-tag { position: absolute; top: 1.8cqw; left: 1.8cqw; padding: 0.5cqw 1cqw; border-radius: 1cqw; background: var(--danger); color: #FFFFFF; font: 500 1.5cqw/1 var(--font-mono); letter-spacing: 0.08em; text-transform: uppercase; }
.bf-live-time { position: absolute; top: 1.8cqw; left: 8cqw; padding: 0.5cqw 1cqw; border-radius: 1cqw; background: rgba(10, 10, 10, 0.72); color: var(--paper); font: 500 1.4cqw/1 var(--font-mono); letter-spacing: 0.06em; text-transform: uppercase; }
.bf-live-grid { display: grid; grid-template-rows: repeat(4, minmax(0, 1fr)); gap: 0.7cqw; }
.bf-live-grid i { border-radius: 0.8cqw; background: radial-gradient(circle at 50% 42%, #55534F 0 16%, transparent 17%), radial-gradient(ellipse at 50% 100%, #55534F 0 34%, transparent 35%), #2A2927; }
.bf-doc {
  left: 11.67%; top: 38%; width: 26.67%; aspect-ratio: 1 / 1.414; z-index: 2; transform: rotate(-6deg);
  display: flex; flex-direction: column; gap: 1.2cqw; padding: 2.2cqw 2cqw; background: var(--ink); color: var(--paper);
  border-radius: 0.8cqw; box-shadow: 0 2.4cqw 4cqw rgba(10, 10, 10, 0.28);
}
.bf-doc-kicker { font: 500 1.3cqw/1.2 var(--font-mono); letter-spacing: 0.08em; text-transform: uppercase; color: var(--brand-accent); }
.bf-doc-title { font: 800 3.8cqw/0.92 var(--font-sans); letter-spacing: -0.03em; text-transform: uppercase; }
.bf-doc-foot { margin-top: auto; font: 500 1.2cqw/1.2 var(--font-mono); letter-spacing: 0.08em; text-transform: uppercase; color: var(--mute-on-ink); }
.bf-cards { left: 43.34%; top: 60%; width: 23.34%; aspect-ratio: 140 / 104; z-index: 2; }
.bf-card {
  position: absolute; left: 0; right: 0; height: 44%; display: flex; align-items: flex-start; padding: 1.3cqw 1.6cqw 0;
  background: var(--surface); border: 1px solid var(--hairline); border-radius: 1cqw; box-shadow: 0 1cqw 2cqw rgba(10, 10, 10, 0.1);
  font: 700 1.8cqw/1.1 var(--font-sans); color: var(--ink);
}
.bf-card:nth-child(1) { top: 0; transform: rotate(-7deg); }
.bf-card:nth-child(2) { top: 28%; left: 6%; right: -6%; transform: rotate(3deg); }
.bf-card:nth-child(3) { top: 56%; transform: rotate(-2deg); background: var(--brand-accent); border-color: var(--brand-accent); }
.bf-phone {
  left: 71.67%; top: 12.4%; width: 21.67%; aspect-ratio: 130 / 275; z-index: 2;
  display: flex; flex-direction: column; gap: 1.1cqw; padding: 2cqw 1.5cqw;
  background: var(--surface); border: 0.9cqw solid var(--ink); border-radius: 3.4cqw; box-shadow: 0 2cqw 4cqw rgba(10, 10, 10, 0.2);
}
.bf-phone-top { font: 500 1.4cqw/1 var(--font-mono); letter-spacing: 0.08em; text-transform: uppercase; color: var(--mute); }
.bf-ring { width: 48%; height: auto; align-self: center; margin: 0.6cqw 0; transform: rotate(-90deg); }
.bf-ring .ring-fg { transition: none; }
.bf-row { display: flex; justify-content: space-between; align-items: center; padding-bottom: 0.8cqw; border-bottom: 1px solid var(--hairline); font: 700 1.8cqw/1 var(--font-sans); color: var(--ink); }
.bf-row::after { content: ""; width: 1.8cqw; height: 1.8cqw; border-radius: 50%; border: 1px solid var(--ink); }
.bf-row.is-on::after { background: var(--brand-accent); }
.bf-phone-badge { margin-top: auto; align-self: flex-start; padding: 0.6cqw 1cqw; border: 1px solid var(--ink); border-radius: var(--r-pill); font: 500 1.2cqw/1 var(--font-mono); letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink); }
.bf-chat {
  left: 70%; top: 70%; width: 26.67%; z-index: 2; display: flex; flex-direction: column; gap: 0.8cqw; padding: 1.3cqw;
  background: var(--surface); border: 1px solid var(--hairline); border-radius: 1.6cqw; box-shadow: 0 1.4cqw 3cqw rgba(10, 10, 10, 0.12);
}
.bf-chat-head { font: 500 1.3cqw/1.2 var(--font-mono); letter-spacing: 0.08em; text-transform: uppercase; color: var(--mute); }
.bf-bubble { align-self: flex-end; padding: 0.7cqw 1.2cqw; border-radius: 1.4cqw; background: var(--brand-accent); font: 600 1.6cqw/1.2 var(--font-sans); color: var(--ink); }
.bf-bubble-b { align-self: flex-start; background: var(--paper); }
.freebies { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s5); }
.freebie { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); background: var(--surface); border: 1px solid var(--hairline); border-radius: var(--r-card); overflow: hidden; }
.freebie-media { min-height: 240px; background: var(--ink); }
.freebie-poster img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 20%; }
.freebie-quiz { display: flex; flex-direction: column; justify-content: center; gap: var(--s2); padding: var(--s5) var(--s4); background: var(--brand-accent); color: var(--ink); }
.freebie-num { font: 800 clamp(72px, 8vw, 112px)/0.85 var(--font-sans); letter-spacing: -0.05em; }
.freebie-sub { font: 500 var(--label)/1.4 var(--font-mono); letter-spacing: var(--track); text-transform: uppercase; }
.freebie-chips { display: flex; flex-wrap: wrap; gap: 4px; margin-top: var(--s2); }
.freebie-chips i { font: 500 10px/1 var(--font-mono); font-style: normal; letter-spacing: 0.08em; text-transform: uppercase; border: 1px solid var(--ink); border-radius: var(--r-pill); padding: 5px 7px; }
.freebie-body { display: flex; flex-direction: column; align-items: flex-start; gap: var(--s3); padding: var(--s5); }
.freebie-body > * { margin: 0; }
.freebie-body .btn { margin-top: auto; }
@media (max-width: 1023px) {
  .bundle { grid-template-columns: minmax(0, 1fr); gap: var(--s6); padding: var(--s4); }
  .freebies { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 479px) {
  .freebie-media { min-height: 200px; }
  .freebie-body { padding: var(--s4); }
}

/* ---------- 34. Big countdown (Home, last section: .cdband, [data-bigcd]) ----------
   Centred. The digits show only once js/pages.js is running them (.is-live) and hide after
   the close (.is-closed). With reduced motion there are no seconds; the pause button stays. */
.cdband { text-align: center; }
.cdband .marker { justify-content: center; }
.cdband .marker::before { content: ""; flex: 1 1 auto; height: 1px; background: var(--ink-2); max-width: 96px; }
.cdband .btn-row { justify-content: center; }
.cdband p { margin-inline: auto; }
.cdband-h { margin: var(--s5) 0 var(--s3); font-weight: 700; font-size: clamp(26px, 3.2vw, 44px); line-height: 1.15; letter-spacing: -0.02em; }
.bigcd-text { font-size: var(--lead); }
.bigcd-digits { display: flex; justify-content: center; align-items: flex-start; gap: clamp(4px, 1.2vw, 18px); margin-top: var(--s5); }
.bigcd-unit { display: flex; flex-direction: column; align-items: center; }
.bigcd-unit b {
  font: 800 clamp(52px, 13vw, 184px)/0.9 var(--font-sans); letter-spacing: -0.04em; font-variant-numeric: tabular-nums;
  background: linear-gradient(180deg, #FFFFFF 0%, var(--paper) 45%, var(--mute-on-ink) 100%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.bigcd-unit small { margin-top: var(--s3); font: 500 var(--label-lg)/1.4 var(--font-mono); letter-spacing: var(--track); text-transform: uppercase; color: var(--paper-70); }
.bigcd-sep { font: 800 clamp(34px, 8vw, 110px)/1 var(--font-sans); color: var(--mute-on-ink); padding-top: 0.08em; }
.bigcd-pause {
  display: block; margin: var(--s4) auto 0; min-height: 32px; padding: 0 2px; border: 0; background: transparent; cursor: pointer;
  font: 500 var(--label)/1.5 var(--font-mono); letter-spacing: var(--track); text-transform: uppercase; color: var(--mute-on-ink);
}
.bigcd-pause:hover, .bigcd-pause:focus-visible { color: var(--paper); }
html:not(.js) .bigcd-digits, html:not(.js) .bigcd-pause,
.bigcd:not(.is-live) .bigcd-digits, .bigcd:not(.is-live) .bigcd-pause,
.bigcd.is-closed .bigcd-digits, .bigcd.is-closed .bigcd-pause { display: none; }
.cdband .cdband-hook { max-width: 30ch; font-weight: 700; font-size: clamp(22px, 2.6vw, 34px); line-height: 1.25; letter-spacing: -0.01em; color: var(--paper); }
@media (prefers-reduced-motion: reduce) { .bigcd-s { display: none; } }

/* ---------- 35. Film pop-up and side tab (Home) ----------
   A native <dialog> (focus stays inside, Escape closes). The side tab is fixed to the left
   edge from 600px up; on phones (and short landscape screens) the pop-up and the sticky bar do
   its job. From 600px to 1319px the page's side gutters widen to 46px while the tab is on the
   page, so the 34px tab never covers text; from 1320px the normal gutter already clears it. */
.sidetab {
  position: fixed; left: 0; top: 50%; z-index: 30; transform: translateY(-50%) rotate(180deg); writing-mode: vertical-rl;
  padding: 18px 11px; border-radius: 10px 0 0 10px; background: var(--brand-accent); color: var(--ink); text-decoration: none; white-space: nowrap;
  font: 500 var(--label-lg)/1 var(--font-mono); letter-spacing: var(--track); text-transform: uppercase;
  box-shadow: 0 6px 20px rgba(10, 10, 10, 0.18); transition: background-color var(--t-fast) ease, padding var(--t-fast) ease;
}
.sidetab:hover { background: #D9CAFC; padding-left: 14px; }
.sidetab:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
@media (max-width: 599px), (max-height: 500px) { .sidetab { display: none; } }
@media (min-width: 600px) and (max-width: 1319px) and (min-height: 501px) {
  body:has(> .sidetab) .container { padding-left: max(var(--gutter), 46px); padding-right: max(var(--gutter), 46px); }
  body:has(> .sidetab) .reviews { margin-inline: 0; padding-inline: 0; scroll-padding-inline: 0; }
}
html.filmpop-open { overflow: hidden; }
.filmpop {
  width: min(780px, calc(100vw - 32px)); max-height: calc(100vh - 32px); padding: 0; border: 0; border-radius: 16px; overflow: auto;
  background: var(--surface); color: var(--text); box-shadow: 0 30px 80px rgba(10, 10, 10, 0.35);
}
@supports (height: 100dvh) { .filmpop { max-height: calc(100dvh - 32px); } }
.filmpop:not([open]) { display: none; }
.filmpop::backdrop { background: rgba(10, 10, 10, 0.72); }
.filmpop[open] { animation: filmpop-in 320ms var(--ease) both; }
@keyframes filmpop-in { from { opacity: 0; transform: translateY(14px) scale(0.98); } }
.filmpop-inner { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); }
.filmpop-art { background: var(--ink); }
.filmpop-art { display: flex; align-items: center; }
.filmpop-art img { width: 100%; height: 100%; object-fit: contain; object-position: 50% 50%; }
.filmpop-body { position: relative; display: flex; flex-direction: column; gap: var(--s3); padding: var(--s6); }
.filmpop-body > p { margin: 0; }
.filmpop-h { margin: 0; padding-right: 40px; font-weight: 800; font-size: clamp(24px, 3vw, 34px); line-height: 1.1; letter-spacing: -0.02em; color: var(--ink); }
.filmpop-close {
  position: absolute; top: 8px; right: 8px; width: 44px; height: 44px; border: 0; border-radius: 50%;
  background: transparent; color: var(--ink); font: 400 30px/1 var(--font-sans); cursor: pointer;
}
.filmpop-close:hover { background: var(--paper); }
.filmpop .form { margin-top: var(--s2); }
@media (max-width: 639px) {
  .filmpop-inner { grid-template-columns: minmax(0, 1fr); }
  .filmpop-art { display: none; }
  .filmpop-body { padding: var(--s5) var(--s4); }
}
@media (prefers-reduced-motion: reduce) {
  .filmpop[open] { animation: none; }
  .sidetab { transition: none; }
  html.reveal-on .strikes.is-in s::after { transition: none; }
}

/* ---------- 36. The way: step label on each tab (Home, 28 Sep 2026) ----------
   The 4 parts read as 1 weekly loop: each panel opens with its step and when it happens. */
.way-step { display: inline-flex; align-items: center; gap: 8px; font: 500 var(--label)/1.4 var(--font-mono); letter-spacing: var(--track); text-transform: uppercase; color: var(--mute); }
.way-step::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--brand-accent); box-shadow: 0 0 0 1.5px var(--ink); }
.way-copy .way-step + .h3 { margin-top: calc(var(--s2) * -1); }

/* ---------- 37. Stats heading, review score and review reel (Home, 28 Sep 2026) ----------
   .stats-h: a second, smaller headline inside § 01 over the 3 statistics.
   .rv-score: the real feedback score, in place of stars (the form asked positive or neutral).
   .reel: 1 full-width row of equal cards. pages.js initReel duplicates the cards (aria-hidden) and adds
   .is-marquee; the track then loops by -50%, paused on hover, on focus and by the Pause motion button.
   Without it (reduced motion, no JavaScript) the row is swiped, card by card. Spacing is a right margin
   on each card, so the duplicated half is exactly half the track. */
.stats-h { font-weight: 800; font-size: clamp(30px, 3.8vw, 56px); line-height: 1.02; letter-spacing: -0.03em; text-transform: uppercase; color: var(--ink); }
.rv-score { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px var(--s3); margin: 0; }
.band-ink .rv-score b { font: 800 clamp(40px, 4.6vw, 68px)/1 var(--font-sans); letter-spacing: -0.03em; color: var(--paper); white-space: nowrap; }
.band-ink .rv-score span { font-size: var(--lead); line-height: 1.4; color: var(--paper-70); }
.reel { position: relative; overflow: hidden; padding-left: max(var(--gutter), calc((100% - var(--container)) / 2 + var(--gutter))); }
.reel-track { display: flex; width: max-content; margin: 0; padding: 0 0 var(--s2); list-style: none; }
.reel .review { flex: 0 0 clamp(280px, 28vw, 380px); margin: 0 var(--s5) 0 0; }
.reel .review-quote p { font-size: 16px; }
.reel.is-marquee { -webkit-mask-image: linear-gradient(to right, transparent 0, #000 4%, #000 96%, transparent 100%); mask-image: linear-gradient(to right, transparent 0, #000 4%, #000 96%, transparent 100%); }
.reel.is-marquee .reel-track { animation: logos-loop var(--reel-dur, 60s) linear infinite; will-change: transform; }
.reel.is-marquee:hover .reel-track, .reel.is-marquee:focus-within .reel-track, .reel.is-paused .reel-track { animation-play-state: paused; }
.reel:not(.is-marquee) { overflow-x: auto; scroll-snap-type: x mandatory; overscroll-behavior-x: contain; scroll-padding-left: max(var(--gutter), calc((100% - var(--container)) / 2 + var(--gutter))); }
.reel:not(.is-marquee) .review { scroll-snap-align: start; }
.reel:not(.is-marquee) .reel-track { padding-right: var(--gutter); }
.reel:focus-visible { outline: 2px solid var(--brand-accent); outline-offset: -2px; }
@media (min-width: 600px) and (max-width: 1319px) and (min-height: 501px) {
  body:has(> .sidetab) .reel { padding-left: 46px; }
}
@media (prefers-reduced-motion: reduce) { .reel.is-marquee .reel-track { animation: none; } }
/* In the reel every card is as tall as the tallest: the name sits on the bottom edge, like a signature */
.band-ink .reel .review .review-by { margin-top: auto; }
@media (max-width: 599px) {
  .reel .review { flex-basis: clamp(290px, 80vw, 340px); padding: var(--s5); gap: var(--s3); }
  .reel .review-quote p { font-size: 15px; line-height: 1.55; }
}

/* ---------- 38. Review form (/review): a real star rating ----------
   5 radios drawn as stars; the chosen one and every star before it fill. Keyboard: arrow keys move
   between the radios as usual, and the focused star shows a ring. */
.review-form fieldset { border: 0; margin: 0; padding: 0; min-width: 0; }
.review-form legend { padding: 0; margin-bottom: var(--s2); font-weight: 600; color: var(--paper); }
.stars { display: flex; gap: 6px; }
.star { position: relative; cursor: pointer; line-height: 0; }
.star input { position: absolute; inset: 0; opacity: 0; margin: 0; cursor: pointer; }
.star svg { width: 40px; height: 40px; fill: transparent; stroke: var(--paper-60); stroke-width: 1.4; stroke-linejoin: round; transition: fill var(--t-fast) ease, stroke var(--t-fast) ease, transform var(--t-fast) var(--ease); }
.star:hover svg { transform: scale(1.08); }
.star input:focus-visible + svg { outline: 2px solid var(--brand-accent); outline-offset: 2px; border-radius: 4px; }
.stars:has(.star:nth-child(1) input:checked) .star:nth-child(-n+1) svg,
.stars:has(.star:nth-child(2) input:checked) .star:nth-child(-n+2) svg,
.stars:has(.star:nth-child(3) input:checked) .star:nth-child(-n+3) svg,
.stars:has(.star:nth-child(4) input:checked) .star:nth-child(-n+4) svg,
.stars:has(.star:nth-child(5) input:checked) .star:nth-child(-n+5) svg { fill: #F2B544; stroke: #F2B544; }
.radios-inline { display: flex; flex-wrap: wrap; gap: 10px 20px; }
.radios-inline .radio { grid-template-columns: 20px auto; }
.band-ink .review-form .radio, .band-ink .review-form label { color: var(--paper-70); }
@media (prefers-reduced-motion: reduce) { .star svg { transition: none; } }

/* ---------- 39. Longevity Avatar result (/start, 29 Sep 2026) ----------
   A big rank beside the avatar name, held or slipped under each basic, and the full ladder of 16
   with your rung lit. The ladder is written by js/site.js initQuiz. */
.avatar-card { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--s6); align-items: center; }
.avatar-rank, .band-ink .avatar-rank { display: flex; align-items: baseline; margin: 0; color: var(--brand-accent); font-weight: 800; line-height: 0.85; letter-spacing: -0.04em; }
.avatar-rank span { font-size: clamp(40px, 5vw, 72px); }
.avatar-rank b { font-size: clamp(96px, 14vw, 200px); font-variant-numeric: tabular-nums; }
.avatar-rank small { margin-left: var(--s2); font: 500 var(--label-lg)/1 var(--font-mono); letter-spacing: var(--track); text-transform: uppercase; color: var(--paper-70); }
.first-move { border-left: 3px solid var(--brand-accent); padding-left: var(--s4); }
.band-ink .first-move b { color: var(--paper); }
.result-totals .st { margin-top: var(--s2); font: 500 var(--label)/1.4 var(--font-mono); letter-spacing: var(--track); text-transform: uppercase; }
.result-totals .st.is-held { color: var(--brand-accent); }
.result-totals .st.is-slipped { color: var(--mute-on-ink); }
.ladder { list-style: none; margin: var(--s4) 0 0; padding: 0; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-rows: repeat(8, auto); grid-auto-flow: column; gap: 1px; background: var(--ink-2); border: 1px solid var(--ink-2); counter-reset: none; }
.rung { display: grid; grid-template-columns: 2.4em minmax(0, 1fr) auto; align-items: center; gap: var(--s3); padding: 10px var(--s4); background: var(--ink); color: var(--paper-70); font-size: 15px; }
.rung-n { font: 500 var(--label-lg)/1 var(--font-mono); color: var(--mute-on-ink); font-variant-numeric: tabular-nums; }
.rung-dots { display: inline-flex; gap: 4px; }
.rung-dots i { width: 8px; height: 8px; border-radius: 50%; border: 1px solid var(--mute-on-ink); }
.rung-dots i.on { background: var(--paper-70); border-color: var(--paper-70); }
.rung.is-you { background: var(--brand-accent); color: var(--ink); font-weight: 700; }
.rung.is-you .rung-n { color: var(--ink); }
.rung.is-you .rung-dots i { border-color: var(--ink); }
.rung.is-you .rung-dots i.on { background: var(--ink); }
@media (max-width: 767px) {
  .avatar-card { grid-template-columns: minmax(0, 1fr); gap: var(--s3); }
  .ladder { grid-template-columns: minmax(0, 1fr); grid-template-rows: none; grid-auto-flow: row; }
}

/* ---------- 40. The 5 weeks (Home § 03 cards, /bootcamp week points), 29 Sep 2026 ----------
   5 equal cards in 1 row from 1200px; below that a row you swipe, card by card. The stage pill and the top
   rule are coloured by stage: Recovery paper, Performance accent, Prevention ink. */
.weeks { list-style: none; margin-bottom: 0; padding: 0; display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: var(--s4); }
.wk { display: flex; flex-direction: column; gap: var(--s3); padding: var(--s5); background: var(--surface); border: 1px solid var(--hairline); border-top: 4px solid var(--hairline); border-radius: var(--r-card); }
.wk > * { margin: 0; }
.wk-performance { border-top-color: var(--brand-accent); }
.wk-prevention { border-top-color: var(--ink); }
.wk-top { display: flex; justify-content: space-between; align-items: center; gap: var(--s2); }
.wk-n { font: 700 15px/1 var(--font-sans); color: var(--ink); }
.wk-stage { font: 500 10px/1 var(--font-mono); letter-spacing: 0.1em; text-transform: uppercase; padding: 5px 8px; border-radius: var(--r-pill); background: var(--paper); color: var(--ink); border: 1px solid var(--hairline); }
.wk-performance .wk-stage { background: var(--brand-accent); border-color: var(--brand-accent); }
.wk-prevention .wk-stage { background: var(--ink); border-color: var(--ink); color: var(--paper); }
.wk-mode { font: 500 var(--label)/1.4 var(--font-mono); letter-spacing: var(--track); text-transform: uppercase; color: var(--mute); }
.wk-title { font-weight: 800; font-size: 21px; line-height: 1.1; letter-spacing: -0.01em; text-transform: uppercase; color: var(--ink); }
.wk-lead { font-size: 15px; line-height: 1.45; color: var(--ink); font-weight: 500; }
.wk-points, .week-points { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.wk-points li, .week-points li { position: relative; padding-left: 16px; font-size: 14px; line-height: 1.45; }
.wk-points li::before, .week-points li::before { content: ""; position: absolute; left: 0; top: 0.55em; width: 6px; height: 6px; border-radius: 50%; background: var(--brand-accent); box-shadow: 0 0 0 1px var(--ink); }
.wk-pillars, .week-pillars { margin-top: auto; padding-top: var(--s3); border-top: 1px solid var(--hairline); font: 500 10px/1.5 var(--font-mono); letter-spacing: 0.08em; text-transform: uppercase; color: var(--mute); }
.week-pillars { margin-top: var(--s2); }
.wk-pillars, .week-pillars, .wk-lead { max-width: none; }
.weeks:focus-visible { outline: 2px solid var(--ink); outline-offset: 6px; border-radius: var(--r-card); }
@media (max-width: 1199px) {
  .weeks {
    grid-template-columns: none; grid-auto-flow: column; grid-auto-columns: minmax(270px, 42%);
    overflow-x: auto; scroll-snap-type: x mandatory; overscroll-behavior-x: contain;
    margin-inline: calc(var(--gutter) * -1); padding: 0 var(--gutter) var(--s3); scroll-padding-inline: var(--gutter);
  }
  .wk { scroll-snap-align: start; }
}
@media (max-width: 599px) { .weeks { grid-auto-columns: minmax(260px, 82%); } }
@media (min-width: 600px) and (max-width: 1199px) and (min-height: 501px) {
  body:has(> .sidetab) .weeks { margin-inline: 0 -46px; padding-inline: 0 46px; scroll-padding-inline: 0; }
}
/* The 5 pillar rules line up across the row; the footer link sits level with its caption */
@media (min-width: 1200px) { .wk-pillars { min-height: 58px; } }
.flex-between > p { margin-bottom: 0; }

/* ---------- 41. Home § 04 "Is this Bootcamp for you?" and the reviews footer (30 Sep 2026) ----------
   3 groups it is built for, in a hairline row; the reviews row ends with "Submit your review" and the
   small pause icon for the moving row (WCAG 2.2.2). */
.forwho { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1px; background: var(--hairline); border: 1px solid var(--hairline); border-radius: var(--r-card); overflow: hidden; }
.forwho-item { display: flex; flex-direction: column; gap: var(--s2); padding: var(--s5); background: var(--surface); }
.forwho-item > * { margin: 0; }
.forwho-item .h4 { color: var(--ink); }
@media (max-width: 767px) { .forwho { grid-template-columns: minmax(0, 1fr); } }
.reel-foot { display: flex; align-items: center; justify-content: space-between; gap: var(--s4); margin-top: var(--s6); }
.reel-pause { position: relative; width: 40px; height: 40px; border-radius: 50%; border: 1px solid var(--mute-on-ink); background: transparent; cursor: pointer; flex: 0 0 auto; }
.reel-pause span, .reel-pause span::after { position: absolute; top: 13px; width: 3px; height: 14px; background: var(--paper); content: ""; }
.reel-pause span { left: 15px; }
.reel-pause span::after { left: 7px; top: 0; }
.reel-pause.is-paused span { left: 15px; top: 12px; width: 0; height: 0; background: transparent; border-style: solid; border-width: 8px 0 8px 13px; border-color: transparent transparent transparent var(--paper); }
.reel-pause.is-paused span::after { display: none; }
.reel-pause:hover, .reel-pause:focus-visible { border-color: var(--paper); }
@media (prefers-reduced-motion: reduce) { .reel-pause { display: none; } }

/* ---------- 42. Home, 1 Oct 2026: tagline on 2 lines; the bundle picture as the Masterclass picture ---------- */
.tl-line { display: block; }
.way-media.way-bundle { aspect-ratio: auto; padding: var(--s4); background: var(--paper); }
.way-media.way-bundle img { height: 100%; }
