/*
  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. Ported from
   Checkout's card (2026-08-23, when this page's own homepage card moved
   from .project to .herocard): 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-entitlements) {
    animation-duration: 650ms;
    animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
  }

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

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

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

  ::view-transition-group(vt-meta-entitlements) {
    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;
}

/* Short list that follows a .prose paragraph (e.g. the billing constraints) */
.bullets {
  margin: 20px 0 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-width: var(--measure);
}

.bullets li {
  position: relative;
  padding-left: 18px;
  font: 400 16px/26px var(--font);
  color: var(--muted);
}

.bullets li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 10px;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--accent);
}

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

.hero {
  /* Matches the homepage hero-echo card's outer .herocard box by name
     (added 2026-08-23, when that card moved from .project to .herocard) —
     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-entitlements;
  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-entitlements;
  /* 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. The -539px constant was derived by
     measuring both blocks' rendered centres via getBoundingClientRect()
     at 1440×783 and solving for the offset that closes that gap — this
     page's art is a taller composite (1526×1740) than the Checkout page's,
     so its constant differs. Re-measure if the title copy, art image, or
     .hero__top's padding/min-height change.

     Sized up 30% + shifted right (2026-08-23, ported from the Checkout
     page's same-day fix) — width 37%→48.1%, min-width 340→442px. Growing
     the image 30% grows its height 30% too (fixed aspect ratio), which
     pushes the top-anchored box's vertical centre down by half that delta
     (~75px at page-max width) — compensated by subtracting from -513px.
     At the bigger size the art's left edge would land under .hero__top's
     text column (620px max-width) at desktop widths, so it's also shifted
     right off its var(--gutter) inset, same as Checkout — -75px bleeds it
     past .hero__inner's right edge into the outer margin that appears once
     the viewport exceeds --page-max (1180px).

     Re-derived again (2026-08-23) after the description moved from a
     below-the-fold block into .hero__top itself (see .hero__top and
     .hero__description) — the extra paragraph made .hero__top taller,
     shifting its true centre down. Measured via getBoundingClientRect()
     at 1440×900 (matching this constant's original calibration width)
     and solved for the offset that re-closes the gap: -588px → -682px.
     Note: .hero__art here is still a sibling of .hero__inner (unlike the
     Checkout page, which nests it inside .hero__inner specifically to
     keep the art's width — and therefore this centring — consistent as
     the viewport widens past --page-max); porting that structural change
     was out of scope for this pass, so this constant is calibrated at a
     typical desktop width same as before, not width-invariant. */
  top: calc(78vh - 682px);
  right: -75px;
  width: 48.1%;
  min-width: 442px;
}

.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 — same structure as the
   Checkout page. */
.hero__top {
  min-height: 78vh;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  max-width: 620px;
  padding-bottom: 64px;
}

.hero__eyebrow {
  view-transition-name: vt-eyebrow-entitlements;
  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-entitlements;
  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 {
  /* Added 2026-08-23, pairing with the homepage herocard's own
     .herocard__meta name once that card moved from .project to .herocard. */
  view-transition-name: vt-meta-entitlements;
  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; }

/* Wide flow diagrams and the concepts matrix — same grouped-card treatment,
   sized to the artwork's own crop rather than stretched to the column. */
.figure--flow .figure__card { padding: 56px 40px; }
.figure--flow .figure__img { width: 1000px; max-width: 100%; height: auto; background: none; }

.figure--matrix .figure__card { padding: 56px 40px; }
.figure--matrix .figure__img { width: 892px; max-width: 100%; height: auto; background: none; }

/* Two annotated screenshots side by side. Fixed card height + max-height on
   the images (rather than a shared width) is what keeps the pair level —
   the two sources have different aspect ratios, so matching widths would
   give mismatched card heights. */
.figure--pair { display: flex; gap: 24px; }
.figure--pair .figure__card { flex: 1; min-width: 0; height: 420px; padding: 40px; }
.figure--pair .figure__img {
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 100%;
  background: none;
}

/* Phone screenshots grouped in a card — kept at Paper's own 264px crop
   rather than filling the card, two or four to a row. */
.figure--phones .figure__card { padding: 56px 40px; gap: 64px; }
.figure--phones .figure__img { width: 264px; max-width: 100%; height: auto; background: none; }

/* Four across needs tighter side padding than the two-up card, or the row
   (4×240 + 3×24 gaps) runs past the 1104px content column. */
.figure--phones-4 .figure__card { gap: 24px; padding-inline: 24px; }
.figure--phones-4 .figure__img { width: 240px; }

/* ── 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 ──────────────────
   Now lives inside the dark .hero (below the fold, alongside
   .hero__description) — positions/sizes unchanged, only entry__text's
   colour was adjusted so it reads on the dark background. */

.block {
  position: relative;
  height: 741px;
  /* Extra separation from .hero__description above (on top of its own
     96px margin-bottom) so Context/Problem/Solution reads as its own
     moment rather than a continuation of the intro paragraph. */
  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); }

/* A chapter that exists only to introduce the section right below it (the
   Launch & Impact head above the dark Result band) — the full inter-chapter
   gap would read as a break between them rather than a lead-in, so the
   statement's own margin-bottom carries the whole gap. */
.chapter--lead-in { padding-bottom: 0; }

.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);
}

/* ── Measures — success criteria as three ruled columns ──────── */

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

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

.measure__title {
  margin: 0;
  font: 500 19px/27px var(--font);
  letter-spacing: -0.01em;
  color: var(--ink);
}

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

/* ── 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. */
  /* Scaled with the base rule's 30% size-up (2026-08-23) — width 30%→39%,
     offset recomputed the same way (half the height delta at the
     min-width-governed 340→442px width, ~58px). right left at var(--gutter)
     — this breakpoint already had a pre-existing text-column overlap before
     this resize (min-width has always won over the % width here), matching
     the same known, undocumented-fix-scope issue on the Checkout page's
     tablet breakpoint; not introduced or worsened in kind by this change,
     just made numerically bigger. Needs the same proper stacked-layout
     breakpoint the Quick Checker page already has, not a quick right-shift. */
  /* Re-derived (2026-08-23) for the same reason as the desktop rule above
     — measured at 1000×900 (this constant's original calibration
     viewport), -430px → -539px. */
  .hero__art { width: 39%; right: var(--gutter); top: calc(78vh - 539px); }
  .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; }
  .measures { gap: 32px; }
  .figure--flow .figure__card,
  .figure--matrix .figure__card { padding: 40px 24px; }
  .figure--pair .figure__card { height: 340px; padding: 28px; }
  .figure--phones .figure__card { padding: 40px 24px; gap: 40px; }
  /* Four 240px phones plus gaps overflow the narrower column here. */
  .figure--phones-4 .figure__card { gap: 16px; padding-inline: 20px; }
  .figure--phones-4 .figure__img { width: 200px; }
  .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 {
    position: static;
    width: 100%;
    min-width: 0;
    height: 416px; /* scaled with the 30% size-up above (2026-08-23) */
    overflow: hidden;
    margin-bottom: 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; }

  .measures { flex-direction: column; gap: 28px; }
  .measure__title { font-size: 17px; line-height: 25px; }

  .bullets li { font-size: 15px; line-height: 24px; }

  .figure--flow .figure__card,
  .figure--matrix .figure__card { padding: 20px 12px; }
  .figure--pair { flex-direction: column; gap: 16px; }
  .figure--pair .figure__card { height: 260px; padding: 20px; }
  /* Phones wrap two-up rather than shrinking to unreadable widths. */
  .figure--phones .figure__card { flex-wrap: wrap; padding: 28px 16px; gap: 16px; }
  .figure--phones .figure__img,
  .figure--phones-4 .figure__img { width: calc(50% - 8px); }
  .figure--phones-1 .figure__img { width: 60%; }

  .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; }
}
