/* ───────── tokens ───────── */
:root {
  /* NATIVE PALETTE. No brand colour of our own — these are Apple's, so the page reads as
     part of the platform rather than as a startup landing page. --bg is pure black like
     apple.com's dark sections; --text is Apple's #F5F5F7 marketing off-white; --muted and
     --faint step down through their grey ramp. */
  --bg: #000000;
  --text: #F5F5F7; --mid: #E8E8ED; --muted: #A1A1A6; --faint: #86868B;
  /* Elevated dark surfaces, measured off apple.com/macbook-pro. Flat #000 everywhere is
     what made the page read as a void; these give sections real surface value. */
  --surface: #1D1D1F;
  --surface-glass: rgba(42,42,45,.72);

  /* ACCENT — apple.com's button blue, not a colour we invented. #0071E3 is the exact blue
     Apple uses for CTAs and is the only value in their ramp that clears WCAG AA with white
     text (4.6:1); #0A84FF, the system blue, only reaches 3.4:1 and would fail on the CTA.
     --accent-soft is Apple's dark-background link blue. Change these four lines and the
     whole site follows — every glow and tint derives from --accent-rgb. */
  --accent-rgb: 0 113 227;
  --accent: rgb(var(--accent-rgb));
  --accent-soft: #2997FF;
  --accent-ink: #FFFFFF;

  --hairline: rgba(255,255,255,.08);
  --maxw: 1140px;
  /* The WIDE measure, for the picture sections. Two of them (the hours grid, the how-it-works
     steps) have to land on exactly the same left edge and card width, and the rail bug earlier
     in this build was two sections computing the same intent from different numbers — one from
     1140, one from 1420 — and drifting 144px apart. One variable, one gutter formula, no drift. */
  /* THE CENTRING TERM DOES NOT BELONG IN THE PADDING, and leaving it there is what broke every
     large monitor. --wide-gutter used to be max(20px, (100vw - 1420)/2 + 24). Every block on the
     page is `max-width: var(--wide); margin: 0 auto` AND padded by that gutter, so the
     (100vw - 1420)/2 half-gutter was applied twice: once by margin:auto doing the centring, and
     again inside the box as padding. Content width came out at 1420 - 2*gutter = 2792 - 100vw, so
     the readable column SHRANK as the screen grew: 1352 at 1440, 1064 at 1728, 872 at 1920, 232 at
     2560, and nothing at all past 2792. At 2560 the hours headline wrapped onto four lines and the
     card was a 232px thumbnail.
     margin: 0 auto already centres a capped box, so the padding only ever needed to be a real
     inner inset. That is what --wide-gutter is now: 20px on a phone, ~37px at 1440 (within 3px of
     what it used to compute there, which is why nothing below 1500 shifts), 48px at the top.

     --wide itself steps up on genuinely large displays. Holding 1420 on a 2560 monitor is not
     wrong, but it leaves 570px of dead margin either side; 1680 is roughly where Apple caps its
     own product pages. Below 1900 nothing changes at all. */
  --wide: 1420px;
  /* THE CEILING HAS TO LAND WHERE THE BOX CAPS, or the same bug survives in miniature. Written
     first as clamp(20px, 2.6vw, 48px), the gutter went on growing with the viewport after the box
     had already stopped at 1420 - so content still shrank, 1345 at 1440 down to 1324 at 1846. Small
     enough to miss by eye; the monotonicity test caught it on its first run. 2.82vw reaches the 40px
     ceiling at exactly 1420, which is where --wide stops, so past that the inset is constant and the
     column can only hold or grow. */
  --wide-gutter: clamp(20px, 2.82vw, 40px);

  /* One step, at 1900. Every laptop and every 1440/1680/1728 display keeps the exact geometry it
     has today; only a 2K/4K/ultrawide desk monitor sees the wider measure. */

  /* ONE VERTICAL SCALE. Before this, section spacing came from five different places - some on the
     section, some on an inner wrapper, some ad hoc - and measured 0, 72, 81 and 108 at the same
     viewport with no system behind it. Two values now: --sy for a normal section, --sy-lg for the
     bands that are meant to breathe. */
  --sy: clamp(64px, 9vh, 118px);
  --sy-lg: clamp(88px, 12vh, 152px);
  --ease-out: cubic-bezier(.16,1,.3,1);
  /* SF Pro, via the system stack. Not self-hosted: Apple's licence doesn't permit
     redistributing the SF font files on the web, and it isn't needed here — every visitor
     to a Mac-app landing page is on a platform where -apple-system already resolves to
     genuine SF Pro (Display above ~20pt, Text below, switched optically by the OS). Ships
     zero font bytes and removes the FOUT the self-hosted webfont had. Micro-labels are the
     same family differentiated by weight + tracking + case; numerals in label contexts get
     tabular figures so timers don't jitter. See spec §10. */
  --font-display: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text", system-ui, sans-serif;
}

/* ═══ LARGE DISPLAYS - the measure ══════════════════════════════════════════════════════════════
   The breakpoint sits at 1900 so no laptop and no 1440/1680/1728 display is touched. 1680 is roughly
   where Apple caps its own product pages; holding 1420 on a 2560 screen is not wrong but it leaves
   570px of dead margin either side. The bento's card heights are sized off vw and top out at the
   same point, so they are raised with it.
   The TYPE ceilings for this breakpoint are at the BOTTOM of this file, and .giant's is at the
   bottom of hero.css - they have to come after the rules they raise, or source order beats them. */
@media (min-width: 1900px) {
  :root {
    --wide: 1680px;
    --b-tall: 486px;
    --b-short: 292px;
  }
}
* { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
body { position: relative;
  background: var(--bg); color: var(--text);
  /* 400, not the 500 the previous webfont wanted: SF Medium is materially heavier than
     General Sans Medium, and Apple sets body copy in Regular. */
  font-family: var(--font-display); font-size: 17px; line-height: 1.6; font-weight: 400;
  -webkit-font-smoothing: antialiased; overflow-x: clip;
}
::selection { background: var(--accent); color: var(--accent-ink); }
a { color: inherit; text-decoration: none; }
img { max-width: 100%; display: block; }
/* Every image element is wrapped in a <picture> to offer WebP first (513 KB of PNG/JPEG became
   174 KB, and the popover screenshot alone dropped 219 -> 30 KB at PSNR 38.5 dB, which is
   indistinguishable at 2x zoom). `display: contents` makes the wrapper vanish from layout
   entirely, so the image lays out exactly as it did before it was wrapped — several of
   these are absolutely positioned against an ancestor, and an inline wrapper box would
   otherwise sit in the flow leaving a stray line box behind. */
picture { display: contents; }
.label { font-size: .72rem; letter-spacing: .16em; text-transform: uppercase; font-weight: 600;
  font-variant-numeric: tabular-nums; }

/* film grain */
/* ABSOLUTE, NOT FIXED — this was the single biggest cause of scroll jank on the page.
   A full-viewport `position: fixed` layer with a blend mode has to be re-composited against
   the whole changing viewport on every scrolled frame, and that cost lands on the GPU, not the
   main thread — which is why it was invisible to long-task profiling (0 long tasks throughout)
   while the page still felt heavy. Measured at 6x CPU throttle over a full-page wheel scroll:
   fixed+overlay p95 31.7ms / 3.2% frames dropped, absolute+overlay p95 25.4ms / 2.0%. That is
   the same as deleting the grain outright (25.4ms / 2.0%), so the blend mode was the entire
   cost and none of it was the element itself.
   HONESTY ABOUT THE NUMBERS: an interleaved 5-run A/B of absolute vs fixed on this same code
   measured NO difference (p95 32.5ms both, 4.5% vs 4.1% dropped — noise). The earlier one-shot
   comparison that showed a win was noise too. It is kept because it is free and theoretically
   right — headless Chromium composites in software, where a fixed blended layer costs roughly
   what an absolute one does, whereas on a real GPU the fixed layer forces a per-frame
   re-composite of the whole viewport. Do not cite a measured improvement for this.
   Scrolling with the document changes nothing visually: it is random noise.
   `body` is the containing block (position: relative below) so `height: 100%` means the whole
   DOCUMENT. Against the initial containing block it would resolve to the viewport, and the
   grain would stop after the first screen. */
.grain { position: absolute; top: 0; left: 0; right: 0; height: 100%;
  z-index: 40; pointer-events: none; opacity: .04; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"); }

/* ───────── nav ───────── */
.nav { position: fixed; inset: 0 0 auto 0; z-index: 50; display: flex; align-items: center; justify-content: space-between;
  padding: 18px 28px; mix-blend-mode: normal; transition: background .4s, backdrop-filter .4s; }
.nav.is-scrolled { background: rgba(0,0,0,.7); backdrop-filter: blur(14px); border-bottom: 1px solid var(--hairline); }
/* THE NAV GETS OUT OF THE FILM'S WAY.
   It is fixed, 79px tall and 70% black, so it covers the top 51 SOURCE pixels of every chapter.
   CH.1 and CH.2 never noticed because nothing important sits at their top. CH.3's notifications do:
   the first banner arrives already veiled, which is the thing Sarthak flagged as the zoom being cut
   off. It was never the zoom.
   While a chapter is live the nav fades to a quarter and drops its plate, so the film has the whole
   frame. It stays in the DOM and stays clickable, so nothing is lost for keyboard or screen-reader
   users; it simply stops painting a bar across the picture. */
.is-filming .nav { background: transparent; backdrop-filter: none; border-bottom-color: transparent;
  opacity: .26; transition: opacity .45s, background .45s, backdrop-filter .45s; }
.is-filming .nav:hover, .is-filming .nav:focus-within { opacity: 1; background: rgba(0,0,0,.7);
  backdrop-filter: blur(14px); }
@media (prefers-reduced-motion: reduce) { .is-filming .nav { transition: none; } }
.nav__brand { display: flex; gap: 9px; align-items: center; font-weight: 700; letter-spacing: -.01em; }
.nav__links { display: flex; gap: 26px; font-size: .88rem; color: var(--muted); }
.nav__links a:hover { color: var(--text); }

/* ───────── buttons & chips ───────── */
.btn { display: inline-block; font-weight: 600; border-radius: 999px; transition: transform .3s var(--ease-out), box-shadow .3s, background .3s; will-change: transform; }
.btn--pill { padding: 9px 20px; font-size: .85rem; border: 1px solid var(--hairline); background: rgba(255,255,255,.04); }
.btn--pill:hover { border-color: var(--accent); color: var(--accent-soft); }
.btn--primary { padding: 17px 38px; font-size: 1.02rem; color: var(--accent-ink); background: var(--accent);
  box-shadow: 0 0 44px rgb(var(--accent-rgb) / .42), inset 0 1px 0 rgba(255,255,255,.35); }
.btn--primary:hover { background: var(--accent-soft); box-shadow: 0 0 70px rgb(var(--accent-rgb) / .58); }
.chip { display: inline-flex; align-items: center; padding: 6px 13px; border: 1px solid var(--hairline); border-radius: 999px;
  color: var(--muted); background: rgba(255,255,255,.03); margin-right: 10px; }
.chips { margin-top: 34px; }

/* WHAT FOLD IS - centred showcase
   Was a 250vh pinned two-column scene. Its animation completed by ~75% progress and then
   held, so 1.5 of its 2.5 screens bought nothing, and the left column carried 69 words.
   Now: one unpinned screen, centred, the mockup big, three triggers in a row beneath, and
   the drop plays once on entry. Apple's shape for "three things" - and it stops the page
   feeling like it has stalled.

   The framed "screen" is deliberately a CROP of a desktop's top-right corner: at true
   relative scale a menu-bar popover is ~25% of screen width and unreadable. */
.is-centred { text-align: center; }
.is-centred .lead { margin-inline: auto; }
.is-centred .display-2 { margin-inline: auto; max-width: 22em; }

/* The ring must be a pseudo-element ABOVE the media, not an inset box-shadow on the card.
   An inset shadow paints on the card's own background layer, and both this pattern and the
   bento fill the card with an absolutely-positioned image that covers it — so only the
   rounded corners, where the image doesn't reach, were showing the ring, and the three tiles
   merged into one continuous strip with their gaps invisible. Needed at all because these
   photographs are near-black on a black page; the reference gets away with borderless tiles
   only because its photography is bright enough to imply the edge. */
.bcard::after { content: ""; position: absolute; inset: 0; z-index: 2;
  border-radius: inherit; pointer-events: none;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.14); }
@media (prefers-reduced-motion: reduce) { .hlcard { transition: none; } }

/* TYPE SCALE
   Rebuilt from apple.com/macbook-pro's RENDERED values, not guessed. Two corrections:

   1. Weight 600, not 700. Apple sets display type in Semibold; 700 reads heavy beside it.
   2. OPTICAL TRACKING. Their letter-spacing is negative at large sizes and turns POSITIVE
      at small ones: -1.2px at 80px, 0 at 40px, +0.196px at 28px. We had a flat -0.03em
      everywhere, which is exactly why big type looked cramped and small type looked loose.

   The em values below are Apple's px values converted at their own size, so they land
   exactly: -0.015em x 80px = -1.2px; -0.005em x 56px = -0.28px; +0.007em x 28px = +0.196px.
   em rather than px keeps the tracking correct as the clamp scales the size. */
/* The eyebrow, after Apple's: the product line set plainly above the headline rather than a tracked
   micro-label with a glowing dot in front of it. Sentence case, white, and it reads as a name.
   ONE rule, not a second one appended later - two .eyebrow blocks fighting is how .whohead2 ended up
   putting a heading 40px off its own content. */
.eyebrow { display: block; font-size: clamp(14px, 1.1vw, 17px); font-weight: 600;
  letter-spacing: -.006em; text-transform: none; color: var(--text); margin-bottom: 10px; }

/* HERO SCALE, measured against apple.com/macbook-pro at the same 1999px viewport: their
   headline renders ~96px and ours rendered ~76px — 26% smaller, which is most of why the hero
   read as weaker. Tracking tightens as it grows, the way large Apple type does; at 100px the
   old -.015em was visibly loose. */
.display   { font-size: clamp(46px, 6.6vw, 104px); font-weight: 600; letter-spacing: -.028em; line-height: 1.02; }
.display-2 { font-size: clamp(34px, 3.9vw, 56px); font-weight: 600; letter-spacing: -.005em; line-height: 1.07; margin-bottom: 20px; }
.display-3 { font-size: clamp(26px, 2.8vw, 40px); font-weight: 600; letter-spacing: 0;      line-height: 1.10; }
.display-4 { font-size: clamp(22px, 2.2vw, 32px); font-weight: 600; letter-spacing: .004em; line-height: 1.13; }

/* Statement type: the sentence sits back in --muted and only the phrase carrying the
   argument comes forward. Apple applies this to BODY COPY as well as headings (see the AI
   and Performance sections of the reference), so .lead gets it too. */
.stmt { color: var(--muted); }
.stmt em, .stmt strong { font-style: normal; font-weight: inherit; color: var(--text); }

.lead { font-size: clamp(19px, 1.5vw, 21px); line-height: 1.48; letter-spacing: .004em;
  color: var(--muted); max-width: 34em; }
.lead em, .lead strong { font-style: normal; font-weight: 600; color: var(--text); }
.micro { font-size: .8125rem; color: var(--faint); margin-top: 14px; letter-spacing: .006em; }
/* The hero's trust line is the only .micro set over FILM rather than over black. On the
   page's black it measures 5.00:1; over the opening frame's backdrop (rgb 17,34,49) the
   same colour falls to 4.47:1 — just under AA for 13px text, on the one line whose whole
   job is to remove the last objection under the primary CTA. Brighter, plus the same halo
   the beats use, since the frame behind it moves and no single ratio holds for all of it. */
.chapter__offer .micro { color: var(--muted); text-shadow: 0 1px 16px rgba(0,0,0,.72); }

/* THE OFFER, inside CH.1
   The hero used to be its own 100vh section showing ch1-poster.jpg — which IS the first
   frame of ch1.mp4, so screens one and two were the same image and the page felt like it
   wasn't moving. Now the offer lives inside the chapter and fades out as the film scrubs:
   one screen saved, no repeat, and the scroll immediately pays off.

   opacity:1 by default and NOT a .beat, so it is complete and clickable before any scroll
   and before GSAP loads. The scrubbed tween only ever fades it out. */
/* BOTTOM-ANCHORED, not vertically centred. Apple's hero copy sits low — their headline's
   baseline lands ~75% down the viewport, ours was at 52%, floating in the middle of the frame
   with dead space above and below it. Anchoring it low also gives the film the upper two thirds,
   which is where the machine actually is. */
.chapter__offer { position: absolute; inset: 0; z-index: 2; display: flex; flex-direction: column;
  justify-content: flex-end; align-items: flex-start; text-align: left;
  width: 100%; max-width: var(--maxw); margin: 0 auto;
  padding: 0 28px clamp(96px, 15vh, 190px); pointer-events: none; }
.chapter__offer > * { pointer-events: auto; }
/* NO SCRIM. The offer used to sit on a near-opaque gradient because CH.1's footage was not
   reliably dark behind it — an early take's lit lid cut a pale diagonal through the headline, 14.7%
   of the offer's region above luminance 90. That is no longer true of this chapter: the machine sits
   at 61% across while the copy ends at 58%, and measured over ALL 111 frames the copy's region peaks
   at 1.57 mean out of 255. A scrim there now protects nothing and only dims the machine, so it is
   gone rather than merely switched off at rest. The suite asserts the OUTCOME — that the pixels
   behind the copy are dark — instead of the mechanism, so re-shot footage that brightens them fails
   whether or not a scrim exists. */
.chapter__offer .lead { margin-top: 18px; max-width: 26em; }
/* A <br> that only exists at desktop widths. `display: none` on a <br> genuinely suppresses
   the break, which makes this the one deterministic way to place a line break responsively —
   text-wrap: balance improves the rag but cannot guarantee WHERE it breaks. */
.brk-lg { display: none; }
@media (min-width: 900px) { .brk-lg { display: inline; } }
.chapter__offer .btn--primary { margin-top: 34px; }
.chapter__hint { position: absolute; left: 0; right: 0; bottom: 4vh; bottom: 4dvh; z-index: 2;
  text-align: center; color: var(--faint); }

/* PERSONA GALLERY
   Horizontal rail, not five stacked rows. Stacked cost 3.4 screens; this costs ~1.2, and a
   scannable rail is how the reference presents comparable sets (174 carousel nodes on
   apple.com/macbook-pro). Native overflow scrolling, so it stays swipeable, keyboard
   reachable and works with GSAP absent - drag is an enhancement, never the mechanism. */
/* THE CASE ROWS. Copy on the LEFT, machine on the RIGHT, heading left-aligned above them all.
   Fourth layout for this section, and each previous one lost for a reason worth keeping:
     · a horizontal drag rail hid four of five cases behind a gesture;
     · a sticky-left aside spent a third of the width on a headline read once, capping the
       machine at 931px;
     · a centred heading over a left-bleeding machine put the copy in the right-hand third,
       where the eye reaches it after the picture rather than before.
   Copy-left is the reading order: the label, then the evidence. The media is also FIRST in the
   DOM's visual order but SECOND in source, so tab and screen-reader order match the layout. */
/* THE LEFT EDGE IS THE PAGE'S, THE RIGHT EDGE IS THE VIEWPORT'S.
   Measured across the page at 1440: every other section's heading starts at 178px — the 1140px
   measure plus its 28px padding — while this section, breaking out to its own 1580px measure,
   started at 28. A 150px step, and the reason the heading looked wrong rather than merely
   different: it was not aligned with anything else on the page.
   So the left padding is computed to land exactly where .content__inner's text lands, and only
   the RIGHT side breaks out, which is where the extra width is actually wanted for the machine. */
/* SYMMETRIC, AND WIDER THAN THE REST OF THE PAGE ON PURPOSE.
   Two goes at this. The original left-aligned the block with page text and let the right break out
   for the machine, which gave 453/60 at 1990px. Tying the right to 0.42 of the left made the ratio
   consistent (2.38 everywhere) but Sarthak still read it as broken, and he is right: the machine
   stops 190px short of the frame, so the asymmetry never reads as a deliberate bleed. It just reads
   as one gutter being bigger than the other.
   A bleed has to actually bleed or not exist. This block now centres itself and runs WIDER than the
   page's 1140 measure, which is a visible, intentional difference: the persona rows are the widest
   thing on the page and they are symmetric, so the extra width reads as emphasis rather than error.
   The heading shares the rule, so it still aligns with the rows beneath it. */
.whohead, .cases { max-width: calc(var(--maxw) + 220px); margin-inline: auto;
  padding-inline: clamp(28px, 3.6vw, 60px); }
.whohead { padding-bottom: clamp(26px, 3.4vh, 44px); }
/* One line at desktop. The shared display-2 is sized for centred settings and wrapped this to
   two lines; at 3.05vw the 37 characters come to ~830px at 1440, which is what the mockup shows.
   It wraps naturally below ~1150px rather than being forced. */
.whohead__h { font-size: clamp(1.75rem, 3.05vw, 3rem); font-weight: 600; line-height: 1.06;
  letter-spacing: -.022em; }
/* FLUSH, not indented. Frame 18 stepped the lead in from the headline and I copied it, but on
   the real page it was the only element in the section off the left edge — heading, number, title
   and body all sat at 28 and the lead at 162 — which reads as a mistake rather than a device. */
.whohead__lead { margin-top: clamp(12px, 1.8vh, 22px); max-width: 52ch; }

/* The measure lives on the CONTAINER, not on each row. `max-width` plus `margin: 0 auto` on
   .case made it an auto-margined FLEX ITEM, and the engines disagree about that: Chromium
   stretched it to the container (left edge 0), WebKit resolved it to content width and centred
   it (left edge 88). The heading and the copy stopped sharing a left edge in WebKit only.
   .whohead and .cases are both plain block children of the section, so identical rules on them
   resolve identically everywhere. */
.cases { display: flex; flex-direction: column; gap: clamp(72px, 10vh, 148px); }
.case { display: grid; align-items: start;
  /* Copy ~38% of the row, machine ~59%, as measured off the mockup. */
  grid-template-columns: minmax(260px, 0.64fr) minmax(0, 1fr);
  gap: clamp(28px, 4vw, 74px); }
.case__media { position: relative; aspect-ratio: 16 / 10;
  overflow: hidden; background: transparent; }
.case__media img { width: 100%; height: 100%; object-fit: cover; display: block;
  -webkit-user-drag: none; user-select: none; }
/* The screen inside the card begins 4.6% down it — measured off the composite: the frame runs
   y 104..884 of the plate and the display starts at y 140. Offsetting the copy by that much
   lands the title's cap height on the app window's own top edge rather than on the aluminium
   above it, which is what makes top alignment look deliberate instead of merely flush.
   Explicit text-align:left so nothing above can centre it by inheritance. */
.case__body { padding-top: 4.6%; text-align: left; }
.case__body h3 { font-size: clamp(1.4rem, 1.95vw, 1.95rem); font-weight: 600;
  letter-spacing: -.014em; line-height: 1.1; margin-bottom: clamp(12px, 1.6vh, 18px); }
/* The number is part of the title, as in the mockup — not a separate label above it. */
.case__n { color: var(--faint); font-variant-numeric: tabular-nums; margin-right: .3em; }
.case__body p { font-size: clamp(.99rem, 1.06vw, 1.14rem); line-height: 1.5;
  color: var(--text); letter-spacing: -.006em; }

/* ─────────────────────────────────────────────────────────────────────────────
   PROTOTYPE ONLY. Everything here is scoped to #how so it can be lifted into
   style.css unchanged. It loads the site's real stylesheet, so what is approved
   is what ships: the type, the black, the hairlines and the reveal timings are
   the page's own, not an approximation of them.
   ───────────────────────────────────────────────────────────────────────────── */

#how .steps {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: clamp(28px, 3.4vw, 56px);
  margin-top: clamp(40px, 5vh, 68px);
}
@media (max-width: 900px) { #how .steps { grid-template-columns: 1fr; gap: clamp(40px, 6vh, 56px); } }

#how .step { display: flex; flex-direction: column; gap: 0; }

/* NUMBERED BECAUSE THE ORDER IS REAL. The persona rows number their entries too, so the device is
   already in the page's vocabulary — but there it labels a list, and here it carries sequence: you
   cannot close the lid before you turn it on. That is the only test worth applying to a numeral. */
#how .step__n {
  font-size: .8125rem; font-weight: 600; letter-spacing: .04em;
  font-variant-numeric: tabular-nums; color: var(--faint);
  padding-bottom: 14px; border-bottom: 1px solid var(--hairline); margin-bottom: 22px;
}

/* The drawing sits in a fixed-ratio well so the three columns keep their baselines even though the
   three illustrations are different shapes. */
#how .step__art {
  aspect-ratio: 16 / 10; display: grid; place-items: center;
  background: linear-gradient(180deg, rgba(255,255,255,.035), rgba(255,255,255,.012));
  border: 1px solid var(--hairline); border-radius: 14px;
  margin-bottom: clamp(20px, 2.4vh, 28px); overflow: hidden;
}
#how .step__art svg { width: 76%; height: auto; display: block; }
/* TWO OF THE THREE ARE PHOTOGRAPHS, and the split is not arbitrary.
   Step one is the only step that happens in software, so it is drawn: the popover with the app's
   own labels, which no photograph of a menu bar could keep accurate. Steps two and three happen in
   the world, and we already shot them — the closing lid and the hand arriving at the sensor are
   frames from ch1 and ch3.
   They were a padlock icon and a fingerprint ring, which is what made them look wrong beside step
   one. That card is SPECIFIC: real labels, real toggle. Stock glyphs next to it read as placeholder
   art, because next to something specific, generic is what generic looks like.
   A photograph fills its well edge to edge, so it loses the inset gradient the drawn card needs. */
#how .step__art--shot { background: none; padding: 0; }
#how .step__art--shot img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ON THE SITE'S OWN SCALE, not a new one.
   The first pass set the body copy at 1rem, which is 16px, while the page's body is 17px. That one
   invented value squeezed the gap to the 13px label down to 1.23 and flattened the hierarchy. The
   sizes here are now the page's existing three: .8125rem for the label, matching .eyebrow and
   .micro; the inherited 17px body; and a heading a step below the persona rows' own h3, since these
   sit three-up rather than two-up. Ratios come out 1.31 and 1.51. */
#how .step h3 {
  font-size: clamp(1.3rem, 1.7vw, 1.6rem); font-weight: 600;
  letter-spacing: -.014em; line-height: 1.14; margin-bottom: 11px;
}
#how .step p { color: var(--muted); line-height: 1.55; max-width: 34ch; }

/* The toggle in step one is drawn ON, because that is the state the sentence describes. */
#how .tgl-track { fill: var(--accent); }
#how .tgl-knob  { fill: #fff; }

@media (max-width: 900px) {
  /* One column: copy, then its machine beneath. */
  .case { grid-template-columns: 1fr; gap: clamp(16px, 2.6vh, 24px); }
  .whohead, .cases { padding-left: 28px; padding-right: 28px; }
  .case__body { padding-top: 0; }
  .cases { gap: clamp(52px, 7vh, 84px); }
}
/* You drag with a mouse and swipe with a finger — say the right one. */
.hint-coarse { display: none; }
@media (pointer: coarse) { .hint-fine { display: none; } .hint-coarse { display: inline; } }

/* Repeated-CTA band: one idea, centred, nothing competing. */
.ctaband .content__inner { text-align: center; }
/* THE MID-PAGE BAND CARRIES THE ARGUMENT NOW, so it gets the height to hold it.
   It was 392px of a 10,893px page — the thinnest section on the site, and the conversion point for
   anyone already sold by the moments above who does not want to read about lease renewal. */
.ctaband .display-2 { margin-inline: auto; max-width: 17em; }
.ctaband .content__inner { padding-block: var(--sy-lg); }
.ctaband__sub { margin: 18px auto 4px; color: var(--muted); max-width: 24em; }

/* ───────── film chapters ───────── */
.chapter { position: relative; height: 200vh; background: var(--bg); }
/* CH.1 IS THE LONGEST CHAPTER, not the shortest, and that reverses an earlier call. It used to be
   cut to 170vh and then 160vh on the reasoning that it sits under the hero where a visitor is least
   patient — but its take is trimmed to 4.6s, and a scrubbed chapter's PACE is footage-seconds per
   scroll-pixel, so a short section made the lid slam shut. 220vh gives 120vh of travel for those
   4.6s, half the speed of 160vh, which is what "it shouldn't be this fast" asks for. Slowing the
   footage itself was the alternative and is worse: duplicated frames mean adjacent scroll positions
   show the same image, which is the staleness this chapter was rebuilt to remove. */
#ch1 { height: 220vh; }
/* iOS Safari: plain `vh` is the LARGE viewport (chrome hidden), so with the URL bar
   visible the real visible area is shorter than 100vh and bottom-anchored content can
   sit under the chrome. `dvh` tracks the current (dynamic) viewport instead. The `vh`
   line ships first as a fallback for browsers without dvh support; the `dvh` line after
   it wins the cascade wherever it's supported. */
.chapter__stage { position: sticky; top: 0; height: 100vh; height: 100dvh; overflow: hidden; }
.chapter__poster, .chapter__canvas { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.chapter__canvas { opacity: 0; transition: opacity .5s; }
.chapter.is-live .chapter__canvas { opacity: 1; }
/* The canvas is NOT held back any more. It used to be, because the poster was a product plate and
   frame one of the film was a different composition, so letting the film in early put the headline
   over the wrong image. The poster is now cut from the master's own first frame — the two are the
   same picture — so holding it only froze the opening: at 220vh, a 0.15 gate meant ~18vh of
   scrolling against a still image before the film cut in at frame 17. That is what read as broken. */
/* The vertical ramp is what joins a film chapter to the black .content section above it. It
   used to start at rgba(0,0,0,.55), so the film was still 45% visible at its own top edge and
   arrived as a hard horizontal line as the section scrolled up — the boundary into CH.2 read
   as a cut rather than a fade. It now starts fully at --bg and clears over 24%, so the frame
   emerges out of the black instead of snapping into it. The bottom already did this. */
.chapter__vignette { position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(120% 90% at 50% 45%, transparent 55%, rgba(0,0,0,.75) 100%),
              linear-gradient(to bottom, var(--bg) 0%, rgba(0,0,0,.86) 6%, rgba(0,0,0,.42) 14%,
                              transparent 24% 76%, rgba(0,0,0,.42) 86%, var(--bg) 100%); }
.chapter__copy { position: absolute; inset: 0; display: flex; flex-direction: column; justify-content: center; align-items: center;
  text-align: center; padding: 0 6vw; }
.chapter__copy::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(75% 55% at 50% 50%, rgba(0,0,0,.62), rgba(0,0,0,.28) 55%, transparent 78%);
}
/* EVERY SUPER LANDS ON THE SAME SPOT — DEAD CENTRE. They used to be flex children stacked in
   normal flow, and because a beat at opacity 0 still occupies its box, the STACK was centred
   rather than each line: measured against their container's centre, CH.2's four supers sat at
   -72, -8, +56 and +120px. Only one is ever visible, so each line appeared at a different
   height and the copy seemed to jump around the frame as you scrolled.

   Each beat is now absolutely positioned over the whole stage and centres its own text, so they
   all occupy the identical position. Centring is done with flex rather than a translate, because
   the fade tween would otherwise fight a transform on the same element.

   Still absolutely positioned rather than relative: that was there so the beat shares the
   scrim's stacking category and, being later in DOM order, paints above it — absolute keeps
   that property. */
.beat { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  opacity: 0; will-change: opacity;
  text-shadow: 0 2px 30px rgba(0,0,0,.75), 0 1px 4px rgba(0,0,0,.6); }

/* SUPERS SIT IN THE FRAME'S NEGATIVE SPACE, WHICH IS NOT ALWAYS ITS CENTRE.
   Every super lands on ONE spot per chapter — that part matters and is unchanged, because supers at
   different heights per line made the copy appear to jump around. But WHICH spot has to come from
   the footage, and CH.3's footage now has typography of its own.
   Measured on the built chapter at 3.6s: the composited lock screen puts its avatar at frame rows
   353-368, its name at 385-392 and its hint at 399-404, while a centred super occupies 316-403.
   A total overlap — the screen's own name and hint were reading through the super.
   The clear band runs from the clock's baseline at 162 to the avatar at 353, centred at 36% of the
   frame. So CH.3's supers sit there, all three of them, which keeps them consistent with each other
   while clear of the screen. This is what the reference does too: its supers go where the picture is
   empty rather than at a fixed 50%. */
.chapter { --beat-y: 50%; }
/* CH.3's SUPERS SIT AT 39%, and it is measured rather than chosen. The chapter is now one Flow take
   as shot, so the screen carries the GENERATOR's lock screen — clock high at about 20%, the name and
   hint cluster at about 72% — and a centred super lands between them on top of the wallpaper's
   brightest diagonal. Measured on the built master in both beat windows: while the lock screen is up a
   centred super is clear only at 36-40% and 87-92%; once the desktop is up, at 39-44% and 59-92%. The
   single band clear in BOTH is 39-40%.
   It was 50% when the screen was composited, because a rendered screen could be laid out around the
   copy. A photographed one cannot, so the copy moves instead. All three of CH.3's supers still share
   one position, which is the property that stops the copy jumping. */
#ch3 { --beat-y: 39%; }
/* The box spans from the top to TWICE --beat-y and the text centres inside it, so the text's own
   centre lands exactly on --beat-y. At the 50% default that is height:100% and identical to plain
   centring. Done this way rather than with padding (which would offset by half the line height) or a
   translate (a transform on a beat is what the drift test forbids, and it would also fight the
   fade). */
.beat { inset: 0 0 auto 0; height: calc(var(--beat-y) * 2); }
/* Film supers are WHITE, not accent blue. Saturated #2997FF set over photography was the
   least Apple-looking thing on the page: the reference's video supers are always white or
   near-white, and its colour lives on solid-black type screens (which is where our own
   gradient emphasis lives). Blue over a moving photographic frame also has no fixed
   contrast ratio — legibility changed shot to shot. The class stays, because it still
   marks the payoff beat of each chapter; it just marks it with weight and a soft halo
   instead of hue. */
.beat--accent { color: #FFFFFF; text-shadow: 0 2px 34px rgba(0,0,0,.55); }
/* Was pinned low, which made it the one super that did NOT share the others' position. Centred
   with the rest now; if the rebuilt CH.3 footage needs it out of the machine's way, move it by
   changing align-items here rather than by re-introducing a second position. */
.beat--low { align-items: center; }
.scrollhint { font-size: .72rem; font-weight: 600; letter-spacing: .3em; text-transform: uppercase; color: var(--faint);
  position: absolute; bottom: 4vh; bottom: 4dvh; }
.chapter__copy .lead { color: var(--text); }
.chapter__copy .lead.beat--accent { color: #FFFFFF; }

/* ───────── content sections ───────── */
.content { position: relative; background: var(--bg); border-top: 1px solid transparent; }
/* Roughly +40% vertical rhythm over the first build. The single biggest lever on whether
   a dark page reads as "luxury" or "cluttered" is how much nothing sits between ideas. */
/* ONE LEFT EDGE FOR THE WHOLE PAGE. This wrapper used to centre a 1140px box, so its contents began
   at 208px while the picture sections began at 104 - one of four different left edges the page had at
   1500px (56, 104, 208, 288). It now shares --wide and --wide-gutter with everything else, and the
   text caps its own line length instead, which is what a measure is for. Centred blocks still centre:
   the middle of a 1420 box centred in the viewport is the middle of the viewport. */
.content__inner { max-width: var(--wide); margin: 0 auto;
  padding: var(--sy) var(--wide-gutter); }
.content__inner--tight { padding-bottom: calc(var(--sy) * .72); }
/* The reading measure, applied to the text rather than to the box around it. */
.content__inner > p:not(.eyebrow):not(.micro) { max-width: 34em; }
/* Centre the measure whenever the block centres its text. Keyed on .is-centred alone this depended on
   someone remembering the class: the closing band centred its heading and button through .ctaband but
   its sub-line kept the 34em measure flush left, so one line in four sat out of alignment. A band is
   centred by definition, so it says so here rather than relying on the markup. */
.content__inner.is-centred > p:not(.eyebrow):not(.micro),
.ctaband .content__inner > p:not(.eyebrow):not(.micro) { margin-inline: auto; }

/* ───────── BENTO (Security)
   Replaces the two flat `.cards` grids. Geometry measured off apple.com/macbook-pro's
   bento: 980px container, two 480px columns, 20px gutter, 28px radius, cards on
   rgb(29,29,31) over #000 - no border, the value step IS the edge.

   Apple's four cards are 401 / 241 / 241 / 401 tall: a pinwheel, tall on the diagonal.
   A tall card is NOT twice a short one, so a uniform row unit can't produce both. Three
   explicit row tracks can. Solving for equal column totals:
       col 1 = tall + gap + short          col 2 = short + gap + tall
       track1 = short, track3 = short, track2 = tall - gap - short
   which at Apple's numbers is 241 / 140 / 241 = 662 total, and both tall cards land on
   401 exactly. track2 is written as that expression, not as 140px, so the whole grid
   stays correct while --b-tall/--b-short scale with the viewport. */
.bento { --b-gap: clamp(14px, 1.4vw, 20px);
  /* Scaled up to Apple's card PROPORTION rather than their pixel sizes. Theirs are 401 and 241 tall in
     a 980px container, so roughly 1.2 and 2.0 times as wide as tall; ours sit in 1292, and at the old
     numbers they were 1.6 and 2.6 - visibly flatter than the reference even though the pixel values
     were copied from it.
     They were not even reaching those numbers: the rows had no explicit heights, so every card sagged
     to whatever its text needed and measured 219 and 180. grid-template-rows is what makes the
     pinwheel real - card one spans rows 1 and 2, card four spans 2 and 3, so the middle row is the
     difference between a tall card and a short one. */
  --b-tall: clamp(304px, 32.8vw, 424px);
  --b-short: clamp(184px, 20vw, 254px);
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--b-gap);
  grid-template-rows: var(--b-short)
                      calc(var(--b-tall) - var(--b-short) - var(--b-gap))
                      var(--b-short);
  /* The shared measure, like everything else. It had its own 980px box, which put the security cards
     at 288 while the rest of the page started at 104. The pinwheel row heights are unchanged; only the
     container's left edge and width move. */
  max-width: var(--wide); margin: 0 auto; padding: 0 var(--wide-gutter) var(--sy); }
.bento > :nth-child(1) { grid-column: 1; grid-row: 1 / 3; }
.bento > :nth-child(2) { grid-column: 2; grid-row: 1 / 2; }
.bento > :nth-child(3) { grid-column: 1; grid-row: 3 / 4; }
.bento > :nth-child(4) { grid-column: 2; grid-row: 2 / 4; }

/* The tile ring is load-bearing, not decoration — drawn by .bcard::after, above the media.
   Without it, two of the four tiles had no visible boundary at all. */
.bcard { position: relative; display: flex; flex-direction: column; overflow: hidden;
  background: var(--surface); border-radius: 28px; }

/* PHOTO CARDS full-bleed the image and overlay the copy, which is what the reference
   does — and it is not a style choice, it is the only thing that fits. Stacking media
   above a flex:none body inside a fixed-height card gave the short cards a 56px-tall
   image strip (measured): the copy took 183 of 239px and the photograph became a
   sliver. Overlaid, every card shows its whole frame.
   object-position sits above centre so the subject stays clear of the scrim. */
.bcard--photo .bcard__media { position: absolute; inset: 0; }
.bcard--photo .bcard__media img { width: 100%; height: 100%; object-fit: cover;
  object-position: 50% 38%; display: block; }
.bcard--photo .bcard__body { position: relative; margin-top: auto;
  padding: clamp(58px, 7vw, 96px) clamp(22px, 2.4vw, 32px) clamp(22px, 2.4vw, 30px);
  /* Scrim, not a flat panel: the photographs are already near-black (measured 13–26/255
     mean), so a short ramp is enough to hold text at AA without hiding the image. */
  background: linear-gradient(to top, rgba(0,0,0,.88) 0%, rgba(0,0,0,.66) 38%, transparent 100%); }
/* THE BENTO'S OWN TYPE SCALE, 40% down from the shared one.
   The cards were reading as walls of text: .display-3 is sized for a section heading standing alone
   (clamp 26-40px) and four of them stacked in a grid, each over a three-line paragraph, is far too
   much voice for a supporting panel. Headings drop to clamp(17-24px) and body to .8rem — roughly
   40% off both — and the descriptions were each cut to a single line, so a card is now a claim and
   one sentence rather than a paragraph.
   Scoped to .bcard so the page's other .display-3 uses (the film beats) keep their scale. */
.bcard__body h3, .bcard__body .display-3 {
  font-size: clamp(17px, 1.7vw, 24px); line-height: 1.14; letter-spacing: -.012em;
  margin-bottom: 7px; }
.bcard__body p { color: var(--mid); font-size: .8rem; line-height: 1.5; max-width: 46ch; }
.bcard--type .bcard__k { font-size: .7rem; }

/* The one card with no photograph. It carries the failure-mode answer — the thing a
   security-sensitive utility actually gets asked — so it gets the room instead of an
   image, and centres to hold its corner of the pinwheel. */
/* Flat --surface (#1D1D1F) made this tile read as visibly lighter than the other three
   and so as the odd one out — the reference gets away with one flat value because its
   photographs are bright, ours are near-black. Sitting it on a darker base with the same
   cool rim falling from the top left puts it in the same light as the photographs. */
.bcard--type { justify-content: center;
  background:
    radial-gradient(78% 62% at 10% -6%, rgba(140,170,255,.10), transparent 68%),
    linear-gradient(158deg, #191A1D 0%, #121214 52%, #0D0D0F 100%); }
.bcard--type .bcard__body { padding: clamp(28px, 3vw, 40px) clamp(26px, 2.8vw, 38px); }
.bcard--type .bcard__k { color: var(--faint); margin-bottom: 16px; }
.bcard--type h3 { margin-bottom: 16px; }
.bcard--type p { color: var(--muted); font-size: 1rem; max-width: 30ch; }
/* ───────── popover scene ─────────
   A full-viewport staged moment, built on the same sticky idiom as the film chapters so
   it reads as part of the same film rather than a figure bolted under the cards. The
   "screen" is deliberately a CROP of a desktop's top-right corner, not a whole display:
   at true relative scale a menu-bar popover would be ~25% of the screen width and
   unreadable, so the crop buys legibility without faking the UI itself. */
/* Wider than --maxw on purpose: this is a full-viewport scene, not a text column. */

.notes { list-style: none; margin-top: 40px; display: grid; gap: 20px; }
.note { position: relative; padding-left: 56px; }
.note__rule { position: absolute; left: 0; top: .66em; width: 38px; height: 1px;
  background: var(--accent); opacity: .8; transform-origin: left center; }
.note__k { display: block; color: var(--accent); margin-bottom: 3px; }
.note__v { display: block; color: var(--muted); font-size: .95rem; line-height: 1.5; }

@keyframes popBreathe { 0%,100% { opacity: .55; } 50% { opacity: 1; } }

/* The pinned pitch column and its five stacked rows are gone - replaced by the gallery
   above. Only the quiet text CTA survives, reused in the finale. */
.who__cta { display: inline-flex; align-items: center; gap: 12px; margin-top: 30px;
  font-weight: 600; font-size: .95rem; color: var(--accent-soft);
  transition: color .4s var(--ease-out); }
.who__arrow { display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border-radius: 999px;
  background: rgb(var(--accent-rgb) / .14); border: 1px solid rgb(var(--accent-rgb) / .22);
  transition: transform .45s var(--ease-out), background .4s var(--ease-out); }
.who__cta:hover { color: var(--accent); }
.who__cta:hover .who__arrow { transform: translateX(4px); background: rgb(var(--accent-rgb) / .24); }

/* faq + download */
.faq { margin-top: 70px; border-top: 1px solid var(--hairline); }
.faq details { border-bottom: 1px solid var(--hairline); padding: 22px 4px; }
.faq summary { cursor: pointer; font-weight: 600; font-size: 1.04rem; list-style: none; display: flex; justify-content: space-between; }
.faq summary::after { content: "+"; color: var(--muted); font-weight: 500; }
.faq details[open] summary::after { content: "–"; }
.faq p { color: var(--muted); padding-top: 12px; max-width: 44em; }
/* ── One rhythm for every download block ────────────────────────────────────────────────────────
   The closing block is the one Sarthak pointed at as correct: headline, a generous gap, the button,
   then the caption tight underneath. The three CTA bands had their sub-line sitting flush against the
   button - measured, zero pixels between them - so they read as a stack rather than a call to action.
   These four numbers now drive all four blocks. */
.download { text-align: center; margin-top: 130px; padding: 90px 20px 40px; }
/* All four download blocks have the same shape now - headline, optional sub-line, then a .cta holding
   the button and its caption - so three numbers govern every one of them instead of three rules plus
   a special case for the closing block. */
.download .cta, .ctaband .cta { margin-top: 40px; }
.download .lead, .ctaband .lead { margin-top: 16px; }
.download .micro, .ctaband .micro { margin-top: 14px; }

.footer { display: flex; justify-content: space-between; padding: 30px 28px; color: var(--faint); font-size: .82rem;
  border-top: 1px solid var(--hairline); }

/* ───────── split lines (SplitText targets) ───────── */
/* THE MASK WAS EATING DESCENDERS. These headings set line-height ~1.06 to close the gap between
   lines, but a font's ink runs about 1.2em from ascender to descender - so the tail of a y, g or p
   falls BELOW the line box, and overflow: hidden (which is what makes the reveal a reveal) cut it
   off. "away." rendered as "awav." at every width; it was simply easier to miss at 60px than at
   30px on a phone. The padding gives the mask room for the tail and the equal negative margin
   gives the space straight back, so nothing moves - verified identical section offsets at 1512px. */
.split-line { display: block; overflow: hidden;
  padding-bottom: .18em; margin-bottom: -.18em; }
.split-line > span { display: block; will-change: transform; }

/* Content-reveal baseline: hidden by CSS (not by inline styles GSAP sets later), so
   there's no FOUC/race between page paint and initReveals() — which now waits on
   document.fonts.ready. The CDN-failure guard and reduced-motion override both know to
   force this back to opacity 1. */
[data-reveal] { opacity: 0; }

/* ───────── responsive ───────── */
@media (max-width: 880px) {
  /* One column: the pinwheel's whole point is two columns of unequal cards, so both the
     explicit placement AND the three row tracks have to be unwound — leaving the tracks
     in place would size the stacked cards from a geometry that no longer exists. */
  .bento { grid-template-columns: 1fr; grid-template-rows: none;
    grid-auto-rows: minmax(var(--b-short), auto); gap: 14px; }
  .bento > * { grid-column: 1 !important; grid-row: auto !important; }
  .bcard--tall { min-height: var(--b-tall); }
  .nav__links { display: none; }
  .chapter { height: 200vh; }
  /* Stacked: the stage can no longer hold both columns in one viewport, so it stops
     being a pinned scene and becomes an ordinary flow section. */
        .notes { margin-top: 32px; }
  /* A fixed aspect box can't hold a 712px-wide screenshot legibly at phone widths — at
     390px it either overflows the frame or shrinks the popover past readability. So the
     screen stops being a fixed crop and lets its height follow the panel, which is then
     free to take most of the column. The menu bar and notch stay, so the "it drops out of
     the menu bar" idea survives the layout change. */
  /* No second column to scroll against, so the pitch stops pinning. */
  .who__row::before { inset: 0 -16px; }
  .screen { aspect-ratio: auto; max-width: 520px; margin-inline: auto; }
}
/* Below ~560px the menu bar's two groups no longer fit side by side and flex-shrink the
   status cluster — which walks the Fold glyph off the notch's fixed --notch-x anchor.
   Dropping the trailing app menus keeps the cluster at its natural width instead. */
@media (max-width: 560px) {
  .mbar__apps span:nth-child(n+4) { display: none; }
}
/* ───────── reduced motion ───────── */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  /* #ch1 is an ID selector (170vh) and outranks a bare .chapter, so it has to be named here or
     the shortened chapter keeps its scroll height with motion disabled. */
  .chapter, #ch1 { height: 100vh; height: 100dvh; } /* consistent with .chapter__stage's dvh fix above */
  .beat, [data-reveal] { opacity: 1 !important; transform: none !important; }
  .chapter__canvas { display: none; }
  /* Same reasoning as the mobile stack: no pin, no scrub, nothing hidden. */
      .pop::after { animation: none; }
}


/* ── The Slack-style scene ─────────────────────────────────────────────────────────────────────
   Drawn in the page's own type on purpose. A faithful copy of a chat app's chrome would make this
   read as a captured real conversation, which for an unreleased product means a testimonial that
   does not exist yet. Timestamps in tabular figures so the two line up and the gap between them is
   the thing the eye measures. */
#scene .thread { max-width: 640px; margin: 0 auto;
  border-top: 1px solid var(--hairline); border-bottom: 1px solid var(--hairline); }
#scene .msg { display: grid; grid-template-columns: 62px 1fr; gap: 0 18px; padding: 24px 0; }
#scene .msg__t { font-size: .8125rem; color: var(--faint); font-variant-numeric: tabular-nums;
  padding-top: 3px; }
#scene .msg__who { display: block; font-weight: 600; font-size: .9375rem; margin-bottom: 4px; }
#scene .msg__b p { color: var(--text); font-size: 1.0625rem; line-height: 1.5; }
/* The gap is the storytelling. A rule with the duration sitting in it, rather than a sentence
   saying time passed. */
#scene .gap { display: grid; grid-template-columns: 62px 1fr; gap: 0 18px; align-items: center; }
#scene .gap::before { content: ""; }
#scene .gap span { position: relative; display: block; font-size: .75rem; letter-spacing: .09em;
  text-transform: uppercase; color: var(--faint); padding: 4px 0; }
#scene .gap span::after { content: ""; position: absolute; left: 8.2em; right: 0; top: 50%;
  height: 1px; background: var(--hairline); }
#scene .scene__note { max-width: 640px; margin: 22px auto 0; color: var(--muted);
  font-size: .9375rem; }
@media (max-width: 620px) {
  #scene .msg, #scene .gap { grid-template-columns: 50px 1fr; gap: 0 12px; }
}

/* The run strip's styles stood here. It was a fixed 40px bar under the nav carrying a fake agent
   job name and a percentage driven by scroll depth. Removed with its markup: it advertised Claude
   rather than Fold, and it cost every screen 40px of permanent chrome - on a 664px phone viewport,
   5% of everything the reader ever sees, spent on a number that measures nothing. */

/* ═══ HOW-IT-WORKS BENTO ════════════════════════════════════════════════════════════════════════
   Three equal cards read as a checklist. A bento gives the steps a hierarchy: the switch you flip
   gets the wide cell, because it is the only thing in the sequence the visitor actually does — the
   other two are the machine's work. The popover is drawn (its labels are the app's own, and a
   screenshot would go stale) but it now sits INSIDE a photograph of a real menu bar rather than
   floating on a gradient, which is what made the old card look like placeholder art. */
/* ═══ HOW IT WORKS — the "closer look" explorer ══════════════════════════════════════════════════
   Controls ON the picture at the left, after apple.com/macbook-pro. Three steps, and the open one
   replaces its own pill with a titled card so the column never grows a second list.

   THE TRACK. .cl is a tall scroll track with a sticky stage inside it. That is why the stepping can
   be scroll-driven without GSAP, without pinning, and without a pin-spacer: the browser holds the
   stage while the track scrolls past, and closer.js only reads progress and sets an index. With no JS
   the stage still sticks and step one still reads, which is the same fail-open contract as the rest
   of the page. */
.clhead { max-width: var(--wide); margin: 0 auto clamp(28px, 4vh, 48px);
  padding: var(--sy) var(--wide-gutter) 0; }
.cl { max-width: var(--wide); margin: 0 auto;
  padding: 0 var(--wide-gutter) clamp(64px, 9vh, 118px);
  /* One viewport for the stage to sit still in, then ~30vh of travel per step. It was 62vh, which
     took two trackpad flicks to advance one step; a flick is roughly 300px, so a step now lands on
     one. Change this number and the stepping speed changes - there is nothing else to tune. */
  min-height: calc(100vh + 90vh); }
.cl__pin { position: sticky; top: clamp(64px, 9vh, 108px); }
@media (max-width: 900px) {
  /* Stacked and static below the breakpoint: a sticky stage with overlaid controls is a poor trade on
     a phone, where the picture would be small and the pills would cover most of it. */
  .cl { min-height: 0; }
  .cl__pin { position: static; }
}

/* 20:11. Twelve per cent off the height it was displaying, which was 16:10 - an earlier edit meant to
   take it to 32:17 silently matched nothing and I did not check, so the stage stayed 16:10 while the
   plates were being generated at 1.882 and cover-cropped by 230px of width. This is close enough to
   the plates' own ratio that the crop is now about 22px a side. */
.cl__stage { position: relative; aspect-ratio: 20 / 11; border-radius: 22px; overflow: hidden;
  background: #0B0C0F; isolation: isolate; }
/* NEVER THROUGH BLACK. This used to fade the outgoing plate out over .26s and bring the incoming one
   in over .42s after a .2s delay, on the theory that a beat of empty stage was cleaner than two
   photographs ghosting through each other. On screen it is a black flash: from ~.2s to ~.45s the two
   opacities sum to nearly nothing and the stage's own #0B0C0F shows through, taking the glass pills
   and the open card down with it because they are translucent and sit on top of it.
   Apple's move, and the fix, is that the outgoing plate never fades at all. It HOLDS at full opacity
   underneath while the incoming one fades in on top of it, so the composite is opaque at every
   instant, and it is cut only once the new plate has fully covered it - a 0s opacity change delayed
   by the incoming plate's whole duration. z-index, not opacity, decides which one you see. */
.cl__slide { position: absolute; inset: 0; z-index: 1; opacity: 0; visibility: hidden;
  transition: opacity 0s linear .6s, visibility 0s linear .6s; }
.cl__slide.is-on { z-index: 2; opacity: 1; visibility: visible;
  transition: opacity .6s var(--ease-out), visibility 0s; }
/* The settle scale lives on the MEDIA rather than the slide. That started as a fix for a horizontal
   scrollbar on phones, and the real cause turned out to be markup - two of the three slides were
   nested outside .cl__stage, so they sized against the column and nothing clipped them. The nesting is
   fixed, which alone resolves it. This stays because it is strictly safer: on the media the transform
   sits inside the stage's own overflow:hidden and cannot escape it however the tree is arranged. */
/* The outgoing plate is now VISIBLE for the whole crossfade, so it must not move while you can see
   it - a plate drifting back to 1.015 under the arriving one reads as a wobble. It holds still and
   resets its scale at the same moment its opacity is cut, when nothing is looking. */
.cl__slide .cl__media { transform: scale(1.015);
  transition: transform 0s linear .6s; }
.cl__slide.is-on .cl__media { transform: none;
  transition: transform .9s var(--ease-out); }
.cl:not(.is-live) .cl__slide:first-child { opacity: 1; visibility: visible; transform: none; }
.cl__media { width: 100%; height: 100%; object-fit: cover; display: block; }


/* Back to a DARK scrim, because the plates are dark again - vivid rather than pale, which is the
   distinction Sarthak drew: black page, colourful pictures. The plates measure luma 13 and 22 overall
   while their blue light is fully saturated, so a light scrim would have fogged them. It stays in CSS
   rather than baked into the plates because these panels are meant to become video, and a clip cannot
   carry a gradient. */
/* THE FILM SITS OVER THE STILLS, AND ONLY ONCE IT HAS PAINTED. Same discipline as the chapters:
   the canvas is transparent until a frame is verifiably on it, so a cold decoder or a failed fetch
   leaves the three photographs doing exactly what they did before. Everything above it moves up one
   layer to make room. */
.cl__canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block;
  z-index: 3; opacity: 0; transition: opacity .5s var(--ease-out); pointer-events: none; }
.cl.is-film .cl__canvas { opacity: 1; }

.cl__scrim { position: absolute; inset: 0; z-index: 4; pointer-events: none;
  background: linear-gradient(90deg, rgba(6,7,9,.9) 0%, rgba(6,7,9,.72) 30%,
                                     rgba(6,7,9,.24) 56%, rgba(6,7,9,0) 72%); }

.cl__ui { position: absolute; inset: 0; z-index: 5; display: flex; align-items: center; gap: 14px;
  padding: clamp(18px, 2.4vw, 40px); pointer-events: none; }
.cl__ui > * { pointer-events: auto; }
.cl__nav { display: flex; flex-direction: column; gap: 10px; flex: 0 0 auto; }
.cl__list { list-style: none; display: flex; flex-direction: column; gap: 10px;
  width: min(46%, 430px); }

/* --cl-ink is declared on the component so a future dark plate can flip the whole control set by
   redefining three values on one selector, rather than by editing six rules. */
.cl { --cl-ink: #F5F5F7; --cl-ink-soft: rgba(255,255,255,.74); --cl-glass: rgba(26,28,32,.72);
  --cl-glass-hi: rgba(42,45,50,.86); --cl-edge: rgba(255,255,255,.12); }
.cl__pill { display: flex; align-items: center; gap: 12px; width: 100%; text-align: left;
  padding: 13px 22px 13px 15px; border-radius: 999px; cursor: pointer;
  background: var(--cl-glass); backdrop-filter: blur(16px) saturate(1.4);
  border: 1px solid var(--cl-edge); color: var(--cl-ink);
  font: 600 clamp(14px, 1.05vw, 16px)/1.25 inherit; letter-spacing: -.008em;
  transition: background .25s, border-color .25s; }
.cl__pill:hover { background: var(--cl-glass-hi); }
.cl__pill:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
/* The open row hides its pill: the card below takes its place, exactly as the reference does, so the
   title is never printed twice. */
.cl__row.is-on .cl__pill { display: none; }

.cl__plus { position: relative; flex: 0 0 auto; width: 21px; height: 21px; border-radius: 50%;
  border: 1px solid rgba(255,255,255,.34); }
.cl__plus::before, .cl__plus::after { content: ""; position: absolute; inset: 50% 4px auto 4px;
  height: 1px; background: currentColor; transform: translateY(-50%); }
.cl__plus::after { transform: translateY(-50%) rotate(90deg); }

/* Opened with grid-template-rows, never max-height: a max-height animation lays out every frame, and
   the ceiling it needs is a guess that silently clips any longer sentence. 0fr to 1fr resolves
   against the real content height. The grid ITEM carries no padding of its own - with the padding on
   the paragraph a collapsed row still measured 18px, being a zero-height box plus its padding. */
.cl__body { display: grid; grid-template-rows: 1fr; }
.cl__in { overflow: hidden; min-height: 0; }
.cl.is-live .cl__body { grid-template-rows: 0fr; opacity: 0;
  transition: grid-template-rows .42s var(--ease-out), opacity .2s ease; }
.cl.is-live .cl__row.is-on .cl__body { grid-template-rows: 1fr; opacity: 1;
  transition: grid-template-rows .42s var(--ease-out), opacity .2s ease; }
/* The BOX arrives before its words. In the reference the card opens as an empty grey rectangle and
   the text appears once it has finished sizing; closing runs the same sequence backwards, the words
   going first so the box is already empty as it collapses. Without the delay the text reflows while
   the row is still growing, which is what made ours read as a jump rather than a transition. */
/* The gap between them was .16s out plus a .24s wait, so for four tenths of a second the panel had
   no copy in it at all - which on top of the black flash is what made the whole change read as a
   flicker rather than a move. Tightened to .12 + .16, which keeps the box-before-words order and
   halves the silence. */
.cl.is-live .cl__body p { opacity: 0; transition: opacity .12s ease; }
.cl.is-live .cl__row.is-on .cl__body p { opacity: 1; transition: opacity .24s ease .16s; }
.cl__body p { border-radius: 20px; background: var(--cl-glass-hi);
  backdrop-filter: blur(16px) saturate(1.4); border: 1px solid var(--cl-edge);
  padding: clamp(16px, 1.6vw, 22px) clamp(18px, 1.8vw, 26px);
  color: var(--cl-ink-soft); font-size: clamp(13.5px, 1.05vw, 16px); line-height: 1.5; }
.cl__body strong { color: var(--cl-ink); font-weight: 600; }

.cl__arrow { width: 36px; height: 36px; border-radius: 50%; cursor: pointer; position: relative;
  background: var(--cl-glass); backdrop-filter: blur(16px) saturate(1.4);
  border: 1px solid var(--cl-edge); }
.cl__arrow:hover { background: var(--cl-glass-hi); }
.cl__arrow:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.cl__arrow::before { content: ""; position: absolute; inset: 0; margin: auto; width: 8px; height: 8px;
  border-left: 1.5px solid var(--cl-ink); border-top: 1.5px solid var(--cl-ink);
  transform: rotate(45deg) translate(1px, 1px); }
.cl__arrow--down::before { transform: rotate(-135deg) translate(1px, 1px); }

@media (max-width: 900px) {
  .cl__ui { position: static; flex-direction: column; align-items: stretch; }
  .cl__list { width: 100%; }
  .cl__nav { flex-direction: row; }
  .cl__stage { aspect-ratio: 4 / 3; }
  .cl__scrim { display: none; }
  .cl__ui { padding: 16px 0 0; }
  .cl { display: flex; flex-direction: column; gap: 16px; }
}
@media (prefers-reduced-motion: reduce) {
  .cl__slide { transition: none; }
  .cl.is-live .cl__body { transition: none; }
}

/* ═══ THE HOURS ═════════════════════════════════════════════════════════════════════════════════
   BLACK, like the rest of the page. Making this section light was the wrong fix for a real problem:
   the photographs were so dark they read as black rectangles, and I lit the room instead of the
   pictures. The page's whole identity is the black; punching a pale panel through it to rescue three
   underexposed images is solving the symptom and losing the thing that makes the site look like
   itself. The images are being reshot rich and luminous instead, which is where the light belongs.
   Apple's own scale kept: two cards per row on their own measure, wider than the page's 1140. */
.hours { padding: var(--sy) 0; }
/* The heading reads the same two variables as the cards below it. It was on a 1420 literal with its
   own clamp() for the gutter and landed at left 80 against the cards' 104 - a 24px step visible in
   Sarthak's own screenshot of the section. Third time in this build that two blocks derived one
   intent from two numbers; the variables exist so it stops happening. */
.hourshead { max-width: var(--wide); margin: 0 auto clamp(36px, 5vh, 64px);
  padding: 0 var(--wide-gutter); }
.hours__h { font-size: clamp(30px, 4vw, 60px); font-weight: 600; letter-spacing: -.022em;
  line-height: 1.06; max-width: 15em; margin-bottom: 16px; }
.hours__lead { font-size: clamp(16px, 1.35vw, 19px); line-height: 1.5; color: var(--muted);
  max-width: 40em; }
/* THREE COLUMNS, because the photographs are portrait. A 2+1 grid would force the third card to
   16:9, and cropping a 4:5 source to that means losing either the pale sky the headline sits on or
   the subject beneath it. */
/* ONE CARD PER ROW, at the full wide measure. Three 4:5 portraits side by side put each moment in
   a 442px column; Apple gives a highlight card the whole measure and lets it be 1420 wide, which is
   what "bigger" means here. Landscape also earns the people who are now in these frames: a runner
   heading away down a path needs somewhere to run to, and a portrait crop has no room for it. */
.hgrid { display: grid; grid-template-columns: 1fr; gap: clamp(16px, 1.8vw, 26px);
  max-width: var(--wide); margin: 0 auto; padding: 0 var(--wide-gutter); }
.hcard--wide { grid-column: 1 / -1; }
/* A card is a lifted panel on the black, the same device the security bento uses, so the section
   reads as part of the page rather than as a visitor from another site. */
/* THE PHOTOGRAPH IS THE CARD, and the copy lives inside it — Apple's own construction, and the
   thing the previous version got wrong by stacking a text panel on top of a cropped strip.
   Two consequences worth stating. The images had to be RESHOT PORTRAIT with a deliberately bright,
   empty upper third, because a headline needs somewhere to sit: overlaying type on a photograph is
   a demand on the photograph, not a CSS decision. And the type is DARK, because that upper third is
   now sky — the same reason Apple sets near-black over an overcast airport window. */
.hcard { position: relative; border-radius: 28px; overflow: hidden; isolation: isolate; }
/* 15:7, which is 3:2 with 30% of the height taken off: 861px tall became 603px at the card's
   1292px measure. The photographs are generated at 3:2 and composed for this letterbox, so the
   crop comes out of the middle of the frame rather than off the bottom. */
.hcard__img { width: 100%; height: auto; object-fit: cover; display: block; aspect-ratio: 15 / 7; }
/* The copy occupies the upper left, and the photographs were shot for it: that region measures
   luma 242-251 at sd 2-9 in all three, so near-black type reads with no scrim over the picture.
   Held to 46% of the width because past that the second line runs into the subject. */
/* A percentage only. The em cap carried over from the portrait cards resolves against the overlay's
   inherited 17px, so min(46%, 20em) was min(594px, 340px) and "The morning run." broke over three
   lines at a 46px display size. The card is never wider than 1292, so 46% needs no ceiling. */
.hcard__over { position: absolute; inset: 0 auto auto 0; z-index: 2;
  padding: clamp(30px, 3.4vw, 58px) clamp(28px, 3.2vw, 54px);
  max-width: 46%; }
.hcard__over h3 { font-size: clamp(26px, 3.1vw, 46px); font-weight: 600; letter-spacing: -.021em;
  line-height: 1.06; margin-bottom: 12px; color: #16181C; }
.hcard__over p { font-size: clamp(15px, 1.3vw, 20px); line-height: 1.42; color: #3A3D42;
  max-width: 26ch; }
/* A whisper of a lift in the top corner only. The photographs are shot with a clean pale band up
   there, so this is insurance against a bright cloud landing behind a word, not a scrim: at .16 it
   is invisible on the page and still buys about a stop of separation where the type sits. */
.hcard::before { content: ""; position: absolute; inset: 0 0 auto 0; height: 46%; z-index: 1;
  background: linear-gradient(180deg, rgba(255,255,255,.16), rgba(255,255,255,0));
  pointer-events: none; }

/* ═══ THE RAIL, at Apple's card scale ═══════════════════════════════════════════════════════════
   Five cards across a 1500px viewport gave each one 268px — a thumbnail with a paragraph under it,
   which is what made the section read as small. Apple's equivalent shows roughly two cards at a
   time and lets the third be cut by the edge. Same here: 46vw columns, so two fill the screen and
   the next one is visibly waiting. */
/* A single clamp(), not minmax(). In a column-flow grid inside an overflow scroller the track
   collapses to minmax()'s MIN — measured 320px on a 1500px viewport where 46vw is 690. clamp()
   resolves to one value with nothing to collapse into. Capped at 760 so the cards do not become
   billboards on a 2560px display. */
/* Everything in this pass is 12% smaller than the previous one: the page was reading as oversized
   rather than as generous. 46vw -> 40vw, and the rail's own type and padding come down with it. */
.rail { grid-auto-columns: clamp(290px, 40vw, 670px); }
.rcard { border-radius: 23px; padding-bottom: clamp(21px, 2.3vw, 32px); }
.rcard__art { aspect-ratio: 16 / 10; }
.rcard__k { padding: clamp(19px, 2.1vw, 28px) clamp(21px, 2.3vw, 32px) 9px; }
.rcard h3 { font-size: clamp(1.15rem, 1.65vw, 1.65rem); padding: 0 clamp(21px, 2.3vw, 32px) 7px; }
.rcard > p:last-child { font-size: clamp(14px, 1vw, 15px);
  padding: 0 clamp(21px, 2.3vw, 32px); max-width: 38ch; }

/* ── One card, one exception ─────────────────────────────────────────────────────────────────────
   The school pickup photograph Sarthak supplied has a high-contrast top left: the dark rear headrest
   against a sunlit window. Measured under the type it runs from luma 0 to 214, so NEITHER ink colour
   works - near-black vanishes into the headrest, white vanishes into the window, and white scored
   1.3:1 where 3.0 is the floor. The other two cards need nothing: they measure 219 and 252, flat.
   So this card alone gets a scrim and white ink. A gradient behind overlaid type is ordinary editorial
   practice, and it is the only way to put type on a picture with both ends of the range in it. */
.hcard--scrim::after { content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(105deg, rgba(6,7,10,.82) 0%, rgba(6,7,10,.66) 26%,
                                      rgba(6,7,10,.26) 52%, rgba(6,7,10,0) 72%); }
.hcard--scrim .hcard__over { z-index: 2; }
.hcard--scrim .hcard__over h3 { color: #FFFFFF; }
.hcard--scrim .hcard__over p { color: rgba(255,255,255,.82); }

/* ═══ WHY NOT JUST ══════════════════════════════════════════════════════════════════════════════
   Deliberately TEXT ONLY. This section is an argument, and the page had just lost one card grid;
   giving this one photographs would have made it the fourth. Three columns, a hairline between
   them, and the code voice for the two things a reader could actually type. */
.why { padding-bottom: var(--sy); }
/* The heading reads the same two variables as the columns under it. Written first with
   .content__inner--tight, it sat at 58 while its cards sat at 20 - the fifth time in this build that
   a heading and its content have derived one left edge from two different numbers. */
.whyhead { max-width: var(--wide); margin: 0 auto clamp(24px, 3.4vh, 40px);
  padding: var(--sy) var(--wide-gutter) 0; }
.whygrid { display: grid; grid-template-columns: repeat(3, 1fr);
  gap: clamp(20px, 2.6vw, 44px);
  max-width: var(--wide); margin: 0 auto; padding: 0 var(--wide-gutter); }
@media (max-width: 860px) { .whygrid { grid-template-columns: 1fr; gap: 28px; } }
.wcard { padding-top: clamp(18px, 2vw, 26px); border-top: 1px solid var(--hairline); }
.wcard h3 { font-size: clamp(15px, 1.2vw, 18px); font-weight: 600; letter-spacing: -.01em;
  margin-bottom: 9px; }
.wcard p { color: var(--mid); font-size: clamp(14px, 1.05vw, 16px); line-height: 1.55;
  max-width: 30ch; }
/* No code voice here any more: the section is written for someone who has never opened Terminal, so
   there is nothing left to set in monospace. */

/* The mid-page band is the same component as the closing one, a touch quieter so the close still
   reads as the close. */
.ctaband--mid .content__inner { padding-block: var(--sy); }
.ctaband--mid .display-2 { font-size: clamp(28px, 3.4vw, 50px); }

/* ═══ HEADINGS ══════════════════════════════════════════════════════════════════════════════════
   A gradient across the headline, after apple.com/macbook-pro. Worth recording that the design hook
   calls gradient text an AI tell and I deleted an unused version of this two passes ago on that basis
   - but Apple ships exactly this on the page Sarthak is referencing, and it is his call. The ramp runs
   pale mint to blue-grey, cool enough to sit on black without tinting the page warm.

   Gated behind @supports because the mechanism needs `color: transparent`: without background-clip the
   text would be invisible rather than merely unstyled. Outside the query it keeps its solid colour.
   Every stop clears AA on black at display size, measured: 16.5 / 13.1 / 9.8 / 7.0 : 1. */
@supports ((background-clip: text) or (-webkit-background-clip: text)) {
  /* The ramp is declared on BOTH the heading and, where SplitText has been through it, on each line's
     inner span. That is not belt and braces, it is the actual requirement: GSAP translates those spans
     to animate them, and a transformed descendant gets its own containing block, which stops the
     parent's clipped background painting across it. Declared only on .stmt, every animated headline on
     the page rendered as nothing at all - three CTA bands with an invisible h2 and no error anywhere.
     Per-line is also what the reference does: the ramp restarts on each line rather than stretching
     across the block. */
  .stmt, .stmt .split-line > span {
    background-image: linear-gradient(96deg, #D8EAE1 0%, #B6D4D0 34%, #96B8C8 68%, #7D9AB4 100%);
    -webkit-background-clip: text; background-clip: text;
    color: transparent; -webkit-text-fill-color: transparent;
  }
  /* ONLY ONE OF THEM MAY PAINT. Both declarations are needed - the parent for headings SplitText has
     not touched, the span because a transformed descendant escapes the parent's clip - but once a
     heading IS split, both paint the same glyphs: the parent at the text's resting position and the
     span at its animated one. Mid-reveal that is the same sentence drawn twice, a few pixels apart,
     resolving to normal as the tween lands. It is what Sarthak caught on the loading recording.
     Once .split-line exists the parent stops painting and the spans own the ramp. */
  .stmt:has(.split-line) { background-image: none; }
  /* An <em> inside carries no colour of its own, so the clipped background shows through it. */
  .stmt em { color: inherit; -webkit-text-fill-color: inherit; }
}

/* ── Colour in the bento, the way the reference uses it ──────────────────────────────────────────
   Not tinted cards and not coloured headings: one phrase per card, in a hue that means something -
   blue for the lock, green for the battery, amber for the timer. Everything else stays monochrome, so
   the colour reads as emphasis rather than decoration. */
.bcard .hot { color: #6FB2FF; }
.bcard .hot--green { color: #5FD08A; }
.bcard .hot--amber { color: #E8B25F; }
.bcard__body h3 .hot { -webkit-text-fill-color: currentColor; }

/* The masked line box. hero.css declares this for .hero only, which left every other split heading
   animating in unmasked - the line visibly travelling up from below instead of being revealed by its
   own edge. Same treatment everywhere now. */
.stmt .split-line { display: block; overflow: hidden;
  padding-bottom: .18em; margin-bottom: -.18em; }   /* descender room; see .split-line above */
.stmt .split-line > span { display: block; will-change: transform; }

/* ═══ MOBILE ════════════════════════════════════════════════════════════════════════════════════
   Found by loading the live site on a phone rather than by narrowing a desktop window, which is how
   both of these survived: one is invisible above 700px and the other needed a nav link to be clicked.

   1. ANCHORS LANDED UNDER THE HEADER. The nav is 78px and the progress strip another 40, and
      scroll-margin-top was 0, so every nav link put its section heading 118px behind fixed chrome.
      Desktop had it too. */
/* Clears the fixed chrome, which is now the nav alone: the 40px run strip that used to sit
   under it is gone, so 130px was 52px of dead space above every anchored heading. */
main > section[id] { scroll-margin-top: 96px; }

/* 2. THE HOURS COPY OVERFLOWED ITS CARD. These cards overlay near-black type on a pale band inside a
      15:7 photograph. At 390px that card is 163px tall and the copy needs 240 - it ran straight out of
      the bottom of the image, half a sentence hanging on the black below it.
      Cropping the picture taller would not work: these frames were composed with the subject on the
      RIGHT and quiet space on the left, so a portrait crop centres on nothing. The photograph keeps
      its full frame and the copy moves below it, which is what it needs light type for. */
@media (max-width: 700px) {
  /* The card clips (overflow: hidden) so its 28px radius can cut the photograph. With the copy now
     sitting BELOW the photograph, that clip runs down the text's own left edge - and the first
     glyph of every line sat on it. A capital Y, whose left arm overhangs its origin, lost that arm
     and read as a chevron. The radius moves onto the image, the card stops clipping, and the copy
     starts flush with the section's gutter instead of 2px inside it. */
  .hcard { overflow: visible; border-radius: 0; }
  .hcard__img { border-radius: 22px; }
  .hcard__over { position: static; max-width: none;
    padding: 14px 0 0; }

  /* PROXIMITY. Stacked, the caption sits 14px under its own photograph and the grid's gap put the
     NEXT photograph 16px under the caption - two distances close enough to read as equal, so the
     words floated between two pictures instead of belonging to the one above them. The gap opens
     to 46px, which is more than three times the bond, and the group reads as one card again.
     The head also needs more air than the 24px it inherits at this width. */
  .hgrid { gap: 46px; }
  .hourshead { margin-bottom: 14px; }
  .hcard__over h3 { color: var(--text); font-size: clamp(21px, 6vw, 27px); }
  .hcard__over p { color: var(--mid); font-size: 15px; max-width: none; }
  .hcard--scrim::after { display: none; }          /* no picture behind the words to hold them off */
  .hcard--scrim .hcard__over h3 { color: var(--text); }
  .hcard--scrim .hcard__over p { color: var(--mid); }
  .hcard::before { display: none; }
}

/* 3. Touch targets. The step arrows were 36px; 44 is the smallest a thumb reliably hits. */
@media (pointer: coarse) {
  .cl__arrow { width: 44px; height: 44px; }
}

/* ═══ PORTRAIT ══════════════════════════════════════════════════════════════════════════════════
   Everything here is inside a portrait query and changes nothing above it: the desktop view is
   untouched by design. */
@media (orientation: portrait) and (max-width: 820px) {
  /* The stage is a 100dvh sticky child, so the SCRUB RANGE is section height minus one viewport.
     At 150vh that left half a screen of travel for a whole film, which reads as stuck on frame one
     rather than slow. 220vh gives it 1.2 screens. #ch1 carries its own height and an ID outranks a
     class even inside a media query, so it has to be named. */
  .chapter, #ch1 { height: 220vh; }

  /* FULL-BLEED, AND THE CAPTION SITS ON THE PICTURE. This was briefly letterboxed - the whole frame
     shown as a band across the middle - which is honest but spends three quarters of a phone screen
     on black bars. Sarthak saw both and chose the zoom. The crop is severe (a 16:9 frame in a
     390-wide stage keeps about a quarter of its width) so each chapter names the point that has to
     survive it with data-focus-portrait; centred, CH.1 and CH.3 would both crop to empty black.
     The caption then goes back over the image where there is now something to sit on, low enough
     to clear the subject, with a scrim under it to carry the type. */
  .chapter, #ch3 { --beat-y: 50%; }
  /* The scrim is weighted to the MIDDLE, not the bottom, because that is where the caption sits.
     A bottom-up gradient left the centre of the picture at full brightness with white type on it,
     and darkened the one part of the frame nothing was written on. Held off the very top and bottom
     so the photograph still opens and closes at full strength. */
  .chapter__stage::after { content: ""; position: absolute; inset: 0; z-index: 1;
    pointer-events: none;
    background: linear-gradient(180deg, rgba(0,0,0,.10) 0%, rgba(0,0,0,.52) 34%,
                                        rgba(0,0,0,.60) 50%, rgba(0,0,0,.52) 66%,
                                        rgba(0,0,0,.10) 100%); }
  .chapter__copy { z-index: 2; }

  /* The explorer plates are 1.88 wide and the mobile stage was 4:3, so cover cropped the subject -
     which on these frames lives on the RIGHT, because the left was deliberately left quiet for the
     controls that are no longer overlaid at this size. Keeping the 4:3 height but anchoring right
     shows the machine and crops the empty side instead. */
  .cl__stage { aspect-ratio: 4 / 3; }
  .cl__media { object-position: 78% center; }
}


/* ═══ LARGE DISPLAYS - the type scale ═══════════════════════════════════════════════════════════
   Ceilings raised, never rules changed. Every display clamp tops out around 1600px of viewport,
   because 6.4vw reaches 104px there - so a 2560 monitor was being served laptop-sized headlines on
   a canvas 60% wider. These rise about 14% against an 18% wider measure, which holds the ratio of
   headline to column near where it sits on a laptop instead of just making things big.

   AT THE BOTTOM OF THE FILE ON PURPOSE. Written up beside the --wide step, it changed nothing: the
   originals are declared further down the same stylesheet at equal specificity, so source order won
   and the measured font sizes at 1920 were identical to 1440. .giant lives in hero.css, which loads
   after this file, so its ceiling is at the bottom of that one. */
@media (min-width: 1900px) {
  .display-2 { font-size: clamp(34px, 3.9vw, 64px); }
  .display-3 { font-size: clamp(26px, 2.8vw, 46px); }
  .display-4 { font-size: clamp(22px, 2.2vw, 36px); }
  .lead { font-size: clamp(19px, 1.5vw, 23px); }
  .hours__h { font-size: clamp(30px, 4vw, 68px); }
  .ctaband--mid .display-2 { font-size: clamp(28px, 3.4vw, 57px); }
}
