/*
  Times Checkout — EDITORIAL variant.
  Same content as ../times-checkout/, laid out to let typography carry the
  page: oversized display type, narrow measures for body copy, and hairline
  rules instead of filled cards.
*/

:root {
  /* Colour — near-monochrome; blue accent appears only in small doses */
  --bg: #ffffff;
  --ink: #14181a;
  --muted: #5c666b;
  --faint: #949da1;
  --rule: #e3e1dc;
  --accent: #181bf3;
  --dark-bg: #14181a;
  --dark-text: #ffffffdb;
  --dark-faint: #ffffff8c;
  --wash: #f4f1ec;

  /* Motion */
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);

  --font: "Helvetica Neue", Helvetica, Arial, sans-serif;

  /* Layout */
  --gutter: 37.6667px;
  --measure: 560px;       /* comfortable line length for body copy */
  --measure-wide: 860px;  /* for large statement type (verdict) */
  --measure-statement: 658px; /* narrower measure used by chapter statements */
  --page-max: 1180px;

  /* Vertical rhythm */
  --gap-s: 24px;
  --gap-m: 48px;
  --gap-l: 96px;
  --gap-xl: 180px;        /* between chapters */
}

* { box-sizing: border-box; }

/* Cross-document view transition — matches the homepage's project card into
   this page's hero on click. Must be present on both ends of the
   navigation (see the fuller comment in home/styles.css); without it here,
   the homepage's own opt-in is a no-op and navigation just falls back to a
   plain cut, which is the correct degradation, not a bug. */
@view-transition {
  navigation: auto;
}

@media not (prefers-reduced-motion: reduce) {
  ::view-transition-group(*) {
    animation-duration: 500ms;
    animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
  }
}

@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation: none !important;
  }
}

/* Mirrors the identical block in home/styles.css — both sides of a
   cross-document transition need to agree on this timing. See that file
   for the full reasoning: the card/background leads (expands first), the
   four content pieces follow on a delay so they read as falling into place
   afterward rather than everything resizing in lockstep. */
@media not (prefers-reduced-motion: reduce) {
  ::view-transition-group(vt-card-checkout) {
    animation-duration: 650ms;
    animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
  }

  ::view-transition-group(vt-media-checkout) {
    animation-duration: 550ms;
    animation-delay: 300ms;
    animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
  }

  ::view-transition-group(vt-eyebrow-checkout) {
    animation-duration: 500ms;
    animation-delay: 350ms;
    animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
  }

  ::view-transition-group(vt-title-checkout) {
    animation-duration: 500ms;
    animation-delay: 420ms;
    animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
  }

  ::view-transition-group(vt-meta-checkout) {
    animation-duration: 450ms;
    animation-delay: 500ms;
    animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
  }
}

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font);
  -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; display: block; }

/* ── Top nav ─────────────────────────────────────────────────── */

/* .nav is already a direct child of <body> (not nested inside the
   max-width-constrained .page), so it just needs width:100% — no
   full-bleed breakout trick needed, and that trick (100vw + left:50% +
   translateX(-50%)) is unreliable combined with position:sticky once the
   element engages its "stuck" state, so don't reach for it here. */
.nav {
  width: 100%;
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--bg);
  transition: transform 0.3s var(--ease-out);
}

.nav.is-hidden {
  transform: translateY(-100%);
}

.nav__inner {
  display: flex;
  justify-content: space-between;
  align-items: center;
  max-width: var(--page-max);
  margin: 0 auto;
  padding: 24px var(--gutter);
}

.nav__logo {
  font: 500 15px/20px var(--font);
  letter-spacing: -0.01em;
  color: var(--ink);
  text-decoration: none;
}

.nav__links {
  display: flex;
  gap: 32px;
}

.nav__links a {
  font: 400 13px/18px var(--font);
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--muted);
  text-decoration: none;
  transition: color 150ms ease;
}

.nav__links a:hover { color: var(--ink); }

/* ── Page column ─────────────────────────────────────────────── */

.page {
  margin: 0 auto;
  max-width: var(--page-max);
  padding: 0 var(--gutter);
}

/* ── Shared type ─────────────────────────────────────────────── */

.prose {
  font: 400 17px/29px var(--font);
  color: var(--muted);
  max-width: var(--measure);
  margin: 0;
}

.prose--lead {
  font-size: 19px;
  line-height: 32px;
  color: var(--ink);
}

/* Big, quiet statement type — the workhorse of this layout */
.statement {
  font: 400 29px/42px var(--font);
  letter-spacing: -0.015em;
  color: var(--ink);
  max-width: var(--measure-statement);
  margin: 0 0 var(--gap-l);
}

.passage {
  margin-bottom: var(--gap-m);
}

.passage__title {
  font: 500 13px/18px var(--font);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 14px;
}

/* ── Hero (v2 — full-bleed image + title, greymac.com-style) ──── */

.hero {
  /* Matches the homepage hero-echo card's outer .herocard box by name —
     this is what makes the rounded, contained card visually grow into this
     full-bleed section on click, not just its inner image/text. */
  view-transition-name: vt-card-checkout;
  width: 100vw;
  position: relative;
  left: 50%;
  /* --parallax-y is driven by Motion.heroParallax (script.js) as the user
     scrolls past the hero, on top of the existing full-bleed centring
     transform — never touched directly by JS so the two never fight.
     Mobile's own .hero rule below sets transform:none outright, which
     naturally disables the effect there without extra JS branching. */
  transform: translateX(-50%) translateY(var(--parallax-y, 0px));
  background: var(--dark-bg);
  overflow: hidden;
  padding-top: 64px;
  /* Gap to the next section lives entirely on .metrics's padding-top below
     (single source, not split across two stacking properties) — see there
     for why. */
  margin-bottom: 0;
}

.hero__art {
  /* Matches the homepage project card's .project__media by name — see the
     view-transition-name comment in home/styles.css. */
  view-transition-name: vt-media-checkout;
  /* near-square two-phone composite (1009×1024), sized down ~20% from the
     first pass and inset from the page edge on its own right margin
     (var(--gutter), matching the page's own content inset) rather than
     bleeding flush to the viewport edge. */
  position: absolute;
  /* Vertically centred against the title/meta text block (.hero__top),
     not the nav or the hero section as a whole. .hero__top's content is
     bottom-anchored and its bottom edge sits at 78vh (matches its own
     min-height) regardless of viewport height, so tying the art's offset
     to that same 78vh anchor keeps the two centred on each other as the
     viewport height changes, rather than a flat px value that would only
     be correct at one specific height. -587px was tuned while .hero__art
     was still a sibling of .hero__inner (positioned relative to the raw
     full-bleed .hero). Moving it inside .hero__inner (2026-08-23, to fix
     the gap-grows-with-viewport issue below) shifted its containing
     block's own top edge down by .hero's 64px padding-top, which the
     absolute-positioning containing block had been ignoring — re-derived
     to -526px to compensate and keep the same centred result. Re-derive
     if the title/description copy, art image, or .hero__top's padding/
     min-height change again. */
  /* Sized up 30% (2026-08-23, Rob: "hero image is too small now") — width
     33.3%→43.3%, min-width 306→398px scaled the same factor. Not measured
     live (Rob is checking visually), so the offset below is computed, not
     re-derived from a screenshot: growing the image by 30% grows its
     height by the same 30% (fixed 1009:1024 aspect ratio), which shifts
     the top-anchored box's vertical centre down by half that height
     delta (~60px at page-max width) — compensated by subtracting that
     from the previous -526px constant. Re-derive live if it looks off. */
  top: calc(78vh - 586px);
  /* Shifted right, off its var(--gutter) inset (2026-08-23) — at the bigger
     43.3%/398px size the art's left edge landed under .hero__top's text
     column (660px max-width) at typical desktop viewports, overlapping the
     description/rule/meta. -60px bleeds it right by that much past
     .hero__inner's own right edge (safe: .hero__inner is centred with
     margin left over past 1180px viewport width, so this only eats into
     that existing outer margin, not the text column). */
  right: -60px;
  width: 43.3%;
  min-width: 398px;
}

.hero__shot {
  /* The artwork already has its own tilt, shadows and transparent ground —
     no rotate/radius/box-shadow needed here (unlike the old flat-screenshot
     treatment, which relied on this to fake depth). */
  position: relative;
  width: 100%;
  height: auto;
}

.hero__inner {
  position: relative;
  z-index: 1;
  max-width: var(--page-max);
  margin: 0 auto;
  padding: 0 var(--gutter);
}

/* Title block fills roughly the first screen, bottom-anchored — kept at
   78vh (its original position) rather than growing to 100vh, so the
   title/meta don't shift down. Now also holds the description (moved in
   from below the fold, see .hero__description) between the title and the
   rule, so the whole eyebrow→title→description→rule→meta stack reads as
   one composition within the initial viewport. */
.hero__top {
  min-height: 78vh;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  /* Widened from 620px (2026-08-23) to close some of the gap to the art —
     safe at this breakpoint (>1080px) since the art moved inside
     .hero__inner (see .hero__art) keeps its distance roughly constant
     above 1080px; the ≤1080px tablet range pins this back to 620px (see
     that media query) since a wider column starts overlapping the art
     there. */
  max-width: 660px;
  padding-bottom: 64px;
}

.hero__eyebrow {
  view-transition-name: vt-eyebrow-checkout;
  display: block;
  font: 500 13px/18px var(--font);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: #fff;
  margin-bottom: 20px;
}

.hero__title {
  view-transition-name: vt-title-checkout;
  font: 700 clamp(44px, 6vw, 80px) / 1.04 var(--font);
  letter-spacing: -0.03em;
  color: #fff;
  margin: 0 0 32px;
}

.hero__rule {
  height: 1px;
  background: rgba(255, 255, 255, 0.18);
  margin-bottom: 28px;
}

.hero__meta {
  view-transition-name: vt-meta-checkout;
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 32px 48px;
}

.hero__meta-item { display: flex; flex-direction: column; gap: 4px; }

.hero__meta dt {
  font: 500 11px/16px var(--font);
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: #fff;
}

.hero__meta dd {
  margin: 0;
  font: 400 14px/21px var(--font);
  color: #fff;
}

/* Intro copy — sits between the title and the hairline rule, inside the
   initial viewport (moved up from a below-the-fold block that used to
   clear the fold with a large margin-top of its own). */
.hero__description {
  font: 400 19px/32px var(--font);
  color: #fff;
  text-align: left;
  max-width: var(--measure);
  margin: 0 0 40px;
}

/* ── Figures ─────────────────────────────────────────────────── */

.figure {
  margin: 0 0 var(--gap-l);
}

/* Plain full-width figure (e.g. workshop board) — no card, just a wash fallback */
.figure__img {
  width: 100%;
  background: var(--wash);
}

.figure__cap {
  margin-top: 14px;
  font: 400 13px/18px var(--font);
  color: var(--faint);
}

/* Grouped/annotated screenshots sit in a light card, sized and centred to
   Paper's exact crop rather than stretched to fill the column. */
.figure__card {
  display: flex;
  align-items: center;
  justify-content: center;
  background: #d3e1e7;
  border-radius: 8px;
}

.figure--audit .figure__card { padding-block: 40px; }
.figure--audit .figure__img { width: 954px; max-width: 100%; height: auto; background: none; }

.figure--variant .figure__card { padding-block: 56px; }
.figure--variant .figure__img { width: 922px; max-width: 100%; height: auto; background: none; }

/* ── Metrics ─────────────────────────────────────────────────── */

.metrics {
  /* Single source for the hero→Impact gap (.hero's own margin-bottom is
     zeroed above). Superseded the earlier "match the solution-copy gap"
     target (276px) — matching that value made the block look bottom-heavy
     once scrolled past (276px of white space above the copy vs. only this
     rule's own 180px padding-bottom below it). Centering the copy in the
     white space instead means the final (fully-scrolled-past) top gap
     should equal this same padding-bottom (180px = var(--gap-xl)), not the
     solution gap. Motion.heroParallax (script.js) pushes .hero up by its
     own maxOffset (180px here) once fully scrolled past, and since .metrics
     doesn't share that transform, the visible top gap = this padding-top +
     180px. So padding-top is set to 180 − 180 = 0 — at rest (pre-scroll)
     Impact sits flush against the hero, then the gap grows in to exactly
     180px as the parallax engages, matching the 180px below and centering
     the copy in the revealed white space. */
  padding-top: 0;
  padding-bottom: var(--gap-xl);
}

.metrics__title {
  display: block;
  margin: 0 0 32px;
}

.metrics__row {
  display: flex;
  gap: 64px;
}

.metric {
  flex: 1;
  border-top: 1px solid var(--ink);
  padding-top: 20px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.metric__value {
  font: 700 clamp(44px, 4.6vw, 64px) / 1 var(--font);
  letter-spacing: -0.04em;
  color: var(--ink);
}

.metric__label {
  font: 400 14px/21px var(--font);
  color: var(--muted);
  max-width: 100%;
  white-space: nowrap;
}

/* ── Context block — cascading diagonal layout ──────────────────
   Lives inside the dark .hero, below the fold, directly after .hero__top
   (the description now sits inside .hero__top, above the fold — see
   .hero__description) — positions/sizes unchanged, only entry__text's
   colour was adjusted so it reads on the dark background. */

.block {
  position: relative;
  height: 741px;
  /* Separation from .hero__top's meta row above, so Context/Problem/
     Solution reads as its own moment rather than a continuation of the
     hero. */
  margin-top: var(--gap-xl);
  margin-bottom: var(--gap-xl);
}

.entry {
  position: absolute;
  display: flex;
  flex-direction: column;
  gap: 16px;
  width: 323px;
}

.entry:nth-child(1) { top: 0;    left: 0px; }
.entry:nth-child(2) { top: 231px; left: 392px; }
.entry:nth-child(3) { top: 462px; left: 783px; }

.entry__label {
  font: 700 11px/22px var(--font);
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: #fff;
}

.entry__text {
  margin: 0;
  font: 400 17px/29px var(--font);
  color: #fff;
}

/* ── Chapters ────────────────────────────────────────────────── */

.chapter { padding-bottom: var(--gap-xl); }

.chapter__head {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  margin-bottom: 40px;
}

.chapter__num {
  font: 500 16px/22px var(--font);
  color: var(--accent);
}

.chapter__title {
  font: 700 clamp(34px, 3.6vw, 46px) / 1.08 var(--font);
  letter-spacing: -0.025em;
  color: var(--ink);
  margin: 0;
}

/* ── Findings / iteration items — rules, not boxes ───────────── */

.findings { margin-bottom: var(--gap-l); }

.finding {
  display: flex;
  gap: 48px;
  padding: 32px 0;
  border-top: 1px solid var(--rule);
}

.finding__icon {
  flex: 0 0 40px;
  color: var(--accent);
}

.finding__icon svg {
  width: 28px;
  height: 28px;
  margin-top: 2px;
  display: block;
}

/* The icon's stroke-draw is its ONLY motion — .finding itself carries no
   opacity/transform reveal (that lives on .finding__body instead, see below),
   so the icon never fades/slides at the same time it's tracing its outline.
   pathLength="100" on each shape normalizes stroke-dasharray/-offset
   regardless of actual path geometry. */
.icon-draw {
  stroke-dasharray: 100;
  stroke-dashoffset: 100;
  transition: stroke-dashoffset 600ms var(--ease-out);
}

.finding.is-visible .icon-draw {
  stroke-dashoffset: 0;
}

/* Filled dots (no stroke to draw) land just after the line finishes. */
.icon-dot {
  opacity: 0;
  transform-origin: center;
  transform: scale(0.5);
  transition: opacity 200ms var(--ease-out), transform 200ms var(--ease-out);
  transition-delay: 500ms;
}

.finding.is-visible .icon-dot {
  opacity: 1;
  transform: scale(1);
}

/* Missing-trust-signals icon keeps its permanent "3 3" dashed stroke — animating
   its own stroke-dashoffset would just phase-shift the existing dash tiling, not
   reveal it, so the dashes wouldn't visibly draw in. Instead an invisible mask
   path (identical "d", solid, pathLength-normalized) draws in behind the scenes
   and progressively unmasks the real dashed path, so the dashes themselves
   appear to trace on one at a time rather than everything popping in at once. */
.icon-mask-draw {
  stroke-dasharray: 100;
  stroke-dashoffset: 100;
  transition: stroke-dashoffset 1050ms var(--ease-out);
}

.finding.is-visible .icon-mask-draw {
  stroke-dashoffset: 0;
}

@media (prefers-reduced-motion: reduce) {
  .icon-draw,
  .icon-mask-draw { stroke-dashoffset: 0; transition: none; }
  .icon-dot { opacity: 1; transform: none; transition: none; }
}

.finding__body {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.finding__title {
  font: 500 22px/30px var(--font);
  letter-spacing: -0.01em;
  color: var(--ink);
  margin: 0;
}

.finding__points {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 9px;
  max-width: var(--measure);
}

.finding__points li {
  font: 400 16px/26px var(--font);
  color: var(--muted);
}

/* ── Hypotheses — large pull-quote treatment ─────────────────── */

.hypotheses {
  display: flex;
  gap: 72px;
  margin-bottom: var(--gap-l);
}

.hypothesis {
  flex: 1;
  border-top: 1px solid var(--ink);
  padding-top: 20px;
}

.hypothesis__label {
  display: block;
  font: 500 11px/16px var(--font);
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 16px;
}

.hypothesis__text {
  margin: 0;
  font: 400 21px/33px var(--font);
  letter-spacing: -0.01em;
  color: var(--ink);
}

/* ── Before / after comparisons ──────────────────────────────── */

.compare__row { margin-bottom: var(--gap-l); }

.compare__intro { margin-bottom: 32px; }

.compare__pair {
  display: flex;
  gap: 56px;
  align-items: flex-start;
}

/* Each shot is a fixed-height card; the horizontal gap around the image
   comes from centring, not from explicit side padding (Paper lets a
   fixed-width image sit inside a fixed/flexible card and centres it). */
.shot {
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 24px;
  padding-block: 40px;
  background: #d3e1e7;
  border-radius: 8px;
}

.shot:first-child {
  flex: 0 0 621px;
  max-width: 100%;
}

.shot:last-child {
  flex: 1;
  min-width: 0;
}

.shot img {
  /* width comes from the HTML width attribute (matches Paper's exact crop);
     height follows the source's natural aspect ratio at that width. */
  max-width: 100%;
  height: auto;
  display: block;
}

.shot figcaption {
  font: 400 13px/18px var(--font);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--faint);
  order: -1;
}

/* ── Usability verdict ───────────────────────────────────────── */

.verdict {
  border-top: 1px solid var(--ink);
  padding-top: 24px;
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.verdict__label {
  font: 500 11px/16px var(--font);
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--accent);
}

.verdict__words {
  margin: 0;
  font: 400 clamp(28px, 3.2vw, 40px) / 1.2 var(--font);
  letter-spacing: -0.025em;
  color: var(--ink);
  max-width: var(--measure-wide);
}

/* ── Result — the one dark moment ────────────────────────────── */

.result {
  background: var(--dark-bg);
  color: #fff;
  /* Full width of .page's content column (matches every other section),
     not a narrower fixed-width card centred within it. */
  width: 100%;
  margin-bottom: var(--gap-xl);
  padding: 96px 56px;
  display: flex;
  flex-direction: column;
}

.result__label {
  font: 500 11px/16px var(--font);
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: #fff;
  margin-bottom: 40px;
}

.result__figure {
  margin: 0;
  font: 700 clamp(64px, 8vw, 112px) / 1 var(--font);
  letter-spacing: -0.045em;
  color: #fff;
}

.result__unit {
  margin: 12px 0 56px;
  font: 400 19px/28px var(--font);
  color: var(--dark-faint);
}

.result__copy {
  display: flex;
  flex-direction: column;
  gap: 20px;
  max-width: 620px;
}

.result__copy p {
  margin: 0;
  font: 400 17px/30px var(--font);
  color: var(--dark-text);
}

/* ── What's next ─────────────────────────────────────────────── */

.nexts { display: flex; flex-direction: column; }

.next {
  display: flex;
  gap: 64px;
  align-items: flex-start;
  padding: 48px 0;
  border-top: 1px solid var(--rule);
}

.next__text {
  flex: 0 0 434px;
  max-width: 100%;
}

.next__label {
  display: block;
  font: 500 11px/16px var(--font);
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 14px;
}

.next__statement {
  margin: 0 0 20px;
  font: 400 19px/31px var(--font);
  color: var(--ink);
}

.next__lever {
  margin: 0;
  font: 400 15px/24px var(--font);
  color: var(--muted);
}

.next__lever span {
  display: block;
  font: 500 11px/16px var(--font);
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--faint);
  margin-bottom: 5px;
}

.next__shots {
  flex: 1;
  min-width: 0;
  height: 571px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  background: #d3e1e7;
}

.next__shots img {
  width: auto;
  height: 437px;
  max-width: 45%;
  object-fit: cover;
  object-position: top;
  flex-shrink: 0;
}

/* ── Footer ──────────────────────────────────────────────────── */

.foot {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 40px 0 64px;
  border-top: 1px solid var(--rule);
}

.foot__name {
  font: 400 14px/20px var(--font);
  color: var(--faint);
}

.foot__links { display: flex; gap: 28px; }

.foot__links a {
  font: 400 14px/20px var(--font);
  color: var(--muted);
  text-decoration: none;
  transition: color 150ms ease;
}

.foot__links a:hover { color: var(--ink); }

/* ── Motion ──────────────────────────────────────────────────── */

.js-fade-up,
.js-reveal {
  opacity: 0;
  transform: translateY(16px);
  transition-property: opacity, transform;
  transition-timing-function: var(--ease-out);
  transition-duration: 600ms;
}

.js-fade-up.is-visible,
.js-reveal.is-visible {
  opacity: 1;
  transform: translateY(0);
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .js-fade-up,
  .js-reveal { opacity: 1; transform: none; transition: none; }
}

/* ── Tablet ──────────────────────────────────────────────────── */

@media (max-width: 1080px) {
  :root { --gutter: 48px; --gap-xl: 128px; --gap-l: 72px; }

  /* Own vertical-centring constant — the title wraps differently at this
     width (shorter lines), so the desktop offset doesn't carry over.
     Derived the same way: measured at 1000×900 and solved for the gap.
     -389px was tuned while .hero__art was still a sibling of .hero__inner;
     re-derived to -450px (2026-08-23) after it moved inside .hero__inner
     (see .hero__art's own comment) shifted its positioning origin down by
     .hero's 64px padding-top. */
  /* Scaled with the base rule's 30% size-up (2026-08-23) — width
     27%→35.1%; min-width (398px, from the base rule, unset here) still
     governs throughout this whole breakpoint range, same as before.
     Offset recomputed the same way: -450px minus half the height delta
     from the min-width-governed 306→398px width change (~47px). */
  .hero__art { width: 35.1%; right: var(--gutter); top: calc(78vh - 497px); }
  /* Pinned back to the pre-2026-08-23 620px value — the wider 660px now
     used above 1080px (see .hero__top) overlaps the art at this narrower
     range. Note: even at 620px this range already runs tight below ~900px
     (the art and text column start crowding each other down toward the
     720px mobile breakpoint) — pre-existing, not introduced by this
     change; worth a proper stacked-layout breakpoint here at some point,
     matching the pattern used on the Quick Checker page. */
  .hero__top { max-width: 620px; }
  .hypotheses { flex-direction: column; gap: 40px; }
  /* .block goes position:static/height:auto at this breakpoint (below), so
     there's no fixed-height dead space below the Solution text any more —
     the solution-to-hero-bottom gap here is just .block's own margin-bottom,
     i.e. --gap-xl at this breakpoint (128px). That's LESS than the 180px
     parallax offset used at wider (>1080px) viewports, so the parallax is
     capped to maxOffsetCompact (128px, see index.html's Motion.heroParallax
     call) at this breakpoint and below — otherwise the hero would overshoot
     past where Impact starts once fully scrolled by, visually sliding over
     it. With the offset capped to exactly the target gap, padding-top can
     be 0 (0 + 128 offset = 128, matching). */
  .metrics { padding-top: 0; }
  .metrics__row { gap: 40px; }
  .next { flex-direction: column; gap: 32px; }
  .next__text { flex: 0 0 auto; width: 100%; }
  .next__shots { flex: 0 0 auto; width: 100%; max-width: 340px; height: auto; padding-block: 32px; }
  .next__shots img { height: 300px; }

  .block { position: static; height: auto; }
  .entry { position: static; width: 100%; gap: 10px; margin-bottom: 32px; }
  .entry:last-child { margin-bottom: 0; }
}

/* ── Mobile ────────────────────────────────────────────────────── */

@media (max-width: 720px) {
  :root {
    --gutter: 20px;
    --gap-l: 56px;
    --gap-xl: 88px;
    --measure: 100%;
  }

  .nav__inner { padding: 16px var(--gutter); }

  .hero {
    position: static;
    left: auto;
    /* Was transform:none, which fully disabled Motion.heroParallax here
       (the JS only ever writes the --parallax-y custom property, never
       touches transform directly, so a flat "none" silently ate the
       effect). translateY doesn't affect layout under position:static, so
       re-enabling it here is safe with the negative-margin full-bleed
       trick below. */
    transform: translateY(var(--parallax-y, 0px));
    width: auto;
    padding: 48px 0 40px;
    margin-left: calc(-1 * var(--gutter));
    margin-right: calc(-1 * var(--gutter));
  }
  /* .hero__art is now a child of .hero__inner (see that rule's own comment,
     2026-08-23), which carries its own gutter padding below — width:100%
     alone would inset the image by that padding on both sides, losing the
     full-bleed-to-the-viewport-edge treatment this had as a sibling of
     .hero__inner. Negative margins matching that padding break it back out,
     same trick .hero itself uses one level up. */
  .hero__art {
    position: static;
    width: auto;
    min-width: 0;
    height: 416px; /* scaled with the 30% size-up above (2026-08-23) */
    overflow: hidden;
    margin: 0 calc(-1 * var(--gutter)) 32px;
  }
  .hero__shot {
    /* contain, not cover — this is a transparent two-phone composite, not a
       full-bleed screenshot, so cropping it would cut phones off oddly. */
    width: 100%;
    height: 100%;
    object-fit: contain;
  }
  .hero__inner { padding: 0 var(--gutter); }
  .hero__top { min-height: 0; max-width: none; padding-bottom: 0; }
  .hero__eyebrow { margin-bottom: 14px; }
  .hero__title { font-size: 40px; letter-spacing: -0.03em; margin-bottom: 24px; }
  .hero__meta { gap: 20px 32px; }
  .hero__description { font-size: 17px; line-height: 28px; margin: 0 0 32px; }

  .statement { font-size: 21px; line-height: 32px; margin-bottom: var(--gap-l); }
  .prose { font-size: 16px; line-height: 26px; }
  .prose--lead { font-size: 17px; line-height: 28px; }

  /* Solution-to-hero-bottom gap at this breakpoint: .block is static/
     auto-height here too (no dead space below the Solution text), so the
     gap is exactly .block's own margin-bottom (--gap-xl, 88px) plus .hero's
     own bottom padding (40px) = 128px — same 128px target as tablet above,
     for a different reason (two stacked values here vs. one there). Uses
     the same capped 128px parallax offset (maxOffsetCompact in index.html's
     Motion.heroParallax call, shared with the tablet breakpoint) so 0
     static padding-top here plus the capped offset lands on 128px once
     fully scrolled past, matching. */
  .metrics { padding-top: 0; }
  .metrics__row { flex-direction: column; gap: 28px; }
  .metric__value { font-size: 44px; }
  .metric__label { max-width: 100%; }

  .block { position: static; height: auto; }
  .entry { position: static; width: 100%; gap: 10px; margin-bottom: 32px; }
  .entry:last-child { margin-bottom: 0; }

  .chapter__head { gap: 4px; margin-bottom: 28px; }
  .chapter__num { font-size: 14px; line-height: 19px; }
  .chapter__title { font-size: 28px; }

  .finding { flex-direction: column; gap: 12px; padding: 24px 0; }
  .finding__icon { flex: none; }
  .finding__icon svg { margin-top: 0; }
  .finding__title { font-size: 19px; line-height: 26px; }
  .finding__points li { font-size: 15px; line-height: 24px; }

  .hypothesis__text { font-size: 18px; line-height: 29px; }

  .compare__pair { flex-direction: column; gap: 32px; }
  .shot { width: 100%; }
  .shot:first-child { flex: 0 0 auto; }
  /* Fixed height + object-fit:cover, matching .next__shots img's mobile
     treatment — without this, .shot img's height:auto (desktop rule) lets
     each source image's own aspect ratio dictate the card height, so
     "before" and "after" end up wildly different heights instead of a
     matching pair. */
  .shot img { width: auto; height: 300px; max-width: 100%; object-fit: cover; object-position: top; }

  .verdict__words { font-size: 24px; }

  .result { padding: 56px var(--gutter); }
  .result__figure { font-size: 60px; }
  .result__unit { font-size: 16px; margin-bottom: 36px; }
  .result__copy p { font-size: 16px; line-height: 27px; }

  .next__statement { font-size: 17px; line-height: 28px; }
  .next__shots { max-width: 100%; }

  .foot { flex-direction: column; align-items: flex-start; gap: 20px; padding: 32px 0 48px; }
}
