/* desktop.css — the landing page's desktop layer, plus the phone footer art and the size
   rules. Hand-maintained; promote.py links it after page.css (generated from the lab source,
   never edited here). It restyles the page's own nodes; desktop.js (a module, desktop only)
   regroups them into per-stop boxes and measures the few seats CSS cannot.
   Thresholds: the layer ≥ 1024 wide (inner tiers: < 1180 · 1024–1279 · ≤ 820 tall ·
   below the 690-tall floor · above 1920 wide the whole picture scales); the phone footer art ≤ 430; the centred phone column 431–1023;
   below the phone floor < 629 tall. The design record is docs/qa/desktop-v2/r5/.

   Contents: THE LAYER (≥ 1024) — tokens · shared type roles + buttons · 1 hero · 2 demo ·
   3 the 170 · 4 packs · 5 October · 6 footer · motion · above 1920 wide (the scaled picture) ·
   the desktop size tiers.
   Then THE PHONE FOOTER ART (≤ 430) and THE SIZE RULES below the desktop. */

/* ============================== THE LAYER (≥ 1024) ============================== */
@media (min-width: 1024px) {

  /* ================= tokens ================= */
  :root {
    /* the layer's units: 1vw / 1vh; above 1920 wide desktop.js sets both inline on <html> to
       the LOCAL (unscaled) box's 1 % (see "above 1920 wide" below); in a window shorter than
       the floor --dvh is the floor's (6.9px) */
    --dvw: 1vw;
    --dvh: 1vh;
    /* the card: 358 / 392 / 522 at 1280 / 1440 / 1920, capped by the height */
    --col-card: min(clamp(358px, calc(27.2 * var(--dvw)), 540px), calc((calc(77.67 * var(--dvh)) - 68px) / 1.32));
    /* a wider reference card, kept only to place the copy column's x */
    --r5-card0: min(clamp(398px, calc(30.2 * var(--dvw)), 600px), calc((calc(77.67 * var(--dvh)) - 68px) / 1.32));
    --r5-cw: 480px;                          /* the copy column */
    --r5-gut: clamp(64px, calc(6.667 * var(--dvw)), 128px);   /* 96 at 1440 */
    --r5-m: calc((calc(100 * var(--dvw)) - var(--r5-cw) - var(--r5-gut) - var(--r5-card0)) / 2);  /* the outer margin = the copy's x */
    --btn-h: 56px;
    --r5-stream: 366px;                      /* the 170's belt card */
    /* a pack in the spread (the pack's own proportions): 296 from 1280 × 800 up; narrower or
       shorter windows scale the spread down with the window (Alex 09-28: at 1180 × 714 the
       cards crowded the copy and the lower row met "Early couples get more"). The height
       term keeps the lower row ≈ 34 over the link, as at 1280 × 800; the width term keeps
       the 1280 proportion of cards to copy. Gaps scale with the pack. */
    --r5-pack: min(296px, calc(23.13 * var(--dvw)), calc(60.1 * var(--dvh) - 184.5px));
    --r5-pack-gap: min(20px, calc(var(--r5-pack) * 0.0676));
    --r5-pack-row: min(36px, calc(var(--r5-pack) * 0.1217));
  }
  @media (max-width: 1179.98px) {
    :root { --r5-cw: 400px; --r5-gut: 48px; }
  }

  /* every stop: the phone's spacers retire */
  #pager > section { height: 100%; min-height: 0; padding: 0; }
  #pager > section > .air,
  #pager > section > .sp-a,
  #pager > section > .sp-b { display: none; }
  #pager .wrap, #pager .mast, #pager .wrap-obj { max-width: none; width: auto; margin: 0; padding: 0; }

  /* ================= shared type roles — one value logic per role ================= */
  /* headline: the bold sans headlines on ONE scale — 46 / 600 / −0.016em / 1.14 */
  #pager .statement, #pager .m3 .nz:not(.act), #pager .s3x-answer, #pager .s4b-header { font-size: 46px; letter-spacing: -0.016em; line-height: var(--lh-headline); }
  /* subhead: 26 / 600 / −0.016em / 1.16 */
  #pager .b2 .prop, #pager .s4b .offer .line { font-size: var(--disp-m); letter-spacing: -0.016em; line-height: 1.16; }
  /* eyebrow / small caps: 13 / 500 / 0.22em (the 170's WISHES stays 16 — the numeral's lockup label) */
  #pager .hero-cta .cta-eyebrow, #pager .m3 .vlabel, #pager .offer .eyebrow { font-size: var(--fs-support); font-weight: 500; letter-spacing: var(--track-caps); }
  /* body: 17 / 400 / 1.55 (the consent stays 15 — the legal paragraph, the form's width) */
  #pager .grounding, #pager .b1-sub, #pager .b2 .free, #pager .launch-sub, #pager #foot .fs-line { font-size: var(--fs-nav); line-height: var(--lh-reading); }
  /* CTA text: 28 / 600 */
  #pager .b2 .bridge a { font-size: var(--disp-title); line-height: 1.2; }
  /* the other sizes and the type's box resets */
  #pager .wm { font-size: var(--disp-xl); }
  #pager .statement { margin: 0; }
  #pager .grounding { margin: 0; }
  #pager .s3x-answer, #pager .s4b-header { margin: 0; max-width: none; }

  /* the buttons: 56 tall, the index size */
  #pager .plaque, #pager .btn-slab, #pager .btn-send { height: var(--btn-h); }
  #pager .plaque input, #pager .btn-slab, #pager .btn-send { font-size: var(--fs-index); }

  /* ================= 1 · THE HERO =================
     two columns: the copy left, the card stack right; the copy group's centre on the
     FRONT card's centre (the stack carries 14 px of head-room above the front card,
     so the copy box takes 14 px on top to match). */
  #pager .hero-cta a { font-size: var(--disp-title); }
  #pager .hero-cta .cta-eyebrow { margin-bottom: 10px; }
  #pager .stop1 {
    display: grid;
    grid-template-columns: var(--r5-m) 520px calc(var(--r5-gut) - 64px) var(--col-card) 1fr;   /* the 46 px statement is 497 wide → copy column 520 */
    grid-template-rows: 3fr auto 2fr;
    overflow: visible;
  }
  #pager .stop1 > .r5-copy { grid-column: 2; grid-row: 2; align-self: center; padding-top: 14px; position: relative; top: -20px; display: flex; flex-direction: column; align-items: flex-start; }
  #pager .stop1 > .r5-obj  { grid-column: 4; grid-row: 2; position: relative; }
  #pager .stop1 .mast .wm { display: block; line-height: 1; }
  #pager .stop1 .statement { margin-top: 28px; }
  #pager .stop1 .grounding { margin-top: 12px; }
  #pager .stop1 .hero-cta { margin: 28px 0 0; padding: 0; text-align: left; }
  #pager .stop1 .hero-cta p { margin: 0; }
  #pager .stop1 .hero-cta a { padding-block: 0; }
  #pager .stop1 .hero-cta .cta-arrow { display: none; }          /* no ⟶ on desktop */
  /* the compact solid button — the page's own .btn-send (wine, cream, the card radius) */
  #pager .stop1 .r5-join { width: 220px; margin: 28px 0 0; padding: 0 14px; }
  #pager .stop1 .deck-seat { margin: 0; padding: 0; }
  /* the stack is the page's own (night cards, its offsets, rotations and brightness dim),
     only at the desktop card size */
  #pager .stack { max-width: none; width: var(--col-card); height: calc(var(--col-card) * 1.32 + 14px); margin: 0; }
  #pager .stack .held { width: var(--col-card); }
  #pager .stack .held .wish-full { position: relative; }
  /* the launch note: an eyebrow ABOVE the stack, centred on the front card (the object box
     = the front card), 40 over the highest rear corner (desktop.js measures --r8-note-gap) */
  #pager .stop1 .caption-w { position: absolute; left: 0; right: 0; bottom: calc(100% + var(--r8-note-gap, 24px)); margin: 0; }
  #pager .stop1 .caption-w .launch-note { margin: 0; text-align: center; font-size: clamp(14px, calc(1.04 * var(--dvw)), 17px); font-weight: 500; letter-spacing: var(--track-caps); color: var(--text-2); opacity: 1; }

  /* ================= 2 · THE DEMO — a centred stage =================
     narrator (one line, centred) → the progress line → the card → the ask. The two
     voices stand beside the card (no tails): Alex upper-left, Jamie lower-right. */
  /* the demo card: ×0.92 of the hero card (every rule inside the demo reads --col-card) */
  #pager #mech { --col-card: calc(min(clamp(358px, calc(27.2 * var(--dvw)), 540px), calc((calc(77.67 * var(--dvh)) - 68px) / 1.32)) * 0.92);
    display: flex; flex-direction: column; justify-content: center; align-items: center; }
  #pager .r5-mech { display: flex; flex-direction: column; align-items: center; }
  #pager .m3 .m3-head { width: min(1000px, calc(100 * var(--dvw)) - 64px); margin: 0; }
  #pager .m3 .nzone { height: calc(46px * 1.14); min-height: 0; margin: 0; }
  #pager .m3 .nz { left: 0; right: 0; margin: 0; text-align: center; white-space: nowrap; line-height: var(--lh-headline); max-width: none; }
  #pager .m3 .nz.act, #pager .m3 .nz .nz-sub { font-size: var(--fs-index); }
  #pager .m3 .nz.act { padding-top: 12px; }
  #pager .m3 .pzone { margin-top: 16px; padding: 0; height: 44px; }   /* one 44 seat for the line AND the rest-state Replay (no jump at the end) */
  /* the progress LINE on desktop (the computed result of the page's p-line mode, set here so
     it needs no script and phones keep the dots): 160 × 2, centred under the narrator */
  #pager .m3 .mp-line { width: 160px; height: 2px; }
  #pager .m3:not(.rested) .mp-line { display: block; }
  #pager .m3 .mprog { display: none; }
  #pager .m3 .mp-replay { font-size: 15px; height: auto; padding: 10px 8px; font-weight: 600; letter-spacing: var(--track-caps); color: var(--ink); }   /* Replay: a real secondary action */
  #pager .r5-stage { position: relative; margin-top: 36px; width: var(--col-card); }
  #pager .m3 .demo { width: var(--col-card); margin: 0; }
  #pager .m3 .m3-seat { margin: 0; }
  #pager .m3 .vzone { position: absolute; inset: 0; height: auto; margin: 0; padding: 0; pointer-events: none; }
  #pager .m3 .vlabel { margin-bottom: 8px; }
  /* the voices: 40 italic, 96 off the card */
  #pager .m3 .vz { font-size: var(--disp-headline); left: auto; right: calc(100% + 96px); top: 12%; bottom: auto; width: max-content; white-space: nowrap; text-align: right; }
  #pager .m3 .vz.right { right: auto; left: calc(100% + 96px); top: 58%; text-align: left; }
  #pager .m3 .r5-mech > .wrap:last-child { margin-top: 36px; }
  #pager .m3 .anchor-ask { margin: 0; text-align: center; }
  /* the closing beat under the card — 44 italic, a proportionally heavier ink */
  #pager .m3 .anchor-ask a { font-size: 44px; }
  #pager .m3 .anchor-ask .ink-u { bottom: -12px; height: 14px; }
  #pager .m3 .anchor-ask .ink-u path { stroke-width: 3.2; }

  /* ================= 3 · THE 170 — the belt behind the copy =================
     the stream runs the whole width as a slow belt (desktop.js: two identical sets,
     22 px/s, wrapped by one set width; drag moves it). The copy sits over it; the
     track's mask = the edge fades ∩ a rectangular reading field around the copy
     (an SVG mask desktop.js generates into --r9-field). */
  #pager #b1 { display: flex; flex-direction: column; justify-content: center; }
  #pager .r5-b1 { display: flex; flex-direction: column; align-items: center; width: 100%; }
  #pager .r5-rail { position: relative; width: 100%; }
  #pager .b1 .stream { margin: 0; padding: 14px 0; overflow: hidden; scroll-snap-type: none; touch-action: pan-y; cursor: grab; }
  #pager .b1 .stream.r9-drag { cursor: grabbing; }
  #pager .b1 .r9-belt { display: flex; gap: 24px; width: max-content; will-change: transform; }
  #pager .r5-track {
    width: 100%;
    mask-image: linear-gradient(to right, transparent 0, #000 160px, #000 calc(100% - 200px), transparent 100%), var(--r9-field, linear-gradient(#fff, #fff));
    mask-mode: alpha, alpha;   /* the field SVG carries its own luminanceToAlpha */
    mask-size: 100% 100%, 100% 100%;
    mask-repeat: no-repeat;
    mask-composite: intersect;
  }
  #pager .b1 .stream .slot { width: var(--r5-stream); flex-basis: var(--r5-stream); height: calc(var(--r5-stream) * 1.32); }
  #pager .b1 .stream .slot .wish-full { transform: scale(calc(var(--r5-stream) / 350px)); }
  @supports not (transform: scale(calc(1px / 1px))) {   /* no typed division: the number from cardscale.js (default 1) */
    #pager .b1 .stream .slot .wish-full { transform: scale(var(--r5-stream-scale, 1)); }
  }
  #pager .b1 .r5-b1copy {
    position: absolute; left: max(var(--r5-m), 48px); top: 50%; z-index: 3;
    transform: translateY(-50%); padding: 0;
    display: flex; flex-direction: column;
    pointer-events: none;
  }
  #pager .b1-lock .num { font-size: 146px; }
  #pager .b1-lock .noun { font-size: 16px; }
  #pager .b1-sub { max-width: 30ch; }
  #pager .b1 .b1-lock { flex-direction: column; align-items: flex-start; gap: 18px; margin: 28px 0 0; }
  #pager .b1 .b1-lock .noun { letter-spacing: var(--track-caps); padding-left: 4px; }
  #pager .b1 .b1-sub { margin: 20px 0 0; }
  /* the ask on night stock, in the page's night madder voice (madder-lum) */
  #pager .b1 .r5-ask { margin: 50px 0 0; text-align: center; }
  #pager .b1 .r5-ask a { font-size: 32px; color: var(--madder-lum); }
  #pager .b1 .send-seat { margin: 24px 0 0; padding: 0; }
  #pager .b1 .btn-send { width: 200px; margin: 0; }

  /* ================= 4 · THE PACKS — the whole library at once =================
     sans copy left; all seven packs as a static 4 + 3 spread (the second row half a
     pack to the right) emerging from behind the copy and cropping past the right edge;
     the bridge bottom-centre with its hand-drawn arrow. */
  #pager #b2 {
    display: grid;
    grid-template-columns: max(var(--r5-m), 48px) 456px minmax(0, 1fr);
    grid-template-rows: 1fr auto 1fr;
    position: relative;
  }
  #pager #b2 > .r5-copy { grid-column: 2; grid-row: 2; align-self: center; position: relative; z-index: 2; }
  /* the field: desktop.js sets its left (--r9-field-pad) and the ellipse around the copy
     (--r8-*); lifted so its centre sits at ≈ 46 % of the stop; its mask = the right-edge
     fade ∩ a soft elliptical dissolve around the copy */
  #pager #b2 > .r5-spread { grid-column: 2 / -1; grid-row: 2; align-self: center; min-width: 0;
    position: relative; z-index: 1; padding-left: var(--r9-field-pad, 165px);
    translate: 0 calc(-4 * var(--dvh));
    --r8-cx: 0px; --r8-cy: 50%; --r8-rx: 400px; --r8-ry: 300px; --r8-core: 60%;
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 280px), transparent calc(100% - 16px)),
      radial-gradient(ellipse var(--r8-rx) var(--r8-ry) at var(--r8-cx) var(--r8-cy), transparent 0, transparent var(--r8-core), rgba(0,0,0,.35) calc(var(--r8-core) + (100% - var(--r8-core)) * .45), rgba(0,0,0,.8) calc(var(--r8-core) + (100% - var(--r8-core)) * .75), #000 100%);
    -webkit-mask-composite: source-in;
            mask-image: linear-gradient(to right, #000 calc(100% - 280px), transparent calc(100% - 16px)),
      radial-gradient(ellipse var(--r8-rx) var(--r8-ry) at var(--r8-cx) var(--r8-cy), transparent 0, transparent var(--r8-core), rgba(0,0,0,.35) calc(var(--r8-core) + (100% - var(--r8-core)) * .45), rgba(0,0,0,.8) calc(var(--r8-core) + (100% - var(--r8-core)) * .75), #000 100%);
            mask-composite: intersect; }
  #pager .price .fig { font-size: var(--disp-xl); }
  #pager .price .unit { font-size: var(--fs-nav); margin-left: 11px; }
  #pager .free { max-width: none; }
  #pager .b2 .head { padding: 0; }
  #pager .b2 .model { padding: 0; margin-top: 32px; text-align: left; }
  #pager .b2 .prop { margin: 0; }
  #pager .b2 .price { margin: 20px 0 0; justify-content: flex-start; }
  #pager .b2 .free { margin: 14px 0 0; width: 440px; text-wrap: pretty; }
  #pager .b2 .pack-count { display: none; }
  #pager .b2 .pack-seat {
    width: calc(var(--r5-pack) * 4 + var(--r5-pack-gap) * 3);
    height: calc(var(--r5-pack) * 0.8386 * 2 + var(--r5-pack-row));
    margin: 0; cursor: default;
  }
  #pager .b2 .pack-seat .pk {
    inset: auto; width: var(--r5-pack); height: calc(var(--r5-pack) * 0.8386);
    transform: none; opacity: 1; transition: none;
  }
  #pager .b2 .pack-seat .pk .pack-card { transform: scale(calc(var(--r5-pack) / 316px)); }
  @supports not (transform: scale(calc(1px / 1px))) {   /* no typed division: the number from cardscale.js (default 1) */
    #pager .b2 .pack-seat .pk .pack-card { transform: scale(var(--r5-pack-scale, 1)); }
  }
  #pager .b2 .pack-seat .pk:nth-child(-n+4) { top: 0; }
  #pager .b2 .pack-seat .pk:nth-child(n+5) { top: calc(var(--r5-pack) * 0.8386 + var(--r5-pack-row)); }
  #pager .b2 .pack-seat .pk:nth-child(1) { left: 0; }
  #pager .b2 .pack-seat .pk:nth-child(2) { left: calc((var(--r5-pack) + var(--r5-pack-gap)) * 1); }
  #pager .b2 .pack-seat .pk:nth-child(3) { left: calc((var(--r5-pack) + var(--r5-pack-gap)) * 2); }
  #pager .b2 .pack-seat .pk:nth-child(4) { left: calc((var(--r5-pack) + var(--r5-pack-gap)) * 3); }
  #pager .b2 .pack-seat .pk:nth-child(5) { left: calc((var(--r5-pack) + var(--r5-pack-gap)) * 0.5); }
  #pager .b2 .pack-seat .pk:nth-child(6) { left: calc((var(--r5-pack) + var(--r5-pack-gap)) * 1.5); }
  #pager .b2 .pack-seat .pk:nth-child(7) { left: calc((var(--r5-pack) + var(--r5-pack-gap)) * 2.5); }
  /* the bridge: bottom-centre; the hand-drawn down stroke under the words (not the page's ⟶) */
  #pager #b2 > .r5-bridge { position: absolute; left: 0; right: 0; bottom: 44px; text-align: center; }
  #pager .b2 .bridge-seat { margin: 0; text-align: center; }
  #pager .b2 .bridge { padding: 0; margin: 0; }
  #pager .b2 .bridge a { padding-block: 0; }
  #pager .b2 .bridge a .cta-arrow { display: none; }
  #pager .b2 .bridge .r8-down { display: block; width: 20px; height: 44px; margin: 10px auto 0; overflow: visible; }
  #pager .b2 .bridge .r8-down path { fill: none; stroke: var(--madder-lum); stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }

  /* ================= 5 · OCTOBER — one centred column over the strip drawing =================
     440 wide, centred; October 140–200 with the height; the full-width strip (3 : 1) along
     the floor, behind the column (desktop.js lifts the column if the consent would come
     within 24 of the strip's ink). */
  #pager #s4b { display: flex; flex-direction: column; align-items: center; justify-content: center; position: relative; overflow: clip; }
  #pager .r5-col { position: relative; z-index: 1; width: 440px; text-align: center; }
  #pager .launch-sub { max-width: none; }
  #pager .facts { font-size: var(--fs-body); }
  #pager .s4b .head { padding: 0; display: flex; flex-direction: column; align-items: center; }
  #pager .s4b .fig-oct { display: inline-block; width: auto; margin: 18px 0 0; padding: 0; font-size: clamp(140px, calc(calc(60 * var(--dvh)) - 340px), 200px); }   /* 200 from 900 tall, 140 at 800 */
  #pager .s4b .offer { margin: 40px 0 0; padding: 0; }
  #pager .s4b .offer .line { margin: 10px 0 0; max-width: none; white-space: nowrap; }
  #pager .s4b .claim { width: 100%; margin: 0; padding: 32px 0 0; }
  #pager .s4b .claim .launch-sub { margin: 0 0 16px; }
  #pager .s4b .facts { margin-top: 16px; text-align: center; color: var(--text-2); }
  #pager .s4b .r5-scene {
    position: absolute; left: 0; right: 0; bottom: 0; width: auto; height: auto; aspect-ratio: 3 / 1; z-index: 0;
    pointer-events: none; background: url(../assets/desktop/october-strip.webp) no-repeat center bottom / 100% auto;
  }
  /* the ink underline is normalised by desktop.js (one path, the stroke scaled to the type,
     one offset under the baseline); October's is drawn with a longer dash */
  #pager .s4b .oct-ink path { stroke-dasharray: 230; stroke-dashoffset: 230; }
  /* short screens (≤ 820 tall): the column's two big steps tighten so the consent keeps
     24 over the strip's ink */
  @media (max-height: 820.98px) {
    #pager .s4b .offer { margin-top: 24px; }
    #pager .s4b .claim { padding-top: 20px; }
  }

  /* ================= 6 · THE FOOTER — a full stop =================
     the wordmark at 150 with a short ink stroke and the hoops drawing (left block), the
     imprint on the right margin; the wordmark's cap and the imprint's first cap share one
     line (text-box trims the first lines to the cap). */
  #pager #foot {
    height: 100%; min-height: 0;
    display: grid;
    grid-template-columns: var(--r5-m) minmax(0, 1fr) max-content var(--r5-m);   /* the left block in a flexible track (the 640 drawing must not push the margin) */
    grid-template-rows: max(36%, min(42%, calc(100% - 567px))) 1fr;   /* the caps at 0.42 where the 320 drawing fits (≥ 56 under it), down to 0.36 */
    align-items: start;
  }
  #pager .fs-links a { font-size: var(--fs-nav); }
  #pager #foot > .r5-foot-l, #pager #foot > .r5-foot-r { grid-row: 2; }
  #pager #foot .fs-mark .wm, #pager #foot > .r5-foot-r > :first-child { text-box: trim-start cap alphabetic; }
  #pager #foot > .r5-foot-r > :first-child { margin-top: 0; }   /* the imprint opens on its first line ("For couples. 18+." since 09-28) */
  #pager #foot > .r5-foot-l { grid-column: 2; }
  #pager #foot > .r5-foot-r { grid-column: 3; }
  #pager #foot .fs-mark { margin: 0; }
  #pager #foot .fs-mark .wm { display: block; font-size: 150px; line-height: 0.92; margin-left: -0.03em; }
  #pager #foot .r5-mark-ink { height: 14px; margin-top: 20px; font-size: 150px; }   /* the ink stroke scales with the wordmark it marks */
  #pager #foot .r5-mark-ink .ink-u { display: block; width: 100%; height: 100%; overflow: visible; }
  #pager #foot .r5-mark-ink path { fill: none; stroke: var(--madder); stroke-linecap: round; }
  /* the hoops: 640 × 320, 32 under the mark; yields on short screens (≥ 56 air under it) */
  #pager #foot .r5-earrings { height: min(320px, calc(calc(64 * var(--dvh)) - 247px)); aspect-ratio: 2 / 1; width: auto; margin-top: 32px; pointer-events: none;
    background: url(../assets/desktop/footer-hoops.webp) left center / contain no-repeat; }
  #pager #foot .fs-notes, #pager #foot .fs-links { margin-top: 32px; }

  /* ================= motion =================
     THE CTA CUE (every wine button): every 7 s the button hops (staggered 2 s by
     desktop.js). Hover: the ground one step darker over 160 ms — a colour change only;
     neither the button nor its label moves (a lift took the button from under a pointer at
     its lower edge and it flickered; Alex 09-28). Reduced motion: hover only. */
  #pager .r5-join, #pager #sendBtn, #pager .btn-slab { transition: background-color 160ms var(--ease-out); }
  #pager .r5-join:hover, #pager #sendBtn:hover, #pager .btn-slab:hover { background: color-mix(in srgb, var(--wine) 86%, var(--ink)); }
  #pager .r9-lbl { display: inline-block; }
  /* keyboard focus on the layer's own controls, in the page's focus style (a 2 px outline,
     3 px off; ink on the light grounds, bone on night stock) */
  #pager .r5-join:focus-visible, #pager .m3 .mp-replay:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }
  #pager .b1 .r5-ask a:focus-visible, #pager .b2 .bridge a:focus-visible { outline: 2px solid var(--bone); outline-offset: 3px; }
  @media (prefers-reduced-motion: no-preference) {
    #pager .r5-join, #pager #sendBtn, #pager .btn-slab { animation: r10-hop 7s var(--ease-out) infinite; }
  }
  @keyframes r10-hop {
    0%, 90% { transform: none; }
    93% { transform: translateY(-5px); }
    96% { transform: translateY(0); }
    98% { transform: translateY(-1.5px); }
    100% { transform: none; }
  }
  /* reduced motion: the layer re-inks October with a longer dash (230) at a higher
     specificity than the page's own reduced-motion rule — restate that rule's result here,
     or the underline never draws when motion is off */
  @media (prefers-reduced-motion: reduce) {
    #pager .s4b .oct-ink path,
    #pager .s4b.ink-on .oct-ink path { stroke-dashoffset: 0; animation: none; }
  }

  /* ================= above 1920 wide: the 1920 picture, enlarged =================
     desktop.js sets k = max(1, min(innerWidth / 1920, innerHeight / 844)); when k > 1 it puts
     .k-scaled, --k, --dvw and --dvh (the LOCAL box's 1 %) on <html>. The pager is laid out at
     the local size and scaled by k from its top-left corner, so a 2560 × 1300 window shows the
     1920 × 975 page, 1.333× bigger; nothing is rearranged. The height term keeps the local
     height ≥ 844, above every height tier here and in page.css, so the media queries (the real
     window) and the layout (the local box) never disagree about a tier. No script ⇒ no class
     ⇒ unscaled. */
  /* THE FIRST PAINT: the pager stays unseen until desktop.js has regrouped the page
     (.r5-ready on <html>), then comes in over the ground. Unseen, not unbuilt: the layout and
     every measurement run as usual. The time limit is the page's own: with no script, or a
     script that never ran, the pager shows itself after 1.5 s. */
  html:not(.r5-ready) #pager { visibility: hidden; animation: r5-show 0s linear 1.5s forwards; }
  @keyframes r5-show { to { visibility: visible; } }
  html.r5-ready #pager { animation: r5-in 240ms var(--ease-out) backwards; }
  @keyframes r5-in { from { opacity: 0; } }
  @media (prefers-reduced-motion: reduce) { html.r5-ready #pager { animation: none; } }

  html.k-scaled #pager {
    right: auto; bottom: auto;
    width: calc(100vw / var(--k)); height: calc(100vh / var(--k));
    transform: scale(var(--k)); transform-origin: 0 0;
  }
  /* page.css rules still active on desktop that read the REAL viewport, restated in local units */
  html.k-scaled .m5-fx.fx-fall .mp { animation-name: mpFallK; }
  @keyframes mpFallK {   /* page.css's mpFall (the demo's confetti) with vh → the local --dvh */
    0%   { transform: translate(0, 0) rotate(0deg) scale(0.4); opacity: 0; }
    6%   { transform: translate(calc(var(--sway) * 0.12), calc(var(--rise) * -0.3))
                      rotate(calc(var(--spin) * 0.06)) scale(0.64); opacity: 1; }
    15%  { transform: translate(calc(var(--sway) * 0.3), calc(var(--rise) * -0.75))
                      rotate(calc(var(--spin) * 0.15)) scale(1); }
    20%  { transform: translate(calc(var(--sway) * 0.4), calc(var(--rise) * -1))
                      rotate(calc(var(--spin) * 0.2)) scale(1); }
    32%  { transform: translate(calc(var(--sway) * 0.1), calc(var(--rise) * -0.94))
                      rotate(calc(var(--spin) * 0.32)) scale(1); }
    42%  { transform: translate(calc(var(--sway) * -0.15), calc(var(--rise) * -0.802 + 8.24 * var(--dvh)))
                      rotate(calc(var(--spin) * 0.42)) scale(1); }
    62%  { transform: translate(calc(var(--sway) * 0.55), calc(var(--rise) * -0.525 + 24.71 * var(--dvh)))
                      rotate(calc(var(--spin) * 0.62)) scale(1); }
    82%  { transform: translate(calc(var(--sway) * 0.05), calc(var(--rise) * -0.249 + 41.18 * var(--dvh)))
                      rotate(calc(var(--spin) * 0.82)) scale(1); }
    92%  { transform: translate(calc(var(--sway) * 0.411), calc(var(--rise) * -0.111 + 49.41 * var(--dvh)))
                      rotate(calc(var(--spin) * 0.92)) scale(1); opacity: 1; }
    100% { transform: translate(calc(var(--sway) * 0.7), calc(56 * var(--dvh)))
                      rotate(var(--spin)) scale(1); opacity: 0; }
  }

  /* ================= the desktop size tiers (see THE SIZE RULES below) ================= */
  /* 3 · BELOW THE DESKTOP FLOOR — a desktop window shorter than 690 (measured: every stop
     fits from 680; 690 leaves 6–22 px at each stop's foot): every stop keeps the 690-tall
     layout (the layer's height unit is pinned to the floor) and the page scrolls softly. */
  @media (max-height: 689.98px) {
    :root { --dvh: 6.9px; }
    #pager { scroll-snap-type: y proximity; }
    #pager > section, #pager > #foot { height: 690px; scroll-snap-stop: normal; }
  }
  /* 4 · THE DEMO'S VOICES, 1024 to 1279 wide (tablets on their side): the voices stay beside
     the card and on the screen — the gap closes from 96 to 40 and the type follows the room
     (40 at 1280 → 32 at 1024; 8.7 = the longest voice's width in em). */
  @media (max-width: 1279.98px) {
    #pager .m3 { --r5-vgap: calc(40px + (calc(100 * var(--dvw)) - 1024px) * 0.21875); }
    #pager .m3 .vz { right: calc(100% + var(--r5-vgap)); font-size: min(40px, calc(((calc(100 * var(--dvw)) - var(--col-card)) / 2 - var(--r5-vgap) - 32px) / 8.7)); }
    #pager .m3 .vz.right { right: auto; left: calc(100% + var(--r5-vgap)); }
  }
}

/* ======================= THE PHONE FOOTER ART (≤ 430) =======================
   the hoops drawing as a plain background image on the footer stop (the centred column
   restates it at 430 below), anchored to the floor, wider than the screen and cropped by
   it. A background, not a pseudo-element: a pseudo-element's own stacking context
   re-rasterised the rounded corners of the form on the stop above. */
@media (max-width: 430.98px) {
  #pager #foot {
    background-image: url(../assets/desktop/footer-hoops.webp);
    background-repeat: no-repeat;
    background-size: 146vw auto;
    /* the two hoops' centre (45.5 % of the drawing) on the screen's centre; the drawing hangs
       12vw below the floor: both hoops stay whole (their lowest ink is at 79 % of the drawing),
       only the fabric lines crop — at both side edges and the floor */
    background-position: calc(50vw - 146vw * 0.455) calc(100% + 12vw);
  }
}

/* ======================= THE SIZE RULES (2026-09-28) =======================
   Designed sizes: phones 375–430 wide from a 629-tall window up (the 375 × 812 phone class
   in Safari — the app's floor phone); desktop from 1280 × 800 up. Everything else gets one
   of four fallback rules. None of them changes a designed size. Rules 3 and 4 (below the
   desktop floor; the demo's voices at 1024–1279) live inside THE LAYER above. */

/* 1 · THE CENTRED PHONE COLUMN — 431 to 1023 wide (tablets held upright, large phones, small
   windows). Alex 09-28. The page computes its grid from 100vw; each rule restates a 100vw
   value as its value at 430, so the page is the 430 phone page, centred. */
@media (min-width: 431px) and (max-width: 1023.98px) {
  .b1 .wrap, .b2 .wrap, .s4b .wrap { padding-inline: max(var(--edge-type), calc((430px - var(--col-card)) / 2)); }
  /* the stream is a phone-wide window: one whole card at rest, the neighbours peek as at 430 */
  .stream { width: 100%; max-width: 430px; margin-inline: auto; padding-inline: max(22px, calc((430px - var(--col-card)) / 2)); }
  .s4b .claim { margin-inline: auto; }
  /* the two lone lines that sit at an edge of the phone's column — "Coming October on
     iPhone" (right) and "Want to try it?" (left) — are centred here: in the wide empty
     field the edge reads as nothing and the line hangs in the air (Alex 09-28). The note
     keeps the page's −0.22em right margin, which offsets its trailing tracking, so its ink
     sits on the centre. */
  .caption-w .launch-note { text-align: center; }
  .m3 .anchor-ask { text-align: center; }
  /* the sizes still growing at 430 */
  .fig-oct, .fs-mark .wm { font-size: 70.95px; }
  .fig170 { font-size: 309.6px; }
  /* the footer drawing: its 430 size (627.8 = 146vw there), growing only as far as it takes
     for the fabric lines to run off both screen edges (110vw = 50vw / 0.455, the hoops'
     centre); the hoops stay on the screen's centre, hanging 8.22 % of the width below the floor */
  #pager #foot {
    --hoops-w: max(627.8px, 110vw);
    background-image: url(../assets/desktop/footer-hoops.webp);
    background-repeat: no-repeat;
    background-size: var(--hoops-w) auto;
    background-position: calc(50vw - var(--hoops-w) * 0.455) calc(100% + var(--hoops-w) * 0.0822);
  }
}
/* a TALL centred column (tablets held upright, from 900 tall): the phone page shares its
   spare height out evenly between its pieces, and with a tablet's spare height the pieces
   drift apart. Here the top of a stop is set tight and its closing link keeps the bottom,
   at one distance on every stop; the spare height collects above the link (Alex 09-28) */
@media (min-width: 431px) and (max-width: 1023.98px) and (min-height: 900px) {
  :root { --tab-foot: clamp(32px, 5.9vh, 64px); }
  /* the hero: headline → 40 → "Coming October" → 44 → the card */
  .stop1 .caption-w { margin-top: 40px; }
  .stop1 .deck-seat { margin-top: 32px; margin-bottom: 0; }
  .stop1 .hero-cta { margin-top: auto; margin-bottom: var(--tab-foot); }
  /* the demo: "Want to try it?" goes to the bottom, on the hero link's line */
  .m3 .m3-seat + .wrap { margin-block: auto 0; }
  .m3 .sp-b { flex: 0 0 calc(var(--tab-foot) + 10px); }
}
@media (min-width: 431px) and (max-width: 1023.98px) and (max-height: 760px) {
  .fig170 { font-size: 189.2px; }
}
@media (min-width: 431px) and (max-width: 1023.98px) and (max-height: 700px) {
  .fig-oct { font-size: 64px; }
}

/* 2 · BELOW THE PHONE FLOOR — a window shorter than 629 (iPhone SE and 8 in Safari, in-app
   browsers, a phone on its side, Display Zoom). The app's floor law: the page keeps its
   layout and scrolls. Stops already grow with their content (min-height: 100%); only the
   snapping is relaxed, so a stop taller than the window can be read to its foot. */
@media (max-width: 1023.98px) and (max-height: 628.98px) {
  #pager { scroll-snap-type: y proximity; }
  #pager > section { scroll-snap-stop: normal; }
}
