/* ============================================================================
   SECTION 02-who-why-b — "1.1 Who and why" — Figma node 2956:1229
   ----------------------------------------------------------------------------
   Sources, in the order the founder's bar demands them:
     - figma-truth/02-who-why-b.spec.md            (measurements, type, colour)
     - figma-truth/sections-en/02-who-why-b.png    (pixel truth, @2x)
     - figma-truth/_scratch/02-section.svg         (Figma's OWN SVG export of
       2956:1229 — pulled this run; it settles three things the payload could
       not: the pill fill, the icon bounding box, and which image fill renders)
     - http://127.0.0.1:5010/salient/elements/video-lightbox/index.html
       "Mouse follow button" — the component this section's play circle IS.

   Blocks marked  >>> LIFTED VERBATIM <<<  are Salient's own declarations,
   copied character-for-character from that demo's critical CSS. Blocks marked
   >>> RETARGETED <<<  change only colour / size to Figma's values, which is
   exactly the founder's "change the text, update the colors, the styles".
   Nothing here is a reimplementation from description.
   ========================================================================== */

/* ==========================================================================
   1. THE BAND — full-bleed photographic ground
   ========================================================================== */

/* Fill stack read off the section node, bottom -> top:
     1  SOLID   #f4f9fb                       -> --mk-surface-mist
     2  IMAGE   0d8b7689…  FILL               -> NOT VISIBLE, see below
     3  IMAGE   2a1c4163…  FILL, identity xf  -> the photograph
     4  GRADIENT_LINEAR #00000000 -> #00000040

   spec 7 item 2 listed "which of the two image fills is visible" as UNRESOLVED.
   RESOLVED this run, and not by inference: exporting 2956:1229 as SVG inlines
   every visible paint as base64. Both images came back; their SHA-1s are
   byte-exact matches for Figma's own imageHash values, which is what an
   imageHash is. Decoding them:
     0d8b7689… = an infinity pool / ocean shot  (1780px tall, ar 1.5000)
     2a1c4163… = the woman in the park, black top, paper cup (ar 1.4986)
   The second is the photograph in the render, and it is fully opaque at
   scaleMode FILL, so it hides the first completely. 0d8b7689… is the leftover
   from the earlier variant of this section, node 3065:1412, which still uses
   it with a different (#12181c) scrim. Only 2a1c4163… is shipped.

   Gradient direction, decoded from gradientTransform in the spec and then
   confirmed against Figma's SVG export, which wrote it out longhand as
   x1=640 y1=0 -> x2=640 y2=900, stop-opacity 0 -> 0.25. Straight down. */
.mk-whowhyb {
  height: 900px;                              /* fixed at BOTH 1280 and 1440 */
  position: relative;                         /* the card and its three layers  */
  background-color: var(--mk-surface-mist);   /* fill 1 — load/fallback ground.
                                                 D08/D10: this is now ALSO the
                                                 ground the clipped card opens
                                                 against, which is why fills 2-4
                                                 moved down to `.row-bg` below.
                                                 `clip-path` clips backgrounds
                                                 too, so a self-clipping section
                                                 would cut a hole in the page
                                                 instead of showing a card on it. */
}

/* ==========================================================================
   1b. THE CARD — the element that actually scrubs. D08 + D10.
   Full size of the section; `clip-path` is written onto it inline every frame
   by js/mk-expanding-card.js from the `data-nectar-animate-settings` attribute
   in the markup. NEVER give it a `transition` on clip-path: the scrub has to
   land exactly on the seeked value each frame, and a transition turns every
   frame into a chase (and defeats the driver's own read-back hand-off check).
   ========================================================================== */
.mk-whowhyb__card {
  position: absolute;
  inset: 0;
  overflow: hidden;                           /* keeps the 4px start radius honest
                                                 on the photograph inside it     */
}

/* The photographic ground, now on Salient's own `.row-bg` inside the lifted
   `.row-bg-wrap` shape, so the donor's video wrapper can drop in beside it
   without moving anything (G3). */
.mk-whowhyb__media,
.mk-whowhyb__media .inner-wrap,
.mk-whowhyb .row-bg {
  position: absolute;
  inset: 0;
}
.mk-whowhyb .row-bg {
  background-image:
    linear-gradient(to bottom, transparent 0%, var(--mk-shadow-25) 100%),
    url("../img/02-who-why-b/hero-park-chair.webp");
  /* `cover` + `center` is not an approximation of the image transform — it is
     an exact restatement of it. Figma's SVG emits the pattern as
     matrix(0.000394792 0 0 0.000561482 -0.0268503 0):
       y scale x 1781 = 1.000000  -> the image is fitted to the 900 height
       x scale x 2669 = 1.053700  -> 1348.74px wide, wider than the 1280 frame
       x offset       = -0.0268503 x 1280 = -34.37px, i.e. exactly centred
     cover on 1280x900 gives scale max(1280/2669, 900/1781) = 0.50533,
     width 1348.7, offset (1280-1348.7)/2 = -34.35. Same numbers. */
  background-size: 100% 100%, cover;
  background-position: 0 0, center;
  background-repeat: no-repeat;
}

/* ==========================================================================
   2. CONTENT LAYER — 2956:1230
   VERTICAL auto-layout, primaryAxisAlignItems MAX, counterAxisAlignItems
   CENTER, itemSpacing 48, padding 48/120/48/120.
   Bottom-anchoring is THE reflow rule for this section (spec 5.1): the caption
   and pills stay pinned 48px off the bottom whatever the height becomes.
   ========================================================================== */
.mk-whowhyb__text {
  position: absolute;                         /* D09: this layer now sits ON TOP
                                                 of a full-card follow surface,
                                                 so it is a layer, not the flow */
  inset: 0;
  z-index: 3;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;                  /* primaryAxisAlignItems: MAX   */
  align-items: center;                        /* counterAxisAlignItems: CENTER*/
  gap: var(--mk-space-48);                    /* itemSpacing 48               */
  height: 100%;
  padding: var(--mk-section-y) var(--mk-page-x);

  /* The donor's own device, and it is load-bearing rather than tidy: its
     caption row ships the class `no-pointer-events` precisely so the caption
     does not punch a dead rectangle through the middle of the follow surface.
     Ours differs in one respect — the pills are real links where the donor's
     caption is inert — so the opt-out is inherited and the pills opt back in. */
  pointer-events: none;
}
.mk-whowhyb__pill { pointer-events: auto; }

/* ==========================================================================
   3. CAPTION — 2956:1236
   ONE Figma text node, two styled runs split by a single \n. The payload
   reports fontSize "mixed" and declares text.segments collapsed, so 36 and 18
   are measured, not read (spec 7 item 4). Two independent checks agree:
     - height algebra   54 + 18 + 27 = 99 = the node's exact reported height
     - Poppins metrics  ascent 1050 / descent -350 / upem 1000 put line-1's
       baseline 39.6px below the box top and line-2's 91.8px below it; the
       spec's measured targets are 39.9 and 91.9 (tolerance +/-1).
   ========================================================================== */
.mk-whowhyb__caption {
  /* Flex column rather than a plain block so the newlines between the two runs
     cannot become anonymous line boxes — a flex container drops whitespace-only
     text nodes, which makes the 99px height independent of how this markup is
     indented. Cheap insurance; the measured 54 + 18 + 27 falls out either way. */
  display: flex;
  flex-direction: column;
  align-items: center;

  width: max-content;      /* textAutoResize WIDTH_AND_HEIGHT — hugs on both
                              axes. NEVER give this a fixed width: the ES
                              string is 648 wide against EN's 473 (spec 2.5). */
  max-width: 100%;
  text-align: center;

  /* CONVENTIONS 8.6, caught by measuring rather than by reading: this box came
     out 129px instead of 99. The extra 30 is Salient's, from skin-material's
       p{padding-bottom:var(--nectar-paragraph-bottom-spacing,1.5em)}
     (style.css sets the same property with a 28px fallback; skin-material wins
     on order). The caption inherits the 20px body size from .mk-page, so 1.5em
     resolved to exactly 30px. Zeroing padding AND margin — Salient's reset also
     puts a margin on every <p> — pins the box to its 99px content height.
     No !important needed: this file loads after every vendored sheet. */
  margin: 0;
  padding: 0;
  color: var(--mk-ink-inverse);
  font-family: var(--mk-font-sans);
  letter-spacing: 0;
}

.mk-whowhyb__headline {
  display: block;
  font-size: var(--mk-size-h2);               /* 36 — measured, spec 2.1      */
  line-height: var(--mk-lh-auto);             /* 1.5 -> 54px, Poppins AUTO    */
  font-weight: var(--mk-w-regular);
}

.mk-whowhyb__duration {
  display: block;
  margin-top: 18px;        /* paragraphSpacing — derived, spec 2.3. Not a
                              token: it is this section's only paragraph gap
                              and tokens.css --mk-para-gap is the footer's 12. */
  font-size: var(--mk-size-body-sm);          /* 18 — measured, spec 2.1      */
  line-height: var(--mk-lh-auto);             /* 1.5 -> 27px                  */
  font-weight: var(--mk-w-regular);
}

/* ==========================================================================
   4. PILL ROW — 2956:1237 "Frame 1847" + the two 2956:1238 / 2956:1240 pills
   ========================================================================== */

/* Stretches to the full 1040 content box, then pushes its children right.
   Right edge lands on 1160 = the content-box right edge (spec 4.1). */
.mk-whowhyb__btns {
  align-self: stretch;                        /* the 1040 / 1200 content box  */
  display: flex;
  justify-content: flex-end;                  /* primaryAxisAlignItems: MAX   */
  align-items: flex-end;                      /* counterAxisAlignItems: MAX   */
  gap: var(--mk-space-12);                    /* itemSpacing 12               */
}

/* The payload reports fills:["#1eb2bc"] on both pills. It does not render —
   an isolated 8x export contains ZERO teal pixels, and Figma's own SVG export
   writes the pill as <rect … rx="20" stroke="white"/> with no fill attribute
   at all. Transparent, white hairline. (spec 3.3)

   Height 40 = 24 line-box + 8 + 8. Width hugs: label + 18 + 18, verified on
   all four labels across both languages — 122+36=158, 137+36=173,
   192+36=228, 153+36=189. So no width is declared here; the box must hug. */
/* This USED TO BE a second, independent implementation of the same button —
   its own box, type, radius and 1px centre-aligned stroke, none of it shared
   with the one in the header. It is now the `myk-btn` primitive
   (css/myk-btn.css) plus the four genuine deltas below, all expressed as
   tokens per the component contract.

   `myk-btn--ring-outline` is the ring RENDERER this section measured: `outline`
   straddles the edge and takes no layout space, where a `border` under the
   global `*{box-sizing:border-box}` would sit fully inside and eat 1px of the
   content box, narrowing the button. Height 40 = 24 line-box + 8 + 8, and the
   width hugs — label + 18 + 18, verified on all four labels across both
   languages (122+36=158, 137+36=173, 192+36=228, 153+36=189), so no width is
   declared here.

   The payload reports fills:["#1eb2bc"] on both buttons. It does not render —
   an isolated 8x export contains ZERO teal pixels, and Figma's own SVG export
   writes the shape as <rect … rx="20" stroke="white"/> with no fill attribute
   at all. Transparent, white hairline. (spec 3.3) */
.mk-whowhyb__pill {
  --myk-btn-justify: center;
  --myk-btn-weight: var(--mk-w-medium);       /* Poppins Medium 500           */
  --myk-btn-blur: none;                       /* this node declares no effects */
  /* The right inset is 18 MINUS the 1px of tracking CSS hangs off the last
     character, which Figma's hug does not carry. Measured, not assumed: with a
     symmetric 18 the buttons came out 158.52 and 173.93 against Figma's 158 and
     173, and because the pair is flush right that 0.93 pushed the FIRST one's
     left edge to 815.55 instead of 817. Trimming the phantom 1px gives
     157.5 / 172.9 — and it keeps the label optically centred, since the dead
     space is all on the right.
     Taken off the PADDING rather than the label's margin (which is what
     `--myk-btn-track-trim` does) because this section measured the padding
     form; the two are not interchangeable once `justify-content: center` is
     in play, since one moves the box edge and the other moves the glyph run.

     NOW A TOKEN, not a raw `padding-right`. `css/myk-btn.css` §1 grew
     `--myk-btn-pad-l` / `--myk-btn-pad-r` this pass, so the asymmetry is
     expressible through the component's own surface instead of over the top of
     it. Identical computed value (18 - 1 = 17); the measurement above is
     unchanged and is still the justification. */
  --myk-btn-pad-r: calc(var(--myk-btn-pad-x) - var(--myk-btn-track));

  /* >>> THE LIFTED `all .45s cubic-bezier(.25,1,.33,1)` IS REMOVED. <<<
     2026-08-18, lane `foldback:buttons-sweep`.
     Provenance, kept because it was real: Salient's see-through button,
     `.nectar-button.see-through{transition:all .45s cubic-bezier(.25,1,.33,1)}`
     from css/build/style.q-98889c766d.css, and spec 6.2 was explicit that ONLY
     the curve was lifted.
     It goes for the same reason the fill below it goes. `--myk-btn-transition`
     is now the RING + LABEL + SHADOW list and it runs on §1's single hover
     clock; a section holding a fourth curve here means these two pills settle
     on a different beat from the ecology CTA, the nav CTA and the closing-CTA
     pill — which is the founders' complaint stated as a duration. The curve
     was also lifted for a hover Salient's see-through button has and ours no
     longer does: our hover is now the board's `3269:5607`, not the donor's.
     `all` was additionally unsafe here — it would animate the padding token
     immediately above it. */
}

/* ---- PENDING DESIGN SIGN-OFF -------------------------------------------
   Figma contains NO hover, focus, active or pressed state for these buttons
   (spec 7 item 10). The curve is lifted; this fill is spec 6.2's first
   suggestion and is NOT founder-approved. It is isolated in this one block so
   it can be deleted or replaced without touching anything else.

   `myk-btn--outline` ships the page's teal cross-fade hover. These buttons do
   NOT take it — retargeting the three hover tokens keeps this section's own
   behaviour, byte-for-byte what it was before the component landed, while
   still going through the component instead of around it. Delete this block
   and they inherit the teal cross-fade, which is the likely sign-off outcome.
   ---------------------------------------------------------------------- */
/* >>> THE FOUR TOKEN OVERRIDES THAT USED TO BE HERE ARE DELETED. <<<
   2026-08-18, lane `foldback:buttons-sweep`.

   This block's own note above predicted its ending: "this fill is spec 6.2's
   first suggestion and is NOT founder-approved … Delete this block and they
   inherit the teal cross-fade, which is the likely sign-off outcome."

   The founders then said it in review, about the outline family as a whole:
   "whatever we do for these white outline buttons that we're calling our
   secondary buttons, make sure the rollover states are consistent."

   Measured before deleting, so the size of the inconsistency is on record.
   These two pills were the THIRD distinct outline hover shipping on one page:
       02-who-why-b   fill rgba(255,255,255,.15) · ring stays white · 450ms
       04-ecology / 18-cta-expand / nav CTA
                      fill #1eb2bc · ring -> teal · 300ms fill / 450ms ring
       16-amenities-52  no visible hover at all
   None of the three is the board's. `3269:5607` is fill `#F4F9FB`, label
   `#1EB2BC`, +2px per side, `0 4px 4px rgba(0,0,0,.15)` — now the
   `myk-btn--outline` default, so these two pills inherit it with no rule here.

   The 450ms/cubic-bezier(.25,1,.33,1) curve went with them: §1 of
   css/myk-btn.css now runs every hover property on ONE clock, and a section
   holding its own curve is the same defect wearing a different value. */
.mk-whowhyb__pill:focus-visible {
  outline: var(--myk-btn-border-width) solid var(--myk-btn-border);
  outline-offset: 2px;                        /* keep the ring legible        */
}

/* ==========================================================================
   5. PLAY CIRCLE — 2956:1231, and the Salient component it is
   --------------------------------------------------------------------------
   >>> REWRITTEN FOR FOUNDER DEFECT D09 — read this before changing it back <<<

   THIS BLOCK USED TO SIZE THE CONTAINER TO THE CIRCLE, 108x108 pinned at
   top-right, and argued that spec 6.1's "make the whole section the trigger
   surface" must NOT be adopted because it "would move the rest point to the
   section's centre ... contradicting both the Figma frame and the reference
   render". The founders reviewed the result and rejected it:

     D09  "The play icon is pinned in the corner; it must be a CURSOR-FOLLOWING
           tooltip like saas/index.html div #fws_6a36b9c4ddd6f3. Turquoise
           (primary action), not black."

   The old argument was internally sound and rested on a premise that was
   wrong. The premise was that the circle's position in the Figma frame is a
   layout position. review/branding/media-misc.md §3.1, extracted from the
   "branding and components with notes" artboard the builder had never been able
   to open, settles it in the artboard's own terms: "Its position in the board
   (x 950, y 130) is just where Jehnean parked it to show the component — it is
   not a layout position", and "this circle is not a fixed corner control. It is
   the cursor."

   So the container is now the WHOLE CARD, exactly as the donor row's is, and
   Salient's own line does the rest:
       this.initialX = this.$el.width()  / 2;
       this.initialY = this.$el.height() / 2;
   A 108px container made "follow the mouse" mean "drift a few pixels inside a
   108px box in the corner". That IS the defect the founders named; it was never
   a missing feature, it was a container size.

   THE THREE COMPONENT NUMBERS, from review/branding/media-misc.md §3.1 (the
   primary-action cursor of G6, and the authority D09 points at):
       size    110 x 110, full circle
       fill    #1EB2BC solid, no stroke, NO blur   (the general-interactivity
               cursor is the one with #000 @ 50% + backdrop-blur — §3.3)
       glyph   Material play_arrow, #FFFFFF, 16.5 x 21
   `#1eb2bc` was already right here; D09's "not black" is a delta against the
   DONOR, whose own control is `data-play_button_color="#0a0a0a"`.
   ========================================================================== */

/* The follow surface is the card. `inset: 0` and nothing else — the moment this
   gets a width or a corner offset again, D09 is back.

   TWO CLASSES DEEP, AND `width/height: auto` RESTATED, BOTH DELIBERATE.
   `css/_band-xs.css` §"02-who-why-b" re-asserts the OLD corner geometry
   (`width: 108px; height: 108px; top: 60; right: 60`) for 691-768px, and it is
   right to have done so — it was written to restore, at 768, the values that
   held at 769, and at the time those values were the corner-pinned ones. The
   band sheets are also emitted LAST by _tools/compose.py, so a single-class
   selector here would lose to it and D09 would come back on a tablet only.
   `.mk-whowhyb .mk-whowhyb__play` is (0,2,0) against the band's (0,1,0) and
   wins wherever it is linked; `width`/`height` have to be restated because
   `inset: 0` resolves against them, and a surviving `width: 108px` would pin
   the box even with all four offsets at zero. Measured before this bump: at
   768 the follow surface came back as 108x108 at the top-left corner.
   Removal of the dead band rule is filed as REQ-WWU-7. */
.mk-whowhyb .mk-whowhyb__play {
  position: absolute;
  inset: 0;
  width: auto;
  height: auto;
  z-index: 2;
}
.mk-whowhyb__play .wpb_wrapper,
.mk-whowhyb__play .wpb_video_wrapper {
  width: 100%;
  height: 100%;
  position: relative;
  /* >>> RETARGETED <<< The donor keeps `wpb_video_widget vc_video-aspect-ratio-169
     vc_video-el-width-100` on this container, and js_composer.css turns that into
     `.wpb_video_widget .wpb_video_wrapper{padding-top:56.25%}` — a 16:9 box. On
     the donor's full-width row 16:9 IS the media, so the box and the row coincide.
     Our band is 1280x900 (64:45), so the class set is dropped and the box is given
     the frame's own size directly. Same element, same role, our aspect — rather
     than keeping the classes and fighting them with !important (CONVENTIONS 8.6).
     Salient's `.wpb_video_wrapper{overflow:hidden}` is still NOT copied: it exists
     to clip a video to a border radius, there is no video, and clipping here would
     shear the circle the moment the follow carried it near an edge. */
}

/* >>> LIFTED VERBATIM <<< — Salient, video-lightbox critical CSS */
.mk-whowhyb__play .play_button {
  z-index: 100;
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
}
.mk-whowhyb__play .play_button .play:after {
  content: "";
  display: block;
  padding-bottom: 100%;
}
.mk-whowhyb__play .play_button.follow_mouse .play {
  pointer-events: none;
  transition: opacity 0.3s ease;
}
.mk-whowhyb__play .play_button.following.follow_mouse .play {
  opacity: 1;
}
.mk-whowhyb__play .play_button .play:before {
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
  border-radius: 100px;
  content: "";
  z-index: 0;
  background-color: #000;
  transition: transform 0.3s ease;
}
/* NOTE on the two rules deliberately NOT lifted:
   `.play_button:not(.follow_mouse):hover .play:before{transform:scale(1.15)}`
   excludes follow_mouse BY ITS OWN SELECTOR — Salient gives this variant no
   hover scale, because the follow IS the affordance. spec 6.1 item 4 asks for
   scale(1.3), but it sources that from
   `.nectar_video_lightbox:not(.play_button_with_text):hover .play`, a selector
   that needs the .nectar_video_lightbox class this component does not carry.
   Following the component over the spec here; flagged in the return notes. */

/* >>> RETARGETED <<< — Salient's declarations, the BRANDING ARTBOARD's numbers.
   Salient ships `.play{width:8%;margin-top:-4%;margin-left:-4%}` so the button
   scales with the video box. Ours is a fixed component size. That size is 110,
   not the 108 this file used to carry: 108 is what section 02's own Figma frame
   draws, 110 is what the component is measured at on the "branding and
   components with notes" artboard (review/branding/media-misc.md §3.1), and
   D09 sends this control to the branding system. G4 and G6 both say the
   branding artboard is the authority for a component's shape; the section frame
   is the authority for where a section's content sits. Those are different
   questions and this is the first one.
   Everything else (the absolute/flex/centring shape, and the top:0/left:0 that
   Gi() re-asserts inline anyway) is Salient's. */
.mk-whowhyb__play .play_button .play {
  position: absolute;
  /* Salient writes `top:0;left:0` and then immediately overrides both with
     `top:50%;left:50%` in the same rule. That is not redundancy — the 50% pair
     is the NO-JS rest position, and Gi() re-asserts top:0/left:0 as an inline
     style at construction before it starts writing transforms. Keeping both
     halves means the rest position is correct with the JS and without it, which
     matters here because the shell defers ten scripts as
     `type="salientlazyscript"` until the visitor's first gesture. */
  top: 50%;
  left: 50%;
  width: 110px;                               /* media-misc.md §3.1 */
  height: 110px;
  margin-top: -55px;
  margin-left: -55px;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* ==========================================================================
   5.3  >>> LIFTED VERBATIM <<<  `play_button_hover` — THE TOOLTIP BEHAVIOUR
   --------------------------------------------------------------------------
   Source: the saas page's own inline critical CSS, captured at
   salient-truth/saas/inline-styles.css @58656. It is NOT in the vendored
   bundle — the shell vendors the `/salient/resort/` family, which ships no
   video-lightbox page — so the four declarations are copied here character for
   character, exactly the way 03-unique.css's Block A copies the architect
   demo's. Copying them IS the lift; do not "tidy" them.

   This is the half of D09 that the word "tooltip" is doing. `Gi()` reads the
   class off the container —
       a.$el.hasClass("play_button_hover") && (a.hoverOnly = !0)
   — and switches the follow from a slow 0.03 lerp that is always running to a
   snap-to-cursor on `mouseenter` (percentage 1, easing back to 0.16 after 60ms)
   with a 400ms grace on exit. These four rules are the visual half: the circle
   does not exist until the pointer is over the band, then it grows from
   scale(0.3) under the cursor. A control that is always on screen is a badge;
   this is a tooltip.

   Salient gates it at >=1000px itself, which is also the width below which the
   clip-path scrub is disabled in the settings JSON. Both gates kept.
   ========================================================================== */
@media only screen and (min-width: 1000px) {
  .mk-whowhyb .nectar_video_player_self_hosted.play_button_hover .play { opacity: 0; }
  .mk-whowhyb .nectar_video_player_self_hosted.play_button_hover:hover .play { opacity: 1; }
  .mk-whowhyb .nectar_video_player_self_hosted.play_button_hover .play:before {
    transform: scale(0.3);
    transition: transform 0.45s ease-out;
  }
  .mk-whowhyb .nectar_video_player_self_hosted.play_button_hover:hover .play:before {
    transform: scale(1);
  }
}

/* Circle paint. Salient keys the colour off the data attribute it renders on
   the trigger, so the retarget is the attribute value plus its matching rule —
   the same shape as Salient's own
   `[data-play_button_color="#000000"] .play:before{background-color:#000000}`.
   #1eb2bc is verified rendered: 76.7% of the isolated play-button export is
   exactly that colour at alpha 255, and Figma's SVG writes fill="#1EB2BC". */
.mk-whowhyb__play .play_button[data-play_button_color="#1eb2bc"] .play:before {
  background-color: var(--mk-teal);
}

/* Glyph. Salient: `svg{height:16px;width:16px;position:relative;z-index:100;
   margin-left:4px}`.

   >>> CORRECTED 2026-08-18 by lane `foldback:video-ecology`. <<<

   The optical nudge and the disc diameter are ONE number, and only one of them
   was updated when this file moved from 108 to 110.

   Figma places the triangle's box at x = 48. In a 108 disc a centred 16.5-wide
   box starts at (108-16.5)/2 = 45.75, so x=48 is +2.25 — which is what this rule
   shipped. But the disc is 110 now (branding artboard, §5.2 above): a centred
   box starts at (110-16.5)/2 = 46.75, and the SAME x=48 is +1.25, not +2.25.
   The circle was corrected in isolation and the glyph offset was left behind, so
   the triangle sat a full pixel right of where the component draws it.

   review/branding/cursors.md §2.7 states both halves independently:
       "`play_arrow` path M 0 21 L 0 0 L 16.5 10.5 Z, box 16.5 x 21, placed at
        x 48, y 44.5 in a 110 disc"                         -> box offset +1.25
       "Ink centre is +1.12px right of the disc centre (payload +1.25)"
   The 0.13 between them is the triangle's antialiased edge: §2.1 measures the
   rendered ink at 16.25 wide starting at x 48.00, so a box whose left edge is
   at 48 renders ink whose centre is at +1.12. Both numbers describe the same
   placement; the box is the one CSS can set.

   In a centred flex line an extra left margin of m shifts the box right by m/2,
   so margin-left: 2.5px puts the svg's left edge on exactly 48.
   Vertically (110-21)/2 = 44.5 falls out of the centring for free — cursors.md
   §2.7's y is 44.5, so the vertical needs no nudge at either diameter.

   >>> AND IT IS DELIBERATELY *NOT* RESPONSIVE. <<<
   The disc steps 110 -> 108 (691-768, css/_band-xs.css) -> 80 (<=690) -> 64
   (<=480), and it is tempting to re-derive `48 - (D - 16.5)/2` at each of those.
   Do not: that formula gives 2.25 / 16.25 / 24.25, and the last two would throw
   the triangle out of the circle. Figma's x=48 is a POSITION inside a 110 frame,
   not a rule. The nudge is an OPTICAL correction whose size depends on the
   GLYPH, and the glyph is a fixed 16.5 x 21 at every width (the svg rule below
   carries no media query, on purpose). So the correct offset is the same +1.25
   everywhere. Verified live at 1440/1280/1024/999/768/720/691/690/480/375: the
   svg centre measures +1.25 at all ten, and the follow container measures the
   FULL CARD at all ten (i.e. D09's container fix survives every band sheet —
   see REQ-WWU-7, whose defensive specificity bump this re-confirms). */
.mk-whowhyb__play .play_button svg {
  width: 16.5px;
  height: 21px;
  position: relative;
  z-index: 100;
  margin-left: 2.5px;                         /* -> +1.25px box, +1.12px ink  */
}
.mk-whowhyb__play .play_button[data-play_button_icon_color="#ffffff"] svg path {
  fill: var(--mk-ink-inverse);
}
/* The 36x36 "Bounding box" RECT 2956:1234 is NOT drawn. It reports
   fills:["#ffffff"], but Figma's SVG export reveals what it actually is:
       <mask id="mask0_2956_1229" style="mask-type:alpha" …>
         <rect x="1148" y="96" width="36" height="36" fill="white"/>
       </mask>
   — the Material icon's alpha clip box, and a no-op here because the 16.5x21
   triangle sits entirely inside it. Omitted, exactly as spec 3.4 concluded. */

/* ==========================================================================
   6. BELOW 1280 — UNSPECIFIED IN FIGMA
   There is no tablet or mobile artboard for this section; only 1280 (EN) and
   1440 (ES) exist. Everything below is spec 5.4's reasoned recommendation and
   is NOT extracted truth. It needs design sign-off before it ships.
   The hard constraint is real and arithmetic, not taste: the ES pill row is
   228 + 12 + 189 = 429px of content and cannot fit a 375px viewport, so the
   pills must stack or the Spanish page breaks.
   ========================================================================== */
@media (max-width: 1024px) {
  .mk-whowhyb__text { padding-inline: 48px; }
}

@media (max-width: 768px) {
  .mk-whowhyb            { height: 640px; }
  .mk-whowhyb__text      { padding-inline: 48px; }
  .mk-whowhyb__headline  { font-size: 28px; }
  .mk-whowhyb__duration  { font-size: var(--mk-size-base); margin-top: 0.5em; }
  /* D09: the CONTAINER stays the whole card at every width — sizing it back to
     the circle is the defect. Only the circle itself steps down. Below 1000px
     Salient's own `play_button_hover` gate is off, so the circle is visible at
     rest and parks at the card's centre, which is the correct touch behaviour
     (Salient disables the follow entirely on touch via `!bt.usingMobileBrowser`). */
  .mk-whowhyb__play .play_button .play {
    width: 80px; height: 80px; margin-top: -40px; margin-left: -40px;
  }
}

@media (max-width: 480px) {
  .mk-whowhyb            { height: 520px; }
  .mk-whowhyb__text      { padding-inline: 24px; }
  .mk-whowhyb__headline  { font-size: var(--mk-size-title); }  /* 24 — the EN
                              string needs 473px at 36px and cannot fit 375  */
  .mk-whowhyb__caption   { width: 100%; }      /* allow the headline to wrap */
  .mk-whowhyb__btns      { flex-direction: column; align-items: stretch; }
  .mk-whowhyb__pill      { justify-content: center; }
  .mk-whowhyb__play .play_button .play {
    width: 64px; height: 64px; margin-top: -32px; margin-left: -32px;
  }
}

/* Salient disables the follow itself on touch (`!bt.usingMobileBrowser`), so
   the circle is simply static there — no CSS needed to pin it.
   prefers-reduced-motion cannot switch the follow off from CSS: Gi() writes
   `transform` as an inline style every rAF frame and inline wins. Killing it
   properly needs a JS guard, which CONVENTIONS 6 puts out of scope for a
   section builder. Raised in the return notes. What CAN be honoured here is
   the paint transition. */
@media (prefers-reduced-motion: reduce) {
  .mk-whowhyb__pill,
  .mk-whowhyb__play .play_button .play,
  .mk-whowhyb__play .play_button .play:before {
    transition-duration: 1ms;
  }

  /* D08/D10 under reduced motion: the card is SHOWN AT ITS END STATE — full
     bleed, no radius. Same ruling, same reasoning, as css/reduced-motion.css §9
     makes for the closing CTA: the end state is the design, and a visitor who
     asked for less motion should land on it rather than on a frozen mid-scrub
     inset. js/mk-expanding-card.js already refuses to install under this query,
     so nothing of ours writes an inline clip-path; this is the half that beats
     Salient's own init.js, which has no reduced-motion handling anywhere (the
     string appears zero times in vendor/) and will happily start seeking if it
     is promoted. `!important` is what outranks the inline value `je` writes
     every frame — the CONVENTIONS 8.6 case, naming the rule being beaten. */
  .mk-whowhyb__card {
    clip-path: none !important;
    border-radius: 0 !important;
    transition: none !important;
  }
}


/* ============================================================================
   7 · R6-08 — THE FULL-SCREEN HOLD (FT-20260820-jehnean-round6)
   ----------------------------------------------------------------------------
   The ecology mechanic, both halves — the amenities collapse taught that the
   recipe is only a recipe when the TRACK height calc AND the stage sizing land
   together, and that the wrapper insertion must be preceded by a child-
   combinator audit (done: ZERO `>` selectors exist in this file, parsed
   comment-stripped 2026-08-21; rhythm.css reaches this section with a plain
   descendant selector only).

     TRACK   the section. `data-myk-hold="1.167"` in the markup; the height
             calc here. 1.167 screens of pinned travel is Omai's own budget
             for one slide of their sticky module (PACING.md §8.5:
             wrapperVh = 100 + N x 116.7, N = 1) — 1050px at a 900 viewport,
             the per-slide span measured live on their module both in the r3
             research pass and by this lane's wheeled re-measure
             (review/r6/r6-whowhy-omai/omai-sb2-scrub.json).
     STAGE   `.mk-whowhyb__stage`. Sticky comes from 04-ecology.css §G1b's
             page-wide `[data-myk-hold] [data-myk-stage]` rule; the 100svh is
             this section's, here.
     READER  the passive scroll reader shipped in 04-ecology.html binds
             `[data-myk-hold]` generically and writes `--myk-hold-p` 0..1.
             Nothing here adds a listener of any kind. REQ-SCROLL-01 intact.

   OVERFLOW, stated because it is the silent killer: the section declares NO
   overflow anywhere in this file — it must stay `visible` on Y or the sticky
   stage acquires a non-scrolling container and unpins without an error. The
   card's own `overflow: hidden` is INSIDE the stage and clips only the
   photograph against the 4px start radius; it contains no sticky descendant.

   (0,3,0) beats rhythm.css's `.mk-page .mk-whowhyb { height: var(--mk-band-12) }`
   at (0,2,0) — B03's "taller" is superseded by R6-08's "held": the section now
   spends 2.167 viewports instead of 1.2, all of it full-bleed. Same 1000px
   gate as every rhythm token; below it the expand is already a settings-level
   no-op and the section keeps its one-viewport composition (stage 100% of a
   definite 900px track = zero travel = a plain static frame, and §8's
   choreography is gated out with it so nothing can hide text on mobile).
   ========================================================================== */

.mk-whowhyb__stage {
  height: 100%;               /* below 1000px: no travel, static frame        */
}

@media (min-width: 1000px) {
  .mk-page .mk-section.mk-whowhyb {
    /* R7-05a — "a little bit faster". 1.167 -> 0.85; see §9.
       R8-11 — "a little bit longer" on the persist. 0.85 -> 0.95; see §11. */
    --myk-hold-screens: 0.95;
    height: calc(100svh + var(--myk-hold-screens) * 100svh);
  }
  .mk-whowhyb__stage {
    height: 100svh;
  }
}


/* ============================================================================
   9 · R7-05a — SHORTEN THE HOLD TRAVEL (FT-20260821-jehnean-round7)
   ----------------------------------------------------------------------------
   "The black-dress full-screen arc: a little bit FASTER."

   She PRAISED this hold in the same review ("you kinda nailed that parallax
   vibe fading in, fading out"), so the instruction is shorten, not remove.

   MEASURED BEFORE (review/r7/r7-whowhy/before-all.json):
       hold-screens   1.167
       section        2.167 x 100svh  =  1950px @ 900,  2124px @ 980
       pinned travel  1050px @ 900,  1144px @ 980
       total scroll from first sight to gone  (2 + 1.167) = 3.167 screens

   AFTER: 0.85 screens.
       section        1.85 x 100svh   =  1665px @ 900,  1813px @ 980
       pinned travel   765px @ 900,    833px @ 980   (-27.1 %)
       total scroll   2.85 screens                    (-10.0 %)

   WHY 0.85 AND NOT LESS. §8's Saint-Barth windows are fractions of the hold,
   so they shorten with it: in 40 % / hold 40 % / out 20 % becomes 306 / 306 /
   153 px at a 900 viewport (was 420 / 420 / 210). 306px of scroll is still
   ~2.5 wheel notches of legible full-screen caption before it starts to leave
   — the "smooth in, hold, smooth out" of C03 survives. Below ~0.7 the hold
   stops reading as a hold and becomes a blink, which is the thing R3-G calls
   "hard and fast" and moves away from.

   THE OMAI 1.167 IS NOT BEING CONTRADICTED, it is being re-scoped: PACING §8.5
   measured 116.7vh per slide on a THREE-slide module, where each slide has to
   carry its own crossfade. This band holds ONE frame. The founder is the
   authority on how long her own frame should hold, and she has now used it.
   ========================================================================== */


/* ============================================================================
   11 · R8-11 — EXTEND THE HOLD, A LITTLE BIT LONGER (FT-20260821-jehnean-round8)
   ----------------------------------------------------------------------------
   "I actually almost want the text to persist a little bit longer on that
   one." She likes this section's choreography overall ("it's pretty good") —
   this is a small precise nudge, not a redo of §9's tuning.

   THE PLATEAU, not the whole arc, is what "persist" names: §8's opacity
   formula holds `.mk-whowhyb__text` at 1 across the MIDDLE 40 % of
   `--myk-hold-p` (frac 0.4-0.8), fading in over the first 40 % and out over
   the last 20 %. Scaling `--myk-hold-screens` scales all three windows by the
   same factor, so the deliberate 40/40/20 in/hold/out ratio §9 tuned is
   preserved exactly — only the absolute px each window spans grows. Widening
   only the hold fraction instead would have reopened that ratio decision;
   this does not.

   MEASURED BEFORE (founder-trace/r8-black-dress-hold/BEFORE.PARTIAL.json,
   live DOM scan — opacity sampled every 1/60th of the pinned travel, not
   recomputed from the formula):
       hold-screens        0.85
       plateau (opacity=1) frac 0.4000 - 0.8000, width 0.4000
       plateau px          306.0px @900  (1280 & 1440),  333.2px @980 (1750)
       pinned travel        765px @900,                   833px @980
       section height       1665px @900 (1.85x100svh),   1813px @980

   AFTER: 0.95 screens (+0.10, +11.8 % over 0.85). Chosen as a MODEST step —
   she said "a little bit," not "a lot" — that stays well inside §9's stated
   safe band (>~0.7, below which the hold reads as a blink) and does not
   walk back toward the original pre-R7-05a 1.167 (this keeps 81 % of that
   round's "faster" cut; 0.95 is still 18.6 % below 1.167).
       pinned travel        855px @900 (+90px, +11.8 %),  931px @980 (+98px)
       plateau (persist)    342px @900 (+36px, +11.8 %),  372.4px @980 (+39.2px)
       section height       1755px @900 (1.95x100svh),    1911px @980
       total scroll, first sight -> gone   2.95 screens (was 2.85, +3.5 %)

   Re-measured live after the edit, same instrument, same five viewports:
   founder-trace/r8-black-dress-hold/AFTER.json. Below the 1000px gate (834,
   390) nothing in this section reads `--myk-hold-screens` at all — §7's
   `.mk-whowhyb__stage { height: 100% }` and the ungated `.mk-whowhyb__text`
   rule both hold the static, always-opacity-1 composition, confirmed
   unchanged by direct sample at both widths.

   R7-05b (the cursor-pin scroll-compensation fix, §1b's inline
   `window.mykCursorPin` reader) and R7-05a's own hold-speed change are both
   geometry-driven off `section.getBoundingClientRect()` and `stage`/`section`
   heights read live every frame — neither hard-codes 0.85 anywhere, so
   neither needed a change and neither regressed; re-verified against R7-05's
   own ≤1px drift assertion after this edit (AFTER.json, `cursor_drift`).
   ========================================================================== */


/* ============================================================================
   10 · R7-06, FIRST HALF — THE PERMANENT WHITE BARS AT >= 1441
   ----------------------------------------------------------------------------
   "The white side bars are visible TOO LONG."

   MEASURED (review/r7/r7-whowhy/before-all.json, scrub02):

       viewport      card left   card width   at FULL expand (right inset 0 %)
       1280 x 900        0         1280        full bleed
       1440 x 900        0         1440        full bleed
       1750 x 980      155         1440        155px of MIST STILL SHOWING
                                               ON BOTH SIDES, FOREVER

   At her effective viewport the bars never close at all. That is not the
   scrub being slow — it is a second, static pair of bars underneath it, and
   it is why "too long" reads as "never" in the band she reviews in.

   WHERE THEY COME FROM. `css/_band-xl.css` §1b puts
   `padding-inline: var(--mk-xl-inset)` on `[data-mk-slug="02-who-why-b"]`
   above 1440, to cap this section's INK at CW = 1440 like the twenty
   `.mk-container` sections. That was correct when it was written, and its own
   comment states the premise it rested on: "Backgrounds are unaffected —
   padding never clips a background — so 02's photographic ground ... keep
   bleeding." R6-08 falsified that premise. The ground is no longer a
   background on the section: it is `.mk-whowhyb__card`, `position:absolute;
   inset:0` inside `.mk-whowhyb__stage`, and the stage is an IN-FLOW block, so
   it resolves against the section's PADDING box and inherits the 155px inset.

   THE FIX IS THE RULE THE BAND FILE ITSELF QUOTES — "content caps at CW and
   centres, backgrounds bleed" — restored by splitting the two again:

     · the SECTION releases its padding, so the stage (and the card that is
       `inset: 0` inside it) spans the full viewport again.
     · the CONTENT LAYER takes over the cap itself, so the INK DOES NOT MOVE:
       `max-width: var(--mk-frame)` + `margin-inline: auto` inside a now
       full-bleed card puts the caption box back at left 155 and its ink at
       155 + 120 = 275 — exactly where the section-level padding had it.
       VERIFIED after: caption/pill ink x unchanged at 1750.

   ONE THING THAT DID NOT WORK, RECORDED SO IT IS NOT RE-TRIED. The first
   attempt cancelled the inset on the STAGE with
   `margin-inline: calc(-1 * var(--mk-xl-inset))` and MEASURED as a no-op:
   computed `margin-left: 0px`, stage still 1440 @ left 155. The token is
   `calc(50% - var(--mk-frame)/2)` and a percentage in it resolves against THE
   CONSUMING ELEMENT'S OWN containing block. On the section that is the
   1750px parent -> 155. On the stage it is the section's already-padded 1440
   CONTENT box -> 50% of 1440 = 720, minus 720 = 0. Same token, two bases.
   Releasing the padding at its source is the form that has one base.
   (`width: 100vw` is not an option either — _band-xl.css §0 reason 1 records
   why: `100vw` includes a classic scrollbar and would put the ground 7-8px
   off from every other section on a non-overlay-scrollbar platform.)

   ONE MEASURED CONSEQUENCE, stated rather than left silent: the donor's 9.375%
   rest inset now resolves against the viewport instead of a 1440 content box,
   so the RESTING card's painted left edge above 1440 changes — 290 -> 164.1 at
   1750, 375 -> 180 at 1920. Below 1441 nothing moves (120 at 1280, 135 at
   1440, both unchanged). It is smaller, i.e. the direction R7-06 asks for, and
   it restores the same viewport-fraction relationship the two artboards state.

   Scoped to this section and to >= 1441 only, so _band-xl.css keeps its single
   ownership of the band token and of the other five sections. Filed for that
   file's owner as OBS-XL-02 in founder-trace/SHARED-REQUESTS.md, because
   03-unique and 08-recovery are in the same §1b selector list and may have
   grown grounds of their own since it was written.
   ========================================================================== */

@media (min-width: 1441px) {
  /* (0,3,0) against _band-xl.css §1b's (0,1,0) `[data-mk-slug="02-who-why-b"]`,
     so it wins on specificity and does not depend on sheet order — which
     matters, because _tools/compose.py emits the band sheets LAST. */
  .mk-page .mk-section.mk-whowhyb {
    padding-inline: 0;
  }
  .mk-page .mk-whowhyb .mk-whowhyb__text {
    max-width: var(--mk-frame);
    margin-inline: auto;
  }
}


/* ============================================================================
   8 · R6-09 — THE SAINT-BARTH TEXT CHOREOGRAPHY, ONE TO ONE
   ----------------------------------------------------------------------------
   Every number below is a live measurement of Omai's sticky-module content,
   taken by this lane with a real wheel on the current deploy
   (review/r6/r6-whowhy-omai/omai-sb2-scrub.json, 2026-08-21), agreeing with
   the r3 research record (review/omai/PACING.md §3) to the third decimal:

     travel    translate3d(0, +120px -> -120px, 0), LINEAR against scroll,
               across the whole window            (ENTER_Y/EXIT_Y = ±120)
     opacity   0 -> 1 over the FIRST 40% of the window
               1        through 40% - 80%   (still travelling — no pause)
               1 -> 0 over the LAST 20%     (out is HALF the in; deliberate
                                             asymmetry, do not even it up)
     ground    opacity only, transform none at every sample — motionless
     follower  a 100ms ease:"none" smoother so the scrub cannot judder

   `--myk-hold-p` is the scroll progress the hold reader writes on the section
   (inherited here). With the hold at 1.167 screens the windows land, at a 900
   viewport, on 420px in / 420px hold / 210px out — Omai's own 420/420/210 —
   and the drift rate is 240/1050 = 0.229 px per px of scroll, their measured
   signature number.

   THE FALLBACK IS THE FAIL-OPEN, and it is exact: `var(--myk-hold-p, 0.5)` at
   its 0.5 fallback computes opacity 1, translateY 0 — byte-for-byte the
   static composition this section shipped yesterday. Reader missing, JS off,
   attribute never written -> the caption and pills simply stand where Figma
   put them. Nothing here can hide content behind a dead script.

   Applied to the WHOLE `.mk-whowhyb__text` layer — heading, 3:45, both quiz
   pills move as one block — exactly as Omai drives one content wrapper per
   slide, not per element. `opacity` (not visibility) so the pills stay
   focusable for keyboard users; they are fully legible through the middle
   60% of the hold, which is where the reader is parked when not scrubbing.

   Gated to the same >=1000px as §7: below it there is no travel, p would sit
   at 0 forever, and this rule would permanently hide the caption. The gate is
   load-bearing, not tidy.
   ========================================================================== */

@media (min-width: 1000px) {
  .mk-page .mk-whowhyb .mk-whowhyb__text {
    --myk-sb-p: var(--myk-hold-p, 0.5);
    /* R10-01 — see §12. `--mk02-text-lead-p` replaces the old `sb-p / 0.4`
       IN term: it is written by the section-scoped reader in
       02-who-why-b.html and reaches 1 BEFORE the section pins, synced to
       the milestone she named ("cup, wrist, chair") instead of a fraction
       of the hold that cannot even start moving until after it. */
    --mk02-lead-p: var(--mk02-text-lead-p, 1);
    opacity: clamp(0, min(var(--mk02-lead-p),
                          calc((1 - var(--myk-sb-p)) / 0.15)), 1);
    transform: translate3d(0, calc(120px - 240px * var(--myk-sb-p)), 0);
    /* Omai's own per-frame smoother: gsap.to(..., duration: 0.1, ease: "none")
       — PACING §3 calls it "not an animation — a 100ms smoothing follower so
       the scrub does not judder frame to frame". A property-NAMED transition:
       clip-path is scrubbed inline on the card by mk-expanding-card.js and a
       transition reaching it would turn that scrub into a chase and trip the
       driver's readback stand-down (its file header forbids exactly this). */
    transition: opacity 100ms linear, transform 100ms linear;
  }
}

/* ============================================================================
   12 · R10-01 — SYNC THE ENTRY TO THE VISUAL MILESTONE, EXTEND THE OUT-START
   (FT-20260822-jehnean-round10)
   ----------------------------------------------------------------------------
   Her words: "by the time it goes full screen, and I can see her cup and
   wrist and chair, I want the text to be on... doesn't appear soon enough
   and doesn't persist long enough." Additive to R8-11 (which extended the
   hold's plateau, §11) and separate from R9-01 (which fixed the MEDIA
   card's own fade-in trigger, in 02-who-why-b.html) — neither touched the
   CAPTION's entry.

   WHY §8's OLD IN-TERM STRUCTURALLY COULD NOT SYNC TO HER MILESTONE. It was
   `sb-p / 0.4`, and `sb-p` IS `--myk-hold-p`, which 04-ecology.html's shared
   reader clamps to 0 for the section's entire ARRIVAL — by construction it
   cannot move until the section PINS (`-r.top/travel`, and `r.top >= 0`
   the whole time before that). The milestone she is naming happens DURING
   arrival (measured below), so no retuning of the 0.4 fraction alone could
   ever have synced to it — the trigger had to start reading BEFORE hold-p
   exists at all.

   MEASURED LIVE, at the two most different desktop aspect ratios this
   section ships (1280×900, cover-crops the photo HORIZONTALLY because the
   viewport is narrower than the image's 1.4986 aspect; 1750×980 — her own
   viewport — crops it VERTICALLY, the wider case): cup and the bracelet on
   her wrist are on-screen early and stay on screen; the CHAIR, lowest in
   frame, is the gating element of the three and first clears the fold at

       viewport      cardTop at first full chair visibility   as a
                      (px, bisected from live screenshots)     fraction of vh
       1280×900       ~110 - 130                                0.122 - 0.144
       1750×980        ~90 - 130                                0.092 - 0.133

   (`cardTop` = `section.getBoundingClientRect().top`; 0 is "full screen" —
   the pin. The Phase-2 clip-path, above, has already reached full bleed by
   cardTop ≈ 0.30·vh at both widths — the clip is never the gate here, the
   plain vertical scroll of the card into view is.) Both viewports land in
   the same ~0.09-0.14·vh band despite the opposite cover-crop axis — good
   evidence this is one real, stable visual event, not a one-width fluke.
   Evidence: review/r10/r10-blackdress/{MILESTONE-SWEEP-1750x980.json,
   shots2/, shots3/, shots_1280/}.

   THE FIX, IN TWO PARTS.

   ENTRY — `--mk02-text-lead-p` (written in 02-who-why-b.html, a second
   section-scoped rAF-batched passive reader, same shape as 04-ecology.html's
   own `read()`/`onScroll` and the same "add a local mechanism instead of
   retuning the shared one" call R9-01 made for the media card — 04-ecology
   .html is this round's OTHER lane's file). It ramps 0 -> 1 as `cardTop`
   runs from 0.30·vh down to 0.10·vh, finishing a small, deliberate margin
   BEFORE the measured 0.09-0.14·vh chair milestone closes, so the text is
   never still fading when all three landmarks are already visible. Past
   0.10·vh — which covers the rest of arrival, the pin itself, and the
   whole hold — it simply latches at 1; nothing downstream needs it to keep
   moving once "in" is done.

   PERSIST — `--myk-sb-p`'s OUT term moves from starting at hold-p 0.8 to
   hold-p 0.85 (0.2 window narrows to 0.15). This is a SEPARATE, modest,
   explicit answer to "doesn't persist long enough" (same "a little, not a
   lot" calibration §11 used), on top of — not instead of — the much larger
   persist gain the entry fix hands over for free: moving the fade-IN
   entirely into the pre-pin arrival frees essentially the WHOLE hold
   (was: the middle 40%) to read as plateau.

   TRANSFORM IS UNCHANGED, DELIBERATELY. §8's own header: the 240px drift is
   "LINEAR against scroll... ACROSS THE WHOLE WINDOW", independent of the
   opacity phase — it already did not pause during the old plateau, so
   leaving it keyed to `--myk-hold-p` alone (starting its climb at the pin,
   same as before) does not create a new mismatch; it means the text is
   already fully "on" and stationary through the tail of arrival, then
   begins its slow climb once truly in the held frame — which is closer to
   "full screen -> text is on" than having it drift while still arriving.

   FAIL-OPEN, same shape as every mechanic in this file: `var(--mk02-text-
   lead-p, 1)` defaults to 1 when the reader never runs. Combined with
   `--myk-hold-p`'s own 0.5 fallback, opacity resolves to 1 and translateY
   to 0 — the static "stand where Figma put them" composition, exactly as
   before this item. Gated by the same >=1000px rule as §7/§8; below it
   nothing here is read (`--mk02-text-lead-p` may still be written, same as
   `--myk-hold-p` is, but no rule below 1000px consumes it).

   DOES NOT TOUCH: 04-ecology.html (shared hold reader — another lane's file
   this round), js/myk-motion.js / css/myk-motion.css (shared entrance
   vocabulary), js/mk-expanding-card.js (the clip-path scrub), or R9-01's
   `.mv-in` media trigger. MEASURED AFTER and the helix writeup are in
   founder-trace/helix/R10-01.md.
   ========================================================================== */

/* ============================================================================
   13 · R11-01 — PERSIST-THROUGH EXIT, PROMOTED FROM EXPERIMENT TO THE
   STANDING PATTERN (FT-20260822-jehnean-round11)
   ----------------------------------------------------------------------------
   HER WORDS, this round, reviewing 18-cta-expand's R10-09 experiment live:
   "I liked persisting the content on the outro... so given that's our new
   pattern for these kinda immersive full screen image/videos, can you go
   back to is a safe stay right for me and just persist that text and
   buttons on the outro instead of having them fade out? I think that's a
   nicer user experience." Stated identically twice across both review
   passes this round (see the founder-trace file's own note) — one item, and
   both this section and 18-cta-expand are no longer experimental as of this
   review.

   REUSE, NOT RE-DERIVE — the task's own instruction, and it applies exactly:
   sections/18-cta-expand.css §5a built this mechanism first (as R10-09, an
   experiment) against `.mk-ctacard__stack`'s formula, which §5's own header
   states is "R6-09's SAINT-BARTH formula from sections/02-who-why-b.css
   VERBATIM." §8/§12 above are that ORIGINAL formula this section owns —
   §5a's mechanism transplants back onto its own source with zero
   translation needed, because the transform body is byte-identical in both
   files: `translate3d(0, calc(120px - 240px * var(--sb-p)), 0)`.

   THE MECHANISM — ONE CUSTOM-PROPERTY OVERRIDE, ZERO NEW JAVASCRIPT, ZERO
   NEW FORMULA. §8/§12's own two declarations (`opacity`, `transform`) are
   left completely untouched below — this block overrides ONLY the custom
   property they both read, `--myk-sb-p`, by re-declaring it on a MORE
   SPECIFIC selector that adds one modifier class to the section. Custom
   properties cascade independently of which rule's OWN declarations consume
   them via `var()`, so §8/§12's `opacity`/`transform` lines keep applying to
   `.mk-whowhyb__text` unedited; only which rule wins the cascade for
   `--myk-sb-p` on that element changes.

   WHY 0.5, DERIVED FROM THIS SECTION'S OWN FORMULA, NOT COPIED AS A NUMBER.
   `transform`'s zero-crossing (rest, translateY 0) is `120 - 240p = 0` ->
   `p = 0.5` — the SAME arithmetic 18-cta-expand.css §5a derived, because
   the coefficients (120, 240) are identical in both files by construction
   (§8's own header: "R6-09's SAINT-BARTH formula... reused VERBATIM").
   Clamping the INPUT at 0.5 — never the output — means: for real progress
   `p` in [0, 0.5], the clamped input equals `p` exactly, so R10-01's own
   entry choreography (§12's `--mk02-text-lead-p` sync to the cup/wrist/chair
   milestone, and the transform's climb toward rest) is BYTE-IDENTICAL to
   before this item — nothing about the entrance changes. At `p = 0.5`
   exactly: `--mk02-text-lead-p` has already latched to 1 (it finishes
   ramping during ARRIVAL, well before the hold reaches its own midpoint —
   §12's own derivation), and the opacity out-term
   `(1 - 0.5) / 0.15 = 3.33` is already >= 1, so
   `clamp(0, min(1, 3.33), 1)` evaluates to `1` — opacity is ALREADY fully
   settled at the SAME point transform reaches rest, exactly the same
   coincidence-that-is-not-a-coincidence §5a documented for 18-cta-expand
   (both properties root in the same shared `sb-p` input by the formula's
   own construction). For any real `p > 0.5` — which covers the rest of the
   hold's plateau AND the out-phase §12 narrowed to start at hold-p 0.85 —
   the clamped input stays pinned at 0.5, so opacity stays 1 and transform
   stays `translate3d(0,0,0)`, Figma's exact rest composition, all the way
   through release. No fade-out window is deleted by removing code; it is
   simply never reached.

   THE TOGGLE. `mk-whowhyb--persist-exit` added to `<section
   id="s02-who-why-b">`'s class list (02-who-why-b.html). Shipped LIVE — she
   asked for the pattern applied, not merely demonstrated, and named it
   "our new pattern," so this is a committed default, not a variant awaiting
   her verdict the way R10-09 still was on 18-cta-expand before this round.
   Rollback = remove that one class; §8/§12 need no change either direction.

   SPECIFICITY, not `!important`. `.mk-page .mk-whowhyb.mk-whowhyb--persist-
   exit .mk-whowhyb__text` is (0,4,0) against §8/§12's (0,3,0) — one
   additional class, unconditionally higher regardless of source order.

   SCOPE: entrance and hold are IDENTICAL to the pre-R11-01 build by
   construction (same clamp for p<=0.5) — only p>0.5 differs, and only for
   `.mk-whowhyb__text` (the caption + the two quiz pills, §8's own "applied
   to the WHOLE .mk-whowhyb__text layer" scope — "text and buttons" in her
   words). The full-bleed photo/video card (`.mk-whowhyb__card`) is a
   SEPARATE element driven by its own clip-path scrub (js/mk-expanding-
   card.js) and is untouched by this block either way — same scope
   discipline §5a used for 18-cta-expand's own full-bleed photo.

   Gated to the same >=1000px as §7/§8/§12: below it there is no hold
   travel, `--myk-hold-p` sits at its fallback, and this block's own clamp
   is a no-op regardless (min(0.5, 0.5) = 0.5, matching the fallback path).
   ========================================================================== */
@media (min-width: 1000px) {
  .mk-page .mk-whowhyb.mk-whowhyb--persist-exit .mk-whowhyb__text {
    --myk-sb-p: min(var(--myk-hold-p, 0.5), 0.5);
  }
}

/* ============================================================================
   14 · RM-02 — THE FULL-SCREEN HOLD, BELOW 1000px (mobile round, 2026-08-31)
   ----------------------------------------------------------------------------
   Founder: on mobile the card reads small next to its neighbours; she wants
   the ecology treatment — "I see it, and then it zooms to full screen." The
   settings JSON now carries real tablet/phone keyframes (see RM-02 in the
   markup); this block is the geometry half of the same recipe §7 states for
   desktop, both halves together per the amenities lesson: the TRACK height
   calc AND the 100svh STAGE must land as a pair.

   TRACK   (0,3,0) beats the section's own phone-tier `height: 640px`/`520px`
           at (0,1,0) (§6 — those rules stay as the fail-open record) and
           _band-xs.css's 691-768 `.mk-whowhyb { height: 900px }` re-assert,
           which is also (0,1,0) and emitted last by compose. 0.95 screens =
           §11's founder-tuned budget, reused rather than re-derived — same
           arc, every width.
   STAGE   (0,2,0) beats §7's ungated `.mk-whowhyb__stage { height: 100% }`
           at (0,1,0). Without this override 100% would resolve against the
           new 1.95-screen track and the card (`inset: 0` in the stage) would
           paint two viewports tall. Sticky itself needs no rule here —
           04-ecology.css §G1b's `[data-myk-hold] [data-myk-stage]` is
           ungated and already reaches every width.

   The hold reader (04-ecology.html) is bound by attribute at every width and
   computes travel from live geometry, so `--myk-hold-p` simply starts moving
   here — but nothing below 1000px consumes it (§8/§12/§13 are all ≥1000px
   gated), so the caption and pills keep their static, always-opacity-1
   mobile composition: full-screen pin, no text choreography, nothing can
   hide content behind a dead script. Fail-open unchanged too: JS absent ->
   no clip-path is ever written -> a static full-bleed 100svh frame.

   OVERFLOW: still none anywhere on the section, at any width — the sticky
   stage must never acquire a non-scrolling container (§7's silent killer).
   ========================================================================== */
@media (max-width: 999px) {
  .mk-page .mk-section.mk-whowhyb {
    --myk-hold-screens: 0.95;
    height: calc(100svh + var(--myk-hold-screens) * 100svh);
  }
  .mk-whowhyb .mk-whowhyb__stage {
    height: 100svh;
  }
}

/* ============================================================================
   15 · RM2-01 — MOBILE ART DIRECTION OF THE CARD'S MEDIA (mobile round 2,
   2026-08-31, videoart lane)
   ----------------------------------------------------------------------------
   FOUNDER, on a real Pixel 7: the full-screen card is "really weird and
   doesn't land" — "the image itself is kinda getting lost... too much of the
   lady is getting cropped." Her two suggested directions: (a) shift the
   focal point so her face is visible; (b) a gradient at the TOP of the image
   blending into the page background so the card reads as an intentional
   composition. Both are applied below; both were measured first.

   THE ARITHMETIC OF THE DEFECT. The photograph is 2669x1781 (ar 1.4986). On
   a 412x780 portrait viewport `cover` scales by max(412/2669, 780/1781) =
   0.4379 -> a 1169px-wide image of which the viewport shows 412/1169 =
   35.2%. `background-position: center` (§1) shows image x 32.5%..67.5%.
   The woman's face+hair bbox, measured off the source file this round:
   x 71.5%..93%, y 22.4%..52%. Zero overlap — at the pinned full-screen
   state the frame is cup/legs/chair/bokeh and she is entirely outside it.
   Verified live before the fix (fresh-load probe, no settle walk, 412x780:
   scratchpad mobile-round/videoart/base-780-pin.png).

   (a) THE FOCAL POINT — `96% center` for the photo layer at <=999px.
   Feasible band, solved for "face fully inside the window" at BOTH the
   full-bleed state and the resting inset state (whose 6% side insets trim
   the window by 6% of the viewport per side), at both Pixel 7 viewports:
       412x780:  window 35.2% wide, left edge = 0.648·P  ->  P in [92.4, 100]
       412x915:  window 30.0% wide, left edge = 0.700·P  ->  P in [92.6, 99.6]
       768x1024: window 50.0% wide, left edge = 0.500·P  ->  P >= 86
   96 sits mid-band for the intersection. Vertically `cover` fills the
   height exactly on every portrait viewport here (scale is height-bound),
   so `center` is a no-op on y and the face band y 22..52% maps 1:1 to the
   viewport — no y knob exists or is needed. In mobile landscape the crop
   axis flips, x 96% becomes the no-op, and center-y keeps her in frame.

   (b) THE TOP GRADIENT — REMOVED (founder review, same day, second pass):
   "you have this white gradient now on the full screen, and I don't want
   you to do that... just make it a solid image, the animation solid." The
   focal-point fix in (a) is what she approved ("moving it over, you did a
   great job"); the gradient was a separate suggestion offered alongside it
   and she's now explicit that it reads wrong in practice. Reverted to a
   plain background-image (photo + the pre-existing bottom shadow for
   caption/button legibility, unchanged) — no top wash of any kind.

   THE EXPAND MECHANIC IS UNTOUCHED: keyframes, offsets, driver, hold — not
   one value changes; this block repaints `.row-bg` (a static layer the
   scrub clips) and nothing else. Desktop >=1000px: byte-identical, the
   §1 rule still stands alone there.

   Specificity/order: (0,2,0) ties §1's `.mk-whowhyb .row-bg` and wins as
   the later declaration in this same file; no band sheet declares
   background-* for this section (grepped css/_band-*.css, rhythm.css,
   grid-fluid.css this round — zero hits).
   ========================================================================== */
@media (max-width: 999px) {
  .mk-whowhyb .row-bg {
    background-image:
      linear-gradient(to bottom, transparent 0%, var(--mk-shadow-25) 100%),
      url("../img/02-who-why-b/hero-park-chair.webp");
    background-size: 100% 100%, cover;
    background-position: 0 0, 96% center;
    background-repeat: no-repeat;
  }
}

/* Reduced motion: the composition, resolved — the rule css/reduced-motion.css
   states for the whole page: show the FINAL state, never hide the content.
   The hold reader still runs under this query (it is a geometry reader, not an
   animation), so without this block the choreography would scrub for a visitor
   who asked for stillness. !important beats the inline-adjacent custom-property
   arithmetic above at equal specificity from a later position, and survives
   reduced-motion.css's own global transition floor. */
@media (prefers-reduced-motion: reduce) {
  .mk-page .mk-whowhyb .mk-whowhyb__text {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
}

/* ==========================================================================
   2026-09-02 — TABLET PORTRAIT (iPad Pro), two founder items.

   (a) HER FACE LEAVES THE FRAME. §11 above measured the face+hair bbox at
       image x 71.5%..93% and fixed the phone (<=999px) with `96% center`.
       An iPad Pro 13" in portrait is 1024px wide — it takes the >=1000px
       desktop composition — and at 1024x1366 `cover` shows only image x
       25%..75% under `center`: she is entirely off the right edge (rendered:
       _tools/_scratch/eyes/ipadpro-02). Any PORTRAIT viewport has this
       problem, so the focal-point rule keys off orientation, not width.
       Founder's general rule, recorded as a fleet predicate: when a
       full-bleed photo's subject would be pushed off screen on a device,
       recentre the image on the subject for that device.

   (b) THE PLAY CIRCLE IS MISSING. >=1000px runs Salient's `play_button_hover`
       gate (opacity 0 until :hover) and its follow-the-mouse controller; a
       touch device never hovers and never sends the mouse move that would
       place the circle, so it stays invisible. On a no-hover device the
       circle is shown at rest and parked at the card's centre — the phone
       treatment (D09), at every width. `!important` because Salient's Gi()
       writes `top:0;left:0` and a transform inline. */
@media (orientation: portrait) and (min-width: 1000px) {
  .mk-whowhyb .row-bg {
    background-position: 0 0, 96% center;
  }
}
@media (hover: none) and (min-width: 1000px) {
  .mk-whowhyb .nectar_video_player_self_hosted.play_button_hover .play { opacity: 1; }
  .mk-whowhyb .nectar_video_player_self_hosted.play_button_hover .play:before { transform: scale(1); }
  .mk-whowhyb__play .play_button .play {
    top: 50% !important;
    left: 50% !important;
    transform: none !important;
  }
}
