/* ==========================================================================
   hero.css — the landing page.

   THE FOLD'S DEVICE IS A CONTAINED OBJECT, NOT A BLEED. It is complete, ringed
   on four sides, seated on the fold's ground plane with an authored --seat
   beneath it, and it holds that distance at every scroll position and every
   window height. Shipped 2026-08-28 as the winner of hero-fold round 1
   (design/gauntlet-log/website.md); the losing take, "clip the object through
   the whole scroll range so its own edge is never on screen", is preserved at
   design/prototypes/website/fold-bleed.css and its measurements are in
   design/rounds/hero-fold-r1/.

   THE DEFECT THIS ANSWERS. The previous fold was a bleed at rest and a
   floating object under scroll, and it chose neither: `@keyframes lift` moved
   the crop 46px up against a boundary that travels with the page, so the
   distance from the object's bottom edge to the fold's boundary ran
   1 -> 12.5 -> 24 -> 35.5 -> 47px on desktop and 8.19 -> 54.19px at 393.
   Under `prefers-reduced-motion: reduce` the same page measured 1px flat at
   every stop, which is how we know it was the animation and not the layout —
   and it is why the sanctioned harness could not see it: tools/shoot.mjs
   emulates `reduce` and freezes animations, so `lift` never ran under it and
   three prior rounds were judged through a lens the defect was invisible to.

   WHAT IT COSTS, WRITTEN DOWN RATHER THAN DISCOVERED LATER:
     · design/system.md §3 says of this element that "it bleeds DOWN and never
       sideways". This file contradicts that rule. The amendment it requires is
       drafted at the foot of this file and has NOT been applied to §3 — that
       is a maintainer edit, not a stylesheet edit.
     · The page loses its one scroll-driven effect (change 5). The depth it was
       buying is bought instead by a cast shadow that a flush composition could
       never show, because a flush object has nothing to cast onto.
     · OPEN, and named by the craft lens against this artifact: the object has
       46px rounded TOP corners and square BOTTOM corners with a 1px closing
       stroke — a shape that is a device at the top and a crop at the bottom.
       Both prescribed fixes were built and measured, and both are unavailable.
       Rounding the bottom to match the top slices live content: measured
       against shots/4-review-source-dark.webp the crop's bottom row sits
       10.9 CSS px below the last ink on desktop and 2.2 CSS px on phone,
       against a screen radius of 51.4 / 41.9 CSS px, so the arc cuts the note
       card on desktop and the "Verbatim · on this iPhone" row on phone (built
       as fold-s1, captured as S1-fold-*). Removing the bottom stroke instead
       is the losing take. The reading this file asks for is that the object is
       a PLATE, not a device: its top corners are rounded because the screen
       behind them is, its bottom is square because the plate ends where the
       crop ends, and its ring closes on four sides because a plate has four
       edges. The competing reading — "cut off, then floated" — is available
       and is the standing falsification condition for this composition.

   THE SIX CHANGES that make the object contained, each marked FOLD R1 below:
     1  .fold pins the device-framing tokens to their dark values, because the
        fold is a dark band in BOTH appearances and its ring was following the
        viewer's appearance anyway (measured: the bottom ring read ΔL 27 in
        dark and ΔL 6 in light — the same object, half-erased).
     2  --seat: the space beneath the object, authored per breakpoint on the
        rhythm. 60px desktop, 50px tablet, 40px phone.
     3  .crop's cast is re-picked to the one .phone__body already uses, so the
        shadow lands INSIDE --seat instead of clipping at the section rule.
     4  the phone/tablet fold stops leaving its slack under the device.
     5  the `lift` keyframe is deleted.
     6  the object settles onto its ground as it arrives — entrance only.

   MEASURED ON THIS FILE, motion live, 5 scroll stops x 3 viewports x 2
   appearances, and again under `reduce` — 60 of 60 stops each:
     crop.bottom - fold.bottom = -61px at 1440, -41px at 393 and at 390, flat.
     No scroll position and no window height in the sweep moves either number.
   ========================================================================== */

/* ==========================================================================
   TOKENS. Light values are design/system.md §2 verbatim where they apply; the
   page ground is white rather than #F2F2F7 because round 2c: "The grey ground
   makes the page read as a spec document rather than a product." #F2F2F7 is
   kept for insets, which is what it is for.
   ========================================================================== */
:root{
  --rhythm:10px;

  --page:#FFFFFF;
  --inset:#F2F2F7;
  --ink:#000000;
  /* SECONDARY AND CAPTION INK, raised 2026-08-30 to clear WCAG AA (4.5:1) on
     BOTH grounds they are printed on. Before: --ink-2 at .72 was 4.74:1 on
     --page but 4.47:1 on --inset — the pricing descriptor and the whole
     footer sit on --inset and FAILED; --ink-3 at .50 was 2.69:1 / 2.60:1,
     the YEARLY and MONTHLY labels, under even the 3:1 large-text floor. .74
     is very nearly the LIGHTEST caption ink that still clears 4.5:1 on
     #F2F2F7 (4.72:1), so the caption-vs-secondary hierarchy is carried from
     here on by size, case and tracking — the rule style.css already states:
     an ink reads as secondary because of what wears it, not because it is
     closer to the ground. Full arithmetic per token per ground is in
     docs/reports/site-a11y-fixes.md.

     UPDATE 2026-08-31: "the pricing descriptor and the whole footer sit on
     --inset" is no longer true of where they render — .term (the unchosen
     MONTHLY card) and .foot now sit on --page with a --hairline border
     instead of an --inset fill (round 2c's reasoning, "the grey ground
     makes the page read as a spec document rather than a product," applied
     one level down from the page to an ordinary block). That only raises
     both ratios above to the --page column, so nothing here regresses. That
     leaves --inset with no remaining consumer ON THIS PAGE — .term--chosen
     is --cta-fill, not --inset (see the .term--chosen note below for why it
     moved off --blue) — but the token itself is left declared rather
     than deleted; the --inset column stays in the comments below because
     it is still a real, correct measurement of the value. */
  --ink-2:rgba(60,60,67,.80);   /* 5.97:1 on --page, 5.56:1 on --inset */
  --ink-3:rgba(60,60,67,.74);   /* 5.02:1 on --page, 4.72:1 on --inset; captions and labels */
  --sep:rgba(60,60,67,.20);
  /* 2026-08-31, ADDED HERE: style.css already carries this exact token
     (same value) for the .rail/.contact/.foot pages; hero.css had no
     equivalent because nothing on this page had needed a border strong
     enough to define a block on its own, un-filled, ground before now.
     Reused, not invented — see the .term / .foot notes below. */
  --hairline:rgba(60,60,67,.29);
  /* THE UNCHOSEN CARD'S EDGE, 2026-09-03. Separate from --hairline because
     the two are answering different questions, and only one of them is a
     3:1 question.

     WCAG 1.4.11 asks for 3:1 only where an edge is needed to identify a
     component or its state. Most of this page's hairlines are section
     rules (.fold, .promise, the .rv list rules, .foot): they separate
     reading from reading, nothing is being identified, and they were
     measured and deliberately LEFT at 1.41-1.94:1 rather than flattened up
     to a floor that does not apply to them. .term is the exception. It is
     one of a pair the reader compares, its sibling .term--chosen is a
     solid fill, and this outline is the only thing that makes the MONTHLY
     card an object at all rather than loose text beside a blue card. It
     replaced a fill (see the --ink-2 note above) so it is doing a fill's
     job, and in dark appearance it measured 1.67:1 and visibly failed to
     do it.

     Measured, pixel-sampled against the real grounds around the card, which
     the card's own blue glow tints (worst side is the bottom, into the
     glow): 1.43 -> 3.29 light, 1.67 -> 3.42 dark. Against the card's own
     fill: 1.71 -> 3.93 light, 1.91 -> 3.90 dark.

     Deliberately kept UNDER .term--chosen's own 3.92-4.56:1 edge. The note
     at .term says fill is spent only on the card that is chosen and never
     on the ordinary one beside it; an outline loud enough to match the
     filled card would take that distinction back. Visible, still second. */
  --card-edge:rgba(60,60,67,.65);
  --blue:#007AFF;

  /* **TEXT LINKS ARE NOT A CONTROL COLOUR.** style.css solved this and hero.css
     never got the fix, so the home page's footer link rendered #007AFF and
     measured 4.02:1 on white, under the 4.5:1 AA floor for normal text. It
     passed in dark only because the ground is darker.
     design/system.md reserves #007AFF for "settled" and "commits". A hyperlink
     is neither. Same pair style.css already carries, same measurements:
       light  #004CB0   7.89:1 on the page ground
       dark   #4DA3FF   8.00:1 on the page ground
     The CTA button is unaffected: it is white ink ON blue, a different
     equation, and keeps --blue. */
  --link:#004CB0;
  --blue-glow:rgba(0,122,255,.34);

  /* the dark bands. Near-black in BOTH appearances; see the header note. */
  --band:#0A0A0C;
  --band-2:#131317;
  --band-ink:#FFFFFF;
  --band-ink-2:rgba(235,235,245,.72);
  --band-ink-3:rgba(235,235,245,.54);   /* 5.29:1 flat, 4.86:1 at the promise tint's centre; was .44 at 3.85:1 */
  --band-sep:rgba(235,235,245,.16);
  --band-blue:#0A84FF;          /* link ink on the DARK band: 5.76:1 on #101014 */
  --cta-fill:#0071E3;           /* Apple's own CTA blue. White label = 4.70:1, both
                                   appearances. #0A84FF was 3.65:1 and failed the
                                   4.5:1 floor at this label's measured size.
                                   2026-09-01: also .skip (was --blue, same
                                   3.65:1 dark failure) and .term--chosen
                                   (was --blue, 2.58-3.35:1) — three
                                   consumers of the same white-on-blue
                                   equation, one fix. */

  /* device framing, lifted from design/product-shots/device-frame.css */
  --bez-band:#1B1B1F;
  --bez-edge:rgba(255,255,255,.14);
  --cast:rgba(17,17,20,.28);
  --cast-tight:rgba(17,17,20,.16);
  --ring:rgba(60,60,67,.16);

  /* FOLD R1 · CHANGE 2 — the space beneath the object.
     Authored per breakpoint, on --rhythm, never inherited from a keyframe.
     This is the whole difference between "it deliberately ends" and "it
     stopped": a value somebody chose, that is the same at every scroll
     position and at every viewport height inside its breakpoint. The shipped
     page's equivalent number runs 1px → 47px with scroll on desktop and 1px →
     124px with window height on phone, and nobody picked any of those. */
  --seat:60px;

  /* AGENTS.md-adjacent house easing: ease-out, never ease-in. */
  --ease:cubic-bezier(.23,1,.32,1);
  --in:200ms;
  --out:140ms;

  /* THE TYPE RAMP — five members, re-authored at the phone breakpoint rather
     than scaled. Ledger line 18 caps the fold at five sizes and TWO weights;
     this page holds two weights (600/400) end to end. That is a deliberate
     deviation from design/system.md §4's 660 caption weight: a measured
     ledger line outranks a spec value it was measured against. */
  /* Fluid so an authored break can never be undone by a narrow column: the
     headline is sized against the space it actually has, at every width
     between 760 and 1600, not at the two widths that get screenshotted. */
  /* REM BOUNDS, 2026-08-30. Every member below was px, so a reader who raised
     their browser or OS default font size got IDENTICAL pixels and was left
     with whole-page zoom — a reflow of a layout they never asked to change.
     The bounds are now rem and the fluid middle stays vw, so each size still
     tracks viewport width AND moves with the reader's root font:
     clamp(2.125rem,4.1vw,3.625rem) scales with both. At the default 16px
     root every value here is the same number of px it always was — 34px is
     2.125rem exactly, 12px is 0.75rem exactly — so the fold's proportions at
     393 / 768 / 1440 cannot move; the computed table is in
     docs/reports/site-a11y-fixes.md. TYPE scales with the reader; spacing,
     --seat and the device's own geometry stay authored px. */
  --t-display:clamp(2.125rem,4.1vw,3.625rem);
  --t-head:clamp(1.5rem,2.2vw,1.875rem);
  --t-lede:clamp(1rem,1.5vw,1.25rem);
  --t-body:1.0625rem;
  --t-meta:0.8125rem;   /* 13px, the masthead nav; same name and value as style.css */
  --t-cap:0.75rem;

  /* THE UPPERCASE MICRO-LABEL, 2026-09-01. .eyebrow/.step__n/.term__k and
     style.css's .caption/.rail__cap are one repeated device — same job
     (a small uppercase tag above a heading or value), same .075em tracking
     in both files — but they were drawing it from each file's own small
     token: --t-cap here at 12px, style.css's --t-cap at 11px (the
     mathematically-derived floor of its own 1.26-ratio document scale,
     17/1.26²=10.7 -> 11). A craft round measured the pair renders 12/600
     on this page and 11/660 on the legal pages and could not find a
     reason the SIZE should differ — --t-cap's other job on this page is
     small print (.act__note, .step__src, .checkable, .price__fine,
     the footer — see --t-cap's scoped override at .foot below), not the
     label device, so it stayed at 12 for that reason, not because 12 is
     the label's own considered size. --t-micro is 11px, style.css's value
     verbatim, given its own name so the label device can move to it
     without shrinking the small-print uses that still want 12. Weight
     stays 600 here rather than moving to style.css's 660: Ledger line 18
     caps this page at two weights (600/400) end to end, a constraint
     style.css does not share (it already runs 600/640/660), so the
     lower-friction fix is style.css's caption weight coming down to 600,
     not a third weight added here. */
  --t-micro:0.6875rem;

  /* THE SMALL-PRINT MEASURE, 2026-09-01 — F1, THIRD PASS. .checkable and
     .price__fine narrowed their visible line with a fixed px padding-right
     (540px / 244px) sized against ONE desktop box measurement. That number
     is only correct at the exact width it was measured at: .promise .four
     (the box .checkable matches) is FLUID below 1180, so the same 540px bite
     produces a different visible column at every other width — a 159px
     ribbon at 760, a 288px column at 900 — and .step__src had no cap at all
     outside one breakpoint. Below 759 both blocks were zeroed out by a
     second rule rather than fixed, because the fixed px ate past the
     now-narrow stacked column entirely.
     One value, expressed in ch, replaces all of it: `max(0px, 100% - Nch)`
     as padding-right caps the CONTENT at N characters' width while the BOX
     stays at its full measured width (border-box, so padding never changes
     outer width) — the alignment .checkable/.price__fine's own comments
     require. On a box narrower than Nch the subtraction goes negative and
     max() floors it at 0, so the mobile zeroing above falls out of the
     formula instead of needing its own rule. .checkable and .price__fine
     each wrap that in one more layer — see their own rules — because a
     plain `100%` is the CONTAINING BLOCK's width (.pad), not this box's own
     narrower max-width; that trap and its min()-of-two-regimes fix are
     explained where it bites, not repeated here.
     N=61ch. .checkable/.price__fine/.step__src all set font-size from
     --t-cap, so 1ch means the same px at every width these blocks render at
     (measured off this font stack: 7.56px at the 12px desktop --t-cap,
     6.93px at the 11px phone --t-cap — the ratio holds because ch scales
     with font-size, not because the px is pinned). 61ch is 461px at 12px,
     the same visible column the old 540px padding produced against
     .checkable's 1000px desktop box (1000-540=460) and within 1px of what
     244px produced against .price__fine's 704px box (704-244=460) — so 61ch
     is not a new target, it is the SAME 460px column the previous two
     passes already measured and accepted, now expressed as a size instead
     of a subtraction.
     MEASURED (tools/probes/cpl-census.js, cplFullLine, full sweep
     393-1720): .checkable holds 81cpl from 505 up through 1720 (67-75cpl at
     393-430, still inside the band) — one number at every width, where the
     fixed-px version ranged from a 159px ribbon to a collapsed column.
     .price__fine[0]/[1] hold 85-86 / 82-83cpl from 505 up (68-77 / 68-76 at
     393-430). .step__src holds 65-78cpl through the fluid tiers (<=959px);
     the >=960px three-column tier can drop as low as 49cpl at 1000-1100px,
     but that floor is the .steps grid's own column width, present and
     identical before this pass (padding-right was already 0px there, box
     narrower than the cap) and shared by .step p, which this pass does not
     touch — a separate, pre-existing narrow-column condition, not the
     measure-cap defect this token exists to fix. All four numbers land at
     or under the 81/86/83 this file's own prior passes already called
     correct. One value for all three: they share a font-size token and a
     comfort target, and nothing about their text needed a different cap. */
  --fine-measure:61ch;
}

/* ==========================================================================
   THE FOLD FOLLOWS THE READER'S APPEARANCE — light half. Added 2026-08-30.

   WHY. The fold was near-black in BOTH appearances (a `--band` of #0A0A0C at
   the light root), so a reader who chose Light got a dark hero anyway. One
   commit earlier (dfd2fc6) the page had just been made to honour the reader's
   TEXT-SIZE setting; ignoring their APPEARANCE setting is the same class of
   defect, and only one half of it was fixed. Filed as docs/todo-site-fold.md §2.

   WHY IT MATTERS BEYOND TASTE: it blocked every bar round on this surface.
   Every blindness-clean bar the repo holds is light, and
   docs/briefs/website-bar-method.md §5 void condition 7 — "a dark candidate
   paired against the light-only bar" — trips before a critic is even
   commissioned. Two dark-bar hunts failed: 24 URLs, 23 captured, 12 dark folds,
   10 judged, ZERO adopted.

   THIS IS NOT A VERDICT THAT LIGHT IS BETTER. The dark treatment below is
   untouched and remains the dark-mode fold, values verbatim. A blind round
   decides; the assertion it will measure is that the fold's mean luminance is
   above 200 in light appearance and stays below 60 in dark. Staged, not
   measured — the capture commands are in docs/reports/site-fold-appearance.md.

   SCOPE — `.mast` AND `.fold` TOGETHER. The masthead rides the fold's band:
   zero gap, the same ground, a 1px rule nowhere between them. A dark strip
   above a light fold is a seam nobody would author, so the masthead follows.

   THE PROMISE BAND — DECIDED 2026-09-01, F2. The fold's light half shipped, so
   this is that pass. `.promise` reads `--band` and used to be near-black in
   both appearances, which measured as 19.78:1 against the page in light and
   1.11:1 in dark — a slab in one appearance and a hairline in the other, on
   the section carrying the site's central privacy claim.

   KEEP THE ASYMMETRY; CLOSE THE GAP ENOUGH THAT THE BAND READS AS A DISTINCT
   SURFACE IN DARK. A black slab on white has no honest equivalent on black —
   inverting it to a light slab would be a different, worse design, since iOS
   does not paint bright slabs on a dark page. iOS shows elevation in dark by
   LIGHTENING the raised surface instead, and its own elevated grouped
   background on black is #1C1C1E. `.promise` is pinned to that value in the
   dark media query below, scoped to `.promise` alone: `.fold`'s own dark band
   is untouched, values verbatim, per the note above this one. Measured after
   the move (tools/probes, dark, 1500 wide): the eyebrow — the ink nearest the
   radial tint's own centre and the most contrast-sensitive ink in the
   section — reads 5.1:1 against the real painted (tinted) ground, up from
   4.9-5.3:1 against the old near-black; every other ink in the section reads
   higher. #1C1C1E is the ceiling this decision accepts, not a floor to push
   past — iOS does not go lighter for this same role, and neither does this.

   WHAT IT COSTS, named here rather than discovered later:
     · The hero image cannot switch. Only shots/4-review-source-dark.webp
       exists; no light variant was ever produced. On the light fold it reads
       as a dark-mode app screen seated on a white ground — ordinary for a
       marketing page, but it caps the fold's mean luminance, and at the phone
       viewport the crop is ~40% of the frame. The >200 assertion is at real
       risk there; the number and the lever (a light hero shot, which needs the
       product-shot pipeline) are in the report.
     · The ink values are the page's own light tokens, so the contrast
       arithmetic is the already-verified dfd2fc6 set, not new hand waving:
       band-ink-2 .80 → 5.97:1 on #FFFFFF; band-ink-3 .74 → 5.02:1 on #FFFFFF
       and 4.59:1 at the blue wash's centre (the fold's worst case, computed in
       the report). h1 black on white is 21:1.
     · ~~The `--band-blue` #0A84FF button is unchanged: its 3.65:1 white label
       wants a design round, not an accessibility patch.~~ OVERRULED 2026-08-30,
       after a measurement pass on the LIVE site found 3.65:1 in all four cells.
       A palette overhaul is a design round; raising the primary action above
       the 4.5:1 floor is one hex value, and the value is Apple's own CTA blue
       #0071E3 (4.70:1) — this page's stated bar, not a compromise against it.
       Link ink and button fill are now separate tokens because they need
       opposite moves: darker for a white label, lighter for ink on a dark
       ground.
   ========================================================================== */
.mast, .fold{
  --band:#FFFFFF;
  --band-2:#F2F2F7;          /* the system inset grey: the gradient's quieter top */
  --band-ink:#000000;
  --band-ink-2:rgba(60,60,67,.80);
  --band-ink-3:rgba(60,60,67,.74);
  --band-sep:rgba(60,60,67,.20);
  --band-blue:#0071E3;       /* 4.70:1 on #FFFFFF; the inherited #0A84FF was 3.65:1 */
}

/* .foot's light-appearance ink, same mechanism as `.mast, .fold` above and
   placed next to it for the same reason: it must come BEFORE the dark
   media query so the dark restore inside that query (below) wins the
   same-specificity tie in dark appearance. See the fuller "THE TWO
   FOOTERS, MEASURED" comment at .foot's own rule, further down this file,
   for why this exists — matching style.css's document ink (#1D1D1F /
   rgba(60,60,67,.90)) on verbatim-identical footer copy, in light
   appearance only. */
.foot{
  --ink:#1D1D1F;
  --ink-2:rgba(60,60,67,.90);
}

@media (prefers-color-scheme: dark){
  :root{
    --page:#000000;
    --inset:#0C0C0E;
    --ink:#FFFFFF;
    --ink-2:rgba(235,235,245,.72);
    --ink-3:rgba(235,235,245,.52);   /* 4.93:1 on --page, 4.98:1 on --inset; .46 was 4.03/4.12, under the 4.5:1 floor */
    --sep:rgba(84,84,88,.60);
    --hairline:rgba(84,84,88,.72);   /* matches style.css's dark --hairline */
    /* NOT rgba(84,84,88,a). That base CANNOT reach the 3:1 floor on this
       ground at any alpha: at a=1.0 it is #545458 and measures 2.79:1 on
       #000000, 2.44:1 against the glow-tinted grounds the card actually
       sits on. Raising --hairline's alpha here would have looked like a
       fix and silently stayed under the floor. The dark ink family
       (235,235,245) is what the rest of this block already uses for
       anything that has to carry on black, so the base changes, not just
       the alpha. .45 lands at 3.90:1 on the card's own fill, matching the
       light column's 3.93:1 so the two appearances read the same. */
    --card-edge:rgba(235,235,245,.45);
    --blue:#0A84FF;
    /* The dark member of the text-link pair. #0A84FF measures 3.65:1 on this
       ground, under the AA floor; this clears it at 8.00:1. */
    --link:#4DA3FF;
    --blue-glow:rgba(10,132,255,.40);

    --band:#101014;
    --band-2:#1A1A1F;

    --bez-band:#2A2A2E;
    --bez-edge:rgba(255,255,255,.20);
    --cast:rgba(0,0,0,.55);
    --cast-tight:rgba(0,0,0,.40);
    --ring:rgba(255,255,255,.13);
  }

  /* The dark half of "the fold follows the reader's appearance": everything
     the light-scoped block above overrides is restored here to today's values,
     verbatim, so the dark-mode fold renders exactly what it did before that
     change — it was never judged against a light bar, because pairing one was
     impossible, and this must not quietly become a redesign of it. Same
     specificity, later in source order — that is the whole mechanism. The ink
     values repeat the :root ones on purpose: the light block overrides them
     at `.mast, .fold`, so the restore has to name every token it touched or
     the dark fold would inherit dark-ink-on-light values through the narrower
     scope. */
  .mast, .fold{
    --band:#101014;
    --band-2:#1A1A1F;
    --band-ink:#FFFFFF;
    --band-ink-2:rgba(235,235,245,.72);
    --band-ink-3:rgba(235,235,245,.54);
    --band-sep:rgba(235,235,245,.16);
  }
  /* .foot's --ink/--ink-2 restore. The light-mode override at .foot (below)
     borrows style.css's document ink; unrestored, it would keep winning here
     too, since a rule that matches .foot directly always beats an inherited
     :root value regardless of which media query last touched :root — the
     first pass at this fix shipped without this block and rendered the
     "Relational" wordmark and its prose at light-mode near-black on the
     dark page's black ground, unreadable. Restored to the SAME values as
     :root's own dark ink above, which is also style.css's dark --ink/
     --ink-2 verbatim — both files already agree here, so dark appearance
     needed no cross-file borrowing at all, only light did. */
  .foot{
    --ink:#FFFFFF;
    --ink-2:rgba(235,235,245,.72);
  }
  /* FOLD R1 · CHANGE 1, appearance-scoped 2026-08-30 — the dark fold's device
     framing pins. They used to sit unconditionally on `.fold` because the fold
     used to ignore the viewer's appearance; it no longer does, so in light
     appearance `.fold` inherits the light :root framing instead (ring
     rgba(60,60,67,.16), the cast the .phone objects below already use). */
  .fold{
    --ring:rgba(255,255,255,.13);
    --cast:rgba(0,0,0,.60);
    --cast-tight:rgba(0,0,0,.42);
  }
  /* F2, 2026-09-01 — THE PROMISE BAND, DARK APPEARANCE ONLY. See the decision
     record at the top of this file (search "THE PROMISE BAND — DECIDED").
     Scoped to `.promise` alone, not to :root's --band, so `.fold`'s own dark
     band stays #101014, values verbatim, as the note above it requires. */
  .promise{
    --band:#1C1C1E;
    /* F2, round 5 craft — MY FAULT, FIXED. Raising the ground above to
       #1C1C1E themed the surface without re-checking what sits on it:
       :root's --band-blue (#0A84FF, chosen against the old near-black
       #0A0A0C at 5.42:1) measures 4.66:1 here, under this file's own 4.70
       floor — a breach the sighted eye would not catch since it still
       clears WCAG AA at this size. The only real `.band a` consumer in the
       whole page is the "In full: what the app sends..." link in this
       section (`.fold` carries no non-button link), so scoping the fix to
       `.promise` fixes the one thing that broke without touching `.fold`'s
       own dark link colour (verbatim #0A84FF, 5.20:1 on #101014, untouched).
       Reused rather than invented: #4DA3FF is already --link's dark-appearance
       twin (see the TOKENS block), same "brighter blue for ink on a near-
       black ground" job this token already does elsewhere. Measured here:
       6.48:1 on #1C1C1E. Light is unaffected — .promise's light ground and
       --band-blue are both untouched, still 5.42:1. */
    --band-blue:#4DA3FF;
  }
}

@media (max-width:759px){
  :root{
    /* FOLD R1 · CHANGE 2 — re-authored, not scaled, like everything else at this
       breakpoint. 40px against a 20px side gutter: an object needs more space
       below it than beside it to read as seated rather than as centred. */
    --seat:40px;

    /* re-authored, not scaled: the display AND the section-head members change
       step, and the body loses a pixel. APPLE-STANDARD.md §2 mechanism 3.
       Same rem discipline as the desktop ramp: identical px at a 16px root,
       and a phone reader who raises their default font is no longer frozen
       out of it. */
    --t-display:2.125rem;
    --t-head:1.5rem;
    --t-lede:1.0625rem;
    --t-body:1rem;
    --t-cap:0.6875rem;
  }
}

/* ------------------------------------------------------------------ base */
*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}

body{
  margin:0;
  background:var(--page);
  color:var(--ink);
  font:400 var(--t-body)/1.30 -apple-system,BlinkMacSystemFont,"SF Pro Text","SF Pro Display","Helvetica Neue",Helvetica,Arial,sans-serif;
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
  text-rendering:optimizeLegibility;
  overflow-x:hidden;
}
/* Ledger line 21: body leading 1.30, not 1.50. Apple measures 1.18-1.29. */

img{max-width:100%}
h1,h2,h3,p,ul,figure{margin:0}
ul{padding:0;list-style:none}

/* The one container. Wide on purpose — Aaron: "your website is narrow". The
   MEASURE is applied to prose blocks individually, not to the page. */
.pad{
  max-width:1280px;
  margin:0 auto;
  padding:0 clamp(20px,4vw,48px);
}

a{color:var(--link);text-decoration:none}
a.link{text-decoration:underline;text-underline-offset:.22em;text-decoration-thickness:1px;text-decoration-color:color-mix(in srgb,currentColor 40%,transparent)}
/* F3, round 11 craft — the generic half of the press-fix (see `.btn:active`,
   below, for the fuller argument): every plain link on the page — masthead
   nav, footer nav, the wordmark, `.link`, and every `.band a` (the "In
   full" link, at whatever ink `--band-blue`/`--link` resolves to there) —
   gets the same currentColor ring `.btn:active` uses, so a real press
   answers on every control, not just the one button. `.btn:active`'s own
   rule wins on the button by specificity (0,2,0) over this one's (0,1,1),
   so the two coexist rather than one overriding the other by accident.
   Paired with `-webkit-tap-highlight-color:transparent`: WITHOUT it, iOS
   Safari's own default tap highlight — a flat grey box, the same shape
   and colour regardless of what is under it — still fires on every tap
   underneath whatever this rule paints, and it is not "good enough" on
   its own for the same reason a single flat ring colour was rejected in
   `.band :focus-visible` above: a fixed grey reads on a near-white rail
   row and disappears (or worse, looks like a stray box) on the promise
   band's near-black ground, and it never appears at all for a mouse or
   keyboard press, which the ring above now also covers. Explicit and
   intentional beats an unstyled platform default neither file was
   actually relying on for anything. */
a:active{box-shadow:0 0 0 1.5px currentColor}
a,button,summary{-webkit-tap-highlight-color:transparent}
/* F5, 2026-09-01 — was var(--blue). style.css's /privacy /support skip link
   already used --link here (7.89:1 light, 8.00:1 dark), which is why the
   ring measured a different colour on the two files for a component both
   comments call "the same skip link, not a lookalike." --blue also fails
   design/system.md's own rule two blocks up: it is reserved for settled/
   commit, and a focus ring is neither. --link clears the 3:1 non-text floor
   the same as --blue did, so this loses nothing and now matches on both. */
:focus-visible{outline:2px solid var(--link);outline-offset:3px;border-radius:4px}
/* F1, round 11 craft — `.band`'s ring, painted, sampled at four band
   centres: --link (#004CB0, light appearance) on the promise band's near-
   black ground (#0A0A0C) measured 2.51:1, under the 3:1 non-text floor
   this exact rule's own comment above claims to clear. --link is built for
   ink on --page/--inset; the near-black band is a different ground and
   already has its own token for exactly this job, one line below `.band
   a{color:var(--band-blue)}` already uses to paint the link text itself at
   5.42:1 (light) / 6.48:1 (dark, `.promise`) / 5.20-5.76:1 (`.fold`'s own
   dark link). `--band-ink` would clear further (19.78:1) but that is the
   page's plain reading-ink token, never used for anything blue-coded
   before; `--band-blue` is the token this exact link already trusts to
   resolve correctly per appearance and per section, so the ring asks the
   same question the text already answers instead of a second, unrelated
   one. One rule, not scoped to `.deeper` or to one appearance: every
   `.band` descendant that can take focus (today, only `.deeper`'s link and
   `.fold`'s CTA) gets it, and `--band-blue` already clears 3:1 everywhere
   it resolves — 4.70:1 on `.fold`'s light band, 5.20-5.76:1 on its dark
   one — so nothing that was already passing regresses. */
.band :focus-visible{outline-color:var(--band-blue)}
/* 2026-09-01 — MEASURED, NOT TASTE. `.band :focus-visible` above scopes
   --band-blue to every `.band` descendant that can take focus, which is
   two controls: `.deeper`'s link inside `.promise`, and this file's own
   CTA inside `.fold`. A craft round flagged the CTA's ring as the dimmest
   on the site AND identical to the fill it surrounds — `.fold`'s
   --band-blue resolves to #0071E3 in both appearances (see the TOKENS
   block and `.mast, .fold`'s light override; nothing in the dark restore
   touches --band-blue), the same value as --cta-fill, so the ring reads
   as 1.00:1 against the pill it rings even though it clears the 3:1
   non-text floor against the surrounding ground (measured, pixel-sampled
   the same way as the finding: light 4.53/4.35/4.56 left/right/top, dark
   3.96/3.83/3.97 — not a failure, just the site's dimmest ring by a wide
   margin; every other ring measures 5.42-8.00).

   Checked --link the same way, pixel-sampled, both appearances:
     light  #004CB0 on #F8FBFF/#F0F7FF/#F9FCFF (left/right/top) — 7.60/7.31/7.67
     dark   #4DA3FF on #0F131B/#0F1723/#0F1319 (left/right/top) — 7.08/6.85/7.09
     vs the fill, #0071E3: 1.68:1 (light) / 1.79:1 (dark) — no longer 1:1,
     now a visibly different blue next to the one it circles.
   Materially better on both measures, in both appearances, with nothing
   else in `.fold` for a ring to break (its only focusable descendant is
   this CTA — no other link, see the markup).

   NOT applied to the shared `.band :focus-visible` rule itself, and this
   is the reason that rule exists at all (see its own comment, immediately
   above): `.promise`'s ground is near-black in BOTH appearances by
   deliberate design, while --link tracks the OS appearance, not the band
   — in light appearance that puts --link's dark #004CB0 on the
   ALWAYS-dark promise band and measured 2.51:1, under the 3:1 floor,
   which is the exact failure that rule was written to fix. `.fold`
   doesn't have that mismatch: its band flips light/dark WITH the OS
   appearance, same as --link, so the two stay in sync here in a way they
   never do on `.promise`. Scoped one selector narrower than the shared
   rule, `.fold :focus-visible`, so it wins the specificity tie (same
   (0,2,0) shape, later in source order) for the CTA alone and leaves
   `.deeper`'s ring on `.promise` exactly as the comment above requires. */
.fold :focus-visible{outline-color:var(--link)}
/* F1, 2026-09-01 — the hover state for .foot__nav a / .link. Unconditional
   here (not gated to prefers-reduced-motion, see the transition rule in the
   MOTION block below): a colour is not motion, so it applies under `reduce`
   too. Was var(--blue) — #007AFF measures 4.02:1 on white, under the 4.5:1
   AA floor this page holds its own body text to, so the hover state failed
   the exact test its resting colour (--link, just above) was built to pass.
   style.css's matching rule reached for the same undefined-in-that-file
   --blue and rendered as flat --ink instead — same root cause, one file
   with the wrong token, one file with no token at all. --link is already
   this page's accessible link colour at rest; keeping it there on hover
   means the link stays the same legible blue throughout instead of trading
   it for a design-system colour (system.md §"Blue is reserved") that is not
   this colour's job.

   SECOND PASS, same day — colour alone left both selectors with NOTHING
   visible on hover, which is a worse defect than the one it replaced: a
   colour swap to a value equal to the resting value is a no-op, and
   .foot__nav a has no decoration at rest for a decoration-only tweak to
   act on either. Split in two, reusing this page's own existing hover
   idioms instead of inventing a third:
     .foot__nav a — no underline at rest, so it gets one, built to this
       page's a.link/.deeper underline spec (40% currentColor, .22em,
       1px) — the same object those already are, not a fourth treatment.
     .link — already permanently underlined (a.link, above) — colour and
       underline are both already spent, so the tell is the SAME move
       style.css's plain `a:hover` already makes for its own already-
       underlined links: thicken the rule to 2px. Neither touches text
       colour, so both stay at --link's 7.89:1 / 8.00:1 regardless. */
.foot__nav a:hover{
  text-decoration:underline;
  text-underline-offset:.22em;
  text-decoration-thickness:1px;
  text-decoration-color:color-mix(in srgb,currentColor 40%,transparent);
}
.link:hover{text-decoration-thickness:2px}

/* 2026-09-01: fill moved from --blue to --cta-fill — white ink on --blue
   measured 4.02:1 light / 3.65:1 dark at this label's size, the exact
   number --cta-fill was already created to fix (see the TOKENS block).
   style.css's /privacy /support skip link is now built to this same
   spec (background, padding, radius, font) so the site has one skip-link
   component instead of two. */
/* OFF-CANVAS ON THE BLOCK AXIS, NOT THE INLINE ONE. `left:-9999px` is the
   classic skip-link technique and it is safe in LTR: Chromium excludes a
   negatively-positioned descendant from scrollWidth while the root direction
   is ltr. Set `dir="rtl"` on <html> and it is included, and the page grows a
   phantom horizontal scroll region of exactly that offset. Measured 11279
   against a 1280 viewport, on all four pages and on production, the difference
   equal to 9999 to the pixel, and proved by moving the offset: -500px gave
   1780, -9999px gave 11279, 0 gave 1280.

   This site never sets `dir` itself, which is the point: a document with no
   explicit `dir` inherits one. Chrome's own translate-into-Arabic sets
   `dir="rtl"` on the live <html>, and some in-app WebViews take it from the OS
   locale. A reader who asks the browser to translate this page gets a ten
   thousand pixel scrollbar.

   `translateY(-100%)` hides the link by exactly its own height, on the axis RTL
   does not touch, and overflow above the viewport top is not scrollable, so
   there is nothing to reach in either direction. */
.skip{
  position:absolute;left:0;top:0;transform:translateY(-100%);
  background:var(--cta-fill);color:#fff;padding:12px 18px;border-radius:0 0 10px 0;z-index:9;
}
.skip:focus{transform:none}
/* R10 — audited for a hover cue and deliberately left without one. .skip
   is off-canvas (translateY(-100%)) until :focus brings it on screen, so the
   only realistic way a pointer ever meets it is already-focused, where the
   :focus-visible ring (fixed this round, F5) is already the affordance.
   A hover-only treatment on a control that is never visible without focus
   would duplicate that ring rather than add anything a user could see. */

/* ------------------------------------------------------- shared type roles */
.eyebrow{
  font-size:var(--t-micro);
  font-weight:600;
  letter-spacing:.075em;
  text-transform:uppercase;
  line-height:1.2;
  color:var(--ink-3);
}
.band .eyebrow{color:var(--band-ink-3)}

h1,h2{
  font-weight:600;
  /* Ledger line 21: Apple tracks display type at the -0.005em order. Candidate
     B was at -0.034em, four to eleven times tighter. */
  letter-spacing:-.006em;
}
h1{font-size:var(--t-display);line-height:1.04}
h2{font-size:var(--t-head);line-height:1.12}
h3{font-size:var(--t-body);font-weight:600;line-height:1.3}

.lede{font-size:var(--t-lede);line-height:1.35;color:var(--ink-2)}
.band .lede{color:var(--band-ink-2)}
.band .fold__tail{color:var(--band-ink-2)}

.measure{max-width:34rem}

/* Every section below the hero sits inside .pad (max-width:1280px;
   margin:0 auto), which is centred. The narrow-measure blocks inside it
   (the promise claim/four/checkable and the pricing grid/fine print) each
   carry their own max-width for readability but never had horizontal
   centring, so they sat flush against .pad's left edge and left a dead
   strip down the right side of the page. One mechanism, applied once,
   fixes all of them: margin-inline:auto centres the block itself inside
   .pad while the text inside it stays left-aligned (text-align is
   untouched). .how__head and .price__head get the same treatment one rule
   down, on the wrapper rather than the child <p> — see the note there for
   why. The hero's own two-column grid already fills .pad and is not part
   of this list — it does not need this rule and must not get it. */
.claim,
.promise .four,
.checkable,
.terms,
.price__fine{
  margin-inline:auto;
}

/* ------------------------------------------------------------------ bands */
.band{
  background:var(--band);
  color:var(--band-ink);
}
.band a{color:var(--band-blue)}

/* F3, 2026-09-01 — index.html carries <a class="deeper"> in the promise
   band (the "In full: what the app sends…" line) but this file had no rule
   naming it, so it rendered through the generic `.band a` alone: inline
   instead of block, 17px/400 instead of a considered small/bold caption,
   splitting across two line boxes with the first starting mid-phrase, and
   no hover affordance at all while every other link on this page answers
   the pointer. style.css already carries the complete component (a.deeper /
   .deeper at --t-meta/600, plus the hover underline) for its own prose
   links, built for a page that never has this class in its markup — the
   component lived in the file with no consumer and was missing from the
   file with the element. Ported here at this page's own sizes rather than
   style.css's literal px (the two files intentionally run different type
   scales elsewhere in this project), and the hover reuses this page's own
   a.link underline treatment (F2, just above) instead of style.css's, for
   the same reason. Colour is left to `.band a` above, unchanged — --band-
   blue already clears AA on this band's dark ground. */
.deeper{
  display:block;
  margin-top:calc(var(--rhythm) * .8);
  font-size:var(--t-cap);
  font-weight:600;
  text-decoration:none;
}
.deeper:hover{
  text-decoration:underline;
  text-underline-offset:.22em;
  text-decoration-thickness:1px;
  text-decoration-color:color-mix(in srgb,currentColor 40%,transparent);
}

/* Sections abut. Ledger line 20: the air is INSIDE the section, and the gap
   between sections is zero. */
section{padding:0}

/* --------------------------------------------------------------- masthead */
/* F1, 2026-09-01 — PAINTS THE FOLD'S OWN STARTING COLOUR, NOT --band.
   The comment above ("THE FOLD FOLLOWS THE READER'S APPEARANCE") already says
   what this rule failed to do: "The masthead rides the fold's band: zero gap,
   the same ground". .fold's gradient is `linear-gradient(180deg, var(--band-2),
   var(--band) 58%)` — its FIRST painted row, directly under the masthead, is
   --band-2, not --band. .mast painted --band, so the masthead was one token
   step darker (or lighter) than the pixel it sits on top of in all four index
   cells: measured +13/+12/+8 light, -9/-9/-11 dark, both 1500 and 393 wide.
   --band-2 already exists, already carries both appearances (the light
   override two rules up sets it to #F2F2F7, the dark restore below sets it to
   #1A1A1F) — reused, not invented. This is scoped to hero.css's own `.mast`
   rule only; style.css's /privacy and /support masthead sits directly on
   --page with no gradient beneath it and is a different rule in a different
   file, untouched by this change. */
.mast{
  background:var(--band-2);
  color:var(--band-ink);
}
.mast__in{
  display:flex;
  align-items:center;
  gap:calc(var(--rhythm) * 2);
  min-height:64px;
  flex-wrap:wrap;
}

/* THE HOME PAGE HAD NO MASTHEAD NAV AT ALL, and the strongest evidence that
   this was an omission rather than a choice is in this same file: the round 11
   comment above `a.link` enumerates "masthead nav" among the links ON THIS
   PAGE that receive the press ring. A round reasoned in detail about a
   component that has never existed in this markup or this stylesheet.
   `grep -c mast__nav site/hero.css` was 0, against style.css's 8.

   What the absence cost: /privacy and /support were reachable from the home
   page only through the footer, whose first nav link sits at y=4543, about 5
   screens of scrolling at a 900px viewport. On an app whose entire pitch is
   that nobody else reads your notes, the privacy page was the hardest thing on
   the site to reach, from the page the App Store listing points at.

   Ported from style.css rather than invented: 13px/600, gap rhythm*2.2, ink
   --band-ink-2, and the out-of-flow ::after that lifts the hit box to 44px
   without touching layout. The one rule deliberately NOT ported is
   `a[aria-current="page"]`, because no item here is ever current: this page is
   the wordmark's own target, so the nav carries only the two pages you cannot
   already be on. */
.mast__nav{
  display:flex;
  gap:calc(var(--rhythm) * 2.2);
  font-size:var(--t-meta);
  font-weight:600;
}
.mast__nav a{
  position:relative;
  color:var(--band-ink-2);
  text-decoration:none;
  padding:2px 0;
  border-bottom:2px solid transparent;
}
.mast__nav a:hover{color:var(--band-ink)}
.mast__nav a::after{
  content:"";
  position:absolute;
  top:calc(50% + 1px);left:0;right:0;
  height:44px;
  transform:translateY(-50%);
}
.wordmark{
  position:relative;
  color:var(--band-ink);
  font-size:var(--t-body);
  font-weight:600;
  letter-spacing:-.01em;
  margin-right:auto;
}
/* F3, round 10 craft — style.css's own `.wordmark` carries this hover
   (added there with the reasoning: "the wordmark did not read as a link at
   all (--ink, no underline, blue only on :hover)"). That reasoning names
   the mark's own resting style, not the nav it happens to sit beside — and
   index's wordmark is byte-identical markup with the exact same resting
   style: --band-ink, no underline, no other cue that it's a link. A two-run
   hover diff found index answering a pointer with zero property changes
   across all 12 watched properties, on both appearances, while the same
   element on /privacy and /support already underlines. Ported verbatim, no
   new colour or timing invented. */
.wordmark:hover{text-decoration:underline;text-underline-offset:.22em}
/* Same hit-area rule style.css already carries for .foot__nav a, applied
   here to the one nav element that lacked it: 73.1x20.8 measured at 393px.
   A generated ::after frame, out of flow, so it cannot recentre this flex
   item against .mast__in's align-items:center or grow the row. */
.wordmark::after{
  content:"";
  position:absolute;
  top:50%;left:0;right:0;
  height:44px;
  transform:translateY(-50%);
}

/* =============================================================== THE FOLD */
/*
   Ledger line 1: the page's ONE action is IN the hero, at every viewport, and
   the masthead deliberately carries none — an action in the masthead is not an
   action in the fold, and two actions is not one action.
   Ledger line 8: one first read. The crop is far and away the heaviest object;
   nothing else competes with it, and the headline sits alone at the top of its
   own column where nothing shares its vertical position on desktop.
*/
/* FOLD R1 · CHANGE 1 — the fold's device framing must be drawn in the values
   the fold's own ground has, or the ring that IS the object's boundary half
   vanishes. Measured on the previous fold, at identical geometry: the crop's
   bottom ring read ΔL 27.3 when the framing matched the band and ΔL 6.7 when
   it did not. Same object, same geometry, half the edge — survivable while a
   ring is decoration, not survivable where the ring does the work the bleed
   used to do.
   2026-08-30: the pins this block used to carry unconditionally now live in
   the dark media query above, because the fold no longer ignores the viewer's
   appearance. In dark appearance the pin is exactly what it always was. In
   light appearance `.fold` inherits the light :root framing, which matches the
   light band the same way the dark pin matches the dark one — same rule, both
   grounds: the framing follows the ground. */
.fold{
  /* THE FOLD'S TYPE GROWS AT HALF RATE, added 2026-08-30. dfd2fc6's rem
     conversion stands everywhere: the page-wide ramp keeps full rem bounds,
     and a raised root still scales every member on every section. But this is
     the one section whose height is pinned to the viewport (min-height 100svh
     below), so it is the one place a fully linear ramp is unsustainable: at a
     raised root the say column outgrew the band and pushed the page's ONE
     action out of the first screen — on desktop the CTA and its qualifier
     fell below the fold entirely; on phone the pill straddled the viewport
     edge with its second line of label cut mid glyph (docs/todo-site-deploy.md).
     A fold without its call to action is not a fold, so here, and only here,
     the members ABOVE the action concede half their growth: every bound is
     half px, half rem, which is exactly the number it always was at a 16px
     root (17px + 1.0625rem is 34px; 29px + 1.8125rem is 58px) and half the
     growth beyond it — a 24px root gets a 45px display ceiling, not 39 and
     not 51. The setting is still honoured, in the same direction, by every
     member including these. Two deliberate exclusions: --t-body, the CTA's
     own label, is NOT overridden, because the action is the one thing that
     must keep growing at the reader's full rate; and .claim in the promise
     band is not touched, because it is mid-page with no first-viewport duty
     and may grow and scroll. The working, the candidates rejected and why,
     and the proof obligations are in docs/reports/site-cta-enlarged.md. */
  --t-display:clamp(calc(17px + 1.0625rem),4.1vw,calc(29px + 1.8125rem));
  --t-head:clamp(calc(12px + .75rem),2.2vw,calc(15px + .9375rem));
  --t-lede:clamp(calc(8px + .5rem),1.5vw,calc(10px + .625rem));
  position:relative;
  /* CLAMPED INSIDE THE MINIMUM, and it has to be here rather than in a
     `max-height`. `min-height` beats `max-height` in CSS — the used value is
     max(min-height, min(max-height, height)) — so a ceiling declared alongside
     this one never binds. Tried exactly that first: at a 1440-tall window the
     fold stayed 1376 and every number below was unchanged, while the narrow
     breakpoint's own cap drove the headline to -38.9px, clipped above the
     fold's top edge by `overflow:hidden`. `min()` inside the minimum works.

     WHY THERE IS A CEILING AT ALL: `100svh` with none meant the fold's
     composition was whatever window it was opened in, and it was judged in
     one. Above that the grid stretches and the halves walk apart, because
     `.fold__grid` centres the text while `.fold__show` is seated against the
     bottom boundary on purpose (FOLD R1 CHANGE 4). Their centres drift -3.3px
     at 900, -93.3 at 1080, -273.3 at 1440 and -513.3 at 1920: linear,
     unbounded, and at 1440 roughly a third of the fold is empty gradient above
     the headline with the phone detached from the sentence it illustrates.

     936px is not invented. It is exactly `100svh - 64px` at the 1000px-tall
     frame this fold was designed and repeatedly measured at, and the number
     `tools/check-fold.mjs` already pins. Every taller window now sees the
     composition that was actually judged; shorter ones are untouched, because
     `min()` yields the viewport term below 1000. A tall window loses empty
     gradient and gains the next section on screen. */
  min-height:min(calc(100svh - 64px), 936px);
  display:flex;
  align-items:stretch;
  overflow:hidden;
  border-bottom:1px solid var(--band-sep);
  background:
    radial-gradient(120% 80% at 78% 92%, rgba(10,132,255,.13), transparent 62%),
    linear-gradient(180deg, var(--band-2), var(--band) 58%);
}

.fold__grid{
  flex:1;
  width:100%;
  display:grid;
  grid-template-columns:minmax(0,1fr) auto;
  gap:clamp(24px,4vw,64px);
  align-items:center;
}

.fold__say{
  align-self:center;
  padding:clamp(24px,4vh,48px) 0;
}
.fold__say .eyebrow{margin-bottom:calc(var(--rhythm) * 2)}
.fold__say h1{margin-bottom:calc(var(--rhythm) * 2.4);text-wrap:balance}

/* The operative half of the promise, inside the h1 rather than beside it.
   The hero used to paraphrase it — "They are never sent to us." — which drops
   "or anyone else" and turns a promise about US into an absolute about the
   DEVICE. It is quoted whole now, at head rather than display size so the fold
   still has one assertion and not two. The <span> may sit BETWEEN the
   sentences; nothing may sit inside one. */
.fold__tail{
  display:block;
  margin-top:calc(var(--rhythm) * 1.4);
  font-size:var(--t-head);
  line-height:1.16;
  letter-spacing:-.004em;
  color:var(--ink-2);
  text-wrap:pretty;
  max-width:24ch;
}
/* 2026-09-01 — text-wrap:pretty, and the reason is the two rules it sits
   between. .fold__say h1 above takes `balance` and .fold__tail below takes
   `pretty`; this block, in the middle of fourteen lines of CSS, got neither,
   and computed `text-wrap: wrap`. A craft round measured what that produced:
   from roughly 768 to 940 and 1040 to 1128 CSS px, the whole iPad-landscape
   and small-laptop range, the paragraph set as 565.9px and 28.8px, with the
   word "not." alone on the second line at 5% of the measure. It is the word
   the sentence exists to deliver, so the site's central privacy claim ended
   on a stranded negation.

   `pretty` rather than `balance`: balance evens the lines of a short display
   block, which is what the h1 wants, and this is running prose where the last
   line is the thing to protect. Same choice .fold__tail already made. */
.fold__say .lede{
  margin-bottom:calc(var(--rhythm) * 3.2);
  max-width:36rem;
  text-wrap:pretty;
}

/* the one action */
.btn{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  min-height:52px;
  padding:0 26px;
  border-radius:100px;
  background:var(--cta-fill);
  color:#fff;
  font-size:var(--t-body);
  font-weight:600;
  letter-spacing:-.012em;
  box-shadow:0 6px 22px -6px var(--blue-glow);
  /* 2026-09-01 — text-wrap:balance. Every other text block this file gives
     a wrap policy states the rule it's applying: `balance` evens the lines
     of a short display block (.fold__say h1), `pretty` protects the last
     line of running prose (.fold__tail, .fold__say .lede, .claim). The one
     action never got either, and at 320/340 CSS px its label set as
     [205, 39.6] — "ships" alone on its own line, off-centre in the pill.
     A button label is the short-display-block case, same as the h1, so
     `balance` is the right member of the pair, not `pretty`. Turns
     [205, 39.6] into [116.7, 127.8] at those widths. Both .fold__say .btn
     and .price__cta .btn pick this up since both share this one rule.
     320/340 sit below the 375px floor of any iPhone running iOS 26, so no
     user of the app hits this on its target device — still fixed, because
     this is the page's one action on a public page open to any browser. */
  text-wrap:balance;
}

/* UNDER forced-colors THE PILL STOPS BEING A PILL, and no tool in this repo
   had ever rendered that mode: both shoot.mjs and measure-rect.mjs hardcode
   `forced-colors:'none'`, so twenty rounds of screenshots could not have shown
   it. .btn draws its shape entirely from `background` and `box-shadow`, and
   forced-colors discards both. Measured with the emulation confirmed active
   (`matchMedia('(forced-colors: active)').matches` true), .btn computed
   `borderStyle:none, borderWidth:0px, outlineStyle:none` — nothing left to
   draw an edge. The site's ONE call to action rendered as bare text,
   indistinguishable from a body link, in both forced themes.

   A border is the whole fix: the system repaints `currentColor` as the theme's
   own ink, so the pill returns in whatever palette the reader chose, and
   `box-sizing:border-box` (hero.css:470) keeps the 52px outer height. Windows
   High Contrast is a real setting a real person turns on. */
/* THE ADDRESS BREAKS AS A LAST RESORT HERE TOO, AND THIS FILE HAD NO SUCH
   RULE AT ALL. `style.css` has carried the policy since round 17 and it was
   revised in 26, 30 and 32; `hero.css` never got a line of it, because every
   copy of the address it had to worry about lived on the document pages. Then
   the footer — the one block every page shares — was measured, and index.html
   loads THIS file.

   Measured at 320px before the fix: 5px of page overflow at a 30px root, 25px
   at 32. Small numbers, and the same class of defect the whole policy exists to
   prevent, on the page the App Store listing points at.

   Round 22 recorded this exact shape: "Two stylesheets, one component, and a
   fix is not done until it is in both." That note was about a nav marker. This
   is the fourth sweep of one string into one policy, and the fourth time a copy
   was missed — the first three by selector, this one by FILE. Enumerate the
   instances from the string and from the pages that render it, not from the
   selectors already written. */
.prose a[href^="mailto:"],.foot a[href^="mailto:"],a.link[href^="mailto:"]{
  hyphens:none;
  overflow-wrap:break-word;
}
/* AND THE CODE SPANS, which are the same problem wearing a different tag. The
   privacy page names vendors and API calls inline — `ingest.de.sentry.io`,
   `eu.i.posthog.com`, `Purchasing.start()` — and a hostname is exactly the
   shape this whole policy exists for: one long token with no space in it.
   Measured at 320px with a 32px root, they pushed the page 44px and 26px
   sideways while every mailto on the same page stayed inside, because the
   mailtos had the rule and these did not.

   Fifth instance of one policy missing a copy. The first three were missed by
   SELECTOR, the fourth by FILE, this one by TAG. The lesson has been the same
   every time and is worth stating once more in the terms that would have caught
   all five: enumerate from the SHAPE — every long unbreakable token a reader
   can meet — not from the elements you already thought of. */
/* THE SIXTH, AND THIS TIME THE RULE GOES ON THE CONTAINER SO THERE CANNOT BE A
   SEVENTH. `relationalnotes.com` sits in privacy.html as BARE PROSE TEXT — no
   link, no code span, no element of any kind to hang a selector on. Every one
   of the five previous sweeps targeted an element type, so every one of them
   walked past it. Measured at 320px: 0px overflow through 36px root, then 32px
   over at 40 and 96px at 48.

   Five sweeps, five misses, and each by a different mechanism: three by
   SELECTOR, one by FILE, one by TAG, and this one by MARKUP — text with nothing
   to select. The right unit was never the element. It is the CONTAINER a reader
   reads in, because that is the only thing guaranteed to enclose every long
   token, including the ones written as plain characters.

   `break-word` on a text container costs nothing for ordinary prose: it breaks
   a word only when the word cannot otherwise fit. The narrower element rules
   above are now redundant and kept only for their recorded reasoning. */
.prose,.doc__sections,.foot p{
  overflow-wrap:break-word;
}

.prose code,.doc__sections code{
  overflow-wrap:break-word;
}

@media (forced-colors: active){
  .btn{border:1px solid currentColor}

  /* AND THE RECOMMENDED PLAN MUST STILL LOOK RECOMMENDED. .term--chosen says
     "this is the one" entirely in colour: a blue fill against a white card.
     forced-colors discards both fills, and the two cards then compute
     IDENTICALLY — same ground, same ink, same 1px border, in both forced
     themes. Two pixel-identical boxes, with nothing marking the default.

     Colour is the one channel forced-colors is guaranteed to take away, so a
     distinction that lives only there has no fallback by construction. Border
     WIDTH survives untouched, which is why the cue is moved into it here
     rather than into another colour. */
  .term.term--chosen{border-width:3px}

  /* The same "you are here" repair style.css carries, because index.html loads
     THIS file and not that one. The first version of this fix went only into
     style.css and the probe caught it immediately: index's two nav links both
     computed rgb(0,0,159). Two stylesheets, one component, and a fix is not
     done until it is in both. */
  .mast__nav a{border-bottom-color:Canvas}
  .mast__nav a[aria-current="page"]{border-bottom-color:LinkText}
}

/* R10 — box-shadow's bigger, glowier hover value used to live entirely
   inside prefers-reduced-motion:no-preference alongside the 1px lift, which
   meant .btn had NO hover cue at all under `reduce` — the same "colour or
   decoration is not motion" mistake .foot__nav a and .link just got fixed
   for. A shadow SIZE is not a position change; only the 1px `translate`
   below is genuinely motion. Unconditional here, snapping instead of
   easing under `reduce`, which is exactly what that preference asks for. */
.btn:hover,.btn:focus-visible{box-shadow:0 10px 30px -6px var(--blue-glow)}
/* F3, round 11 craft — press feedback. Until now the MOTION block below
   held exactly one `:active` rule on the whole site, `.btn:active{translate:
   0 0}`, which only cancels the hover lift — nothing for anyone with
   `prefers-reduced-motion: reduce` on (that block never runs for them),
   nothing for a touch user in either setting (there is no hover to
   cancel), and style.css carried none at all. Unconditional here, outside
   the MOTION block, same reasoning as the hover fixes just above: a ring
   is not motion. `currentColor` rather than a new token, and for the same
   reason `.band :focus-visible` above reuses `--band-blue` instead of
   inventing a colour: whatever ink is already correct for THIS control's
   own label, in whatever appearance and whatever band it is sitting in,
   is by construction already checked against its own ground — white on
   this button's blue fill, `--link`/`--band-blue` on every plain link
   below. One idiom, one declaration shape, reused by the generic `a:active`
   rule further down for every other control in both files, so the site
   gains one press cue rather than three. Kept as its own rule (not folded
   into the generic one) only to preserve the rest glow underneath the
   ring, since `box-shadow` cannot be added to, only replaced. Does not
   touch text: the constraint "clears 4.5:1 for text on the pressed state"
   is trivially met because no ink or fill actually changes colour here. */
.btn:active{box-shadow:0 0 0 1.5px currentColor,0 6px 22px -6px var(--blue-glow)}
/* `.band a` is (0,1,1) and `.btn` was (0,1,0): the label rendered blue-on-blue
   and vanished. Caught in the first capture; kept as a comment because the
   whole page is inside .band twice. */
.band a.btn{color:#fff}
/* 2026-09-03: the action while there is nothing to act on.
   The App Store link was removed because it 404s (see the comment beside the
   hero action in index.html). What replaces it keeps `.btn`'s size, radius and
   place in the layout so the fold still has one prominent thing at the bottom
   of it, and gives up exactly two properties: the fill and the lift.

   It must NOT wear --cta-fill. §2 of design/system.md spends the page's hue
   budget on one meaning, blue is "this commits", and this element commits
   nothing; a blue pill that cannot be pressed spends that budget on a
   disappointment. It also must not be an <a>, because there is no address.

   currentColor rather than a token, because this rule is used twice in two ink
   contexts: inside .band (--band-ink, white on the dark fold) and inside
   .price (--ink, dark on the page). Inheriting the surrounding ink keeps the
   ring and the label at whatever contrast that context already passes, and
   .btn's own forced-colors fallback already draws itself this way.

   Written as `.btn.btn--pending` (0,2,0) rather than `.btn--pending` (0,1,0)
   on purpose. The hover lift lives in the reduced-motion block ~900 lines
   BELOW this one, so a single-class override here would be beaten on source
   order and the pill would still rise 1px under the pointer, which is the one
   cue that says "press me". Doubling the class wins on specificity instead of
   on position, so this rule cannot be undone by moving it.

   Delete this rule when the link comes back and nothing else uses it. */
.btn.btn--pending{
  background:none;
  color:inherit;
  box-shadow:inset 0 0 0 1.5px currentColor;
  cursor:default;
}
.btn.btn--pending:hover,
.btn.btn--pending:focus-visible,
.btn.btn--pending:active{
  translate:0;
  box-shadow:inset 0 0 0 1.5px currentColor;
}
/* design/system.md §2: blue means "this is settled" or "this commits", and
   nothing else. The page's single commit affordance wears the same blue as the
   Confirm button inside the screenshot beside it. That is the whole hue budget
   of the fold, and it is spent on meaning — ledger line 11. */
.act__note{
  margin-top:calc(var(--rhythm) * 1.4);
  font-size:var(--t-cap);
  color:var(--band-ink-2);
  letter-spacing:.01em;
}

/* FOLD R1 · CHANGE 4 (desktop) — the object is pinned to the boundary and then
   held --seat away from it. `align-self:end` was already here and is what made
   the shipped desktop fold flush at rest; the margin is what turns "flush"
   into "seated", and because the pin is to the bottom of a full-height grid
   row, the distance is the same at every window height. */
.fold__show{
  align-self:end;
  display:flex;
  justify-content:flex-end;
  margin-bottom:var(--seat);
}

/* ------------------------------------------------------------- the crop
   Treatment 2 from device-frame.css: no device, the screen rounded at the top
   and running off the bottom of its container. Ledger line 2 — the artifact
   that proves the mechanism completes its read INSIDE the fold at every
   viewport — decides where the cut lands, and the cut is different at each
   breakpoint rather than the same picture scaled:
     desktop  --rev .76  the note, the three facts taken from it, and the one
                         sentence left alone. Aspect 0.61.
     phone    --rev .47  the note and the source line that ends "Verbatim ·
                         on this iPhone". Aspect 0.98.
   design/system.md §3: it bleeds DOWN and never sideways. */
.crop{
  --dw:400;
  --rev:.76;
  /* F4, 2026-09-01 — HEIGHT AND RADIUS NOW READ THE RENDERED BOX, NOT --dw.
     .fold__show is a flex row with the default flex-shrink:1, so below 360px
     and again at 381-392px this box renders narrower than --dw (it has to,
     to stay inside .pad's own padding) while height and the radius were
     still computed from the uncapped token — the crop over-revealed (.5368
     at 320 against the authored .47) and the corner overshot (38.27px on a
     280px object against the authored 33.49px). width:min(...,100%) makes
     the cap explicit instead of an accident of flex-shrink, aspect-ratio
     derives height from THIS box's own resolved width whatever that turns
     out to be, and the two border-radius percentages (horizontal read
     against width, vertical against height, per the border-radius spec) land
     on the same px circle the fixed-width formula drew — 280*47/393 =
     33.49px either way — instead of the ellipse a single shared percentage
     would draw once width and height stop matching each other 1:1. */
  --rh:calc(47 / 393 * 100%);
  --rv:calc(47 / 852 / var(--rev) * 100%);
  /* 2026-09-01, SECOND ATTEMPT. This was `min(calc(var(--dw) * 1px), 100%)`
     for about an hour and it destroyed the desktop fold at every width from
     960 up, live: `.fold__grid` resolved to `24px 1100px` at 1500, the
     headline column was 24px wide, and the fold stood 2,423.8px tall against
     886.

     Why: inside a grid `auto` track, a `100%` in `min()` is a percentage
     against an indefinite containing block, so Chromium falls back to the
     <img width="1100"> intrinsic contribution when sizing the track. The auto
     column took 1,100px and `minmax(0,1fr)` collapsed to what was left. The
     crop itself still painted at its correct 430px, right-aligned inside a
     1,100px column, which is why a capture of the IMAGE looked fine and only
     the grid was wrong.

     `max-width` as a percentage is treated as `none` for intrinsic sizing, so
     it caps the box without poisoning the track. Same cap, no side effect. */
  width:calc(var(--dw) * 1px);
  max-width:100%;
  aspect-ratio:393 / calc(852 * var(--rev));
  overflow:hidden;
  border-radius:var(--rh) var(--rh) 0 0 / var(--rv) var(--rv) 0 0;
  /* FOLD R1 · CHANGE 3 — the ring stays on all four sides, and the cast is
     re-picked to fit the space.

     THE RING. It closes on all four sides, deliberately, and this is the one
     place a contained object has an easier job than a bleed: a ring that
     closes is what makes a rectangle an object, and a ring present on three
     sides and absent on the fourth is an accident. On the PREVIOUS fold the
     bottom ring was not painted at rest (it fell in the 1px border strip
     outside the fold's overflow:hidden padding box) and WAS painted from 25%
     of the scroll range on — so the object had three edges at the top of the
     page and four edges once you scrolled. This file paints four at every
     position, in both appearances, at every viewport.
     The measured objection to the bottom ring — that it reads as a short line
     24px above a full-width rule — is answered by --seat, not by deleting the
     edge: 60px is far enough that the two are an object and a boundary rather
     than a stripe pair.

     THE CAST. 0 30px 70px -14px carries meaningful density ~50px below the
     element and a tail past 85px, which on the previous fold was entirely
     academic because a flush object has nothing to cast onto. Seated, it would
     clip at the section rule. These are .phone__body's values verbatim — the
     three complete devices further down the page — so the hero object and the
     step objects are lit the same way and seated the same way, and the whole
     shadow lands inside --seat. */
  box-shadow:
    0 0 0 1px var(--ring),
    0 1px 2px var(--cast-tight),
    0 22px 48px -12px var(--cast);
}
.crop img{display:block;width:100%;height:auto}

/* ==================================================== 2 · THE MECHANISM */
.how{padding:calc(var(--rhythm) * 13) 0 calc(var(--rhythm) * 10)}
/* max-width + margin-inline:auto sit on the wrapper, not on the <p> alone:
   the heading and its paragraph read as one intro unit with only a line's
   worth of gap between them, so centring just the paragraph left the
   heading flush at the page edge and the paragraph starting well to its
   right — a stagger inside a single unit, not two separate blocks. Centring
   the whole head keeps both lines sharing one left edge. */
/* F6, 2026-09-01 — LEFT AS-IS, MEASURED. .how__head (46rem, 736px) and
   .price__head (44rem/704px, further down) share one mechanism — the
   comment at line ~463 says so — but not one measure, and a craft round
   filed the 32px/9.5px gap between them as an unexplained divergence. It has
   a reason: .how__head's own paragraph is the page's longest, 8 lines at
   46rem; narrowed to .price__head's 44rem it measures 9 (183.5px -> 206.4px
   at 1500 wide, tools/measure-rect.mjs --eval against a live copy). .price__
   head's paragraph is 2 lines regardless of which of the two widths it gets.
   Narrowing .how__head to match would cost its own intro block a whole line
   for no reader benefit; widening .price__head to match buys its 2-line
   paragraph nothing. Left divergent on purpose, not by omission — this
   comment is that decision, in place of the "if a reason exists, say so"
   note the finding asked for. The margin-bottom gap (57px/47.5px) is smaller
   and softer to defend on the same grounds — more air ahead of `.steps`,
   a taller three-column section, than ahead of `.terms`, a two-card row —
   and is left with it rather than split into its own separately-argued
   value. */
.how__head{margin-bottom:clamp(36px,6vh,64px);max-width:46rem;margin-inline:auto}
.how__head h2{margin-bottom:calc(var(--rhythm) * 1.6)}
/* max-width:none overrides the generic .measure class (max-width:34rem) that
   this <p> also carries in markup: the paragraph is meant to fill the whole
   of its now-constrained .how__head parent, not be narrowed a second time. */
.how__head p{color:var(--ink-2);line-height:1.35;max-width:none}
/* 2026-09-03. .how__head gained a second paragraph: the capability claim and
   the dated distribution fact are two different kinds of statement and must
   not read as one run of prose. Nothing in this sheet gives adjacent <p>s a
   gap (the only p + p rule on the page is .foot's), so without this the two
   would butt together and look like one paragraph that changes subject.
   rhythm * 1.2 is .foot p + p's value, reused rather than invented. */
.how__head p + p{margin-top:calc(var(--rhythm) * 1.2)}
/* The dated line is a footnote to the paragraph above it, not a peer of it:
   one step down in size, and it keeps .how__head p's ink-2 rather than going
   quieter still, because a date the reader cannot see is not a dated fact. */
.how__head p.hw{font-size:calc(var(--t-body) * .92)}

.steps{
  display:grid;
  grid-template-columns:repeat(3,minmax(0,1fr));
  gap:clamp(20px,3vw,44px);
  align-items:start;
}
/* 2026-09-01 — SPECIFICITY BUG, same shape as style.css's documented
   .foot .foot__wm / .foot p fix. <p class="step__n"> is both `.step__n`
   (0,1,0) and, since it is a <p> inside `.step`, `.step p` (0,1,1) below —
   which is HIGHER regardless of source order, so .step__n's own --ink-3
   never won: computed colour was --ink-2 (rgba(60,60,67,.80), 5.97:1),
   the outlier a craft round measured against .eyebrow and .term__k's
   --ink-3 (rgba(60,60,67,.74), 5.02:1) and hero.css's own --ink-3 comment
   ("captions and labels"). Scoped one class deeper, `.step .step__n`
   (0,2,0), the same fix `.foot .foot__wm` already used for the identical
   defect shape. */
.step .step__n{
  font-size:var(--t-micro);
  font-weight:600;
  letter-spacing:.075em;
  text-transform:uppercase;
  color:var(--ink-3);
  margin-bottom:calc(var(--rhythm) * .8);
}
.step h3{margin-bottom:calc(var(--rhythm) * .8)}
.step p{color:var(--ink-2);line-height:1.35}
.step__pic{margin-bottom:calc(var(--rhythm) * 2.2)}

/* the provenance note that answers ledger line 13, in the same visual group as
   the picture it is about */
/* F1, THIRD PASS, 2026-09-01 — .step__src used to get its measure cap
   (max-width:34rem) from only ONE breakpoint block (760-959px, see below);
   outside that window — the <=759 stacked phone column and every width at
   or above 960 — it had no cap at all and ran the full width of its .step
   grid column, up to 125cpl measured at 744. Given the same --fine-measure
   treatment as .checkable/.price__fine above, as a base rule so it holds at
   every width instead of one breakpoint: .step has no reference edge to
   keep aligned the way .promise .four / .price__head do, so there is no
   box-width constraint to preserve here — padding-right alone is enough. */
.step__src{
  margin-top:calc(var(--rhythm) * 1.4);
  padding-top:calc(var(--rhythm) * 1.4);
  padding-right:max(0px,100% - var(--fine-measure));
  border-top:1px solid var(--sep);
  font-size:var(--t-cap);
  line-height:1.45;
  color:var(--ink-2);
}

/* -------------------------------------------------------------- the phone
   Treatment 1 from device-frame.css: the whole device, complete, on desktop.
   No side buttons, no titanium, no glare — round 2c: "If the prettiest object
   in our fold is the phone's edge, we have advertised Apple." */
.phone{
  --dw:280;
  --r-in:calc(var(--dw) * 47px / 393);
  --bez:calc(var(--dw) * 11px / 393);
  width:calc(var(--dw) * 1px + var(--bez) * 2);
  max-width:100%;
  margin:0 auto;
}
.phone__body{
  padding:var(--bez);
  border-radius:calc(var(--r-in) + var(--bez));
  background:var(--bez-band);
  box-shadow:
    0 1px 2px var(--cast-tight),
    0 22px 48px -12px var(--cast),
    inset 0 1px 0 var(--bez-edge);
}
.phone__body img{
  display:block;width:100%;height:auto;
  border-radius:var(--r-in);
  overflow:hidden;
}
/* F5, 2026-09-01 — PINNED IN CSS, NOT RE-EXPORTED. Steps one and two's source
   shots are 1100x2386; step three's is 1100x2392, 6px taller at the same
   width. `height:auto` let that difference leak into the desktop "whole
   device" treatment above: step three's .step__pic ran 1.78px taller than
   its siblings at 1500px, dragging its own ONE/TWO/THREE label, heading and
   body copy 1.78px low — a layout that agreed with itself only as long as
   three unrelated source files happened to share a height. Pinned here to
   the two images that already agree (786:1704) and gated to the desktop
   "whole device" treatment (>=760px) ONLY: below 760px `.phone__body` switches
   to the cropped aperture treatment further down this file, which already
   sets its own explicit height off `--dw` and must keep reading each image's
   own natural ratio for its calibrated .58/.65 crop fractions to stay
   correct. `object-fit:cover` rather than the default `fill` so the ~0.3%
   difference crops a sliver off step three's top and bottom evenly instead
   of squeezing/distorting the image to fit. Steps one and two, already at
   786:1704, are unaffected byte for byte — cover with a box ratio matching
   the source ratio crops nothing. */
@media (min-width:760px){
  .phone__body img{
    aspect-ratio:786 / 1704;
    object-fit:cover;
  }
}

/* ================================================== 3 · THE PROMISE, IN FULL */
.promise{
  padding:calc(var(--rhythm) * 10) 0;
  border-top:1px solid var(--band-sep);
  border-bottom:1px solid var(--band-sep);
  background:
    radial-gradient(90% 70% at 12% 0%, rgba(10,132,255,.10), transparent 60%),
    var(--band);
}
/* **Share the section's left edge.** Centring `.claim` and `.four` moved both
   inward while this eyebrow, having no measure of its own, stayed flush to the
   container margin about 87px to their left. The hero sets the pattern of an
   eyebrow sitting directly above its heading on one edge, and this broke it.
   Matching `.four`'s 1000px measure puts all three on the same line. */
.promise .eyebrow{
  margin-bottom:calc(var(--rhythm) * 2.4);
  max-width:1000px;
  margin-inline:auto;
}

/* The sanctioned claim from AGENTS.md, in the exact required wording. Ledger
   line 12 is marked MUST NOT RETURN: it was absent from BOTH round-2
   candidates and candidate A stated a forbidden unconditional form.
   site/check-privacy-claim.sh fails the build on either. */
.claim{
  font-size:clamp(1.4375rem,2.7vw,2.25rem);
  font-weight:600;
  line-height:1.18;
  letter-spacing:-.006em;
  /* 2026-09-01 — same device as .fold__tail and .fold__say .lede (see the
     2026-09-01 comment on .fold__tail above): `pretty` protects the last
     line of running prose. .claim carries the identical sanctioned clause
     and, left at computed `text-wrap: wrap`, stranded "contents." (the
     first sentence's own last line) at 0.275 of the measure at 393px, and
     "else." at 0.063-0.130 across four separate width bands from 410px to
     1200px. `balance` was not used here: unlike the h1, this is running
     prose the guard requires verbatim, not a short display block to even. */
  text-wrap:pretty;
  /* Wide on purpose. The sanctioned clause cannot carry a <br> — the guard
     greps it as one contiguous string — so the only lever on where it breaks
     is the measure, and a narrow one left "yourself." alone on a line. */
  /* Was 44ch, which centred to a different edge than the eyebrow and the grid.
     The clause carries its own <br> in the markup, so the measure is no longer
     the only lever on where it breaks and can match the section instead. */
  max-width:1000px;
  margin-bottom:clamp(36px,6vh,64px);
}
.promise .four{
  display:grid;
  grid-template-columns:repeat(2,minmax(0,1fr));
  gap:clamp(20px,2.6vw,40px) clamp(28px,4vw,72px);
  max-width:1000px;
}
.four li{
  padding-top:calc(var(--rhythm) * 1.8);
  border-top:1px solid var(--band-sep);
  color:var(--band-ink-2);
  line-height:1.4;
}
.four b{font-weight:600;color:var(--band-ink)}

/* F4 · 169.4px of dead ground under item 1, TRIED AND REVERTED 2026-09-01.
   Kept as a record because the fix was measured, shipped, judged and lost, and
   the numbers are the argument against trying it again.

   The defect is real: a 2x2 grid at default stretch pairs item 1 (4 lines)
   with item 2 (11, and 12 after a copy pass), so item 2 sets the row height
   and item 1's own hairline frames the leftover as a box that ran out of
   copy. `align-items:start` was tried first and rejected with a reason: row
   TRACK height in CSS Grid is set by the tallest item regardless, and these
   cells paint no background, so it renders identically.

   The fix that shipped gave items 1 and 2 their own full-width rows. It
   closed the hole to 26.6px, and a craft round measured what it cost:

     item 1, full width  1000px  ->  127 characters per line
     item 2, full width   996px  ->  130 characters per line
     item 3, half width   465px  ->   61
     item 4, half width   466px  ->   62

   The comfort band is 55 to 75; `tools/probes/measure-cpl.js` names 90 as the
   point where the eye loses the line return; every 17px block on the legal
   pages measures 69 to 74, and `style.css:492` blesses 67.4 and 64.3 as
   correct. So it put the site's two most legally consequential paragraphs at
   130 cpl, 73% past that ceiling and 56 wider than the same site's own
   document pages, and stacked two visibly different measures inside one band
   with 61 and 62 still showing under the hairline.

   **The hole was the lesser defect.** 470px at 61/62 cpl is dead centre of the
   band, and dead space costs a reader less than a line they lose their place
   on. Widening to 44rem would still land at 91.

   If the hole is closed later, close it by balancing the columns or by
   stacking all four near 470 to 544px. Not by widening the line. */

/* F1, round 4 craft, SECOND PASS — 52rem (832px) at --t-cap (12px) measured
   145 characters per line, the worst measure on the site. The first pass
   narrowed max-width to 23rem and left margin-inline:auto in place, which
   fixed the measure and broke something else: centring a NARROWER box
   re-centres it, so the block's left edge moved from wherever it started to
   a new, unrelated point (566px), lining up with nothing else on the page —
   worse than a long line, because it reads as stranded rather than merely
   wide. `.promise .four` above it is the section's own grid and sits at
   left:250 (measured, 1000px wide, centred in `.pad`). This rule now keeps
   max-width:1000px — THE SAME BOX .four USES — so margin-inline:auto (still
   set on both by the shared selector list above) centres them identically
   and their left edges match at every viewport, not just 1500. The actual
   line length is narrowed from the RIGHT instead, with padding-right, so the
   outer box stays 1000px for alignment while the text column is 460px.
   460/5.74 px-per-character (measured off the original 832px/145cpl box) is
   ~80cpl, confirmed by measurement at 81: past the 55-75 band this file's
   continuous body prose uses, and deliberately so — fine print is read in
   short bursts, not continuously, and conventionally runs tighter and wider
   than body copy; 81 is comfortably under the 90cpl ceiling
   tools/probes/measure-cpl.js names and a fraction of the original 145.
   Height check: at 1500 wide this now runs 7 lines (was 4 at 832px, 9 at the
   first pass's 368px) — shorter than the first pass, and
   .checkable still sits last in the section with clamp(32px,5vh,56px) of its
   own air above it. */
/* F1, THIRD PASS, 2026-09-01 — see --fine-measure's own comment (TOKENS
   block) for why this moved from a fixed 540px to a ch-based cap: the box
   above (.promise .four) is fluid below 1180px, so a fixed px bite was only
   correct at the one width it was measured at. max-width:1000px here is
   unchanged and still does the alignment work; padding-right now derives
   the visible column from --fine-measure instead of subtracting a constant,
   and needs no separate mobile override — see the <=759 block below, which
   no longer touches this property.
   THE %-TRAP, CAUGHT BY MEASUREMENT: `100% - Nch` alone reads correctly
   only while this box is still tracking its parent's width. Percentages on
   padding resolve against the CONTAINING BLOCK (`.pad`, max-width:1280px),
   not against this element's own (narrower) max-width — so past ~1180px,
   where .pad outgrows .checkable's 1000px cap, `100%` silently became
   ~1280px instead of 1000px and the padding overshot the box, collapsing
   the visible column to single digits (measured: cplFullLine 49 at 1280,
   unchanged through 1720). Fixed with the identity
   max(0,min(a,b)-c) = min(max(0,a-c),max(0,b-c)): take the SMALLER of the
   two paddings implied by "box tracking its parent" and "box pinned at its
   own 1000px cap" — whichever regime is actually active, that term is the
   one that matches this element's real resolved width, and min() always
   picks it without needing to know which regime the current viewport is
   in. */
.checkable{
  margin-top:clamp(32px,5vh,56px);
  padding-top:calc(var(--rhythm) * 2);
  padding-right:min(
    max(0px,100% - var(--fine-measure)),
    max(0px,1000px - var(--fine-measure))
  );
  border-top:1px solid var(--band-sep);
  max-width:1000px;
  color:var(--band-ink-2);
  font-size:var(--t-cap);
  line-height:1.6;
}
.checkable code{
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
  font-size:.94em;
  color:var(--band-ink-2);
}

/* ============================================================ 4 · THE PRICE */
.price{padding:calc(var(--rhythm) * 10) 0}
/* Same reasoning as .how__head above: the heading and its paragraph are one
   intro unit, so the wrapper carries the measure and the centring, not the
   <p> alone. */
.price__head{margin-bottom:clamp(32px,5vh,56px);max-width:44rem;margin-inline:auto}
.price__head h2{margin-bottom:calc(var(--rhythm) * 1.6)}
/* max-width:none overrides the generic .measure class (max-width:34rem) that
   this <p> also carries in markup, for the same reason as .how__head p. */
.price__head p{color:var(--ink-2);line-height:1.35;max-width:none}

/* F1, round 5 craft — 760px was arithmetically arbitrary: .term's own ink
   inset is padding (rhythm*2.4 = 24px) + its 1px border = 25px, so a card's
   first-line ink sits 25px right of `.terms`'s own left edge. `.price__head`
   and `.price__cta` are both max-width:44rem (704px), centred the same way
   inside `.pad`, so their ink lands 0px off their own left edge — the
   column those two establish. For the cards' ink to land on that same
   column, `.terms` must sit exactly 25px left of it on each side, i.e. its
   own box must be the column plus twice the card's inset: 704 + 2*25 = 754.
   760 was 6px proud of that (3px each side), which is why the cards' ink
   measured 3px left of 398 at every width from 834 to 1720 — not a rounding
   residue, a target the file never actually computed against. Written as a
   calc from the column and the card's own inset, not the hardcoded 754,
   so it cannot drift again if 44rem, --rhythm, or the card border change:
   the outdent this rule authors is by definition the padding+border a card
   already spends getting from its box edge to its own ink. */
.terms{
  display:grid;
  grid-template-columns:repeat(2,minmax(0,1fr));
  gap:clamp(16px,2vw,24px);
  max-width:calc(44rem + (var(--rhythm) * 2.4 + 1px) * 2);
  align-items:stretch;
}
/* design/system.md §1: the strongest option is already chosen, and chosen-ness
   is a DIFFERENT WEIGHT OF THING — solid blue, white ink, a check — not a
   differently coloured peer. The pricing table is the app's own control.
   2026-08-31: taken literally. The unchosen MONTHLY card no longer wears a
   grey --inset fill of its own — a filled peer next to the chosen fill is
   exactly the "differently coloured peer" this comment already says not to
   do. It sits on the page's own ground with a --hairline border, so the
   fill in this pair means only one thing: chosen. Fill is spent on the one
   card that is genuinely selected, never on the ordinary one beside it. */
/* 18px HERE AND 14px ON THE LEGAL PAGES IS A DISTINCTION, NOT A DRIFT, and it
   is written down because round 18 filed it as drift and was right that nothing
   recorded the reason.

   This is the only ELEVATED FILLED card on the site: a solid blue ground, a
   hairline, and a shadow with a glow under it. The one thing it can fairly be
   compared with is style.css's .rail, a flat inset panel on a white ground with
   a hairline and no shadow, at 14px. A raised filled surface carrying a larger
   radius than a flat inset one is ordinary practice.

   The other two cards the finding named, .claim and .contact, declare 14px and
   COMPUTE TO 0px, with transparent grounds and 0px borders. They have no corner
   to round in the measured state. Grepping the adjacent declaration found three
   disagreeing values; measuring found one comparison. */
.term{
  padding:calc(var(--rhythm) * 2.4);
  border-radius:18px;
  background:var(--page);
  border:1px solid var(--card-edge);
  line-height:1.35;
  box-shadow:0 10px 34px -10px var(--blue-glow);
}
/* 2026-09-01: fill moved from --blue to --cta-fill, and the ink from
   translucent white to solid white — a craft round measured YEARLY/the
   descriptor at 2.77:1 / 3.35:1 (light) and 2.58:1 / 3.08:1 (dark), under
   the 4.5:1 floor. --cta-fill exists for exactly this shape of failure —
   .btn hit the same wall (#0A84FF at 3.65:1 on white ink) and #0071E3 was
   the fix, at 4.70:1 in both appearances (see the TOKENS block). Reused
   verbatim here rather than re-solved, and it is still "solid blue, white
   ink" — design/system.md §1's own description of chosen-ness — closer to
   the letter of it than the old translucent whites were: #0071E3 is
   Apple's own CTA blue, one step off #007AFF, not a different colour
   family. Ink went to solid #fff (4.70:1, was .72/.86 alpha) on ALL THREE
   labels, term__k/__v/__w alike — the hierarchy between them is carried by
   size, case and tracking, the same rule this file's own --ink-3 comment
   states for the unchosen card ("an ink reads as secondary because of what
   wears it, not because it is closer to the ground"), not by fading ink on
   a ground that cannot afford it. */
.term--chosen{
  background:var(--cta-fill);
  border-color:var(--cta-fill);
  color:#fff;
}
.term__k{
  font-size:var(--t-micro);
  font-weight:600;
  letter-spacing:.075em;
  text-transform:uppercase;
  color:var(--ink-3);
  margin-bottom:calc(var(--rhythm) * 1.2);
}
.term--chosen .term__k{color:#fff}
.term__v{font-size:var(--t-head);font-weight:600;letter-spacing:-.01em;margin-bottom:calc(var(--rhythm) * .8)}
.term__w{color:var(--ink-2)}
.term--chosen .term__w{color:#fff}

/* F1, round 4 craft, SECOND PASS — 44rem (704px) at --t-cap (12px) measured
   129/123 cpl, both past the 55-75 comfort band. The first pass narrowed
   max-width to 23rem, which also narrowed the CENTRED box and moved this
   block's left edge from 398 to 566 — off the column `.price__head` and
   `.price__cta` both establish at 398 (44rem/704px, centred the same way).
   Kept at max-width:44rem here — the SAME box those two use, so
   margin-inline:auto (shared selector list above) lands all three at the
   same left edge, at every viewport, not just 1500 — and narrowed the
   visible line from the right with padding-right instead, same mechanism as
   .checkable above. 460px text column, matching .checkable's: 704/129 = 5.46
   and 704/123 = 5.72 px per character puts it at ~84/80cpl, confirmed by
   measurement at 86/83 — past the 55-75 body-prose band and deliberately so,
   for the reason .checkable's comment gives (fine print reads in short
   bursts, not continuously); both land under the 90cpl ceiling and a long
   way from 129/123. Height check: each
   paragraph now runs one more line than at 704px unconstrained but fewer
   than the first pass's 368px; .price already has clamp(32px,5vh,56px)
   above .terms and the CTA's own fixed gap below (F8, this file) is
   untouched, so the extra height reads as more paragraph, not a broken
   rhythm.

   F8, round 4 craft — the floor here used to be 28px, so at a 393x852 phone
   (4vh = 34.08px) this gap and .price__cta's fixed 32px margin-top (below)
   sat 2.08px apart and read as equal, undoing the hierarchy this comment
   block's own F3 note argues for ("cards-to-caption stays the section's
   loosest gap"). Raised the floor to 40px — the value 4vh already resolved
   to at a 1000px-tall viewport, so nothing shrinks, it just stops shrinking
   further. Holds the order at all three reported heights: 852 -> 40 (floor),
   950 -> 40 (floor), 1000 -> 40 (floor meets 4vh exactly) — each a clear 25%
   above the CTA's fixed 32px, against 2.08px before. Above a 1000px-tall
   viewport 4vh keeps scaling to the unchanged 44px ceiling. */
/* F1, THIRD PASS, 2026-09-01 — same move as .checkable above, same reason:
   see --fine-measure's comment in the TOKENS block. max-width:44rem is
   unchanged and keeps doing the alignment work against .price__head /
   .price__cta; padding-right now derives from --fine-measure instead of a
   fixed 244px, and no longer needs the <=759 override this file used to
   zero it with. Same min()-of-two-regimes shape as .checkable's own
   comment explains — this box's cap is 44rem, not 1000px, but the %-trap
   is identical: .pad (this element's containing block) outgrows 44rem
   above ~800px, so plain `100% - Nch` overshoots past that width. */
.price__fine{
  margin-top:clamp(40px,4vh,44px);
  max-width:44rem;
  padding-right:min(
    max(0px,100% - var(--fine-measure)),
    max(0px,44rem - var(--fine-measure))
  );
  color:var(--ink-2);
  font-size:var(--t-cap);
  line-height:1.6;
}
/* F3, 2026-09-01 — MY FAULT, FIXED. .price__fine used to be one paragraph;
   splitting it left the second half inheriting the same clamp(28px,4vh,44px)
   authored for one block following the pricing cards, so the split half sat
   as far from its own other half (38.00px at 1500, 34.08px at 393) as the
   whole block sat from .terms — the loosest bond in the stack landing INSIDE
   one thought, with .price__cta's fixed 32px lead-in (already the page's
   established "space before the one action", see .price__cta's own comment)
   reading as the tightest gap by comparison. The two halves now bond at
   rhythm*1.2 = 12px, the same mechanism and the same number .foot already
   uses for its own paragraph-to-paragraph gap on identical --t-cap/--ink-2
   prose (.foot p + p, further down this file) — reused, not invented. The
   first .price__fine's own margin-top is untouched, so the cards-to-caption
   transition stays the section's loosest gap, and .price__cta's margin-top
   is untouched too: once the intra-thought bond drops to 12px, the CTA's own
   already-established 32px reads as real air again without needing to grow. */
.price__fine + .price__fine{
  margin-top:calc(var(--rhythm) * 1.2);
}

/* The page's one action, again, after the trust section and the price block
   have had their say. Ledger line "no closing call to action": a visitor
   convinced at the bottom of the page had nothing to click without scrolling
   back to the hero. This is the hero's .act/.btn/.act__note markup verbatim —
   same copy, same mailto target, same button — just re-seated here. The
   margin-top matches the hero's own lede-to-button distance
   (.fold__say .lede's margin-bottom, calc(var(--rhythm) * 3.2)) so the
   "space before the one action" reads as the same rule everywhere it appears. */
/* max-width + margin-inline:auto again: without it the button sat flush at
   the page's true left edge while .price__head/.price__fine above it were
   now centred to 44rem, so the CTA broke rank from the column it visually
   belongs to. Same 44rem measure keeps the button's left edge lined up with
   the copy above it. */
.price__cta{margin-top:calc(var(--rhythm) * 3.2);max-width:44rem;margin-inline:auto}
/* .act__note's color is --band-ink-2, correct inside the fold (a .band
   context, overridden light/dark) and inside .promise (also a .band, always
   dark). .price is plain page ground, not a band, so it never gets that
   override and would inherit the dark band's near-white ink here — invisible
   on this section's white/black page background. Same token role the rest of
   .price already uses (.price__fine is --ink-2 too), just resolved against
   the ground this copy actually sits on. */
.price__cta .act__note{color:var(--ink-2)}

/* ================================================================= FOOTER */
/* 2026-08-31: page ground + hairline top rule, not an --inset band. Same
   move as .term above, and the same reasoning as the page-ground decision
   at the top of this file's TOKENS block ("the grey ground makes the page
   read as a spec document rather than a product") applied one level down,
   to an ordinary block instead of the whole page. */
.foot{
  /* 2026-09-01 — THE TWO FOOTERS, MEASURED. This element's own comment
     already claims "the two footers stay the same object"; a craft round
     measured that they were not, on verbatim identical copy: this file's
     --t-cap (12px) is a small-print token doing double duty (see the
     --t-micro comment above) where style.css has a token dedicated to
     exactly this job (--t-meta, 13px). Reused verbatim as its own rem
     value (0.8125rem) rather than reinvented. The matching --ink/--ink-2
     half of this fix is NOT here — a directly-matching rule on an element
     always beats an inherited :root value regardless of appearance, so an
     override placed at this unconditional `.foot` rule would win in BOTH
     appearances and break dark mode (shipped that way once; the "Relational"
     wordmark rendered near-invisible, light ink on the dark page's black
     ground). It sits instead next to `.mast, .fold`'s own light override,
     BEFORE the dark media query, with its restore inside that query,
     which is the only ordering that lets dark appearance win its tie
     against this same-specificity selector. See that comment for the
     restore's reasoning. */
  --t-cap:0.8125rem;
  background:var(--page);
  border-top:1px solid var(--hairline);
  padding:calc(var(--rhythm) * 10) 0 clamp(36px,5vh,56px);
}
.foot__grid{
  display:grid;
  grid-template-columns:minmax(0,1.4fr) minmax(0,1fr);
  gap:clamp(24px,4vw,64px);
}
.foot .foot__wm{
  font-size:var(--t-body);
  font-weight:600;
  letter-spacing:-.01em;
  /* 2026-09-01 — was rhythm*0.6 (6px), the only place either stylesheet
     used that multiplier. It never produced a visible defect here, only
     because it happens to sit next to .foot p + p's margin-top:rhythm*1.2
     (12px) and adjacent block margins collapse to the larger of the two —
     so this rule rendered at 12px by a collapse it never named, not by its
     own declared value. style.css's matching rule already states 1.2
     directly (it has no next-sibling collapse to lean on, since it puts
     the margin on .foot p's own margin-bottom instead). Matched to that
     value so the two footers are the same declared rule, not a 6px rule
     and a 12px rule that coincidentally paint the same pixel today. No
     rendered change: max(12,12) is still 12. */
  margin-bottom:calc(var(--rhythm) * 1.2);
  color:var(--ink);
}
.foot p{color:var(--ink-2);font-size:var(--t-cap);line-height:1.6;max-width:40rem}
.foot p + p{margin-top:calc(var(--rhythm) * 1.2)}
.foot__nav{display:flex;flex-direction:column;gap:calc(var(--rhythm) * 1.2)}
/* Privacy and Support are real links (see index.html) but were painted
   --ink, the same flat black as the non-interactive "Relational" heading
   beside them — no static affordance, only a :hover cue a pointer or a touch
   never triggers. --link is the token this file already carries for exactly
   this job (AA on both grounds); the :hover state (see the unconditional
   rule just above :focus-visible's own fix, F1/F5, 2026-09-01) keeps this
   same --link on hover rather than moving to --blue, which measured 4.02:1
   on white and failed the 4.5:1 floor this fix exists to hold. */
.foot__nav a{
  font-size:var(--t-body);
  font-weight:600;
  color:var(--link);
  /* Two lines tall because the anchor wraps its description, which lands near
     44pt without reliably clearing it. Guaranteed rather than estimated: a hit
     frame has no pixels, so no capture can check this. */
  display:block;
  min-height:44px;
}
.foot__nav a span{display:block;font-size:var(--t-cap);font-weight:400;color:var(--ink-2);margin-top:3px;line-height:1.5}

/* ==========================================================================
   AUTHORED LINE BREAKS — RETIRED 2026-09-01, round 16, rules removed with the
   policy they enforced.

   This block said "every break in the headline is authored, per breakpoint" and
   defined .brk-p and .brk-d. NEITHER CLASS APPEARS IN index.html, the only page
   this file serves, and index.html:244 records why: check-privacy-claim.sh
   greps each promise sentence as one contiguous string, so a <br> inside one
   would break the guard. text-wrap:balance does that job now without putting a
   tag inside the claim.

   So the stylesheet asserted a policy the markup had cancelled. Same
   two-artifact disagreement this site keeps producing, and the reason repair 4
   of round 15 swept style.css's dead selectors and missed this file's.

   The measurement is worth keeping and the rules are not: candidate B carried
   zero <br> at either viewport and filled 96.8% of its longest phone line,
   where Apple fills 75.4% and breaks on meaning. That is why the headline is
   balanced rather than left to run out.
   ========================================================================== */

/* ========================================================= THE PHONE PASS
   Ledger line 17: composed, not reflowed. Three things change here that a
   scaled layout would not change — the hero crop shows a different part of the
   screen at a different aspect, the headline and lede are broken differently,
   and the type ramp above has different members.
   ========================================================================== */
@media (min-width:1180px){ .crop{--dw:430} }
@media (min-width:960px) and (max-width:1179px){ .crop{--dw:360} }
/* 760-959 — the narrow-desktop / tablet-portrait tier. A two-column fold here
   is two short columns floating in a nearly square band, and three phones side
   by side are 190px wide each, which is a texture rather than a screen. So the
   fold stacks and the steps stack, while the type ramp stays on the desktop
   fluid scale. Judged viewports are 1440 and 393; this tier is checked, not
   optimised. */
@media (min-width:760px) and (max-width:959px){
  /* FOLD R1 · CHANGE 2/4 — same treatment as the phone tier below; see there
     for why the slack moves to the top of the fold. */
  :root{--seat:50px}
  .fold__grid{
    grid-template-columns:minmax(0,1fr);
    grid-template-rows:auto auto;
    align-content:end;
    align-items:start;
    gap:clamp(20px,4vh,34px);
    padding-top:clamp(16px,3vh,32px);
  }
  .fold__say{align-self:start;padding:0}
  .fold__show{justify-content:flex-start;align-self:start;margin-bottom:var(--seat)}
  .crop{--dw:420;--rev:.47}

  .steps{grid-template-columns:minmax(0,1fr);gap:clamp(40px,7vh,64px)}
  .phone{--dw:320;margin:0}
  /* .step__src moved to a base rule (see its own comment) that holds at
     every width instead of just this one breakpoint; .step p keeps its
     own tablet-only cap here, unchanged. .step__src is itself a <p>, so it
     also matches `.step p` below (0,1,1) at HIGHER specificity than the
     bare `.step__src` rule (0,1,0) — the same collision this file already
     names and fixes for `.step .step__n` vs `.step p` above. Scoped one
     class deeper, `.step .step__src` (0,2,0), to reset the width this
     breakpoint would otherwise force back onto it. */
  .step p{max-width:34rem}
  .step .step__src{max-width:none}
}

@media (max-width:759px){
  /* Phone half of the half-rate fold ramp (see the .fold rule above). The
     phone ramp is fixed rather than clamped, so the concession is the same
     blend, identity at a 16px root: 34 / 24 / 17 exactly. This block is what
     the phone defect actually rode in on — the fixed members grow linearly
     from the first raised pixel, and the pill is the last thing in the stack. */
  .fold{
    /* Same clamp, this breakpoint's own judged number: 796px is
       `100svh - 56px` at the 852-tall frame the comment above names. Narrow
       was the worse of the two, because `align-content:end` pins the WHOLE
       stack and not just the image — headline top measured 81.5px at the
       judged 852, then 103.2 at 1000, 295.2 at 1200 and 695.2 at 1600, two
       thirds of a tall window scrolling past before the headline appears at
       all. The comment below states plainly that the change was validated at
       one height: "at the judged 393x852 there is no free space to place
       either way". True, and that was exactly the gap. */
    min-height:min(calc(100svh - 56px), 796px);
    --t-display:calc(17px + 1.0625rem);
    --t-head:calc(12px + .75rem);
    --t-lede:calc(8.5px + .53125rem);
  }
  .mast__in{min-height:56px}

  /* FOLD R1 · CHANGE 4 (phone) — the slack stops living under the device.

     THE PROBLEM, MEASURED. This tier is single-column with `align-items:start`,
     so nothing pins the crop to anything; where it lands is `min-height:
     calc(100svh - 56px)` minus the content stack. Sweeping window height at
     393 wide on the previous fold, the at-rest distance from the crop's bottom
     edge to the fold's boundary runs 1px at 600–820, then 4.59 / 8.19 / 21.22
     / 39.81 / 58.41 / 77 / 124px as the window grows to 1100. Nobody chose any
     of those numbers and nothing holds them stable. The 8.19px in the round's
     headline table is residue, not composition — which is fatal here
     specifically, because this composition's entire claim is that the space
     beneath the object is chosen.

     THE FIX. Stop the auto rows stretching (naming `align-content` is what
     does that) and pack the stack against the bottom, so the object's
     relationship to the boundary is `margin-bottom: var(--seat)` and nothing
     else. Free height then collects ABOVE the eyebrow, under the masthead,
     where it reads as a top margin.

     THIS IS A TRADE AND IT IS NOT FREE. Ledger line 10 wants the air above the
     eyebrow chosen rather than left over, and on a window taller than ~880px
     some of it is now left over. The trade is deliberate: leftover space under
     a masthead reads as breathing room, and the same space above a section
     boundary reads as a mistake — which is what this round is about. At the
     judged 393×852 there is no free space to place either way, so the judged
     frame is unaffected by this change. */
  .fold__grid{
    grid-template-columns:minmax(0,1fr);
    grid-template-rows:auto auto;
    align-content:end;
    gap:clamp(20px,4vh,34px);
    align-items:start;
    padding-top:clamp(20px,3vh,32px);
  }
  .fold__say{padding-bottom:0;align-self:start}
  .fold__say h1{max-width:none;margin-bottom:calc(var(--rhythm) * 1.8)}
  .fold__say .lede{margin-bottom:calc(var(--rhythm) * 2.4)}
  .fold__show{justify-content:flex-start;align-self:start;margin-bottom:var(--seat)}

  .crop{--dw:350;--rev:.47}

  .steps{grid-template-columns:minmax(0,1fr);gap:clamp(36px,6vh,56px)}
  /* the step pictures become crops too, so three screens do not cost three
     full phone heights on a 393pt page */
  .phone{--dw:353;width:calc(var(--dw) * 1px);margin:0}
  .phone__body{
    padding:0;
    background:none;
    /* .58 rather than .50: at .50 step two's Confirm/Change row landed exactly
       on the cut and read as two half-buttons. Each crop now ends after the
       thing its caption is about and starts the next one, which is what says
       "there is more" without cutting a control in half. */
    height:calc(var(--dw) * 1px * 852 / 393 * .58);
    overflow:hidden;
    border-radius:var(--r-in) var(--r-in) 0 0;
    box-shadow:
      0 0 0 1px var(--ring),
      0 1px 2px var(--cast-tight),
      0 22px 48px -12px var(--cast);
  }
  .phone__body img{border-radius:0}

  /* STEP THREE'S APERTURE, RE-TUNED, 2026-09-01. .58 was checked against
     controls (step two's Confirm/Change row) and never against type. A
     row-luminance scan of shots/6-person-deep-{light,dark}.webp (1100x2392
     natural, both appearances agree to the pixel) found the last solid ink
     above the cut is "The other 214 of 218 notes", ending at natural
     y=1072; the next ink, the CONNECTIONS caption, does not start until
     y=1137. .58 lands the cut at natural y≈988 — inside the EARLIER/back-
     to-2007 row above the note card entirely — which is what was cutting
     type. .65 lands at natural y≈1108, in the middle of the 65px clear
     band between the two, giving ~16 CSS px of clear space at this
     breakpoint's dw — matching step one's clearance, not step two's,
     because this image's content falls differently; a shared ratio across
     all three steps is not guaranteed to keep working as the source shots
     change, so this is pinned to .rv-3 rather than folded back into the
     shared rule. */
  .rv-3 .phone__body{
    height:calc(var(--dw) * 1px * 852 / 393 * .65);
  }

  .promise .four{grid-template-columns:minmax(0,1fr)}
  .claim{max-width:none}
  .terms{grid-template-columns:minmax(0,1fr)}
  .foot__grid{grid-template-columns:minmax(0,1fr)}

  /* F1, round 4 craft, SECOND PASS — RETIRED, 2026-09-01, F1 THIRD PASS.
     This block used to zero the fixed-px padding-right below 760, because
     that padding was sized against the DESKTOP box (1000px / 704px) and ate
     past the stacked mobile column. .checkable/.price__fine/.step__src now
     cap their line with padding-right:max(0px,100% - var(--fine-measure))
     (see --fine-measure's own comment, TOKENS block) — on a box narrower
     than --fine-measure the subtraction goes negative and max() floors it
     at 0px on its own, so this override is redundant and removed rather
     than kept as dead weight. */
}

@media (max-width:380px){
  .crop{--dw:320}
  .phone{--dw:320}
}

/* ==========================================================================
   MOTION. Everything below is inside prefers-reduced-motion: no-preference.
   Under `reduce` there is nothing to turn off, because nothing is declared —
   the page above is the finished composition and the page below only ever
   animates INTO it. Scroll-driven work is additionally behind @supports, so a
   browser without view()/scroll() timelines gets the same finished page.
   ========================================================================== */
@media (prefers-reduced-motion: no-preference){

  /* 1 · the fold arrives. @starting-style supplies only the FROM state, so an
     engine without it renders the finished state and nothing is hidden. */
  .fold__say .eyebrow,
  .fold__say h1,
  .fold__say .lede,
  .fold__say .act,
  .fold__say .act__note,
  .fold__show{
    opacity:1;
    translate:0 0;
    /* SHORT on purpose. A fold that fades in from nothing is a black screen
       until it lands, and the first capture of this page caught it mid-flight
       at ~600ms with the evidence not yet drawn. Everything has arrived by
       520ms; the stagger is a sequence, not a performance. */
    transition:opacity 400ms var(--ease), translate 400ms var(--ease);
  }
  @starting-style{
    .fold__say .eyebrow{opacity:0;translate:0 10px}
    .fold__say h1{opacity:0;translate:0 14px}
    .fold__say .lede{opacity:0;translate:0 14px}
    .fold__say .act{opacity:0;translate:0 14px}
    .fold__say .act__note{opacity:0;translate:0 14px}
    .fold__show{opacity:0;translate:0 26px}
  }
  .fold__say h1{transition-delay:40ms}
  .fold__say .lede{transition-delay:80ms}
  .fold__say .act{transition-delay:110ms}
  .fold__say .act__note{transition-delay:130ms}
  .fold__show{transition-delay:60ms;transition-duration:460ms}

  /* 2 · the action answers the pointer. Asymmetric: enter 200ms, exit 140ms,
     because the user has already decided by the time it leaves. */
  .btn{
    transition:translate var(--out) var(--ease), box-shadow var(--out) var(--ease), background-color var(--out) var(--ease);
  }
  .btn:hover,.btn:focus-visible{
    translate:0 -1px;
    transition-duration:var(--in);
  }
  .btn:active{translate:0 0;transition-duration:90ms}

  /* Both hover states themselves are unconditional now (see .foot__nav a
     and .link above, F1 second pass) because a colour or decoration change
     is not motion; only the SPEED of a transition belongs here. .foot__nav a
     gains its underline as a snap — text-decoration-line is not an
     animatable property in any browser, with or without this rule — so
     there is nothing here for it to transition. .link's hover thickens an
     underline that is already drawn, and text-decoration-thickness DOES
     interpolate, so that one gets the same timing every other hover on
     this page gets. */
  .link{transition:text-decoration-thickness var(--out) var(--ease)}
  .link:hover{transition-duration:var(--in)}

  @supports (animation-timeline: view()) and (animation-range: entry 10%){

    /* 3 · sections arrive as they are scrolled to.
       TRANSFORM ONLY, AND THAT IS THE WHOLE POINT. The first version faded
       from opacity 0, and Chrome's own full-page capture rendered the promise
       section BLANK — the view timeline never advanced, so every element sat
       at its `from` state with nothing on screen. That is one real client
       today, and a print stylesheet, a reader mode or a future engine quirk is
       the same failure. A reveal that can hide content when the timeline does
       not run is a reveal that fails closed.
       So nothing here animates opacity. The worst case is a block sitting
       14px lower than it should, which nobody can see. Ranges are entry-only
       so a block taller than the viewport still completes. */
    .rv{
      translate:0 14px;
      animation:rv linear both;
      animation-timeline:view();
      animation-range:entry 4% entry 62%;
    }
    .rv-2{animation-range:entry 10% entry 68%}
    .rv-3{animation-range:entry 16% entry 74%}
    @keyframes rv{to{translate:0 0}}
  }

  /* 4 · the object settles onto its ground as it arrives.

     FOLD R1 · CHANGE 5 — THE `lift` KEYFRAME IS GONE. It read:

         @supports (animation-timeline: scroll()){
           .crop{ animation:lift linear both;
                  animation-timeline:scroll(root); animation-range:0 92svh; }
           @keyframes lift{to{translate:0 -46px}} }

     and it is the entire defect this round exists to fix: 46px of upward
     travel measured against a boundary that travels with the page, which
     opened the crop's bottom edge by 1 → 12.5 → 24 → 35.5 → 47px on desktop
     and 8.19 → 54.19px on phone. Under `reduce` the same page measured 1px
     flat at every stop, which is how we know it was the animation and not the
     layout.

     A PARALLAX CANNOT BE RESCUED HERE, and it is worth writing down why rather
     than leaving the next builder to rediscover it. The obvious repair is to
     move the 46px inside the aperture — translate the <img>, not the .crop —
     so the object holds its place while its content drifts. It does not
     survive contact with the picture: the shot's iOS status bar is ~62px tall
     at the rendered size, so 46px of upward drift eats three quarters of it,
     and a status bar that scrolls is a lie about how an iPhone works, told on
     the one image whose whole job is to be checkable. Any drift small enough
     to spare the status bar is too small to read as depth.

     FOLD R1 · CHANGE 6 — SO THE DEPTH IS BOUGHT SOMEWHERE ELSE, and it is an
     entrance, which is the category this page already sanctions and the only
     category that cannot interact with a scroll position. The object arrives
     from 26px below (unchanged, above) with its shadow tight against it, and
     the shadow opens as it lands. That is a solid thing coming to rest on a
     ground plane, and it is the motion a seated object is entitled to.

     It is also the only depth cue the previous fold could never have used: a
     flush object has nothing to cast onto. Every pixel of `.crop`'s cast
     shadow on the previous fold fell outside the fold's overflow:hidden box
     at rest and is discarded. --seat is what gives the shadow somewhere to
     land, which makes this change and change 3 the same change seen twice.

     Ledger line 23 is safe by construction: no state here has the crop
     unpainted, and nothing in this block touches the action or its sentence.
     @starting-style supplies only the FROM state, so an engine without it
     renders the finished object and nothing is hidden. */
  .crop{
    transition:box-shadow 560ms var(--ease) 60ms;
  }
  @starting-style{
    .crop{
      box-shadow:
        0 0 0 1px var(--ring),
        0 1px 2px var(--cast-tight),
        0 4px 10px -8px var(--cast);
    }
  }
}

/* ==========================================================================
   THE AMENDMENT THIS FILE OWES design/system.md §3, drafted here so that
   adopting this file and editing that rule are one decision rather than two.
   IT HAS NOT BEEN APPLIED. §3 still says this element bleeds; a maintainer
   edits that file, not this one.

   §3 currently reads, of vertical edges:

     "Clip, do not pad — vertically. A scrollable band ends by clipping a row
      mid-height. That reads as 'there is more' without spending a pixel saying
      so. Trailing whitespace reads as 'there is nothing'."

   and hero.css cites it as "it bleeds DOWN and never sideways".

   PROPOSED AMENDMENT — an exception, narrowly drawn, with its reason attached:

     The rule is about a CONTAINER's own trailing edge: a list, a scrollable
     band, a card whose content runs past its floor. There, padding below the
     last row is space the container spent on nothing, and clipping is the
     cheaper and truer signal.

     It does not govern the space between a FINISHED OBJECT and the boundary of
     the surface it sits on. A device shown in a hero is not a band that ran
     out of rows; it is an object on a ground plane, and the space beneath it
     is the ground, not trailing whitespace. The object's own bottom edge still
     clips its content mid-document — §3's mechanism is intact and doing its
     job INSIDE the aperture, which is where the "there is more" reading lives.

     The test that separates them: does the whitespace sit inside the thing's
     own border, or outside it? Inside is trailing whitespace and §3 forbids
     it. Outside is composition, and it must then be a chosen value that holds
     at every viewport and every scroll position — which is the burden this
     composition accepts and the previous fold failed.

   WHAT WOULD FALSIFY THE AMENDMENT: a judge reading the seated object as
   "cut off and then floated" rather than "complete". That reading is available
   and this file does not pretend otherwise — see hero-fold round 1 in
   design/gauntlet-log/website.md, which records it as an open ledger line
   rather than a closed one.
   ========================================================================== */

/* ===================================================================== print
   Added 2026-09-01, round 16. This file had NO print rules while style.css had
   four lines, and the asymmetry was never a decision, only an omission.

   Chrome and Safari print with background graphics OFF by default, so every
   ground on this page vanishes and the near-white ink that sat on it stays.
   Measured off a real Page.printToPDF at US Letter, backgrounds off:

     the promise band's body ....... 2.02:1   (19.78:1 on screen)
     the promise headline .......... 2.30:1
     the YEARLY price .............. 2.30:1
     the MONTHLY price beside it ... 21.00:1
     both CTA labels ............... 2.30:1 and 1.49:1

   The two price cards are the sharpest reading of it: the same component, on
   the same sheet, at ten times the contrast, because one has a fill and one
   does not. And the section that failed worst is the site's central privacy
   claim, on a page the App Store listing sends people to.

   Turning backgrounds ON does not rescue it either: the promise sheet becomes
   75% near-black by area, a full page of solid ink.

   So: every ground goes to paper, every ink goes to black, and the glows go
   too, because a box-shadow prints when its fill does not and leaves a pale
   rectangle with a ghost label inside it. --band-blue keeps a link looking like
   a link, at a value that survives on white.

   Print width here is 739 CSS px, which puts the max-width:759px phone pass in
   force, so this block is read against the phone layout and not the desktop
   one. Round 16 measured that; it is not an assumption. */
@media print{
  /* THE REVEAL TRANSFORMS MUST GO, and this is the finding round 17 caught on
     the surface round 16's repair shipped. .rv carries `translate: 0 14px`, and
     a translated box is MONOLITHIC under fragmentation: Chrome cannot break
     inside it, so it cuts it. Two lines printed severed through the letterforms
     rather than between them, one of them the promise itself, "What you write
     stays on your device and is never sent to us or", its bottom half on page 5
     and its top half on page 6.

     hero.css:1843 anticipated exactly this class, reasoned it through for
     opacity, and concluded "the worst case is a block sitting 14px lower than
     it should, which nobody can see." The worst case was the central claim cut
     in half on paper.

     Proven rather than argued: printed under prefers-reduced-motion, where the
     whole motion block is off, both cuts vanish. This does the same thing
     unconditionally for print.

     Round 16 could not see it because its instrument measured ink COVERAGE per
     page, and a coverage mean cannot see a line sliced through the glyphs. */
  .rv,.rv-2,.rv-3,.crop,.fold__say h1,.fold__say .lede,.fold__say .act{
    translate:none !important;
    transform:none !important;
    opacity:1 !important;
    animation:none !important;
    view-timeline:none !important;
  }

  /* PRINT MUST USE THE LIGHT PLATES, and <picture> will not do it on its own.
     Chromium forces prefers-color-scheme:light for print CSS, so every colour
     in this stylesheet comes out right. Source selection inside <picture> is
     not CSS: it resolved once at load, against the screen's appearance, and
     printing does not make it resolve again. On a Mac set to dark, page 2 came
     out of the printer at 24.94% near-black against 1.135% from the same page
     on a light Mac — a near-solid dark rectangle, on paper, from a stylesheet
     that had correctly switched everything it controlled.

     `content` on a replaced element overrides the rendered image regardless of
     which <source> won, and each rule points at the same light asset already in
     that element's own src. So this needs no new files and cannot drift: if a
     screenshot is renamed, the selector stops matching and the plate reverts to
     whatever <picture> chose, which is the pre-existing behaviour rather than a
     broken URL.

     Round 17 nearly missed this and then retracted its first attempt: it drove
     print emulation through CDP setEmulatedMedia, which DEFEATS Chromium's
     forcing of light and produced phantom blank pages and black-on-black
     footers — artifacts of the instrument, not the page. The real measurement
     needs --blink-settings=preferredColorScheme=0 and no emulation at all. */
  img[src$="2-capture-open-light.webp"]{content:url("shots/2-capture-open-light.webp")}
  img[src$="3-review-queue-light.webp"]{content:url("shots/3-review-queue-light.webp")}
  img[src$="4-review-source-light.webp"]{content:url("shots/4-review-source-light.webp")}
  img[src$="6-person-deep-light.webp"]{content:url("shots/6-person-deep-light.webp")}
  .mast,.skip{display:none}
  /* NOTHING THAT READS AS ONE THING MAY BE SPLIT ACROSS TWO SHEETS.
     Before this rule the site had no fragmentation policy at all: `grep -n
     break-inside site/*.css` returned nothing, on four pages that all print.
     What that produced on 404.html was a footer link severed from its own
     description — "Home" as the last line of page 1, "What Relational is." as
     the first line of page 2, a dangling heading above an unlabelled fragment.

     The other three pages were not safe, only lucky: the same markup and the
     same missing policy, with content that happened to put the break somewhere
     harmless. One added paragraph moves it. So this is written as a rule about
     which boxes are indivisible, not as a patch on the one that broke.

     `break-after:avoid` on headings is the same idea from the other side: a
     heading alone at the foot of a sheet is a promise the page does not keep
     until you turn it over.

     Related but distinct: hero.css resets .rv's transform for print, because a
     TRANSLATED box is monolithic and gets cut through the glyphs rather than
     broken between them. That is the engine refusing to fragment. This is us
     telling it not to. Both are needed; neither implies the other. */
  .foot__nav,.foot__nav a,.term,figure,.crop,.phone{break-inside:avoid;page-break-inside:avoid}
  h1,h2,h3{break-after:avoid;page-break-after:avoid}

  body,.fold,.promise,.band,.how,.price,.steps{
    background:#fff !important;
    color:#000 !important;
  }
  /* `.four li` IS IN THIS LIST BECAUSE INHERITANCE LOSES TO A DIRECT
     DECLARATION, and no amount of !important on an ancestor changes that.
     `.four` and `.four strong` were both here; `.four li` was not, and
     `.four li{color:var(--band-ink-2)}` is a rule ON the element, so it won.
     What printed was the promise band's four bold lead-ins in black and every
     word after them at rgba(235,235,245,.72) on white paper — measured 1.13:1,
     against 21:1 for the bold. The Files caveat, the Sentry/PostHog/RevenueCat
     disclosure, the iCloud readability caveat: all of it invisible.

     On the page that invites the reader to print it and check the claim, and
     on the band the site treats as its centre. The bold headings survived,
     which is what made it hard to see: a printed page that looks like it
     worked. */
  .fold__say h1,.fold__tail,.lede,.claim__text,.four,.four li,.four strong,
  .eyebrow,.step__n,.term__k,.term__v,.term__w,.checkable,.price__fine,
  .act__note,.foot,.foot p,.foot__wm{
    color:#000 !important;
  }
  .btn,.term,.term--chosen{
    background:#fff !important;
    color:#000 !important;
    border:1px solid #000 !important;
    box-shadow:none !important;
  }
  .crop,.phone__body,.step__pic{box-shadow:none !important}
  a{color:#000 !important;text-decoration:underline}
  .deeper{color:#000 !important}
}
