/* /v6 — fixed 1122px pixel-match skin for the painted reference mockup.
   Everything lives on a 1122x1897 stage and is absolutely positioned in
   reference-image coordinates, so the render overlays reference.png 1:1 —
   down to y=690, where the painted "How Noodl works" block used to be. That
   block was replaced on 2026-08-03 by the ten-card "Everything you need" grid,
   which has no painted counterpart, so nothing below y=690 traces the plate any
   more. The same day the two painted sections that followed the grid — the
   flexibility evolution and the badge shelf — were cut; the CTA banner is the
   only block left below the grid, hung 60px under the last card row rather than
   at its reference y. Scoped under body.v6 so it cannot leak into the other
   landing versions.

   Since 2026-08-03 the 1122x1897 stage described above is only served to
   /v6-full, the frozen complete page. The homepage adds `v6-hero` to the body
   and stops at 720px — nav + hero, one screen, no scroll — so every rule below
   the hero still exists but nothing on / matches it. Nothing here may be
   deleted for being unused by the homepage; /v6-full is what it is for. */

body.v6 {
  --v6-cream: #FCF4EA;
  --v6-card: #FBF4E9;
  --v6-card-line: #EEE3CF;
  --v6-beige: #FAF0E1;
  /* Named for the badge shelf's locked card, which was cut on 2026-08-03; the
     pair outlived it as the waitlist dialog's error colours. */
  --v6-locked-bg: #FAECD9;
  --v6-locked-line: #E89A6C;
  --v6-lavender: #E6DFF2;
  --v6-lavender-line: #343C3C;
  --v6-orange: #DD5605;
  --v6-orange-action: #C64B03;
  --v6-orange-l: #E4640C;
  --v6-green: #0F2A1B;
  --v6-body: #2C3A2F;
  --v6-muted: #37423A;
  --v6-navlink: #17281C;
  --v6-sans: "Avenir Next Condensed", "Avenir Next", "Helvetica Neue", Helvetica, Arial, sans-serif;

  margin: 0;
  background: var(--v6-cream);
  color: var(--v6-body);
  font-family: var(--v6-sans);
  -webkit-font-smoothing: antialiased;
}

body.v6 h1, body.v6 h2, body.v6 h3, body.v6 p, body.v6 ol, body.v6 ul, body.v6 dl,
body.v6 dt, body.v6 dd, body.v6 figure, body.v6 figcaption {
  margin: 0; padding: 0;
}
body.v6 ol, body.v6 ul { list-style: none; }
body.v6 img { display: block; max-width: none; }
body.v6 a { text-decoration: none; }

body.v6 .v6-skip {
  position: absolute; left: -9999px; top: 0; z-index: 90;
  background: var(--v6-green); color: #fff; padding: 10px 16px; border-radius: 0 0 10px 0;
  font: 600 15px/1 var(--v6-sans);
}
body.v6 .v6-skip:focus { left: 0; }

/* The stage: a fixed 1122x1897 canvas, centered. */
body.v6 .v6-stage {
  position: relative;
  width: 1122px;
  height: 1897px;
  margin: 0 auto;
  overflow: visible;   /* the hero scene deliberately bleeds past the stage */
  background: var(--v6-cream);
}
/* Hero-only homepage (2026-08-03). Same stage, cut off under the hero: 720 =
   the 68px nav band + the 668px painted scene, which is where the page now
   ends. Nothing else changes — the grid and banner rules below are still
   served in full to /v6-full, which keeps body class `v6` without this one.

   720 is not an arbitrary crop: the `@media (min-width: 1000px)` zoom rule
   already keys its height term to the same 720px (it was written to keep the
   hero above the fold on the long page). With the stage *being* 720px, that
   term now sizes the whole page. Change one number and the other has to change
   with it.

   Which of the zoom's two terms binds still depends on the window: at 1440x900
   (1.6) the height term wins and the scene fills the screen edge to edge, but
   on a window proportionally taller than the hero's 1122:720 — 1122x800, say —
   the width term wins and a band of page cream is left under the scene. That is
   the deliberate trade: `min()` never scales past the width, because scaling to
   cover would push the headline and the store badges off the sides on a tall
   narrow window. Cream under a hero is quiet; a cut-off headline is not.

   The clip is what makes "no scroll" true rather than nearly true. The phone
   deck's cream wash (.v6-phones::before) is a 700px-tall radial centred at
   y528, so it reaches stage y878 — 158px past the end of a 720px stage, which
   is enough to give the document a scrollbar with nothing in it. Clipping it
   costs nothing visually: below the painted scene the wash is page cream on
   page cream. Only the vertical axis is clipped — the hero scene's 300px bleed
   past each edge is the design, and body's overflow-x: hidden is what handles
   that. (Longhands, not the `visible clip` shorthand: a browser that does not
   know `clip` then drops one declaration instead of both.) */
body.v6-hero .v6-stage {
  height: 720px;
  overflow-x: visible;
  overflow-y: clip;
}

body.v6 .v6-stage main,
body.v6 .v6-stage section,
body.v6 .v6-stage header { display: block; }

/* Shared orange pill button */
body.v6 .v6-btn {
  position: absolute;
  display: block;
  background: var(--v6-orange-action);
  color: #fff;
  border-radius: 999px;
  text-align: center;
  font-weight: 600;
  letter-spacing: .01em;
  transition: background .15s ease;
}
body.v6 .v6-btn:hover { background: #B94704; }

body.v6 .v6-accent { color: var(--v6-orange); }
body.v6 .v6-accent-l { color: var(--v6-orange-l); }

/* ============================== NAV ============================== */
body.v6 .v6-brand {
  position: absolute; left: 47px; top: 8px; z-index: 10;
  display: block; width: 148px;
}
body.v6 .v6-brand-lockup {
  display: block;
  width: 148px;
  height: auto;
}

/* z-index matches .v6-brand above: the animated hero plate is hung at top:4px so
   it reaches up into the nav band, and the nav has to stay above it. */
body.v6 .v6-nav-links a {
  position: absolute; top: 29px; z-index: 10;
  font: 500 14.5px/14.5px var(--v6-sans);
  color: var(--v6-navlink); white-space: nowrap;
}
body.v6 .v6-nav-links a:hover { color: var(--v6-orange); }
/* Two links: "How it works" went with its section and Journey/Rewards went with
   theirs (both 2026-08-03). The 90px step from the four-link version is kept,
   but the pair is re-centred on the painted band's optical middle (x290..660,
   last label ending ~x598) instead of hugging its left edge, which would have
   left the whole right half of the band empty up to the CTA pill at x910. */
body.v6 .v6-nav-links a:nth-child(1) { left: 380px; }
body.v6 .v6-nav-links a:nth-child(2) { left: 470px; }

body.v6 .v6-nav-cta {
  left: 910px; top: 17px; width: 146px; height: 33px; z-index: 10;
  font: 600 15px/33px var(--v6-sans); letter-spacing: .03em;
}
body.v6 .v6-nav-cta-short { display: none; }

/* ============================== HERO ============================== */
/* The painted scene is 1722px wide — 300px of generated extension on each side of
   the original 1122px crop — so it can cover the full viewport width while the
   stage is scaled to fit the hero's height. Centred on the stage, it bleeds
   300px past both edges; body's overflow-x: hidden clips it to the window. The
   original crop sits in the middle: its inner ~982px are the untouched reference
   pixels, and only its outermost 70px on each side are cross-faded into the
   generated extension (a hard join showed a seam, because the generator redraws
   the interior and matches its edges to that redraw, not to the original). */
body.v6 .v6-hero-scene { position: absolute; left: -300px; top: 52px; width: 1722px; height: 668px; }

/* PREVIEW (2026-07-29): the animated plate. It sits in exactly the same box as
   the still scene, so `zoom` on the stage scales it identically. Desktop only,
   and only when motion is welcome — everywhere else it stays display:none and
   the page behaves exactly as it did before this existed. The still plate is
   left in the flow underneath rather than removed, so it remains the LCP image
   and the fallback if the video fails to decode.

   No z-index: it must not create a stacking context, or it would paint above
   the hero copy (h1, lede, buttons), which are all z-index:auto. Instead the
   element sits immediately after the still <picture> in the DOM, so among the
   auto-z siblings it paints over the still and under everything declared after
   it. The phone deck keeps its own z-index 2/3 and stays on top.

   The clip is 716px tall, not 668: Noodl rises out of his side bend as he
   stretches and reaches 37px above the plate's top edge at the peak (measured
   across every 4th frame), so the frame carries 48px of headroom above y=0 and
   is hung at top:4px to keep plate y=0 landing on stage y=52. That headroom
   band is flat cream apart from his hand — median deviation from the page cream
   is 8/765 — so it reads as page background, not as a taller image. */
body.v6 .v6-hero-motion,
body.v6 .v6-hero-motion-phones { display: none; }
/* Same (min-width: 1000px) and (min-aspect-ratio: 3/2) pair as the zoom block
   and the <picture>'s own source: the animated plate belongs to the painted
   fixed composition, and showing it while the layout has reflowed paints a
   second, differently-scaled copy of the scene over the copy. The three have to
   agree — they are one decision ("is this the desktop composition?") expressed
   in three places, because one of them is a markup attribute. */
@media (min-width: 1000px) and (min-aspect-ratio: 3/2) and (prefers-reduced-motion: no-preference) {
  body.v6 .v6-hero-motion {
    display: block;
    position: absolute; left: -300px; top: 4px; width: 1722px; height: 716px;
  }
}

/* ---- Hero phone deck -------------------------------------------------
   The three phones are lifted out of the painted scene into their own layers
   (the plate behind them was inpainted, so nothing is missing when they move).
   Positions are the cutouts' own bounding boxes in scene space, offset by the
   scene's own placement (-300px x, +52px y), so at rest they sit exactly where
   they were painted.

   Motion is vertical only, and deliberately so: the side phones are cut at the
   centre phone's edge, where their hidden strip was never painted. Vertical
   movement keeps that cut line behind the centre phone; horizontal movement
   would slide it out and expose a bite. */
/* The deck gets a box of its own so it can host the veil below. `inset: 0` makes
   it exactly the stage, so the phones' existing stage-space coordinates are
   unchanged; no transform is applied, so it does not become a stacking context
   and the phones keep painting at z-index 2/3 against the stage as before. */
body.v6 .v6-phones {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

/* The painted plaza is the same cream as the devices, so the deck had no edge to
   win on — it read as part of the painting rather than as the subject of it.
   This lifts a soft wash of page cream behind the phones: the scene keeps its
   detail at the edges and yields the middle, without repainting the plate.
   Sits at z-index auto, so it covers the plate and video (earlier siblings) but
   stays under the hero copy and the phones themselves. */
body.v6 .v6-phones::before {
  content: "";
  position: absolute;
  left: 544px;   /* deck centre — the phones span x 325–763, y 371–684 */
  top: 528px;
  width: 820px;
  height: 700px;
  transform: translate(-50%, -50%);
  background: radial-gradient(closest-side,
    rgba(252, 244, 234, .90) 0%,
    rgba(252, 244, 234, .74) 40%,
    rgba(252, 244, 234, .34) 68%,
    rgba(252, 244, 234, 0) 100%);
}

/* The plate has no shadows under the phones (they were erased with them), so
   the layers carry their own — drop-shadow follows the cutout's alpha, and it
   scales with the stage because zoom scales lengths.

   Two shadows, not one: a tight contact shadow that plants the device on the
   plaza, and a wide ambient one that separates it from the scene behind. The
   single .20 shadow this replaces read as neither, which is why the phones
   looked painted into the plate instead of standing in front of it. */
body.v6 .v6-phone-wrap { position: absolute; }
body.v6 .v6-phone {
  display: block;
  width: 100%;
  height: 100%;
  filter:
    drop-shadow(0 2px 3px rgba(94, 72, 43, .34))
    drop-shadow(0 16px 24px rgba(94, 72, 43, .20));
}
body.v6 .v6-phone-l { left: 325px; top: 393px; width: 144px; height: 291px; z-index: 2; }
body.v6 .v6-phone-r { left: 617px; top: 381px; width: 146px; height: 299px; z-index: 2; }
body.v6 .v6-phone-c { left: 469px; top: 377px; width: 153px; height: 313px; z-index: 3; }

/* ---- Signs of life inside the painted screens ------------------------
   The screens were the only completely static thing in an animated hero, which
   is a large part of why the deck read as scenery rather than as the product.
   These spans add motion *inside* the painted UI without redrawing any of it:
   each one covers a painted element's measured box and animates opacity only,
   so the illustration is untouched and the hand-drawn style is never in
   competition with live type or vector shapes.

   Boxes were measured off the @2x cutouts by colour-blob detection (the orange
   CTA pill, the orange streak count, the orange pause button, the six green
   consistency dots) and halved to CSS px, relative to each phone's own box.
   Everything is deliberately kept inside the painted screen area: nothing may
   spill over a bezel, which is also why these are soft fills rather than the
   outer glows they started as. */
body.v6 .v6-live {
  position: absolute;
  z-index: 1;
  opacity: 0;
  pointer-events: none;
}

/* left phone — the session is running, so the pause button breathes */
body.v6 .v6-live-pause {
  left: 122.5px; top: 213.5px; width: 17.5px; height: 17.5px;
  border-radius: 50%;
  background: radial-gradient(circle,
    rgba(255, 240, 222, .52) 0%, rgba(255, 216, 172, .22) 60%, rgba(255, 216, 172, 0) 100%);
}

/* centre phone — the primary CTA brightens, and the streak count warms up */
body.v6 .v6-live-cta {
  left: 13.5px; top: 236px; width: 125px; height: 23.5px;
  border-radius: 12px;
  background: linear-gradient(180deg, rgba(255, 255, 255, .34), rgba(255, 255, 255, .03));
}
body.v6 .v6-live-streak {
  left: 113px; top: 81px; width: 26px; height: 26px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 176, 88, .52) 0%, rgba(255, 176, 88, 0) 70%);
}

/* right phone — the consistency dots light up in order, left to right, which is
   the one bit of narrative in the deck: the streak filling in. Positions are the
   painted dots' own centres, so the tilt is inherited from the artwork. */
body.v6 .v6-live-dot {
  width: 9px; height: 9px;
  border-radius: 50%;
  background: radial-gradient(circle,
    rgba(236, 255, 230, .58) 0%, rgba(142, 222, 132, .26) 55%, rgba(142, 222, 132, 0) 100%);
}
body.v6 .v6-live-dot:nth-of-type(1) { left:  7.25px; top: 205.75px; }
body.v6 .v6-live-dot:nth-of-type(2) { left: 20.00px; top: 207.75px; }
body.v6 .v6-live-dot:nth-of-type(3) { left: 32.25px; top: 209.50px; }
body.v6 .v6-live-dot:nth-of-type(4) { left: 44.00px; top: 211.25px; }
body.v6 .v6-live-dot:nth-of-type(5) { left: 55.25px; top: 213.25px; }
body.v6 .v6-live-dot:nth-of-type(6) { left: 67.50px; top: 215.00px; }

@media (prefers-reduced-motion: no-preference) {
  /* `translate` and `transform` are separate properties, so the scroll-driven
     parallax and the idle float compose without fighting for one declaration. */
  @keyframes v6-phone-float { from { transform: translateY(0); } to { transform: translateY(-9px); } }
  /* Only the centre phone floats. With all three drifting on their own timings,
     ambient motion was everywhere in the hero and therefore drew the eye nowhere;
     one moving device inside a still deck reads as the subject. */
  body.v6 .v6-phone-c { animation: v6-phone-float 4.6s ease-in-out infinite alternate; }

  /* Scroll parallax, only where the browser really supports scroll timelines —
     without the guard the keyframes would run once on the time timeline and
     leave the deck parked at its end state. This stays on all three: it is depth
     cueing tied to the scroll, not ambient motion competing for attention. */
  @supports (animation-timeline: scroll()) {
    @keyframes v6-phone-rise-far  { to { translate: 0 -34px; } }
    @keyframes v6-phone-rise-near { to { translate: 0 -58px; } }
    body.v6 .v6-phone-l,
    body.v6 .v6-phone-r {
      animation: v6-phone-rise-far linear both;
      animation-timeline: scroll(root block);
      animation-range: 0 80vh;
    }
    body.v6 .v6-phone-c {
      animation: v6-phone-float 4.6s ease-in-out infinite alternate,
                 v6-phone-rise-near linear both;
      animation-timeline: auto, scroll(root block);
      animation-range: normal, 0 80vh;
    }
  }

  /* Signs of life. Slow and offset from each other on purpose: the point is that
     something in the screens is always just changing, not that three things
     blink together. Opacity only — no transforms, so none of these can drift out
     of register with the painted element underneath. */
  @keyframes v6-live-breathe { 0%, 100% { opacity: 0 } 50% { opacity: 1 } }
  body.v6 .v6-live-pause  { animation: v6-live-breathe 2.4s ease-in-out infinite; }
  body.v6 .v6-live-cta    { animation: v6-live-breathe 3.2s ease-in-out infinite; }
  body.v6 .v6-live-streak { animation: v6-live-breathe 3.2s ease-in-out .8s infinite; }

  /* The streak sweep: each dot lights briefly in turn, then the row rests for
     most of the cycle before filling again. */
  @keyframes v6-live-sweep {
    0%   { opacity: 0 }
    4%   { opacity: 1 }
    16%  { opacity: 0 }
    100% { opacity: 0 }
  }
  body.v6 .v6-live-dot { animation: v6-live-sweep 4.6s ease-in-out infinite; }
  body.v6 .v6-live-dot:nth-of-type(2) { animation-delay: .16s; }
  body.v6 .v6-live-dot:nth-of-type(3) { animation-delay: .32s; }
  body.v6 .v6-live-dot:nth-of-type(4) { animation-delay: .48s; }
  body.v6 .v6-live-dot:nth-of-type(5) { animation-delay: .64s; }
  body.v6 .v6-live-dot:nth-of-type(6) { animation-delay: .80s; }
}

body.v6 .v6-h1 {
  position: absolute; left: 48px; top: 103px;
  font: 600 65px/62.5px var(--v6-sans);
  color: var(--v6-green);
  letter-spacing: .038em;
}
body.v6 .v6-hero-spark { position: absolute; left: 400px; top: 104px; width: 32px; height: 44px; }

body.v6 .v6-lede {
  position: absolute; left: 52px; top: 240px;
  font: 500 16.3px/20px var(--v6-sans);
  color: var(--v6-body);
  letter-spacing: -.012em;
}

/* CUT 2026-07-31, both in the same pass: the painted "Start stretching" pill
   (left:52 top:293, 154x33) and the "Watch how it works" play link beside it
   (left:220 top:294, with a 32px ring and a 10x12.5 triangle). The pill was a
   duplicate of the App Store badge — both opened the waitlist — and the play
   link promised a video the page does not have. Desktop keeps the badges in
   that space; the separately art-directed mobile layout restores a primary CTA. */

/* App-store style buttons, directly under the lede. NOTE: these are CSS
   recreations, not Apple's / Google's official badge artwork — both require
   their own assets and have brand rules, so swap in the official badges (and
   real store URLs) at launch. Until then they read "Coming soon" and point at
   the waitlist, because there is nothing to download yet. */
body.v6 .v6-stores {
  position: absolute; left: 51px; top: 296px;
  display: flex; align-items: center; gap: 8px;
  z-index: 4;
}
body.v6 .v6-mobile-action { display: none; }
body.v6 .v6-mobile-cta {
  min-width: min(250px, 100%);
  min-height: 50px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 0 17px 0 20px;
  box-sizing: border-box;
  background: var(--v6-orange-action);
  color: #fff;
  border-radius: 999px;
  font: 600 16px/1 var(--v6-sans);
  letter-spacing: .01em;
  box-shadow: 0 3px 0 rgba(15, 42, 27, .20);
  transition: background .15s ease, transform .12s ease, box-shadow .12s ease;
}
body.v6 .v6-mobile-cta:hover { background: #B94704; }
body.v6 .v6-mobile-cta:active {
  transform: translateY(2px);
  box-shadow: 0 1px 0 rgba(15, 42, 27, .20);
}
body.v6 .v6-mobile-cta:focus-visible {
  outline: 2.5px solid var(--v6-green);
  outline-offset: 3px;
}
body.v6 .v6-store {
  display: flex; align-items: center; gap: 7px;
  height: 38px; padding: 0 11px;
  background: #16281B; color: #FFF9F0;
  border-radius: 9px;
  transition: background .15s ease, transform .15s ease;
}
body.v6 .v6-store:hover { background: #0C1A10; transform: translateY(-1px); }
body.v6 .v6-store small {
  display: block; font: 500 7.4px/9px var(--v6-sans);
  letter-spacing: .06em; text-transform: uppercase; opacity: .82;
}
body.v6 .v6-store strong { display: block; font: 600 13px/14px var(--v6-sans); letter-spacing: .005em; }
body.v6 .v6-store-web {
  background: transparent; color: var(--v6-green);
  border: 1.4px solid #B9C3B2; padding: 0 10px;
}
body.v6 .v6-store-web:hover { background: rgba(255,255,255,.5); border-color: #8E9C88; }

/* ============================ HEADINGS ============================ */
body.v6 .v6-h2 {
  position: absolute;
  color: var(--v6-green);
  font-weight: 600;
  letter-spacing: -.005em;
}
/* The one heading left, and it was never a left-rail label off the painted
   plate: it spans the stage and centres over the card grid, so it is set in the
   wider face the banner headline uses rather than the condensed one. */
body.v6 .v6-feat-h {
  left: 0; top: 752px; width: 1122px; text-align: center;
  font: 600 27px/34px "Avenir Next", var(--v6-sans);
}

/* ======================= EVERYTHING YOU NEED =======================
   Ten cards, five columns of 192px on a 206px pitch, which leaves the same
   53px of cream on both edges of the stage. Only the boxes are placed in stage
   coordinates: nothing in this section traces reference.png, so inside a card
   the content is ordinary flow and the card is tall enough for the longest of
   the ten bodies rather than measured off a plate. */
body.v6 .v6-featcard {
  position: absolute; width: 192px; height: 400px;
  background: var(--v6-card);
  border: 1px solid var(--v6-card-line);
  border-radius: 14px;
  overflow: hidden;
  box-sizing: border-box;
}
/* Column lefts repeat between the two rows, so they are grouped by column. */
body.v6 .v6-featcard-1, body.v6 .v6-featcard-6  { left: 53px; }
body.v6 .v6-featcard-2, body.v6 .v6-featcard-7  { left: 259px; }
body.v6 .v6-featcard-3, body.v6 .v6-featcard-8  { left: 465px; }
body.v6 .v6-featcard-4, body.v6 .v6-featcard-9  { left: 671px; }
body.v6 .v6-featcard-5, body.v6 .v6-featcard-10 { left: 877px; }
body.v6 .v6-featcard:nth-child(-n+5) { top: 840px; }
body.v6 .v6-featcard:nth-child(n+6)  { top: 1258px; }

/* Same painted-circle treatment as the old step numbers — highlight and halo,
   not a flat fill — in the page's dark green rather than terracotta, so ten of
   them in a row do not turn the grid orange. */
body.v6 .v6-feat-num {
  position: absolute; left: 14px; top: 12px; width: 28px; height: 28px;
  background: radial-gradient(circle at 32% 28%, #2E5B3E 0%, #1E4230 55%, #142E21 100%);
  box-shadow: 0 1px 3px rgba(15, 42, 27, .25);
  color: #fff; border-radius: 50%;
  font: 700 14px/28px var(--v6-sans); text-align: center;
}
/* The PNGs are transparent-background with the subject centred, so the art sits
   on the card's own cream; the top margin clears the number chip. */
body.v6 .v6-feat-art {
  margin: 44px auto 0; width: 140px; height: 180px;
  object-fit: contain;
}
body.v6 .v6-featcard h3 {
  margin: 14px 16px 0;
  font: 600 15.5px/19px "Avenir Next", var(--v6-sans);
  color: var(--v6-green);
}
body.v6 .v6-featcard > p {
  margin: 7px 16px 0;
  font: 400 12.3px/16.5px var(--v6-sans);
  color: var(--v6-body);
}

/* CUT 2026-08-03: "Your flexibility evolution" (the beige band, the five Noodl
   stages with their arrows and captions, and the bendiest-Noodl figure) and
   "Collect progress. Unlock joy." (the four unlocked badges, the locked card and
   the lounging Noodl) were both removed at Martin's call. The page ends on the
   feature grid and its CTA now. Their art is still in app/assets/images/v6/. */

/* ============================ CTA BANNER ============================ */
/* The whole block moved up 275px on 2026-08-03, when the evolution and badge
   sections between it and the feature grid were cut. Every coordinate below is
   its painted offset minus 275, so the banner's internal composition is
   untouched; it lands 60px under the grid's second row (which ends at y1658). */
body.v6 .v6-cta-band {
  position: absolute; left: 49px; top: 1718px; width: 1024px; height: 160px;
  /* Sampled from reference.png: the painted band averages (230,223,242) under the
     top border and lifts to about (233,226,244) near the bottom edge. */
  background: linear-gradient(180deg, #E6DFF2 0%, #E9E2F4 100%);
  border: 1.5px solid var(--v6-lavender-line);
  border-radius: 16px;
  box-sizing: border-box;
}
body.v6 .v6-cta-left { position: absolute; left: 49px; top: 1717px; width: 294px; height: 163px; z-index: 2; }
body.v6 .v6-cta-bird { position: absolute; left: 866px; top: 1742px; width: 208px; height: 139px; z-index: 2; }

body.v6 .v6-cta-h {
  position: absolute; left: 300.5px; top: 1738px; width: 501px;
  text-align: center; z-index: 3;
  /* The painted banner headline is set in a wider face than the condensed one
     used elsewhere: at the reference's 318px line-1 width its cap-to-baseline is
     only ~25px, which the condensed face cannot hit without heavy tracking. */
  font: 600 32px/36.5px "Avenir Next", var(--v6-sans);
  color: var(--v6-green); letter-spacing: 0;
}
/* Line 1 is tracked wider than line 2 in the painted reference (318px vs 204px),
   so each line keeps its own tracking. */
body.v6 .v6-cta-line1 { letter-spacing: 0; }
body.v6 .v6-cta-line2 { letter-spacing: -.037em; }
body.v6 .v6-cta-spark-l { position: absolute; left: 411px; top: 1776px; width: 27px; height: 35px; z-index: 3; }
body.v6 .v6-cta-spark-r { position: absolute; left: 663px; top: 1776px; width: 27px; height: 35px; z-index: 3; }

body.v6 .v6-cta-btn {
  left: 439px; top: 1820px; width: 216px; height: 34px; z-index: 3;
  font: 600 17px/38px var(--v6-sans); letter-spacing: .02em;
}
body.v6 .v6-cta-foot {
  position: absolute; left: 291px; top: 1862px; width: 499px; text-align: center; z-index: 3;
  font: 500 11px/12px var(--v6-sans); color: #3B443A;
}

/* Sticky note. The element itself is the BACK sheet; ::before paints the front
   sheet on top of it (a negative z-index child would still paint above the
   parent background, so the sheets are ordered this way instead). Every text
   offset below is therefore measured from the back sheet's box. */
body.v6 .v6-note {
  position: absolute; left: 765px; top: 1747px; width: 150px; height: 121px;
  background: #F6E1C8;
  border: 2px solid #2B2A26;
  border-radius: 3px;
  transform: rotate(-2.75deg);
  box-sizing: border-box;
  z-index: 6;
}
body.v6 .v6-note::before {
  content: ""; position: absolute; left: 5.5px; top: -7.5px; width: 150px; height: 121px;
  background: #FBEBD5; border: 2px solid #2B2A26; border-radius: 3px;
  box-sizing: border-box;
}
/* The two clips are painted upright in the reference, so they sit in stage
   coordinates outside the rotated note (sliced straight from reference.png). */
body.v6 .v6-note-clip { position: absolute; z-index: 7; }
body.v6 .v6-note-clip-l { left: 779px; top: 1738px; width: 10px; height: 16px; }
body.v6 .v6-note-clip-r { left: 852px; top: 1733px; width: 12px; height: 15px; }
body.v6 .v6-note-title {
  position: absolute; left: 0.5px; top: 8.5px; width: 100%; text-align: center;
  font: 600 11px/14px var(--v6-sans); color: #40403A;
  letter-spacing: .013em;
}
body.v6 .v6-note-body {
  position: absolute; left: 29.5px; top: 32px;
  /* Same wider face as the banner headline: the painted note lines are 89px and
     69px wide but only 10px tall, which the condensed face renders far too tall. */
  font: 600 10px/17px "Avenir Next", var(--v6-sans); color: #4A4A3E;
  letter-spacing: -.012em;
}
/* 20x17 heart, placed so it lands on the painted one (stage x886..906, y1831..1848)
   once the note's -2.75deg rotation is applied. */
body.v6 .v6-note-heart {
  position: absolute; left: 117.4px; top: 84.6px; width: 20px; height: 17px;
}

/* ============================== RESPONSIVE ==============================
   The stage is a fixed 1122x1897 canvas, so at any viewport other than exactly
   1122px it either leaves cream margins or does not fit. Down to 1000px the
   whole canvas is scaled instead of reflowed, which keeps the painted
   composition intact; below that, scaling would push the 10-12px caption text
   under 9px, so the layout reflows into a real fluid one instead.

   Every reflow rule repeats the stage class (`.v6-stage.v6-stage`). The fixed
   layout above reaches specificity (0,3,2) — `.v6-nav-links a:nth-child(1)` —
   and the reflow has to outrank it. Repeating one class is the least invasive
   way to do that: the alternative is gating 300 lines of pixel-matched CSS
   behind a media query and restating every colour, border and font under it. */

/* Scale the canvas to exactly fill the viewport width, at every width — so the
   design never sits in a column with cream margins beside it, and a wide screen
   gets a big hero rather than a small one floating in the middle.

   `zoom` is what makes this work at all: it scales layout (unlike `transform`,
   which would leave the page's height measured at the unscaled 1897px). The
   factor has to be a plain number, and CSS cannot divide a length by a length
   portably — `tan(atan2(a, b))` is the standard way to type-cast a ratio of two
   lengths into a unitless number, and is supported everywhere trig functions
   are. At exactly 1122px this evaluates to 1, so the pixel match is untouched. */
/* The canvas is only scaled while the window is at least as wide-shouldered as
   the hero itself (3/2 — see the note on the reflow block below). Narrower than
   that and there is no scale factor that both fills the screen and keeps the
   copy on it, so the fluid layout takes over instead. */
@media (min-width: 1000px) and (min-aspect-ratio: 3/2) {
  /* Fill the width, but never so much that the hero (nav + scene = 720px of the
     design) grows past the fold — whichever constraint binds first wins. On a
     window wider than the hero's 1122:720 aspect the height term binds, the
     stage is then narrower than the window, and the scene's 300px of extension
     on each side covers the difference. Everything below the hero is cream on a
     cream page, so a narrower stage leaves no visible edge there. */
  body.v6 .v6-stage {
    zoom: min(tan(atan2(100vw, 1122px)), tan(atan2(100svh, 720px)));
  }

  /* The hero-only page has nothing below the fold, so the same "narrower stage"
     that is invisible on /v6-full shows there as a band of cream under the
     scene — 12px on a 1512x982 laptop, and growing every time the window is
     narrowed. The fix is to let the height term win a little sooner: measuring
     the width against 1080px rather than the full 1122px canvas lets the stage
     run up to 3.9% wider than the window, which is exactly enough for the height
     term to bind at every aspect down to 3/2, where the reflow takes over.
     What the overflow costs: `margin: 0 auto` resolves to 0 once there is no
     free space, so the excess is cut from the right edge only, and the
     right-most thing on the canvas is the nav pill, which ends at x1056 — 94.1%
     of 1122, clear of the 96.1% where the cut starts. Everything past it is
     painted scenery and the scene's own bleed. */
  body.v6-hero .v6-stage {
    zoom: min(tan(atan2(100vw, 1080px)), tan(atan2(100svh, 720px)));
  }
}

/* 100vw counts the classic scrollbar that Windows/Linux reserve, which would
   leave the scaled canvas a scrollbar-width too wide. Clipping that is
   invisible; a permanent horizontal scrollbar would not be. */
body.v6 { overflow-x: hidden; }

/* Two triggers, and together with the query above they tile the whole space of
   window shapes — exactly one layout is always in force.

   The width trigger is the original one: under 1000px, scaling the canvas would
   push the 10-12px caption text below 9px.

   The aspect trigger (added 2026-08-03) is about the *shape* of the window, not
   its size. Dragging a laptop window narrower lowers the aspect until the
   canvas is being scaled to fit the width, which leaves it shorter than the
   window — harmless on a page that scrolls, but on the hero-only homepage it is
   a band of cream under the painting that grows as you drag. Below 3/2 no scale
   factor fixes that (covering the height would carry the headline off the side),
   so the fluid layout takes the job: it has no fixed height to run out of. */
@media (max-width: 999px), (max-aspect-ratio: 3/2) {

  body.v6 .v6-stage.v6-stage {
    width: auto; height: auto; overflow: visible;
    max-width: 860px; margin: 0 auto;
    padding: 0 20px 40px;
    box-sizing: border-box;
    /* Both aspect features are inclusive, so at exactly 3/2 the canvas query
       above matches too and its `zoom` would scale this fluid layout — a page
       1.39x bigger than the window. This block is later and one class more
       specific, so putting the reset here hands the tie to the fluid layout and
       makes the overlap harmless instead of load-bearing. */
    zoom: 1;
  }

  /* The hero-only page's 720px is a desktop-zoom device — it only means "one
     screen" while the stage is still the fixed canvas being scaled to fit.
     Here the layout is static and fluid, so a fixed height would either clip
     the scene or strand a band of cream under it. The rule above already
     resets height, but it ties with this selector on specificity, so state it
     explicitly rather than leave the hero page depending on source order.
     Mobile is allowed to scroll: it is one screen by intent, not by height. */
  body.v6-hero .v6-stage.v6-stage { height: auto; }

  /* Drop the whole fixed-stage coordinate system in one pass. */
  body.v6 .v6-stage.v6-stage :is(header, section, div, ol, ul, dl, li, figure,
                                 figcaption, aside, h1, h2, h3, p, dt, dd, a, span, img) {
    position: static;
    left: auto; top: auto; right: auto; bottom: auto;
    width: auto; height: auto;
  }
  body.v6 .v6-stage.v6-stage img { max-width: 100%; height: auto; }

  /* Decorative marks with nowhere to sit once the art is fluid. */
  body.v6 .v6-stage.v6-stage .v6-phones { display: none; }

  body.v6 .v6-stage.v6-stage :is(.v6-hero-spark,
                                 .v6-cta-spark-l, .v6-cta-spark-r,
                                 .v6-note-clip, .v6-cta-bird) { display: none; }

  /* Padding-sized rather than a fixed height + matching line-height: at 320px
     the label would wrap and spill straight out of the pill. */
  body.v6 .v6-stage.v6-stage .v6-btn {
    display: inline-block;
    padding: 12px 24px;
    height: auto;
    font-size: 15px; line-height: 1.15;
    letter-spacing: .02em;
    white-space: nowrap;
  }

  /* -------------------------------- nav -------------------------------- */
  body.v6 .v6-stage.v6-stage .v6-nav {
    display: flex; align-items: center; justify-content: space-between;
    flex-wrap: wrap; gap: 10px 16px;
    padding: 20px 0 6px;
  }
  body.v6 .v6-stage.v6-stage .v6-brand-wordmark { width: 122px; }
  body.v6 .v6-stage.v6-stage .v6-brand-sub { top: 51px; font-size: 12px; line-height: 13px; }
  body.v6 .v6-stage.v6-stage .v6-nav-links {
    order: 3; width: 100%;
    display: flex; flex-wrap: wrap; gap: 6px 20px;
    padding-top: 2px;
  }
  body.v6 .v6-stage.v6-stage .v6-nav-links a { font-size: 14.5px; }
  body.v6 .v6-stage.v6-stage .v6-brand {
    flex: 0 0 auto;
    display: block; width: 134px;
  }
  body.v6 .v6-stage.v6-stage .v6-brand-lockup { width: 134px; }
  /* Never let the pill shrink under its own label — if the row runs out of
     room it wraps to its own line instead of clipping the text. */
  body.v6 .v6-stage.v6-stage .v6-nav-cta { flex: 0 0 auto; white-space: nowrap; }

  /* ------------------------------- hero -------------------------------- */
  /* The hero owns the first screen: copy at the top, painted scene pinned to
     the bottom edge, so above the fold is the whole hero and nothing else. */
  /* Grid rather than flex-wrap, so the copy stays packed on rows 1-3 and the
     scene has a row of its own. */
  body.v6 .v6-stage.v6-stage .v6-hero {
    display: grid;
    grid-template-columns: auto auto;
    grid-template-rows: auto auto auto auto;
    justify-content: start; align-items: center;
    column-gap: 18px; row-gap: 14px;
    padding-top: 22px;
  }
  body.v6 .v6-stage.v6-stage .v6-h1 {
    grid-area: 1 / 1 / 2 / -1;
    font-size: clamp(34px, 8.4vw, 54px);
    line-height: 1.06;
    letter-spacing: .01em;
  }
  body.v6 .v6-stage.v6-stage .v6-lede {
    grid-area: 2 / 1 / 3 / -1;
    font-size: 16px; line-height: 22px;
  }
  body.v6 .v6-stage.v6-stage .v6-lede br { display: none; }
  /* Row 3 is the badges: the pill and the play link that used to hold rows 3 and
     4 were both cut on 2026-07-31. */
  body.v6 .v6-stage.v6-stage .v6-stores {
    grid-area: 3 / 1 / 4 / -1;
    position: static; gap: 8px; flex-wrap: wrap; padding-top: 2px;
  }
  /* the blanket reset above zeroes their height, which squashes the badges */
  body.v6 .v6-stage.v6-stage .v6-store { height: 42px; padding: 0 13px; }
  body.v6 .v6-stage.v6-stage .v6-store small { font-size: 8px; line-height: 10px; }
  body.v6 .v6-stage.v6-stage .v6-store strong { font-size: 14px; line-height: 15px; }
  body.v6 .v6-stage.v6-stage .v6-stores svg { width: 15px; height: 15px; }
  body.v6 .v6-stage.v6-stage .v6-hero-scene {
    grid-area: 4 / 1 / 5 / -1;
    width: calc(100% + 40px); max-width: none;
    margin: 12px -20px 0;
  }

  /* ------------------------- everything you need ------------------------ */
  body.v6 .v6-stage.v6-stage .v6-feat { padding-top: 34px; }
  body.v6 .v6-stage.v6-stage .v6-h2 {
    font-size: clamp(23px, 5.4vw, 28px); line-height: 1.14; letter-spacing: 0;
  }
  /* The five stage columns are far too narrow to survive here, so the cards go
     back to being cards: as many per row as 240px allows, each as tall as its
     own copy. */
  body.v6 .v6-stage.v6-stage .v6-feats {
    display: grid; gap: 16px;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    margin-top: 20px;
  }
  /* Relative, not static: the number chip is still absolute and would otherwise
     anchor to the stage. */
  body.v6 .v6-stage.v6-stage .v6-featcard { position: relative; padding-bottom: 18px; }
  body.v6 .v6-stage.v6-stage .v6-feat-num {
    position: absolute; left: 14px; top: 12px;
    width: 28px; height: 28px;
  }
  /* The art keeps its `auto` side margins from the fixed layout, so it stays
     centred at whatever width the card lands on. */
  body.v6 .v6-stage.v6-stage .v6-feat-art { width: 140px; margin-top: 36px; }
  body.v6 .v6-stage.v6-stage .v6-featcard h3 { font-size: 16px; line-height: 20px; }
  body.v6 .v6-stage.v6-stage .v6-featcard > p { font-size: 13.5px; line-height: 18px; margin-top: 6px; }

  /* ----------------------------- CTA banner ----------------------------- */
  body.v6 .v6-stage.v6-stage .v6-cta {
    position: relative;
    margin-top: 44px;
    padding: 28px 20px 30px;
    text-align: center;
  }
  body.v6 .v6-stage.v6-stage .v6-cta-band {
    display: block;
    position: absolute; inset: 0;
    width: auto; height: auto;
  }
  body.v6 .v6-stage.v6-stage .v6-cta > *:not(.v6-cta-band) { position: relative; z-index: 2; }

  /* This crop's own background is the page cream (on the stage it straddles the
     band's edge), so it needs blending to sit inside the lavender on mobile. */
  body.v6 .v6-stage.v6-stage .v6-cta-left {
    width: 160px; margin: 0 auto 4px;
    mix-blend-mode: multiply;
  }
  body.v6 .v6-stage.v6-stage .v6-cta-h {
    width: auto; font-size: clamp(24px, 6vw, 34px); line-height: 1.18;
  }
  body.v6 .v6-stage.v6-stage .v6-cta-btn { margin-top: 18px; }
  body.v6 .v6-stage.v6-stage .v6-cta-foot { font-size: 12.5px; line-height: 16px; margin-top: 12px; }

  body.v6 .v6-stage.v6-stage .v6-note {
    width: min(250px, 100%); height: auto;
    margin: 26px auto 0;
    padding: 14px 16px 16px;
    text-align: center;
  }
  /* ::before is the front sheet and paints over static children, so the note's
     own content has to be lifted back above it. */
  body.v6 .v6-stage.v6-stage .v6-note > * { position: relative; z-index: 1; }
  body.v6 .v6-stage.v6-stage .v6-note::before { left: 6px; top: -7px; width: 100%; height: 100%; }
  body.v6 .v6-stage.v6-stage .v6-note-title { font-size: 13px; line-height: 17px; }
  body.v6 .v6-stage.v6-stage .v6-note-body { font-size: 12.5px; line-height: 19px; margin-top: 4px; }
  body.v6 .v6-stage.v6-stage .v6-note-heart { display: block; width: 20px; margin: 8px auto 0; }
}

/* ---- The hero-only page below the stage breakpoint -------------------------
   The reflowed page has no grid and no banner under the hero any more, so it
   ends wherever the badges and the art happen to end — on a phone that left a
   ~260px band of empty cream under the scene, which is exactly the failure the
   659px block above was written to get rid of the first time.

   The fix the old `min-height: 100svh - 104px` could not manage: give the art a
   *definite* box to fill instead of asking an intrinsically-sized <img> to
   stretch. The stage is a flex column of at least one screen, main and the hero
   pass the leftover height down, and the hero's last grid row takes it as 1fr;
   the <picture> stretches into that row and the image fills it with `cover`,
   bottom-anchored so the plaza and the phone deck are what survives the crop.
   No magic numbers: the nav can change height and this still lands on the
   viewport's bottom edge.

   Deliberately AFTER the 659/389px blocks, not inside the 999px one: their
   `.v6-hero-scene` rules match at the same specificity, so only source order
   puts this last. Scoped to body.v6-hero, so /v6-full — which has a whole page
   below its hero and wants none of this — is untouched.

   Mobile is not held to the desktop no-scroll rule; it just has to end on the
   painting rather than on a band of cream. Same trigger pair as the reflow
   block: a narrowed laptop window lands here too, and it is the reason it does
   — this is what actually fills the screen once the canvas has given up. */
@media (max-width: 999px), (max-aspect-ratio: 3/2) {
  body.v6-hero .v6-stage.v6-stage {
    display: flex; flex-direction: column;
    min-height: 100svh;
    padding-bottom: 0;
  }
  body.v6-hero .v6-stage.v6-stage main {
    flex: 1 1 auto; min-height: 0;
    display: flex; flex-direction: column;
  }
  body.v6-hero .v6-stage.v6-stage .v6-hero {
    flex: 1 1 auto; min-height: 0;
    grid-template-rows: auto auto auto 1fr;
  }
  /* `picture` is the grid item here — it is not in the reflow's blanket reset,
     and the image is its content. It has to stretch before the image can. */
  body.v6-hero .v6-stage.v6-stage .v6-hero picture {
    display: block;
    grid-area: 4 / 1 / 5 / -1;
    align-self: stretch;
    min-height: 0;
  }
  /* The stage's 860px cap is a reading measure, and it is right for the copy —
     but this block now also catches a laptop window dragged narrow, where an
     860px column would stop the painting short of both edges and leave the
     cream at the sides that the block exists to remove. So the hero page drops
     the cap and holds the measure on the copy instead; the scene's -20px
     margins then reach the window's edges on their own, because the stage is
     the window. */
  body.v6-hero .v6-stage.v6-stage { max-width: none; }
  body.v6-hero .v6-stage.v6-stage :is(.v6-h1, .v6-lede) { max-width: 640px; }

  body.v6-hero .v6-stage.v6-stage .v6-hero-scene {
    height: 100%; min-height: 0;
    margin: 0 -20px;              /* full-bleed past the stage's side padding */
    object-fit: cover;
    object-position: 50% 100%;
  }
}

/* Portrait phones use a separate, text-free 941x1672 plate derived from the
   approved mobile composition. Live HTML is positioned in the plate's original
   UI coordinates, preserving accessible copy and controls while matching the
   reference art exactly. Every length below is proportional to the plate width,
   so the composition scales as one piece from 320px through 659px. */
@media (max-width: 659px) and (orientation: portrait) {
  body.v6 { --v6-cream: #FCF4EA; }
  body.v6-hero .v6-stage.v6-stage {
    position: relative;
    display: block;
    width: 100%;
    height: 177.68vw;
    min-height: 177.68vw;
    max-width: none;
    padding: 0;
    overflow: hidden;
  }
  body.v6-hero .v6-stage.v6-stage main {
    position: absolute;
    inset: 0;
    display: block;
    width: 100%;
    height: 100%;
  }
  body.v6-hero .v6-stage.v6-stage .v6-nav {
    position: absolute;
    inset: 0;
    z-index: 3;
    display: block;
    padding: 0;
  }
  body.v6-hero .v6-stage.v6-stage .v6-brand {
    position: absolute;
    left: 5.1vw;
    top: max(2.4vw, env(safe-area-inset-top));
    width: 25.1vw;
  }
  body.v6-hero .v6-stage.v6-stage .v6-brand-lockup { width: 100%; }
  body.v6-hero .v6-stage.v6-stage .v6-hero {
    position: absolute;
    inset: 0;
    z-index: 1;
    display: block;
    width: 100%;
    height: 100%;
    padding: 0;
  }
  body.v6-hero .v6-stage.v6-stage .v6-hero picture {
    position: absolute;
    inset: 0;
    z-index: 0;
    display: block;
    width: 100vw;
    max-width: 100vw;
    height: 177.68vw;
    margin: 0;
    overflow: hidden;
  }
  body.v6-hero .v6-stage.v6-stage .v6-hero-scene {
    position: static;
    width: 100vw;
    height: 177.68vw;
    min-height: 0;
    margin: 0;
    object-fit: fill;
    object-position: 50% 0;
  }
  body.v6-hero .v6-stage.v6-stage .v6-h1 {
    position: absolute;
    left: 5vw;
    top: 19.7vw;
    z-index: 2;
    width: 57vw;
    max-width: none;
    font-family: "Avenir Next", var(--v6-sans);
    font-size: clamp(32px, 8.4vw, 54px);
    line-height: .99;
    letter-spacing: -.012em;
    text-wrap: nowrap;
  }
  body.v6-hero .v6-stage.v6-stage .v6-hero-spark {
    position: absolute;
    left: 56.1vw;
    top: 18.6vw;
    z-index: 2;
    display: block;
    width: 4.4vw;
    height: auto;
  }
  body.v6-hero .v6-stage.v6-stage .v6-lede {
    position: absolute;
    left: 5.4vw;
    top: 40.3vw;
    z-index: 2;
    width: 48vw;
    max-width: none;
    font-size: clamp(13px, 3.05vw, 18px);
    line-height: 1.25;
    letter-spacing: -.012em;
    text-wrap: nowrap;
  }
  body.v6-hero .v6-stage.v6-stage .v6-lede br { display: block; }
  body.v6-hero .v6-stage.v6-stage .v6-mobile-action {
    position: absolute;
    left: 5vw;
    top: 50.8vw;
    z-index: 2;
    display: block;
    width: 44.7vw;
  }
  body.v6-hero .v6-stage.v6-stage .v6-mobile-cta {
    position: relative;
    width: 100%;
    min-width: 0;
    min-height: 0;
    height: clamp(32px, 8.1vw, 52px);
    justify-content: center;
    padding: 0 16px;
    font-size: clamp(15px, 3.2vw, 19px);
  }
  body.v6-hero .v6-stage.v6-stage .v6-mobile-cta::before {
    content: "";
    position: absolute;
    inset: -6px 0;
  }
  body.v6-hero .v6-stage.v6-stage .v6-mobile-cta svg { display: none; }
  body.v6-hero .v6-stage.v6-stage .v6-stores {
    position: absolute;
    left: 5.1vw;
    top: 61.6vw;
    z-index: 2;
    display: flex;
    align-items: center;
    gap: 3px;
    width: auto;
    padding: 0;
  }
  body.v6-hero .v6-stage.v6-stage .v6-store {
    height: clamp(25px, 6.4vw, 42px);
    min-width: 0;
    justify-content: center;
    gap: 3px;
    padding: 0 4px;
    box-sizing: border-box;
    border-radius: 7px;
  }
  body.v6-hero .v6-stage.v6-stage .v6-store:nth-child(1),
  body.v6-hero .v6-stage.v6-stage .v6-store:nth-child(2) { width: 15.2vw; }
  body.v6-hero .v6-stage.v6-stage .v6-store:nth-child(3) { width: 12.7vw; }
  body.v6-hero .v6-stage.v6-stage .v6-store small {
    display: block;
    font-size: clamp(5px, 1vw, 6.5px);
    line-height: 1.1;
    letter-spacing: .025em;
  }
  body.v6-hero .v6-stage.v6-stage .v6-store strong {
    font-size: clamp(9px, 1.8vw, 11.5px);
    line-height: 1;
    letter-spacing: 0;
    white-space: nowrap;
  }
  body.v6-hero .v6-stage.v6-stage .v6-store svg {
    flex: 0 0 auto;
    width: clamp(10px, 2.4vw, 15px);
    height: clamp(10px, 2.4vw, 15px);
  }
}

/* A phone turned sideways has too little height for the portrait stack. Treat
   the illustration as the second half of the composition instead: the message
   remains fully readable on the left and the product stays visible on the right,
   without requiring a scroll just to discover what Noodl looks like. */
@media (max-width: 999px) and (orientation: landscape) and (max-height: 520px) {
  body.v6-hero .v6-stage.v6-stage .v6-nav {
    padding-top: max(12px, env(safe-area-inset-top));
    padding-bottom: 0;
  }
  body.v6-hero .v6-stage.v6-stage .v6-brand,
  body.v6-hero .v6-stage.v6-stage .v6-brand-lockup { width: 110px; }
  body.v6-hero .v6-stage.v6-stage .v6-hero {
    grid-template-columns: minmax(280px, .9fr) minmax(0, 1.1fr);
    grid-template-rows: auto auto 1fr;
    align-items: start;
    column-gap: 22px;
    row-gap: 10px;
    padding-top: 8px;
  }
  body.v6-hero .v6-stage.v6-stage .v6-h1 {
    grid-area: 1 / 1 / 2 / 2;
    font-size: clamp(36px, 5.7vw, 46px);
    line-height: 1.02;
    letter-spacing: -.012em;
  }
  body.v6-hero .v6-stage.v6-stage .v6-lede {
    grid-area: 2 / 1 / 3 / 2;
    font-size: 15px;
    line-height: 20px;
    max-width: 36ch;
  }
  body.v6-hero .v6-stage.v6-stage .v6-stores { display: none; }
  body.v6-hero .v6-stage.v6-stage .v6-mobile-action {
    grid-area: 3 / 1 / 4 / 2;
    display: grid;
    justify-items: start;
    align-self: start;
    gap: 7px;
    padding-top: 2px;
  }
  body.v6-hero .v6-stage.v6-stage .v6-hero picture {
    grid-area: 1 / 2 / 4 / 3;
    height: 100%;
    min-height: 0;
  }
  body.v6-hero .v6-stage.v6-stage .v6-hero-scene {
    width: calc(100% + 20px);
    height: 100%;
    margin: 0 -20px 0 0;
    object-fit: cover;
    object-position: 53% 100%;
  }
}

/* The animated plate follows the layout, not the breakpoint: a laptop window
   dragged narrower than 3/2 is still a laptop, and losing the motion at the
   moment the canvas gives way was the most visible thing about that handover.
   It gets the phones-baked clip, cover-cropped and bottom-anchored onto exactly
   the same grid row as the still it covers — source order is what puts it on
   top, the same way the desktop clip sits over the desktop plate.

   Under 1000px the still stays. The clip is a 3MB desktop-weight asset and the
   still is the LCP image; that was a deliberate call when the motion shipped and
   narrowing a laptop is not a reason to revisit it for phones.

   The `display: none` on the desktop clip is what keeps the exact-3/2 tie
   honest: both aspect queries match there, and without this both clips would be
   displayed — the phone-free one painting over the baked one. */
@media (min-width: 1000px) and (max-aspect-ratio: 3/2) and (prefers-reduced-motion: no-preference) {
  body.v6-hero .v6-stage.v6-stage .v6-hero-motion { display: none; }

  body.v6-hero .v6-stage.v6-stage .v6-hero-motion-phones {
    display: block;
    grid-area: 4 / 1 / 5 / -1;
    align-self: stretch;
    width: calc(100% + 40px); height: 100%; min-height: 0;
    margin: 0 -20px;
    object-fit: cover;
    object-position: 50% 100%;
  }
}

/* ============================= MUSIC TOGGLE =============================
   A viewport-fixed control, deliberately outside .v6-stage. Inside the stage it
   would inherit `zoom` (so its hit target would shrink and grow with the window),
   scroll away with the nav, and get flattened to `position: static` by the mobile
   reflow's blanket rule. Fixed and stage-independent, it is in the corner and
   reachable at every width and every scroll position.

   Chrome matches the painted plates: cream card fill, ink outline, and the
   letterpress offset shadow the buttons and cards already use. */
body.v6 .v6-music {
  position: fixed;
  top: 14px; right: 12px;
  z-index: 60;
  width: 40px; height: 40px;
  display: grid; place-items: center;
  padding: 0;
  background: var(--v6-card);
  color: var(--v6-green);
  border: 1.6px solid var(--v6-green);
  border-radius: 999px;
  box-shadow: 0 2px 0 rgba(15, 42, 27, .16);
  cursor: pointer;
  -webkit-appearance: none; appearance: none;
  transition: background .15s ease, color .15s ease, transform .12s ease,
              box-shadow .12s ease;
}
body.v6 .v6-music:hover { background: var(--v6-beige); transform: translateY(-1px); box-shadow: 0 3px 0 rgba(15, 42, 27, .18); }
body.v6 .v6-music:active { transform: translateY(1px); box-shadow: 0 1px 0 rgba(15, 42, 27, .16); }
body.v6 .v6-music:focus-visible { outline: 2.5px solid var(--v6-orange); outline-offset: 3px; }
body.v6 .v6-music-icon { display: block; line-height: 0; }

/* Off state: the horn is an empty outline, waves hidden, a small x beside it.
   On state: the horn fills terracotta and the waves take the x's place. */
body.v6 .v6-music .v6-music-wave { opacity: 0; }
body.v6 .v6-music .v6-music-off  { opacity: .75; }
body.v6 .v6-music[aria-pressed="true"] {
  background: var(--v6-orange-action);
  color: #FFF3E4;
  border-color: var(--v6-green);
}
body.v6 .v6-music[aria-pressed="true"] .v6-music-horn { fill: #FFF3E4; }
body.v6 .v6-music[aria-pressed="true"] .v6-music-wave { opacity: 1; }
body.v6 .v6-music[aria-pressed="true"] .v6-music-off  { opacity: 0; }
body.v6 .v6-music[aria-pressed="true"]:hover { background: #B94704; }

/* Screen-reader-only state text, so the button announces a change and not just
   a pressed flag. */
body.v6 .v6-music-sr {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}

/* The waves breathe outward while the track plays — the same "something is
   quietly alive" register as the phone screens, at the same slow tempo. */
@media (prefers-reduced-motion: no-preference) {
  @keyframes v6-music-wave { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }
  body.v6 .v6-music[aria-pressed="true"] .v6-music-wave-1 {
    animation: v6-music-wave 1.8s ease-in-out infinite;
  }
  body.v6 .v6-music[aria-pressed="true"] .v6-music-wave-2 {
    animation: v6-music-wave 1.8s ease-in-out .45s infinite;
  }
}

/* The gap between the nav's CTA pill and the window edge is a fixed share of the
   stage — the pill ends at stage x=1056 of 1122 — so on a width-constrained
   desktop it is only ~5.9% of the viewport: 58.8px at 1000px wide, where a 40px
   button on a 12px offset leaves 6.8px of daylight (measured). Shrink the button
   over that band rather than let it crowd the pill. */
@media (min-width: 1000px) and (max-width: 1199px) {
  body.v6 .v6-music { width: 34px; height: 34px; right: 8px; top: 12px; }
  body.v6 .v6-music svg { width: 18px; height: 18px; }
}

/* The fluid layout hides the desktop nav CTA, leaving the top-right corner free
   for the music control. Keeping it in the header makes the control predictable
   and stops it floating over the illustrated product UI at the bottom. */
@media (max-width: 999px), (max-aspect-ratio: 3/2) {
  body.v6 .v6-music {
    top: max(16px, env(safe-area-inset-top));
    right: max(16px, env(safe-area-inset-right));
    bottom: auto;
    width: 44px; height: 44px;
  }
}

/* ============================ WAITLIST MODAL ============================
   The painted plate has no room for an email field, so every CTA opens this
   instead. Same reasoning as the music button: it sits outside .v6-stage, so
   none of the stage's `zoom` or its mobile reflow rules reach it — and a
   showModal()'d dialog is promoted to the top layer, above both.

   Chrome is the page's own vocabulary: cream paper, 2px ink outline, the
   letterpress offset shadow, terracotta pill. The second sheet behind the card
   (::before) is the same trick the pinned note in the CTA banner uses. */
/* Opening a modal <dialog> locks the document's scroll, which on any machine with
   classic (non-overlay) scrollbars — a Mac with a mouse attached, or Windows —
   makes the scrollbar disappear. The viewport widens by its width and everything
   centred, the dialog included, jumps sideways at the moment of the click.
   Reserving the gutter permanently keeps the page still. */
html:has(.v6-wait) { scrollbar-gutter: stable; }

body.v6 .v6-wait {
  padding: 0;
  border: 0;
  background: none;
  overflow: visible;
  /* application.css opens with `* { margin: 0 }`, which beats the UA stylesheet's
     `dialog { margin: auto }` — without this the modal pins to the top-left. */
  margin: auto;
  max-width: min(430px, calc(100vw - 32px));
  max-height: calc(100vh - 40px);
  color: var(--v6-body);
}
body.v6 .v6-wait::backdrop {
  background: rgba(28, 34, 26, .58);
  backdrop-filter: blur(2px);
}

/* No-JS / no-showModal path: an anchor to #waitlist still opens the card. The
   dialog is not in the top layer here, so it has to place itself.

   Scoped to documents WITHOUT the v6-js class (set in the head before paint):
   with JS, showModal owns the dialog, and a live :target rule would re-show the
   card as an inline block the instant it was closed — `history.replaceState`
   takes the hash out of the URL but browsers do not recompute :target from it. */
html:not(.v6-js) body.v6 .v6-wait:not([open]):target {
  display: block;
  position: fixed;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  z-index: 100;
}

body.v6 .v6-wait-card {
  position: relative;
  background: var(--v6-card);
  border: 2px solid #2B2A26;
  border-radius: 14px;
  box-shadow: 0 6px 0 rgba(15, 42, 27, .17), 0 24px 48px rgba(15, 42, 27, .22);
  overflow: hidden;   /* clips the art band into the card's rounded corners */
}
/* The sheet of paper underneath, peeking out at a slight angle. It hangs off the
   dialog rather than the card: the card clips its own overflow, which would cut
   the second sheet off at exactly the edges where it is supposed to show. */
body.v6 .v6-wait::before {
  content: "";
  position: absolute; inset: 0;
  background: var(--v6-beige);
  border: 2px solid #2B2A26;
  border-radius: 14px;
  transform: rotate(-1.5deg) translate(-7px, 6px);
  z-index: -1;
}

body.v6 .v6-wait-x {
  position: absolute; top: 12px; right: 12px; z-index: 3;
  width: 30px; height: 30px;
  display: grid; place-items: center;
  padding: 0;
  background: var(--v6-card);
  color: var(--v6-green);
  border: 1.6px solid var(--v6-green);
  border-radius: 999px;
  box-shadow: 0 2px 0 rgba(15, 42, 27, .16);
  cursor: pointer;
  -webkit-appearance: none; appearance: none;
  transition: background .15s ease, transform .12s ease;
}
body.v6 .v6-wait-x:hover { background: var(--v6-beige); transform: translateY(-1px); }
body.v6 .v6-wait-x:active { transform: translateY(1px); }
body.v6 .v6-wait-x:focus-visible { outline: 2.5px solid var(--v6-orange); outline-offset: 3px; }

/* Noodl on his deckchair, sitting straight on the card.

   The crop used to carry its own painted paper, which is not flat — it drifts
   from rgb(252,239,223) to rgb(253,242,230) across one 210px crop, and the 2x
   variant is warmer still — so against any single backdrop colour it read as two
   tones. It has true alpha now (art/v6/tools/alpha-key.py --flood, originals in
   versions/), so the card's cream is the only paper in the card. */
body.v6 .v6-wait-art {
  padding: 20px 0 0;
  display: grid; place-items: center;
  background: var(--v6-card);
}
body.v6 .v6-wait-miso {
  /* Locked to the source's 210x178: the @2x webp is 420 wide, so anything larger
     upscales a painted plate on a retina screen. */
  width: 210px; height: 178px;
}

body.v6 .v6-wait-body { padding: 20px 26px 24px; text-align: center; }

body.v6 .v6-wait-h {
  font: 700 25px/29px "Avenir Next", var(--v6-sans);
  letter-spacing: -.018em;
  color: var(--v6-green);
}
body.v6 .v6-wait-lede {
  margin-top: 8px;
  font: 500 14.5px/20px var(--v6-sans);
  color: var(--v6-muted);
}

body.v6 .v6-wait-form { margin-top: 16px; display: grid; gap: 9px; }
body.v6 .v6-wait-hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

body.v6 .v6-wait-field {
  width: 100%;
  box-sizing: border-box;
  padding: 12px 16px;
  background: #FFFDF8;
  border: 1.8px solid #2B2A26;
  border-radius: 999px;
  font: 500 15px/1.2 var(--v6-sans);
  color: var(--v6-body);
  -webkit-appearance: none; appearance: none;
}
body.v6 .v6-wait-field::placeholder { color: #94907F; }
body.v6 .v6-wait-field:focus-visible { outline: 2.5px solid var(--v6-orange); outline-offset: 2px; }
body.v6 .v6-wait-field-bad { border-color: var(--v6-orange); background: #FFF6EC; }

body.v6 .v6-wait-btn {
  width: 100%;
  padding: 12px 20px;
  background: var(--v6-orange-action);
  color: #fff;
  border: 1.8px solid #2B2A26;
  border-radius: 999px;
  box-shadow: 0 3px 0 rgba(15, 42, 27, .2);
  font: 600 15.5px/1.2 var(--v6-sans);
  letter-spacing: .01em;
  cursor: pointer;
  -webkit-appearance: none; appearance: none;
  transition: background .15s ease, transform .12s ease, box-shadow .12s ease;
}
body.v6 .v6-wait-btn:hover { background: #B94704; transform: translateY(-1px); box-shadow: 0 4px 0 rgba(15, 42, 27, .22); }
body.v6 .v6-wait-btn:active { transform: translateY(2px); box-shadow: 0 1px 0 rgba(15, 42, 27, .2); }
body.v6 .v6-wait-btn:focus-visible { outline: 2.5px solid var(--v6-green); outline-offset: 3px; }

body.v6 .v6-wait-flash {
  margin-top: 12px;
  padding: 9px 14px;
  border-radius: 10px;
  border: 1.5px solid;
  font: 500 13.5px/18px var(--v6-sans);
}
body.v6 .v6-wait-ok  { background: #EAF1E4; border-color: #6F7A62; color: #24361F; }
body.v6 .v6-wait-bad { background: var(--v6-locked-bg); border-color: var(--v6-locked-line); color: #7A3406; }

/* Success state. Its button is a direct child of the body, not a row of
   .v6-wait-form, so it carries none of the form's spacing and would otherwise sit
   flush against the line above it. Same rhythm as the form: a clear step down from
   the message, then the action. */
body.v6 .v6-wait-ok + .v6-wait-lede { margin-top: 10px; }
body.v6 .v6-wait-body > .v6-wait-btn { margin-top: 18px; }

body.v6 .v6-wait-fine {
  margin-top: 12px;
  font: 500 12.2px/16px var(--v6-sans);
  color: #6C7466;
}
body.v6 .v6-wait-link { color: var(--v6-orange-l); text-decoration: underline; text-underline-offset: 2px; }

/* The card lands like a page being put down — never on the success state, where
   the movement would read as the message arriving twice. */
@media (prefers-reduced-motion: no-preference) {
  @keyframes v6-wait-in {
    from { opacity: 0; transform: translateY(10px) scale(.975); }
    to   { opacity: 1; transform: none; }
  }
  body.v6 .v6-wait[open] .v6-wait-card { animation: v6-wait-in .26s cubic-bezier(.2, .9, .3, 1.1); }
}

@media (max-width: 420px) {
  /* The plate shrinks, and the frame shrinks with it — height has to stay on the
     image alone, or a fixed band height clips it into the headline below. */
  body.v6 .v6-wait-art { padding: 18px 0 2px; }
  body.v6 .v6-wait-miso { width: 178px; height: 151px; }
  body.v6 .v6-wait-body { padding: 16px 18px 20px; }
  body.v6 .v6-wait-h { font-size: 22px; line-height: 26px; }
  body.v6 .v6-wait-x { width: 44px; height: 44px; top: 10px; right: 10px; }
}

@media (max-width: 999px), (max-aspect-ratio: 3/2) {
  body.v6 .v6-stage.v6-stage .v6-nav-cta { display: none; }
}

@media (max-width: 659px) and (orientation: portrait) {
  body.v6 .v6-music { display: none; }
}
