/* ============================================================================
   SECTION 16 · "5.2 Amenities" · Figma 2924:349 · 1280 x 900 @ page y 15609
   ----------------------------------------------------------------------------
   SPEC   figma-truth/16-amenities-52.spec.md
   PIXELS figma-truth/sections-en/16-amenities-52.png (2560x1800, @2x)
   HTML   sections/16-amenities-52.html  <- read its header first. It records
          what was lifted from the Salient "Nonprofit" demo and what was
          retargeted.

   This file does two jobs and they are kept apart:

     PART A  §1..§6   Figma's layout, type and colour for this section.
     PART B  §7..§10  the minimum set of rules needed to make Salient's real
                      `mouse_follow_image` post grid sit on Figma's geometry.
                      Every rule in Part B names the Salient declaration it is
                      out-specifying and why. No `!important` is used anywhere
                      in this file — every conflict is won on specificity, per
                      CONVENTIONS §8 trap 6 ("measure the computed style before
                      adding !important").

   ---------------------------------------------------------------------------
   THREE PAYLOAD CLAIMS THIS SECTION'S SPEC OVERTURNS (spec §0). The Figma MCP
   does not serialise the per-paint `visible` flag, so `get_node_full` reports
   paints that never reach a pixel. Each was settled by sampling the render:

     1. `#1eb2bc` on the CTA button  -> DOES NOT RENDER. Interior pixel at
        (230,712) is #cbd6dc, identical to the section ground. The CTA is an
        OUTLINE pill with no fill. Painting the teal here is the single most
        likely way to get this section visibly wrong.
     2. `#d9d9d9` on the nine 24x24 `Bounding box` rectangles -> DOES NOT
        RENDER. There is no grey square anywhere in the export. They are the
        Material-Symbols export artefact; they are not built.
     3. The 1px `#000000` CENTER stroke on the heading DOES render. Stems
        measure 3.73-3.90 design px at 48px type, heavier than Merriweather
        Light 300 alone. See §3.

   ---------------------------------------------------------------------------
   THE GRID. Spec §6.3 tests this section against a 12-column grid and returns
   an explicit NO: for the 298.67 columns at a 370.67 pitch to be 4-column
   spans, `12c + 11g = 1040` forces g = 72 / c = 20.667, which is arithmetic
   accommodating a layout that was never gridded. The true structure is three
   equal fluid tracks inside a fixed 120px margin:

       3 x 298.67 + 2 x 72 = 896 + 144 = 1040   exact at 1280
       3 x 352    + 2 x 72 = 1056 + 144 = 1200  exact at 1440

   so `repeat(3, 1fr)` with a FIXED 72px gutter reproduces both frames to the
   pixel. `.mk-grid12` is not used here (CONVENTIONS §5, grid.css DERIVATION 3).

   ---------------------------------------------------------------------------
   VERTICAL RHYTHM IS COMPUTED, NOT AUTHORED (spec §1.3). The `Text` frame is
   `primaryAxisAlignItems: CENTER` inside 900 - 96 - 12 = 792 of free height:

       content 24 + 24 + 60 + 24 + 284 + 24 + 40 = 480
       slack   (792 - 480) / 2 = 156   ->  first child top y = 96 + 156 = 252

   The only reason ES differs is one extra wrapped label (grid 316 not 284),
   which re-centres the stack 16px up. So this is built as a centred column and
   the language delta falls out for free. NO y OFFSET IS HARD-CODED.
   ========================================================================== */


/* ==========================================================================
   PART A — FIGMA
   ==========================================================================
   §1. THE BAND
   ====================================================================== */

/* Root frame 2924:349: 1280 x 900, SOLID #cbd6dc (pixel-verified at (20,20),
   (640,120) and (640,850)). Height is authored FIXED at both captured widths;
   it ships as min-height because every text node is AUTO-sizing and will grow
   past 900 once the labels wrap further (spec §7.3, first forced decision). */
.mk-amenities52 {
  background-color: var(--mk-surface-stone);
  min-height: 900px;
}

/* `position: relative` ONLY. See the HTML header: a transform / filter /
   perspective / backdrop-filter / contain:paint / will-change:transform on any
   ancestor would make `position: fixed` resolve against THIS box and trap the
   cursor-follower inside the section. */
.mk-amenities52__frame {
  position: relative;
  min-height: 900px;
}


/* ==========================================================================
   §2. `Ellipse 7` 2931:631 — the decorative photo circle
   ====================================================================== */

/* ==========================================================================
   D09 — `Ellipse 7` AND ITS HAND-OFF RULE ARE DELETED
   --------------------------------------------------------------------------
   What stood here: `.mk-amenities52__ellipse` (absolute, left 960 / top 360,
   200x200, circle-masked), plus the `:has(.nectar-post-grid.mouse-over)`
   opacity hand-off that faded it out while the follower was live, plus that
   rule's reduced-motion counter-rule.

   Founder D09, verbatim: *"That was in Figma just me showing you an example of
   what the hover tooltip could look like. I need that to not be there by
   default. It's only a hover tooltip on the bathroom."* The rest state has no
   circle, so there is no plate to position, no plate to fade, and no plate to
   protect under reduced motion. All three rules go, rather than one being
   neutralised with `display: none` — a rule that paints nothing in every state
   is dead code that reads as intent.

   THE HAND-OFF RULE WAS THE RIGHT FIX TO THE WRONG PROBLEM, and that is worth
   keeping on the record. It existed because two 200px circles painted at once
   during a hover. It made that stop. It could not make the *resting* frame stop
   covering three of the nine labels, because it was gated on `.mouse-over` and
   was therefore inert at rest — which is exactly the frame the founder was
   looking at when she filed D09. A hover-gated rule can never repair a rest
   state. The rest state was the defect the whole time.

   DEAD WITH IT, further down: §11's `@media (max-width: 1279px)
   { .mk-amenities52__ellipse { display: none } }`, which hid the plate below
   1280 because Figma positions it for no other width (spec §7.3). With no plate
   at any width there is nothing to hide. Deleted there, noted here.
   ====================================================================== */

/* ==========================================================================
   §3. THE CONTENT COLUMN — `Text` 2924:350
   ====================================================================== */

.mk-amenities52__col {
  position: relative;
  min-height: 900px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;            /* counterAxisAlignItems: MIN */
  justify-content: center;            /* primaryAxisAlignItems: CENTER */
  gap: var(--mk-space-24);            /* itemSpacing 24 */
  /* padding 96 / 120 / 12 / 120 — the 120s come from .mk-container. */
  padding-block: var(--mk-space-96) var(--mk-space-12);
}

/* eyebrow 2924:351 — Poppins Light 16, tracking 3px, box height 24, fill
   #000000 (NOT --mk-ink-body). `.mk-eyebrow` already supplies the family,
   weight, size, 24px line box, 3px tracking and the uppercase transform.

   `textCase` is NOT serialised by the MCP (spec §4.2, lossiness 5): the stored
   characters are mixed case, both renders are UPPERCASE. Inferred from the
   render. No other text node in this section carries a case transform.

   The box measures 1040 = the full content width; it is LEFT aligned so the
   width is inert, but `align-self: stretch` keeps the DOM box honest against
   the spec table. This eyebrow is NOT centred, so the trailing-letter-space
   compensation in CONVENTIONS §8 trap 3 does not apply.

   SALIENT TRAP — the same one that cost 15-amenities-51 39px and 10-recovery-41
   a whole column (NOTES 15-G / R41-3). `skin-material.q-2c163bc272.css` ships
   `p{padding-bottom:var(--nectar-paragraph-bottom-spacing,1.5em)}`, which at
   16px resolves to 24px UNDER this eyebrow — turning the parent's 24px
   itemSpacing into 48 and, because the column is centre-aligned, dropping the
   whole stack 12px. Figma has no paragraph spacing anywhere in this subtree;
   the 24 rhythm is the parent frame's itemSpacing (spec §1.3). Zeroed, not
   worked around. `p` is (0,0,1) so a class beats it; no !important needed. */
.mk-amenities52__eyebrow {
  align-self: stretch;
  margin: 0;
  padding: 0;
  color: var(--mk-ink-strong);
}

/* heading 2924:352 — Merriweather Light 300 / 48, box height 60, fill #000000
   PLUS a 1px #000000 stroke, strokeAlign CENTER.

   The stroke DOES render (spec §0 / §4.2): measured off a 6x export, the
   vertical stems are 22-23 device px = 3.73-3.90 design px at 48px type
   (0.078-0.081 em), heavier than Light 300 alone. `-webkit-text-stroke` with
   `paint-order: stroke fill` is the spec's prescribed implementation because
   Figma's CENTER alignment straddles the outline. VERIFY THE STEM before
   accepting this — see the LOSSINESS note returned with this section.

   `.mk-page :is(h1,h2,h3,.mk-serif)` in tokens.css already pins
   `font-optical-sizing: none` and `"opsz" 18`, which is a fidelity
   requirement, not a preference (CONVENTIONS §8 trap 4). Not repeated here.

   textAlignHorizontal is CENTER in the payload but INERT — the box hugs its
   text at 585 wide and sits flush at content-left 120 (spec §4 / §6.1). Left
   is correct; do not centre it.

   !! OPEN FIDELITY GAP, NOT INTRODUCED BY THIS SECTION — THE MERRIWEATHER CUT.
   Measured three ways and they do not agree:

     Figma node width  (spec §6.1)                              585.00
     @2x export ink    (design y 300..360)      125.0 .. 699.5  574.50
     fonts/Merriweather-variable.ttf, hmtx of the DEFAULT
       instance, which fvar confirms IS wght 300 / wdth 100 /
       opsz 18 — i.e. exactly Figma's "Merriweather Light"     618.86

   So the self-hosted face sets this heading ~5.8% WIDER than Figma renders it
   (+33.9px on a 585 box). The same method reproduces the Poppins values to
   within a bearing — the eyebrow measures 242.65 advance against 238.5 ink at
   a 122 ink-start on a 120 box — so the arithmetic is sound and the delta is
   the FACE, not the maths. Almost certainly the installed variable Merriweather
   is the recent redesign rather than the cut Figma is composing with.

   This is a SHELL-level issue: it hits every Merriweather heading on the page,
   not just this one. tokens.css §"FONT FACES" and NOTES.md F2 already flag that
   the faces "must be sourced and verified independently"; this section is
   simply the first place it has been quantified. NOT patched here — closing it
   with a letter-spacing fudge would be exactly the slop the founder ruled out.
   Escalated in the lossiness returned with this section. */
.mk-amenities52__heading {
  /* Salient's `h2{margin-bottom:var(--nectar-heading-bottom-spacing,…)}`
     (style.q-98889c766d.css) is (0,0,1) and loses to this class. */
  margin: 0;
  padding: 0;
  /* Family, tracking and the optical-size pin are set EXPLICITLY rather than
     inherited from `.mk-page :is(h1,h2,h3,.mk-serif)` in tokens.css. That rule
     does win — `:is()` takes the specificity of its most specific argument, so
     it is (0,2,0) against `body h2{font-family:Cormorant;letter-spacing:-.03em}`
     (0,0,2) from the resort demo's dynamic stylesheet — but the whole heading
     hangs on a two-point margin in a rule that belongs to another file. Pinned
     here so a future edit to tokens.css cannot silently turn this heading into
     Cormorant.

     THE opsz PIN IS REMOVED (2026-08-16), and with it §16-D's conclusion. 16-D
     read `opsz 18` hmtx = 618.86 against Figma's 585.00 node / 574.50 ink and
     escalated it as "the installed Merriweather is not Figma's cut, ~5.8 %
     wide". The face is fine; the axis was wrong. Rendered ink for this exact
     string: pin 602.00 (+4.79 %) vs auto 576.00 (+0.26 %) against 574.50. No
     font-sourcing decision is needed. tokens.css "MERRIWEATHER OPTICAL SIZE". */
  font-family: var(--mk-font-serif);
  font-optical-sizing: auto;
  font-variation-settings: "wdth" 100;
  letter-spacing: 0;                  /* absent from the payload — spec §4 / lossiness 7 */
  font-weight: var(--mk-w-light);
  font-size: var(--mk-size-display);  /* 48 */
  line-height: var(--mk-lh-display);  /* 60 — box height, AUTO in Figma */
  color: var(--mk-ink-strong);
  -webkit-text-stroke: 1px var(--mk-ink-strong);
  paint-order: stroke fill;
}

/* ==========================================================================
   R10-05 — HEADER STAGGER, "sequential, not serial"
   --------------------------------------------------------------------------
   Her words: "not animating in where it fades and then comes up... a little
   abrupt... maybe needs to be a little bit slower." MEASURED BEFORE this fix
   (review/r10/r10-amenities-offers/header-before.json, fresh headless Chrome,
   all 5 mandated widths, SHA served == disk): `.mk-amenities52__eyebrow` and
   `.mk-amenities52__heading` above both carry the shared LEAD-role schedule
   VERBATIM and IDENTICALLY —
       transitionProperty "opacity, translate", duration 0.7s/0.7s,
       delay 0.1s/0.1s, at every one of the 5 widths.
   The IntersectionObserver's own geometry (js/myk-motion.js §2,
   `elementTop <= 0.90*vh - 0.20*elementHeight`) gives only 51-59px of
   INCIDENTAL scroll separation between the two crossing that line (eyebrow
   24px tall + 24px itemSpacing puts heading's own elementTop 48px behind
   eyebrow's, which nets out to that much less scroll headroom on heading's
   own crossing — MEASURED per-width in the same file's `geo` block). At
   anything but a slow, deliberate scroll that gap collapses into the SAME
   IntersectionObserver callback batch — CONFIRMED live with a
   synchronized-clock probe (both classed `.mv-in` in the same tick): eyebrow
   and heading's sampled opacity/translate were IDENTICAL frame-for-frame,
   settling together at ~778-780ms across every width. Two elements on one
   identical clock, fired in one tick, is a single block popping in — not two
   beats of a wave.

   FIX — same technique as `sections/14-amenities.css`'s R9-04/R9-05 stagger
   (read its own comment for the full derivation this borrows rather than
   re-deriving): a hand-authored `transition-delay` override, section-scoped,
   layered ON TOP of the shared vocabulary's own 0.1s LEAD delay.
   `js/myk-motion.js` / `css/myk-motion.css` are untouched — ONE WRITER PER
   ARTIFACT, this lane does not own them. R9-04/R9-05 landed 220ms of stagger
   on a 550ms duration (~40%) with the reasoning that the step must be wide
   enough to read as a separate beat but still land inside the leading
   element's own travel so the pair overlaps rather than waits-then-goes.
   Applied to this section's 700ms LEAD duration: 700 * 0.4 = 280ms.

       eyebrow starts  t=0.10s, finishes t=0.80s (unchanged)
       heading starts  t=0.38s, finishes t=1.08s (NEW)

   Heading now begins while eyebrow is 40% through its own travel and
   overlaps it for the remaining 420ms of eyebrow's motion — sequential, not
   serial, per the round's own definition. It also settles the whole block
   ~280ms later than before (~0.78s -> ~1.06s), which is the "a little bit
   slower" she asked for — without touching `--myk-mv-dur-lead`, the token
   every other LEAD element on the page still reads off.

   Only `transition-delay` is set. Duration and easing stay the shared
   token's (`var(--myk-mv-dur-lead)`, `var(--myk-ease-entrance)`), so this
   heading keeps the exact same FEEL as every other LEAD element on the page —
   just offset later in time, not a different animation. A single value
   applies to both comma items of the inherited `opacity, translate`
   transition-property list (CSS cycles a shorter value-list up to match).

   Specificity: `#s16-amenities-52 .mk-amenities52__heading[data-mv]` is
   (1,2,1) — the section id lands this in the (1,x,x) bucket — which beats
   myk-motion.css's own `html.mv [data-mv]` at (0,2,1) outright, so this is
   not a specificity accident that could flip if that file is ever edited.

   ---------------------------------------------------------------------------
   R12-02 / R12-04 — RETUNED, 280ms -> 350ms, one shared "half-step" cadence
   ---------------------------------------------------------------------------
   Her round-12 words: order confirmed CORRECT live before touching anything
   (review/r12/r12-amenities-refine/ — the eyebrow's own 100ms delay already
   fires before this heading's delay at every width, unchanged since R10-05)
   — but "the little overline... animating in a little fast, and then
   'what Vista Pacifico offers' should load in after that... the timing
   still doesn't feel right compared to other sections," even after R11.
   R12-04's own instruction: re-measure against the reference sections she
   keeps citing and slow further if genuinely short of that bar, not assume
   "already fixed" a second time (R10-04's own precedent for that
   discipline). MEASURED, this round, the two references' own step ratios —
       hero (00-hero.css, sections/00-hero.css):    120ms / 700ms = 17.1%
       footer (R10-11, 21-logos-footer.css §10):    150ms / 700ms = 21.4%
       this section, pre-R12 (280ms / 700ms):                     = 40.0%
   The HEADER stagger (280ms) was already MORE separated than either
   reference by this measure — not the genuinely-short-of-the-bar gap. The
   short gap, measured below, was the ROW WAVE's 120ms step (§8d, unmodified
   until this round) — a literal hero-copy that, spread over NINE rows
   instead of hero's four short lines, compounds into a long, tightly-packed
   cascade that reads as "too fast to catch," which is exactly what R12-04
   and R12-05 both independently describe. See §8d below for that fix.

   Retuned the header stagger alongside it so the WHOLE section (eyebrow ->
   heading -> grid -> CTA, §8d/§8e) reads as ONE consistent cadence rather
   than a different ratio at the top than lower down: every beat below now
   starts exactly 350ms — HALF of the shared 700ms LEAD/hero duration —
   after the previous one, deliberately MORE separated than both cited
   references (350/700 = 50% vs hero's 17% and footer's 21%), which is the
   "slow further" this round's own instruction asked for once the 40%-ratio
   number was checked against the actual cited bar and found to not
   universally clear it (footer's per-step gap, specifically, at 21%, is
   bigger than the OLD 280ms/40%... no — 40% > 21%, so the header itself
   already cleared footer's own ratio; 350ms/50% clears it by a wider,
   intentional margin so the same clock reads consistently against every
   beat in this section, not just the header pair):

       eyebrow starts  t=0.10s, finishes t=0.80s (unchanged, base LEAD token)
       heading starts  t=0.45s, finishes t=1.15s (was 0.38s / 1.08s)
       grid    starts  t=0.80s, finishes t=1.50s (§8d — was a 9-step cascade
                                                    100ms..1060ms, now ONE beat)
       CTA     starts  t=1.15s, finishes t=1.85s (§8e — was 1.18s)

   Each beat starts exactly when the previous one is 50% through its own
   700ms travel — a single, repeating, easy-to-verify half-duration offset
   the whole way down the section, not four independently-tuned numbers. */
#s16-amenities-52 .mk-amenities52__heading[data-mv] {
  transition-delay: calc(var(--myk-mv-delay-lead) + 350ms);
}



/* ==========================================================================
   §4. THE AMENITY ICON — `Icon` 40x40, one child GROUP, one glyph VECTOR
   ====================================================================== */

/* Fixed 40 x 40, does not grow or shrink; itemSpacing to the label is 4 and
   the two are TOP aligned (counterAxisAlignItems: MIN), which is why a 3-line
   label leaves the icon at the first line, not centred on the block.
   The 24x24 `Bounding box` RECTANGLE inside it is hidden — see the header. */
.mk-amenities52__icon {
  flex: 0 0 40px;
  width: 40px;
  height: 40px;
  display: block;
}
.mk-amenities52__icon svg {
  display: block;
  width: 40px;
  height: 40px;
}
/* Glyph fill #1c1b1f — a THIRD ink, distinct from --mk-ink-body (#1a2328) and
   --mk-ink-strong (#000). Painted from the token, not from an attribute, so
   there is no raw hex in the markup (CONVENTIONS §4). */
.mk-amenities52__icon path {
  fill: var(--mk-ink-icon);
}


/* ==========================================================================
   §5. THE CTA — `btns` 2925:507 / label 2925:508
   ====================================================================== */

/* 217 x 40 at content-left 120. padding 8 / 18, radius 54 (authored; clamps to
   a stadium on a 40px box). Stroke 1px #1a2328 @ 15%, strokeAlign CENTER —
   it composites to #b0bbc1 over #cbd6dc, verified in the export (spec §0).

   NO FILL. The payload's #1eb2bc is a hidden layer (spec §0, claim 1).
   NO BLUR. `effects` is absent on every node in this subtree (spec §5), so the
   page-wide --mk-pill-blur is deliberately not applied here.
   NO HOVER STATE. Figma has one variant and no prototype reactions were
   fetched (spec §8.4 / lossiness 14) — unspecified, so nothing is invented
   beyond a focus ring, which 19-cta-b asks for explicitly.

   THE STROKE STRADDLES. strokeAlign is CENTER, so a 1px stroke on the 217-wide
   box paints 119.5 .. 337.5. Measured off the @2x export at design y 692..732:
   ink runs 119.5 .. 337.0, i.e. half a pixel outside the box on each side, NOT
   the crisp inside pixel a plain `inset 0 0 0 1px` would give. The 0.5/0.5 pair
   below reproduces the straddle and therefore the export's antialiasing.

   >>> 2026-08-18, lane `foldback:buttons-sweep` — ON THE PRIMITIVE NOW. <<<

   The eight declarations that used to be here (display / align / justify /
   padding / radius / background / box-shadow / text-decoration) are DELETED:
   every one of them is a `myk-btn` default, and re-declaring them is what
   `buttons.md` §8 row 6 flagged as "bespoke, outside `myk-btn` entirely".
   They are also the exact four-property fork signature D41 §3 names — a
   selector matching `*cta*` that declares background, border, radius, padding
   and font-size together.

   What survives is the only thing that is genuinely different about this
   button, and it survives as TOKENS ON A SCOPE, one per line with its
   evidence:

   THE "NO HOVER STATE" NOTE ABOVE IS NOW WRONG, and I am leaving it visible
   rather than quietly rewriting it, because its reasoning was right at the
   time. It said Figma has one variant and no prototype reactions, so nothing
   was invented. Correct then. The hover state existed the whole time on
   artboard `3269:5586`, which no lane had read — trace Q-C, and the root cause
   of ~11 of the founders' 48 defects. The board's SECONDARY hover
   (`3269:5607`) is fill `#F4F9FB`, label `#1EB2BC`, +2px per side,
   `0 4px 4px rgba(0,0,0,.15)`, and it arrives here through the primitive with
   no rule in this file.

   ONE THING THE BOARD CANNOT ANSWER — RAISED, THEN ANSWERED BY THE RENDER.
   Every SECONDARY on the board is drawn over a PHOTOGRAPH, and this is the
   page's only SECONDARY on a LIGHT surface, so `#F4F9FB` looked like it might
   land invisible. It does not: this section's ground is `--mk-surface-stone`
   `#cbd6dc`, not white, and the near-white pill reads clearly against it
   alongside the turquoise label, the shadow and the growth. Photographed at
   `review/foldback-buttons/proof/B08-hover-forced.png`. Recorded because the
   worry was reasonable and the answer was a picture, not an argument. */
/* R16-02 — MERGED. Two blocks under this exact selector used to live here
   (historically at ~429 and ~482), and the round-16 founder-trace spec's own
   pre-check flagged that shape as "almost certainly" the cause of the
   reported missing outline and asked for the real collision to be found and
   resolved, not papered over with a third rule.

   LIVE-VERIFIED, not assumed: loaded the composed page on a local server
   (SHA served == disk), read `getComputedStyle` on this exact `<a>` at rest —
   `outline: rgba(26,35,40,.15) solid 1px`, `outline-offset: -0.5px`,
   `--myk-btn-border` / `--myk-btn-border-width` both resolving to this
   section's own values, not `myk-btn.css`'s `.myk-btn--outline` defaults —
   then confirmed visually with a 4x-scaled screenshot of the live button:
   the ring renders. The two former blocks never actually collided on any
   property — block A set the `--myk-btn-*` custom properties (border,
   justify, weight, fg, blur) and block B set only `transition`; disjoint
   sets, so cascade order between them was never load-bearing for the
   outline. (One real candidate WAS found and is intentional, not a bug:
   myk-btn.css's shared `:hover` rule swaps `--myk-btn-border` to
   `--myk-btn-hover-border`, which defaults to `transparent` — §2 of that
   file documents this as deliberate, "the board hovers FROM white outline TO
   near-white fill", i.e. the ring is meant to cede to the hover fill+shadow.
   That is a HOVER-state design choice, not the resting-state defect being
   fixed here.)

   Merged into ONE rule anyway, because two identically-selected blocks are a
   structural risk even when they do not currently fight — the next hand that
   edits either one can no longer create a real collision by accident. Every
   declaration and its original comment moved here unchanged; nothing was
   dropped or re-derived. Full verification trail: founder-trace/helix/R16-02.md. */
.mk-amenities52__cta {
  /* The stroke: 1px CENTER, colour `--mk-pill-hairline-dark`, straddling the
     box — measured off the @2x export at design y 692..732 as ink 119.5..337.0
     on a 217-wide box. `--ring-outline` reproduces the straddle with
     `outline-offset: -0.5px`; the box-shadow pair it replaces is the same
     geometry by a different renderer. Same paint, one implementation. */
  --myk-btn-border:       var(--mk-pill-hairline-dark);
  --myk-btn-border-width: 1px;
  --myk-btn-justify:      center;      /* the label is CENTER-aligned here —
                                          §4 `cta-label`, unlike the nav's MIN */
  --myk-btn-weight:       var(--mk-w-medium);   /* Poppins Medium 500 — §4 */
  --myk-btn-fg:           var(--mk-ink-body);   /* #1a2328, not the white the
                                          board draws: this is the one
                                          SECONDARY on a light surface */
  --myk-btn-blur:         none;        /* this node declares no effects */

  /* R11-09 — THE ENTRANCE, sequenced last in the wave (§8e above). Confirmed
     live before writing this: the button had zero `data-mv`, zero transition,
     opacity 1 / translate 0 for the entire drive at every width — genuinely
     never animated. It is `.myk-btn`, which `js/myk-motion.js` §1 SKIPs from
     the page-wide AUTO-adoption ("a button label belongs to the button, not to
     the entrance layer") — but that skip only guards the automatic
     selector-based adopt() pass; a HAND-authored reveal on the button's own
     OUTER element, same shape as R10-12's footer `.mk-newsletter` fix, is
     unaffected by it and does not fight the button's existing mechanics:
     `.myk-btn`'s own `--myk-btn-transition` covers `color` / `box-shadow` /
     `outline-color` only (myk-btn.css §1) — never `opacity`, never
     `translate` — and the hover fill lives on a SEPARATE `::before` pseudo
     (myk-btn.css §4), so widening THIS element's transition list cannot touch
     either. The five properties below are written as one explicit list, each
     with its OWN delay, specifically so `transition-delay` cannot be
     mis-applied uniformly and delay the hover response.

     R12-05 — delay retuned 1180ms -> 1150ms. Was "row 9's 1060ms + one more
     120ms hero-step"; the grid is now one beat (§8d) rather than nine, so the
     CTA's delay is derived from THAT beat instead: 1150ms = the grid beat's
     own 800ms start + 350ms, the same repeating half-duration step every beat
     in this section now shares (comment above `.mk-amenities52__heading[data-mv]`).
     Still comfortably 350ms after the grid beat begins and 700ms before it
     would otherwise be needed to avoid the hover-delay bleed R11-09 already
     guarded against — verified live, unaffected, R12 verify record.

     R13-01 — RE-CHECKED, not re-derived: §8d's single grid beat is now three
     column beats (800/920/1040ms, see §8d's own R13-01 comment) instead of
     one at 800ms. 1150ms still lands after all three — 110ms past column 3's
     1040ms start, still inside column 3's own 700ms travel — so "then the
     CTA" still holds and this literal value is untouched. Confirmed live in
     the R13-01 verify pass, not assumed from the arithmetic alone. */
  transition:
    color         var(--myk-btn-hover-dur) var(--myk-btn-hover-ease) 0s,
    box-shadow    var(--myk-btn-hover-dur) var(--myk-btn-hover-ease) 0s,
    outline-color var(--myk-btn-hover-dur) var(--myk-btn-hover-ease) 0s,
    opacity       700ms cubic-bezier(.4, 0, .2, 1) 1150ms,
    translate     700ms cubic-bezier(.4, 0, .2, 1) 1150ms;
}
.mk-amenities52__cta:focus-visible {
  outline: 2px solid var(--mk-ink-body);
  outline-offset: 3px;
}
html.mv #s16-amenities-52 .mk-amenities52__cta {
  opacity: 0;
  translate: 0 40px;
}
#s16-amenities-52 .mk-amenities52__gridwrap[data-mv].mv-in ~ .mk-amenities52__cta {
  opacity: 1;
  translate: 0 0;
}

/* Poppins MEDIUM 500 / 16, tracking 1px, box height 24, fill #1a2328.

   NO TRAILING-TRACK COMPENSATION HERE — and that is a measured decision, not
   an oversight. CONVENTIONS §8 trap 3 (from 15-amenities-51) says Figma's hug
   width excludes the letter-space after the last glyph while CSS includes it,
   so a centred element needs a negative right margin. THIS PILL IS THE OTHER
   CASE. Read straight out of Poppins-Medium.ttf (hmtx, upem 1000):

       "See all 47 amenities" @16px + 1px track, incl. trailing = 181.04
       + padding 18 + 18                                        = 217.04
       Figma `btns` width                                       = 217

   Dropping the trailing 1px would hug at 216.04 and pull the right edge a
   pixel in. Corroborated independently by the @2x export, where the pill's
   stroke ink measures 119.5 .. 337.0 = 217.5 across including the straddle.
   So: do NOT add `margin-right: -1px` to this label. The trap is real, it just
   points the other way here — always measure, never inherit the compensation. */
.mk-amenities52__cta-label {
  font-family: var(--mk-font-sans);
  font-weight: var(--mk-w-medium);
  font-size: var(--mk-size-base);       /* 16 */
  line-height: var(--mk-lh-node);       /* 24 */
  letter-spacing: var(--mk-track-nav);  /* 1px */
  /* `inherit`, NOT `--mk-ink-body`, and this one line is the difference
     between having a hover and only appearing to. The primitive drives the
     label colour by retargeting `--myk-btn-fg` on the element; a hard colour
     on the label span wins over inheritance and the turquoise never arrives.
     Measured before the change: the <a> went #FFAC66 -> #1a2328 on hover
     (a stray inherited link colour changing under a label that could not),
     so the button had a computed hover and NO VISIBLE one. The resting value
     is unchanged — `--myk-btn-fg` is set to `--mk-ink-body` on the scope. */
  color: inherit;
  white-space: nowrap;
}


/* ==========================================================================
   PART B — RETARGETING SALIENT
   ==========================================================================
   Everything below exists to sit Salient's real `mouse_follow_image` post grid
   on Figma's geometry. Nothing below changes the mechanic; the rAF follower,
   the cross-fade, the counter-scale reveal and the blend-mode title ghost are
   all still driven by the vendored element-post-grid CSS and init.js.

   Each block names the Salient declaration it displaces and its specificity,
   so the next person can see the fight rather than re-run it.

   §7. TRACK GEOMETRY — Salient's flex grid becomes Figma's 3 x 72 / 48
   ====================================================================== */

/* The grid box is the full 1040 content width. */
.mk-amenities52__gridwrap {
  align-self: stretch;
}

/* Displaces, in order:
     `.nectar-post-grid{display:flex;flex-wrap:wrap}`                 (0,1,0)
     `@media(min-width:1000px) .nectar-post-grid-wrap[data-style=
      mouse_follow_image] .nectar-post-grid[data-columns="3"]
      {margin:0 -50px}`                                               (0,4,0)
   The -50px bleed plus 50px item padding is Salient's 100px gutter; Figma's is
   72 with no bleed. Selector below is (0,5,0) so it wins in both media states.
   `align-items: start` is counterAxisAlignItems: MIN — spec §2.1 is explicit
   that shorter cells DO NOT stretch (EN row 3 has a 72-tall Starlink cell
   top-aligned in a 108-tall row).

   R17-01 — row-gap 48 -> 24, HER CALL, NOT THE SPEC'S. `row-gap: 48px` above
   was spec §2.1's own Figma-derived number for the ORIGINAL nine-item grid
   and was exactly right for that grid. Her round-17 words are about the
   47-item grid this became in round 16: "it's quite spaced out... this list
   is quite long... tighten up the vertical spacing... occupy a little less
   space" — a live judgment call on a much longer list, not a correction to
   the original nine-row spec, so this is a deliberate founder-directed
   deviation (same category as R10-06/R11-08/R13-01 elsewhere in this file),
   not a bug fix. 24, not an arbitrary smaller number: `--mk-space-24` is
   tokens.css's own "THE dominant stack gap" (tokens.css:249) — the value
   already used for stack rhythm throughout this page — so tightening reuses
   an established constant instead of inventing one. Halves the row-gap
   without touching column-gap (72, untouched — R17-01 is "vertical spacing"
   only) or any type size. The var() carries a literal fallback per this
   file's own §"THE BREATH" convention (below, `--mk-breath`). */
.mk-amenities52 .nectar-post-grid-wrap[data-style="mouse_follow_image"] .nectar-post-grid[data-columns="3"] {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  column-gap: 72px;                     /* spec §2.1 — derived from child x, UNCHANGED */
  row-gap: var(--mk-space-24, 24px);    /* R17-01 — was 48px (spec §2.1); tightened, her call */
  align-items: start;
  margin: 0;
}

/* Displaces every width/padding Salient puts on the cell:
     `.nectar-post-grid-item{width:100%}`                             (0,1,0)
     `@media(min-width:1000px) ...[data-columns="3"] .nectar-post-grid-item
      {padding:0 50px}`                                               (0,4,0)
     `@media(max-width:999px)and(min-width:691px) ...[data-columns="3"]
      [data-grid-spacing=none] .nectar-post-grid-item{width:50%}`      (0,5,0)
     `@media(max-width:690px) body .nectar-post-grid[data-columns]
      [data-grid-spacing] .nectar-post-grid-item{width:100%;
      padding-bottom:75%}`                                            (0,3,1)
   The last one is the dangerous one: `padding-bottom:75%` is Salient's aspect
   box for a card grid and would give every amenity row a 224px tail.
   Selector below is (0,6,1) — above all four. */
body .mk-amenities52 .nectar-post-grid-wrap[data-style="mouse_follow_image"] .nectar-post-grid[data-columns="3"] .nectar-post-grid-item {
  width: auto;
  min-width: 0;
  padding: 0;
}

/* Salient makes `.inner` an absolutely-positioned 100%/100% card face with a
   10% black wash and clips it:
     `.nectar-post-grid-item .inner{overflow:hidden;position:relative;
      width:100%;height:100%;position:absolute;top:0;left:0;
      background-color:rgba(0,0,0,.1)}`                               (0,2,0)
   The `mouse_follow_image` sheet already undoes most of that, but only inside
   `@media (min-width:1000px)`. Restated unconditionally, and carried to (0,6,0)
   rather than the (0,3,0) the shorter selector would give, so it also clears
   `...[data-style=mouse_follow_image] .inner{overflow:visible;width:auto}`
   (0,3,0) on cascade order rather than on a tie. `overflow: visible` is
   mandatory: the follower is a descendant and must escape. */
.mk-amenities52 .nectar-post-grid-wrap[data-style="mouse_follow_image"] .nectar-post-grid .nectar-post-grid-item .inner {
  position: static;
  overflow: visible;
  width: auto;
  height: auto;
  background-color: transparent;
}

/* `.content` is the `Icon and text ` frame: HORIZONTAL, itemSpacing 4,
   counterAxisAlignItems MIN (spec §2.4).

   THE PADDING HERE IS THE ONE THAT BITES. Three Salient rules set it and they
   are NOT all low-specificity:
     `.nectar-post-grid .nectar-post-grid-item .content{padding:35px}` (0,3,0)
     `.nectar-post-grid-wrap:not([data-style=content_overlaid])
      .nectar-post-grid .nectar-post-grid-item .content{padding:25px 0}` (0,5,0)
        <- `:not()` contributes its argument's specificity, and our wrap has
           `data-style="mouse_follow_image"`, so this DOES match. It would add
           25 top + 25 bottom to every amenity row and take the 40px rows to 90.
     `.nectar-post-grid .nectar-post-grid-item .content
      {position:absolute;width:100%;z-index:200}`                     (0,3,0)
   The `mouse_follow_image` `position:static` fix is gated behind
   `min-width:1000px`, so it is restated here unconditionally.
   `data-mouse_follow_post_spacing` is absent from the markup precisely so the
   `{padding:45px 0}` variant never matches — see the HTML header.
   Selector below is (0,6,0), above all three.
   No z-index is set — `z-index:200` would put the label above the follower. */
.mk-amenities52 .nectar-post-grid-wrap[data-style="mouse_follow_image"] .nectar-post-grid .nectar-post-grid-item .content {
  position: static;
  display: flex;
  align-items: flex-start;              /* icon top-aligned to the label */
  gap: 4px;                             /* itemSpacing 4 */
  width: 100%;
  padding: 0;
  z-index: auto;
}

/* Label box = cell 298.67 - icon 40 - gap 4 = 254.67 (spec §2.4b).
   Displaces `.nectar-post-grid-wrap:not([data-style=content_overlaid])
   .content .item-main{width:100%}`                                   (0,4,0),
   which as a flex item would be 100% of the CELL and overflow by 44px.
   Selector below is (0,5,0).

   `pointer-events:none` from Salient's base rule was PREVIOUSLY kept here on
   the theory that it is what lets the pointer fall through the text to
   `.nectar-post-grid-item`, which is where `:hover` lives now that
   `a.nectar-post-grid-link` has been dropped. R19-01 found that theory is
   what actually BREAKS the hover live (founder-confirmed the mix-blend title
   overlay + follower photo were not appearing — reproduced, not assumed,
   with a real trusted pointer via review/regression/cdp.py, not a synthetic
   dispatch):

     R11's entrance-reveal (§8b below) rests `.post-heading`/
     `.mk-amenities52__icon` at `translate: 0 40px` — 40px BELOW their
     settled position — until the section's own reveal wave finishes (up to
     ~1.5s+ after entering view for this section's LAST-firing column, which
     is exactly where "Bathtub" — the founder's own example — sits: nth-
     child(3n+3), §8d above). A short, 1-line row's own box is exactly
     `--myk-mv-travel` (40px) tall (confirmed live:
     `.nectar-post-grid-item` computes `height:40px` for a 1-line label), so
     while still resting, the label paints EXACTLY at/below that box's own
     bottom edge — outside it. Hit-testing there, with the label itself
     `pointer-events:none`, falls through PAST `.nectar-post-grid-item`
     entirely to whatever is physically behind that pixel instead — no
     element in this component's own subtree, so `:hover` never reaches it.
     Confirmed live: `item.matches(':hover')` reads `false` the instant the
     cursor arrives on the (visible, still-rising) label, and STAYS `false`
     even ~1.5s later once the label has fully risen into place — the
     browser does not retroactively re-run hit-testing under a STATIONARY
     cursor merely because a CSS transform animated the paint underneath it.
     A single hover-and-hold — exactly how someone checks "does hover
     work" — permanently misses.

   FIX: give the label normal hit-testing back, so it is itself hoverable
   wherever it actually paints, transform-shifted mid-reveal or not —
   `:hover` still cascades to every DOM ancestor of whatever element is
   actually hit, regardless of that hit element's visual box relative to the
   ancestor, so `.nectar-post-grid-item:hover` (and everything keyed to it:
   the follower photo, §9's title-overlay ghost) fires correctly through the
   whole reveal, not only after it settles. There is no link under the label
   any more for a restored pointer to "miss" (the reason pass-through
   existed in the first place), and `.content` itself carries no
   pointer-events override of its own (Salient sets it only on
   `.item-main`), so nothing else in the hover chain is touched by this. */
.mk-amenities52 .nectar-post-grid-wrap .nectar-post-grid-item .content .item-main {
  flex: 1 1 auto;
  width: auto;
  min-width: 0;
  display: block;
  pointer-events: auto;
}


/* ==========================================================================
   §8. THE LABEL — `post-heading` retargeted to Poppins 20/36
   ====================================================================== */

/* Poppins Regular 400 / 20, lineHeight PERCENT 179.99999523162842 = exactly
   36px, letterSpacing 0, fill #1a2328 (spec §4). Pinned in px, not 1.8, to
   remove rounding drift (spec §2.4).

   Three sheets fight for this element:
     `body h3{font-family:Cormorant;font-size:38px;line-height:42px;
      font-weight:500;letter-spacing:-0.03em}`                        (0,0,2)
        <- the RESORT demo's dynamic stylesheet, vendored with the shell
     `.mk-page :is(h1,h2,h3,.mk-serif){font-family:var(--mk-font-serif);
      font-optical-sizing:none;font-variation-settings:"wdth" 100,"opsz" 18}`
                                                                      (0,1,1)
        <- tokens.css. Correct for the Merriweather headings, wrong here.
     `.nectar-post-grid-wrap[data-style=mouse_follow_image]
      .nectar-post-grid-item .content .post-heading{line-height:1.5em}` (0,4,0)
        <- would give 30px, not 36.
     `@media(min-width:1400px) ... .content .post-heading{max-width:85%}` (0,4,0)
        <- would clamp the label to 216 and re-wrap it at 1440.
   Selector below is (0,5,0) and beats all four.

   `position: relative` is load-bearing, not cosmetic — see §9.
   The optical-size / variation reset undoes the Merriweather pin from
   tokens.css; Poppins is a static face and would otherwise carry a stale
   `font-variation-settings`.

   LINE BREAKS VERIFIED, not assumed. Greedy wrapping computed from
   Poppins-Regular.ttf (hmtx, upem 1000) at 20px in the 254.67 label box
   reproduces Figma's line counts for all nine labels, and the break points
   match the @2x export word for word:

       Full kitchen                       110.70            1 line
       Free washer in unit                186.90            1
       Free dryer in unit                 165.98            1
       AC split, ductless system          246.34            1   (8.3 to spare)
       Dedicated workspace                218.16            1
       Bathtub                             79.46            1
       Starlink wifi with battery  235.90 / backup power  143.72   2
       Free parking on 154.66 / premises, paved road 218.30 /
         and driveway 135.88                                       3
       Shared salt water, infinity 250.12 / pool outdoor - open all
         230.76 / year 44.64                                       3

   Two are tight: "AC split, ductless system" clears the box by 8.33px and
   "Shared salt water, infinity" by 4.55px. Both hold with the shipped face —
   but they are the first things to break if the Poppins source is ever swapped
   or if a `letter-spacing` leaks onto this element. Row heights follow from the
   line counts: 40 / 40 / 108 (spec §2.1, total 40+48+40+48+108 = 284). */

/* ==========================================================================
   R10-06 — CARD LABELS FADE BUT DO NOT TRAVEL: root cause + fix
   --------------------------------------------------------------------------
   Her words: all nine amenity rows ("full kitchen, free washer in unit, free
   dryer in unit, and the rest") "only fade in" — no translate-up, unlike the
   page's standard fade+move-up grammar. Every row already carries
   `data-mv="body"` (R8-13, `sections/16-amenities-52.html`) and R8-13's own
   testing confirmed `.post-heading` computed `translate: none / transform:
   none` at rest, i.e. `translate` was free for the shared vocabulary to use --
   correct, at the time, and still true today (`translate` is not the bug).

   THE ACTUAL BUG, MEASURED (review/r10/r10-amenities-offers/header-before.json,
   fresh headless Chrome, all 5 widths, SHA served == disk): computed
   `transitionProperty` on every `.post-heading` reads
       "transform, opacity, color"     — NOT "opacity, translate"
   at duration "0.45s, 0.45s, 0.45s" / delay "0s, 0s, 0s" — Salient's own
   numbers (element-post-grid.q-98228494a0.css:
   `.nectar-post-grid .nectar-post-grid-item .content .post-heading{
   transition:transform .45s cubic-bezier(.15,.75,.5,1),opacity .45s
   cubic-bezier(.15,.75,.5,1),color .45s cubic-bezier(.15,.75,.5,1)}`,
   specificity (0,4,0)). That vendor rule is what the browser resolves the
   `transition` PROPERTY from, because nothing in this file's own §8 selector
   below — despite winning every other declaration on this element at
   (0,6,0) — ever declared `transition` itself, so there was nothing to
   contest that one property with. `[data-mv]`'s own start/rest values (`html.mv
   [data-mv]{translate:0 var(--myk-mv-travel)}` / `.mv-in{translate:0 0}`,
   myk-motion.css) still WIN the `translate` VALUE at every moment — the
   number genuinely changes from 40px to 0 on reveal — but `translate` is
   absent from the winning `transition-property` LIST, so that value change is
   never interpolated: it snaps in one frame, invisibly, while `opacity` (which
   IS in Salient's list, just at 0.45s/no-delay rather than the vocabulary's
   0.2s/no-delay BODY numbers) visibly fades over time. A snap-then-fade reads
   exactly as "only fades in, no translate" — because the translate genuinely
   is not animating, even though the value is correct at both ends.

   FIX: extend THIS rule's own `transition` — the one already winning every
   other property here — to also cover `translate`, using the page's own BODY
   role tokens (`--myk-mv-dur-body` 200ms / `--myk-mv-delay-body` 0ms /
   `--myk-ease-entrance`) so the added travel matches every other BODY-role
   element on the page. Salient's own transform/opacity/color entries are kept
   VERBATIM — they still drive the hover colour-swap and the vendor's own
   subtext transforms elsewhere in this component; nothing about hover
   behaviour changes. `translate` is simply the fourth item this element was
   always supposed to transition and never did. */
.mk-amenities52 .nectar-post-grid-wrap[data-style="mouse_follow_image"] .nectar-post-grid-item .content .post-heading {
  position: relative;
  margin: 0;
  max-width: 100%;
  font-family: var(--mk-font-sans);
  font-weight: var(--mk-w-regular);
  font-size: var(--mk-size-body);       /* 20 */
  line-height: 36px;                    /* 180% of 20, exactly */
  letter-spacing: 0;
  text-transform: none;
  color: var(--mk-ink-body);
  font-optical-sizing: auto;
  font-variation-settings: normal;
  /* R10-06 — adds `translate` to Salient's own transition-property list
     (transform/color kept verbatim: transform still drives the vendor's own
     hover subtext-slide, color still drives the hover swap — hover is
     untouched by any of this).

     R11-08 (2026-08-22) — her words: "same speed, same timing, copy and
     paste that [hero] approach." `opacity` and `translate` were on the page's
     generic BODY tokens (0.45s Salient / 200ms `--myk-mv-dur-body`) — REPLACED
     here with the literal values read off sections/00-hero.css's own
     `mykHeroRise` keyframe (700ms, `cubic-bezier(.4, 0, .2, 1)`), not
     approximated. `color` genuinely never changes on this element (confirmed:
     no `.post-heading` — as opposed to `.post-heading:before`, the separate
     blend-mode ghost — rule in element-post-grid.q-98228494a0.css ever sets
     `opacity` on hover), so widening opacity's own duration cannot touch any
     hover behaviour; same reasoning R10-06 already used for `translate`. */
  transition:
    transform .45s cubic-bezier(.15,.75,.5,1),
    opacity 700ms cubic-bezier(.4, 0, .2, 1),
    color .45s cubic-bezier(.15,.75,.5,1),
    translate 700ms cubic-bezier(.4, 0, .2, 1);
}

/* ==========================================================================
   R11-06 / R11-07 / R11-08 / R11-09 / R11-10 — THE AMENITIES WAVE
   --------------------------------------------------------------------------
   R11-06, WHICH CASE (determined live before any of the below was written,
   full receipt in founder-trace/helix/R11-06-07-08-09-10.md): a realistic
   wheel-driven drive (review/r11/r11-amenities-wave/drive-before-*.json,
   `build/v1-en/_tools/r11-amenities52-drive-probe.py`, her own 1750x980
   first) confirmed R10-05's header stagger and R10-06's label travel are
   BOTH still genuinely working, byte-identical to round 10's own verified
   numbers — this is not a regression and not a stale-page misread of a fix
   that already works. It IS a genuine residual gap in what was never built:
   (1) the nine rows had no deterministic wave, only incidental IO-timing
   gaps (measured 67-142ms apart depending on width/scroll speed — not an
   authored, verifiable overlap); (2) each row's own motion ran on the 200ms
   BODY token, four times faster than hero's 700ms, which reads as a "quick
   pop" rather than a fade a human eye can track — literally her words,
   "animating them up really quickly, not fading in"; (3) the icons and the
   "See all 47 amenities" button had ZERO animation, confirmed live
   (opacity:1/translate:0 for the entire drive, every width) — two of the
   picture's moving parts were simply always-on. All three are now fixed
   together, below, because they are one mechanism.

   §8a. THE TRIGGER, NEUTRALISED — R10-11's exact technique
   (founder-trace/helix/R10-10-11-12.md §2): `.mk-amenities52__gridwrap`
   carries the ONE real `data-mv="body"` in this subtree (16-amenities-52.html
   R11-07), so the shared engine's IntersectionObserver watches exactly one
   element and adds `.mv-in` to it once, off the grid's OWN scroll geometry —
   MEASURED close to where the old first-row trigger fired (within ~40-135px
   of scroll across all 5 widths, review/r11/r11-amenities-wave/geometry.json)
   so this is not a worse-positioned trigger, just a single deterministic one.
   Its own opacity/translate output is neutralised — nothing about the WRAP
   itself is meant to be seen moving; only its `.mv-in` STATE is used, to
   drive every row below via CSS. `(1,2,1)` (this section's id) outranks
   myk-motion.css's own `html.mv [data-mv]` START state `(0,2,1)` and its
   `.mv-in` END state `(0,3,1)` outright — an id beats any class count. */
#s16-amenities-52 .mk-amenities52__gridwrap[data-mv] {
  opacity: 1;
  translate: none;
  transition: none;
}

/* §8b. REST STATE — icons + labels, hidden under `html.mv` same as every
   other adopted element (Guard A fail-open, myk-motion.css §2), but keyed off
   the CLASS SELECTOR rather than `[data-mv]`: R11-07 deliberately removed
   `data-mv="body"` from all nine `.post-heading` rows (16-amenities-52.html),
   so the shared engine's generic `html.mv [data-mv]` rule no longer reaches
   them — this section now owns their rest state directly, same specificity
   shape, same fail-open guarantee (reduced motion / no-JS -> `html.mv` never
   lands -> this rule never applies -> opacity:1/translate:none, the default).
   `40px` is `var(--myk-mv-travel)`'s CURRENT value, read and pinned literally
   per R11-08's "don't approximate" discipline — same number, written the way
   hero's own rule writes it. */
html.mv #s16-amenities-52 .mk-amenities52__icon,
html.mv #s16-amenities-52 .post-heading {
  opacity: 0;
  translate: 0 40px;
}

/* §8c. THE ICON'S OWN TRAVEL — R11-10. Confirmed live before writing this
   (review/r11/r11-amenities-wave/drive-before-*.json): `.mk-amenities52__icon`
   carried zero `data-mv`, zero transition, opacity 1 / translate none for the
   entire drive at every width — genuinely never animated, not merely missed
   by R10-06's text-only fix (R10-06 only ever touched `.post-heading`). No
   `transform`/`translate` is set anywhere else on this element (§4 above), so
   the travel is free — same `travelProp()` check the JS runs before hand-
   authoring, done here by hand since this element is hand-adopted, not
   selector-adopted. Same literal hero numbers as §8 above, same reasoning. */
#s16-amenities-52 .mk-amenities52__icon {
  transition:
    opacity   700ms cubic-bezier(.4, 0, .2, 1),
    translate 700ms cubic-bezier(.4, 0, .2, 1);
}

/* §8d. THE WAVE, R11-07/R11-08 — SUPERSEDED BY R12-05, collapsed to ONE
   BEAT. R11-07/08 gave the nine rows nine independent fixed delays (base
   100ms, step 120ms, copied literally from hero's 4-line ladder) — this
   worked exactly as measured (R11 verify: every consecutive pair genuinely
   overlapping, all 5 widths) but her round-12 report persisted anyway:
   "still too fast... timing doesn't feel right," alongside her own explicit
   offered alternative: "it would even be okay with me if you animate in the
   whole list as one set... I see you did a whole grid there, that would be
   fine too."

   ROOT CAUSE, MEASURED, not assumed a second time (R12-04's own
   instruction): hero's 120ms step suits FOUR short lines of a headline: it
   is not a per-element defect, it is a translation mismatch — spreading the
   SAME hero-copied step across NINE small, visually similar list rows
   compounds into a long (100ms -> 1060ms, 960ms end-to-end before the CTA
   even starts) tightly-packed cascade where any one row's own 700ms motion
   is 83%-overlapped by its neighbour's (700-120=580ms of simultaneous
   motion) — objectively hard to consciously track as nine distinct beats,
   which is the literal shape of "I can't actually catch how nice all the
   animations are." Retuning the STEP alone does not fix this: a wider step
   under the same nine-item shape either still compresses (fast) or pushes
   the total wave past 2+ seconds (a fresh regression, "why is this section
   slower to finish than every other one"), and would need re-tuning again
   the next time a tenth amenity is added — a structural problem, not a
   number to nudge.

   FIX — her own offered alternative, taken because it is structurally
   correct, not merely permitted: every icon + label across all nine rows
   now shares ONE `transition-delay`, so the whole grid fades and rises
   together as a SINGLE beat — this section's third beat (see the R12-02/04
   comment above `.mk-amenities52__heading[data-mv]`), landing 350ms (half
   of the shared 700ms duration) after the heading's own beat starts, the
   same repeating half-duration cadence as every other beat in this section.
   `:nth-child` is removed entirely — one rule instead of nine, and it no
   longer needs editing if a tenth amenity is ever added (self-maintaining,
   "more reliable" per this round's own framing of the choice). Icon and
   label of a row still share the identical delay, unchanged from R11-07's
   own reasoning ("a button label belongs to the button" logic extended to
   "an icon and its label belong to the same beat").

   ---------------------------------------------------------------------------
   R13-01 — SUPERSEDED AGAIN. One beat was structurally right (self-
   maintaining, no per-row hand-editing) but threw away information her R13
   report specifically named: "it's still loading in in a very strange
   order where some of the things at the bottom load in before things at
   the top." A single uniform delay across all nine rows cannot itself
   cause a top/bottom ordering complaint — every row fires on the SAME
   clock tick — so this was never really about the grid beat's internal
   order; it was the residual complaint from BEFORE R12-05's collapse,
   re-read against the DOM. Verified against the real markup (this file,
   grep for `.nectar-post-grid-item`, all 9 confirmed direct children of
   `.nectar-post-grid` in this exact order, no interleaved siblings to
   perturb `:nth-child` arithmetic):

       1 Full kitchen   2 Free washer   3 Free dryer
       4 AC split       5 Workspace     6 Bathtub
       7 Starlink       8 Free parking  9 Salt water pool

   Read as the 3x3 grid it renders as (`data-columns="3"`), that DOM order
   is ROW-MAJOR — but her named groups ("kitchen, AC split, and Starlink...
   free washer, dedicated workspace, and free parking... free dryer,
   bathtub, and shared salt water infinity pool") are exactly the grid's
   three COLUMNS: col 1 = items 1/4/7, col 2 = items 2/5/8, col 3 = items
   3/6/9 (`founder-trace/FT-20260822-jehnean-round13.md`'s own DOM-order
   table, re-verified live here rather than re-trusted). R12-05's single
   beat was already order-safe in isolation (nothing could read as
   "backwards" when everything fires at once) but gave up the clean
   left-to-right column sweep she is asking for now that she has named it
   explicitly — this is a MORE PRECISE instruction superseding R12-05's
   collapse for the ordering question specifically, not a reversal of its
   "don't hand-edit nine rows" reasoning (still true: three `:nth-child`
   rules, not nine).

   FIX — three rules, one per column, keyed by `:nth-child(3n+1|+2|+3)` on
   `.nectar-post-grid-item` (the direct parent the nth-child count is taken
   against, not the icon/label descendants themselves): each column's own
   three items (icon + label, both) still share ONE identical delay so a
   column reads as a single simultaneous unit exactly as her words describe
   ("as one set") — the fix R12-05 already made for "share the identical
   delay within a row" is unchanged, just re-scoped from all nine rows to
   three at a time. Columns step 120ms apart — not a new number: the exact
   hero-derived per-item step R11-08 already established for this section
   (comment table above `.mk-amenities52__heading[data-mv]`: hero's own
   120ms/700ms = 17.1% ratio). R12-04's regression (this same 120ms step,
   applied nine times, compounded into an 83%-overlapped 960ms cascade) does
   not reapply here: three steps of 120ms is 240ms of total spread, not
   R11-08's 960ms — the problem R12 fixed was the STEP COUNT (nine), not the
   step size, and nine is gone for good (three grouped beats, not three
   times as many rows). Column 1 keeps the exact base value R12-05 shipped
   (`+700ms` off the LEAD delay, i.e. this section's third macro-beat,
   still 350ms after the heading's own beat per R12-04's cadence) so this
   diff is additive — two new delay values, nothing already-correct
   disturbed. `.mk-amenities52__cta` (§8e) is UNCHANGED: its literal 1150ms
   already lands 110ms after column 3's new 1040ms start — later than every
   column, still comfortably inside column 3's own 700ms travel, so "then
   the CTA after those things" already held without touching that number;
   confirmed live, not assumed, in the verify pass below. */
#s16-amenities-52 .mk-amenities52__gridwrap[data-mv].mv-in .nectar-post-grid-item:nth-child(3n+1) .mk-amenities52__icon,
#s16-amenities-52 .mk-amenities52__gridwrap[data-mv].mv-in .nectar-post-grid-item:nth-child(3n+1) .post-heading {
  /* COLUMN 1 — Full kitchen (1) / AC split (4) / Starlink (7). Unchanged
     base: this section's third macro-beat, 350ms after the heading.

     R19-FIX — `translate: 0 0` -> `translate: none`. VERIFIED live by
     r19:verify:amenities (fresh Fable verifier): a settled, non-`none`
     translate value (even one that computes to a visual no-op offset) opens
     a NEW STACKING CONTEXT on this element, which traps §9/§9b's
     `z-index:1000` title/icon overlay ghosts inside it — they can then never
     compete with the hover-follower photo's `z-index:100` in the correct
     stacking layer, so both ghosts render zero pixels on hover despite every
     computed property (opacity, mix-blend-mode, z-index, fill) reading
     correct. `translate: none` is the identical visual rest position (no
     stacking context is not a position change) and interpolates the same as
     an explicit `0 0` endpoint for the CSS transition already running on
     this element (`translate` animates from/to `none` as zero, per the CSS
     Transforms spec) — so the reveal motion itself is unaffected; only the
     settled END state stops creating a stacking context. */
  opacity: 1; translate: none; transition-delay: calc(var(--myk-mv-delay-lead) + 700ms);
}
#s16-amenities-52 .mk-amenities52__gridwrap[data-mv].mv-in .nectar-post-grid-item:nth-child(3n+2) .mk-amenities52__icon,
#s16-amenities-52 .mk-amenities52__gridwrap[data-mv].mv-in .nectar-post-grid-item:nth-child(3n+2) .post-heading {
  /* COLUMN 2 — Free washer (2) / Dedicated workspace (5) / Free parking
     (8). +120ms off column 1 — hero's own established per-item step.
     R19-FIX — `translate: none`, same reasoning as column 1 above. */
  opacity: 1; translate: none; transition-delay: calc(var(--myk-mv-delay-lead) + 700ms + 120ms);
}
#s16-amenities-52 .mk-amenities52__gridwrap[data-mv].mv-in .nectar-post-grid-item:nth-child(3n+3) .mk-amenities52__icon,
#s16-amenities-52 .mk-amenities52__gridwrap[data-mv].mv-in .nectar-post-grid-item:nth-child(3n+3) .post-heading {
  /* COLUMN 3 — Free dryer (3) / Bathtub (6) / Shared salt water pool (9).
     +240ms off column 1, i.e. +120ms off column 2 — same repeating step.
     R19-FIX — `translate: none`, same reasoning as column 1 above. */
  opacity: 1; translate: none; transition-delay: calc(var(--myk-mv-delay-lead) + 700ms + 240ms);
}

/* §8e. THE BUTTON — R11-09, sequenced LAST, the fourth beat of this
   section's now-uniform 350ms/50%-of-700ms cadence (R12-02/04/05 comment
   above `.mk-amenities52__heading[data-mv]`): 1150ms, i.e. 350ms after the
   grid beat (§8d) starts, not R11-09's original 1180ms (that number was
   "one more 120ms hero-step past row 9's 1060ms," which no longer exists as
   a concept now that the grid is one beat rather than nine). "See all 47
   amenities" is a sibling of the gridwrap (both direct children of
   `.mk-amenities52__col` — confirmed live, the two elements' opening/closing
   `<div>`s balance between them), reached with a general sibling combinator
   off the SAME one trigger — the exact shape R10-11 used for the footer's
   newsletter heading (`~`, off `.mk-footer__links`'s `.mv-in`). Full
   rest-state + transition + reveal live with the button's own rule in §5
   below, not here, so this section's CTA styling stays in one place. */


/* ==========================================================================
   §9. THE BLEND-MODE TITLE GHOST — the part that makes the effect read
   ====================================================================== */

/* Salient paints a white duplicate of the label over the photo with
   `mix-blend-mode: overlay` so the label survives wherever the image passes
   behind it (nonprofit.lift.md §1d). Everything about it is inherited
   verbatim from the vendored sheet — `content: attr(data-title-text)`, the
   `mix-blend-mode`, `z-index:1000`, the white fill from
   `[data-text-color=dark][data-post-title-overlay=yes]`, and the
   `opacity 0 -> 1` on `:hover`. Two things had to change:

   (a) ANCHORING. `.post-heading::before` is `position:absolute; left:0; top:0`
       and resolves against the nearest positioned ancestor. Salient's own
       layout has the heading at the item's top-left so `.nectar-post-grid-item
       {position:relative}` is good enough. Ours starts 44px in, after the
       icon, so the ghost would sit 44px left of the label it is meant to
       cover. Fixed with `position: relative` on `.post-heading` in §8 — which
       is Salient's own remedy for its centred-text variant:
         `.col.center ...[data-post-title-overlay=yes] .nectar-post-grid-item
          .post-heading{display:inline-block;position:relative}`

   (b) WIDTH. Salient ships `max-width:70%` on the ghost. Its own titles are
       one or two lines, so the mis-wrap barely shows. Ours run to three lines
       ("Free parking on premises, paved road and driveway"), and at 70% the
       ghost re-wraps to four or five and hangs below the real label. Set to
       100% so the ghost registers exactly. THIS IS A DELIBERATE DEVIATION FROM
       THE REFERENCE — it is listed in the lossiness returned with this
       section, not hidden here.

   Salient's rule is (0,5,1); the selector below is (0,6,1). */
.mk-amenities52 .nectar-post-grid-wrap[data-style="mouse_follow_image"] [data-post-title-overlay="yes"] .nectar-post-grid-item .post-heading:before {
  max-width: 100%;
  width: 100%;
}


/* ==========================================================================
   §9b. THE ICON'S OWN GHOST — R19-02, new work extending §9's pattern
   ====================================================================== */

/* R19-02: "extend the SAME technique... to each item's ICON, not just its
   heading." §9's ghost is `content: attr(data-title-text)` because its
   payload is text — a pseudo-element can generate text from an attribute,
   but it cannot generate an SVG glyph (`content` has no vector-graphics
   form). The icon is an inline `<svg>`, unique per amenity (47 distinct
   glyphs, `sections/16-amenities-52.html` R19-02 pass) — there is no single
   shared shape a CSS mask/`content` value could reference for all of them.
   So the duplicate here is a second, identical `<svg>` sibling in the DOM
   (`sections/16-amenities-52.html`, `.mk-amenities52__icon-ghost`,
   machine-generated from each item's own real glyph, not hand-retyped —
   guarantees the ghost is byte-identical to its own icon, no drift risk
   across 47 items) rather than a generated pseudo-element. Everything ELSE
   about the technique is the SAME as §9: absolutely positioned exactly over
   the original, `mix-blend-mode: overlay`, `z-index: 1000` (identical value
   to the heading's ghost — same stacking tier, same reasoning: above the
   follower photo, which tops out at `z-index: 100` on hover, §10 below),
   `opacity: 0` at rest with no transition (instant toggle, matching §9 —
   the heading's own hover rule has none either), driven straight off
   `.nectar-post-grid-item:hover`.

   `.mk-amenities52__icon` gets `position: relative` here so the ghost's
   `position: absolute` resolves against the icon's own 40x40 box, not some
   further ancestor — the same anchoring fix §9's own comment (a) documents
   for the heading.

   TRIGGER — deliberately simpler than §9's two-branch vendor selector.
   Salient's own rule branches on `[data-animation=fade-in-from-bottom]` /
   `.finished-animating` because IT has to serve both of Salient's entrance
   modes. This rule is not vendored — it is new, Mykrobial-owned CSS — and
   this section's `data-animation` is pinned to `"none"` deliberately (HTML
   comment above the grid, R19-01/R11-era: ungates the hover from
   `.finished-animating` entirely). One selector, keyed directly off
   `:hover`, covers the one entrance mode this section actually ships;
   adding the vendor's second branch back in would be dead weight for a
   condition that can never occur here.

   COLOR — white, same literal value as §9's own `[data-text-color=dark]
   .post-heading:before{color:#fff}`, not the icon's own resting
   `var(--mk-ink-icon)` fill (§4 above): overlay-blending the icon's own
   dark ink against itself would stay dark (overlay's math for a backdrop at
   or below 50% gray is `2×backdrop`, i.e. still dark for a dark backdrop),
   defeating the effect the SAME way it would for the heading if the
   heading's ghost were left at `--mk-ink-body` instead of white — §9
   already made this exact call for the text; the icon ghost makes it too,
   for the same reason. */
.mk-amenities52__icon {
  position: relative;
}
.mk-amenities52__icon-ghost {
  position: absolute;
  left: 0;
  top: 0;
  width: 40px;
  height: 40px;
  display: block;
  mix-blend-mode: overlay;
  z-index: 1000;
  opacity: 0;
  pointer-events: none;
}
.mk-amenities52__icon-ghost path {
  fill: #fff;
}
/* R19-03 (below, §9c) strips the follower photo entirely from every
   Unsplash-sourced row, and with it marks the row `data-has-img="false"` —
   the same attribute value already used by the one row that always had no
   image. Gating the trigger on `[data-has-img="true"]` here, rather than
   leaving it unconditional, is what makes those rows behave "exactly like
   [they] currently would with no hover image at all" (her words) instead of
   still popping a white icon ghost against nothing. */
.mk-amenities52 .nectar-post-grid-wrap[data-style="mouse_follow_image"] .nectar-post-grid-item[data-has-img="true"]:hover .mk-amenities52__icon-ghost {
  opacity: 1;
}


/* ==========================================================================
   §9c. R19-03 — NO HOVER AFFORDANCE ON UNSPLASH-SOURCED ROWS
   ====================================================================== */

/* Her words: "if you can't find the image on Vista Pacifico... just don't
   do the hover for now... we don't need any interaction on those." Reverses
   part of round 17's Unsplash-fallback instruction — Unsplash stops being an
   acceptable substitute for THIS component specifically (the amenity is
   still listed; only the hover mechanic is withdrawn). Mechanical rule, no
   per-item quality judgment: every row whose `data-mk-credit` contained
   "Unsplash" had its `.nectar-post-grid-item-bg-wrap` (the photo) deleted
   outright in the HTML and its `data-has-img` flipped to `"false"` — the
   exact value the one amenity that always had zero image already carries.
   41 of 47 rows; the 5 genuinely Vista-Pacifico/Airbnb-sourced rows (kitchen,
   AC, workspace, bathtub, pool) are untouched, keeping R19-01/R19-02's fixes
   above in full.

   Deleting the bg-wrap already removes the photo and its `opacity:1`/
   `z-index:100` hover rule can no longer match (no element left to match
   it). The icon ghost is closed at the source, above (added the
   `[data-has-img="true"]` condition directly into its own trigger rule,
   since we own that selector outright). The TITLE ghost's hover-to-opacity-1
   rule is Salient's own vendored rule (element-post-grid.q-98228494a0.css)
   and is not ours to edit — so it is overridden here instead, at higher
   specificity via this section's own id (id beats any run of classes
   regardless of count, the same technique this file already uses
   throughout to out-rank vendor selectors without touching the vendored
   file). No tooltip exists anywhere in this component to remove separately —
   confirmed by grep, there never was one; "no tooltip" in her ask is
   already satisfied by removing the image and the two ghosts. */
#s16-amenities-52 .nectar-post-grid-item[data-has-img="false"]:hover .post-heading:before {
  opacity: 0;
}


/* ==========================================================================
   §10. THE FOLLOWER — 250x250 square retargeted to Figma's 200x200 circle
   ====================================================================== */

/* Figma supplies exactly ONE image in this section: the 200x200 `Ellipse 7`
   (imageHash 4308451f...). There are nine rows and no per-row image fill
   anywhere in either subtree. Spec §8.4 is explicit — "Do not invent nine
   images" — and offers two readings, of which (a) is the one the geometry
   supports: `Ellipse 7` IS the follower, and the circle drawn at (960,360) is
   its resting state. So the same real photograph drives all nine rows, and the
   follower is 200 and round rather than Salient's 250 and square.

   Consequence, stated plainly because it is a founder question and not a fact:
   the resting circle at (960,360) is still painted while the follower is
   active, because that is what the Figma render shows and what the parity
   probe compares against. Whether it should hide on hover is unresolved.

   Displaces:
     `...[data-style=mouse_follow_image] .nectar-post-grid-item-bg,
      ...-bg-wrap{width:250px;height:250px;position:absolute}`         (0,3,0)
     `...[data-mouse-follow-image-alignment=middle] .nectar-post-grid-item-
      bg-wrap{left:-125px;top:-125px}`                                 (0,4,0)
   Note the second one also settles nonprofit.lift.md lossiness 18, which could
   not decide between -125/-125 and the later 10px/10px rule: the -125 rule is
   (0,4,0) and the 10px rule is (0,3,0), so -125 wins on specificity regardless
   of source order. Half of 200 is 100, so the circle centres on the cursor.

   `position: fixed`, `opacity: 0`, `pointer-events: none`, `overflow: hidden`,
   `will-change: transform, opacity` and `z-index: 1` all stay Salient's. */
.mk-amenities52 .nectar-post-grid-wrap[data-style="mouse_follow_image"] .nectar-post-grid-item-bg,
.mk-amenities52 .nectar-post-grid-wrap[data-style="mouse_follow_image"] .nectar-post-grid-item-bg-wrap {
  width: 200px;
  height: 200px;
  border-radius: var(--mk-radius-circle);
}
.mk-amenities52 .nectar-post-grid-wrap[data-style="mouse_follow_image"] [data-mouse-follow-image-alignment="middle"] .nectar-post-grid-item-bg-wrap {
  left: -100px;
  top: -100px;
}
/* The inner box carries the `scale(.3) -> scale(1)` half of the counter-scale
   reveal, so it must be clipped round too or the corners flash square during
   the 800ms. Its transform-origin, transforms and transition stay Salient's. */
.mk-amenities52 .nectar-post-grid-wrap[data-style="mouse_follow_image"] .nectar-post-grid-item-bg-wrap-inner {
  border-radius: var(--mk-radius-circle);
  overflow: hidden;
}

/* The exported asset is already circle-masked at 800x800 (4x of the 200px
   design box). Inside the follower it is drawn at `object-fit: cover` and then
   scaled 1.8 -> 1, so the visible 200px aperture always sits well inside the
   source circle and never reveals the mask edge. */
.mk-amenities52 .nectar-post-grid-item-bg__media {
  object-fit: cover;
}

/* REDUCED MOTION — REVERSED BY D09, because D09 deleted this rule's premise.
   --------------------------------------------------------------------------
   What was here: `…:hover .nectar-post-grid-item-bg-wrap { opacity: 0 }`, i.e.
   HIDE the follower entirely under reduced motion. Its stated reasoning was
   sound at the time and is quoted so the reversal is auditable: *"Salient's
   follower is a `requestAnimationFrame` loop with no reduced-motion path. The
   rAF cannot be stopped from CSS … so the honest fallback is to leave the
   follower hidden and let the resting `Ellipse 7` carry the imagery."*

   `Ellipse 7` no longer exists (§2). The second half of that sentence is now
   false, and with it the trade: hiding the follower used to cost a reader
   nothing, and would now cost them every photograph in the section.

   So the follower STAYS VISIBLE and the *animation* is what is reduced:

     · the 800ms counter-scale reveal (frame .3 -> 1 while the image inside
       goes 1.8 -> 1) is `transition: none` here, so the circle appears at its
       final size instead of blooming
     · Salient's 200ms fade is left alone — a cross-fade is not vestibular
       motion and it is what stops the row-to-row swap reading as a jump cut

   WHAT IS NOT FIXED, STATED RATHER THAN GLOSSED: the rAF lerp (damp 0.18)
   still glides the circle toward the pointer and still coasts briefly after
   the pointer stops. It cannot be stopped from CSS, and pinning `transform`
   with `!important` would park the circle at the viewport origin — visible,
   in the wrong place, on every hover. Stopping it properly means a JS
   reduced-motion branch in the shared follower, which is not this lane's file.
   Filed at founder-trace/SHARED-REQUESTS.md REQ-MCF-REDUCED-01.

   Specificity: Salient's hover rule is (0,5,0); these are (0,6,0). */
@media (prefers-reduced-motion: reduce) {
  .mk-amenities52 .nectar-post-grid-wrap[data-style="mouse_follow_image"] .mouse-over .nectar-post-grid-item:hover .nectar-post-grid-item-bg-wrap-inner,
  .mk-amenities52 .nectar-post-grid-wrap[data-style="mouse_follow_image"] .mouse-over .nectar-post-grid-item:hover .nectar-post-grid-item-bg {
    transition: none;
    transform: none;
  }
}


/* ==========================================================================
   §11. RESPONSIVE — PROPOSAL, NOT DESIGN TRUTH
   ====================================================================== */

/* Only two frames exist for this section: 1280 (EN) and 1440 (ES). There is no
   tablet frame and no mobile frame (spec §7.1 / lossiness 17). The 1280->1440
   delta proves exactly one thing (spec §7.2): the three columns are FLUID and
   absorb the whole +160 at 53.33 each, while the 120 margin, the 72 gutter,
   the 48 row gap, the 24 block gap, the 96/12 padding, the 40 icon, the 4 gap
   and every type size are CONSTANT. Everything below 1280 is reasoned from
   that, per spec §7.3, and is labelled as a proposal. Take it to the founder
   before treating any of it as decided. */

/* D09 — the `@media (max-width: 1279px) { .mk-amenities52__ellipse
   { display: none } }` rule stood here. It hid the resting plate below 1280
   because `left: 960` is a hard 1280-frame coordinate (1280 - 120 - 200) that
   clips at any narrower viewport, and because re-anchoring it to the right
   margin would have put it at left:776 at 1024, colliding with grid text that
   runs to x=925 (review/deepdive/responsive-1024.md §10 P2).

   Deleted with the plate itself — see §2. The reasoning is preserved rather
   than the rule, because the collision it describes is a real property of the
   1024 layout and anything else ever parked at a hard 1280 coordinate in this
   section will hit it. */

@media (max-width: 1023px) {
  /* 2 columns, gutter 48 — keeps a ~330 column, close to the 352 that the ES
     frame independently validates. Spec §7.3. */
  .mk-amenities52 .nectar-post-grid-wrap[data-style="mouse_follow_image"] .nectar-post-grid[data-columns="3"] {
    grid-template-columns: repeat(2, 1fr);
    column-gap: 48px;
  }
  /* `Ellipse 7` is decorative and overlaps live text. Spec §7.3 says it should
     be hidden or moved out of the text band below the 2-column breakpoint, and
     says in the same sentence that it is a founder call because Figma does not
     position it for any width other than 1280. Hidden here as the
     lower-risk option. UNRESOLVED. */
}

@media (max-width: 767px) {
  /* 1 column. Originally "row gap 48 -> 32" here (the 48px Merriweather
     heading proposal, LEFT AT 48 because Figma does not say what it becomes
     below 1280 — spec §7.3 / lossiness 17 — is unrelated and still applies
     to the heading, not this grid).

     R17-01 — the 32px restatement is GONE, not just renumbered. Its own job
     was to be tighter than the old 48px base; the base above is now 24px
     (var(--mk-space-24)), already tighter than the 32 this rule used to
     assert, so restating 32 here would make mobile's row-gap LARGER than
     desktop's — backwards. No override needed: this breakpoint now simply
     inherits the 24px base, which is exactly the number a fresh "what should
     mobile be" call would land on (the same dominant stack-gap token, same
     as every other viewport). One value, one place — the D09/R12-05 pattern
     this file already uses for "the divergent number stopped earning its
     rule". */
  .mk-amenities52 .nectar-post-grid-wrap[data-style="mouse_follow_image"] .nectar-post-grid[data-columns="3"] {
    grid-template-columns: 1fr;
  }
}

/* ============================================================================
   R16-03/04 — THE EXPAND, REPLACING D34's ALL-AMENITIES DIALOG
   ----------------------------------------------------------------------------
   Her words (round 16, verbatim): "that really discussing amenities,
   dialogue, modal card thing is still on the page... why is that there?"
   The whole D34 dialog ruleset that used to sit here — `.mk-amenities52__all`
   and its ~20 descendant selectors, the `::backdrop`, the `:target` no-JS
   fallback — is DELETED, not superseded. Grep this file for
   `mk-amenities52__all`: zero hits below this comment. The 38 extra rows
   this replaces it with need almost none of this section's own CSS, because
   they are genuine `.nectar-post-grid-item` siblings of the original nine
   (HTML, "R16-03" comment) and inherit §7's grid/column rules and §8's
   typography rules for free. Only the show/hide state itself is new.

   ONE STATE CLASS, on the SECTION — `#s16-amenities-52.is-expanded` — not on
   `.mk-amenities52__gridwrap` or `.nectar-post-grid`, because the two
   buttons this drives (`.mk-amenities52__cta` / `.mk-amenities52__hide-btn`)
   are SIBLINGS of the gridwrap inside `.mk-amenities52__col`, not its
   descendants (see the HTML) — the section element is the nearest common
   ancestor of the grid rows AND both buttons, so it is the one place a
   single class can drive all three. */
#s16-amenities-52 .mk-amenities52__extra-item { display: none; }
#s16-amenities-52.is-expanded .mk-amenities52__extra-item {
  /* Any non-`none` value makes a CSS Grid child a participating grid item
     regardless of its own specified display (spec: grid blockifies grid
     items) — `block` is chosen only because it is what the original nine's
     un-styled `.nectar-post-grid-item` divs already compute to by default,
     so collapsed and expanded rows are byte-identical once shown. */
  display: block;
}

/* The two buttons swap; see the HTML comments on each for why there are two
   elements rather than one relabelled button ("at the bottom of the
   expanded list" is a POSITION her round-16 spec named explicitly, and the
   bottom of the expanded list is a different place in the DOM than the top
   of the collapsed one). Both already carry `.mk-amenities52__cta`, so both
   already inherit R16-02's outline/ring/weight/fg tokens, §8e's entrance
   timing and the FLIP hover mechanic (js/myk-motion.js) for free — only the
   display toggle itself needs a new rule. `.myk-btn`'s own base display is
   `inline-flex` (myk-btn.css §2.1); restated explicitly here rather than
   relying on `revert`, because `revert` targets the UA stylesheet's default
   for the element (`inline` for a bare `<button>`), not the `.myk-btn`
   author rule this element also matches — `revert` would silently drop the
   flex layout the label/icon-gap alignment depends on.

   R16-FINISH FIX: this rule used to read bare `.mk-amenities52__hide-btn`
   (specificity 0,1,0). Below 1000px, `_band-xs.css` §(WCAG 2.5.5 touch
   targets) and `_band-mobile.css` §2.2 both carry
   `.mk-page .mk-amenities52__cta { display: inline-flex; ... }` at
   specificity 0,2,0 — and the hide button also matches `.mk-amenities52__cta`
   (see comment above), so at <=999px that band rule out-specified this one
   and forced the collapsed-at-rest hide button to render `inline-flex`
   instead of `none`. Fix is to id-scope this selector to the section, which
   lifts it to 1,1,0 — higher than the band rules' 0,2,0 regardless of file
   load order — while staying lower than the `.is-expanded` reveal rule
   below (1,2,0), which still wins when expanded. Verified live at
   834x1112 and 390x844: hide button now computes `display: none` at rest
   and only the expand button is visible; 1280/1440/1750 unaffected (band
   rules don't apply above 999px, and the hide button already computed
   `none` there via the original bare-class rule at those widths). */
#s16-amenities-52 .mk-amenities52__hide-btn { display: none; }
#s16-amenities-52.is-expanded .mk-amenities52__cta:not(.mk-amenities52__hide-btn) {
  display: none;
}
#s16-amenities-52.is-expanded .mk-amenities52__hide-btn {
  display: inline-flex;
}


/* ============================================================================
   R7-09 · REQ-ZEBRA-4 — THE BIGGEST SINGLE DEAD BAND ON THE PAGE
   ----------------------------------------------------------------------------
   THE RULE (founder-trace/FT-20260821-jehnean-round7 R7-09, derived by lane
   `r7:zebra`; full derivation in sections/01-who-why.css §8):

     ONE BREATH. The empty space between any two neighbouring things on this
     page is one breath, and a breath is always the same fraction of the screen
     you are looking at: one fifth of its SHORTER side, never under 96px and
     never over 208px. A section whose photograph runs to its own edge spends
     no breath there and its neighbour supplies the whole one.

       --mk-breath: clamp(96px, 20vmin, 208px)
         1280x900 -> 180   1440x900 -> 180   1750x980 -> 196
          834x1112 -> 166.8   390x844 -> 96 (floor)

   Both this section's neighbours bleed — `14-amenities` is a 1.4-screen photo
   hold and `17-amenities-54` is a full-bleed map — so this section carries the
   whole breath at BOTH of its edges.

   MEASURED BEFORE (this lane, five fresh headless viewports, served bytes
   SHA-verified against disk; review/r7/r7-seams/seam-before-*.json):

       14 -> 16    252 / 270 / **270** / 157.3 / 40
       16 -> 17    356 / 374 / **442** / 116.7 /  22
                                   at 1280 / 1440 / **1750 (HERS)** / 834 / 390

   442px at her band, between the "See all 47 amenities" button and the top of
   the map, with nothing in it. More than twice a breath. It is the largest
   whitespace anywhere on this page.

   ---------------------------------------------------------------------------
   THE ROOT CAUSE IS A MISSED LINK, NOT A SPACING DECISION
   ---------------------------------------------------------------------------
   Nobody chose 270/470. Measured live at 1750x980 before this block:

       #s16-amenities-52            1176   <- css/rhythm.css §2, --mk-band-12
       .mk-amenities52__frame       1176   <- css/rhythm.css §2, --mk-band-12
       .mk-amenities52__col          900   <- §3 above, its OWN min-height

   rhythm.css raises the section and the frame for B05 ("Amenities taller so the
   map is not yet visible") and names both boxes — but the COLUMN keeps the
   authored 900 from §3, and the column is the flex box that centres the
   content. So the content centres inside a 900px box that is top-aligned inside
   a 1176px frame, and the entire 276px difference lands at the BOTTOM. That is
   the asymmetry, exactly: 270 above, 462-470 below, and 270 + 276 = 546 ~ the
   bottom pair. It is the same three-boxes-must-move-together failure that
   rhythm.css itself writes out for 08-recovery two rules earlier.

   ---------------------------------------------------------------------------
   AND THE HONEST PART: 196/196 IS NOT REACHABLE, AND HERE IS THE ARITHMETIC
   ---------------------------------------------------------------------------
   Measured content height (eyebrow top -> CTA bottom), all five widths:

       480 / 444 / 444 / 636 / 932

   One breath at each edge means the band is `content + 2 x breath`:

       840 / 804 / **836** / 969.6 / 1124

   At 1750 that is 836 in a 980 viewport, so 144px of the map would be on
   screen underneath it — which is precisely what B05 asked to stop. R7-09 and
   B05 cannot BOTH be satisfied exactly for a section whose content is 444px
   tall and whose neighbour must not show.

   THE RECONCILIATION SHIPPED HERE: B05's floor is ONE SCREEN — that is the
   whole of what "so the map is not yet visible" requires — and `--mk-band-12`
   is 1.2 screens, i.e. 196px MORE than B05 needs at her band. That surplus is
   the thing R7-09 is complaining about. So the band drops to exactly one
   screen, the content is centred in it, and the breath is stated as padding so
   that the moment the content is tall enough to want it, it is exact.

   PREDICTED, AND THEN MEASURED IN review/r7/r7-seams/seam-after-*.json:

       edge space  210/210 · 228/228 · **268/268** · 166.8/166.8 · 96/96
       breath      180     · 180     · **196**     · 166.8       · 96

   Tablet and phone land on the breath EXACTLY, because there the content is
   taller than the band and the padding is the only term. Desktop keeps a
   residual of +30 / +48 / **+72**, which is one half of the slack B05's floor
   forces, and it is now SYMMETRIC at every width instead of 270-against-470.
   Her band goes 270/442 -> 268/268: the dead band is cut by 174px and the two
   edges finally agree.

   THE RESIDUAL IS A DESIGN CALL AND IT IS FILED, NOT SILENTLY ABSORBED —
   OBS-SEAMS-02 in founder-trace/SHARED-REQUESTS.md. Removing it needs either
   (a) B05 relaxed so the section may be shorter than one screen, or (b) the
   content given the slack — the grid-to-CTA gap is the only internal gap that
   could carry it without breaking the Figma 24px itemSpacing. Both are the
   founder's to choose; neither is an engineering fix.

   ---------------------------------------------------------------------------
   MECHANICS
   ---------------------------------------------------------------------------
   ID-SCOPED, because it has to be. css/rhythm.css is linked LAST (index.html
   line 192, after every section sheet) and its rule is
   `.mk-page .mk-amenities52, .mk-page .mk-amenities52__frame` at (0,2,0), so an
   equal-weight rule here loses on source order. `#s16-amenities-52` is (1,0,0)
   and wins on weight, which is the same device sections/07-building.css already
   uses throughout. CONVENTIONS §8.6: the rule being overridden is named above.

   THIS IS A FOLD-BACK, NOT A FIGHT. rhythm.css §2's own header says every §2
   rule is a candidate to move into its section's sheet once the concurrent
   round closes. REQ-SEAMS-1 asks its owner to delete the `.mk-amenities52`
   entry rather than leave two rules describing one band.

   SCOPED TO >= 1000px for the band, matching rhythm.css's scope. Below it
   `_band-xs.css` and `_band-mobile.css` own the ladder and §3's `min-height:
   900px` stands; the content is taller than the band at both of those widths
   anyway, so the padding alone decides and it is exact there.

   THE BREATH IS A `var()` WITH A LITERAL FALLBACK ON PURPOSE. `--mk-breath`
   belongs in css/tokens.css (REQ-ZEBRA-1, not yet landed, tokens.css is
   single-owner). Until it does, the fallback IS the value; after it lands this
   file picks the token up with no edit.
   ========================================================================== */

@media (min-width: 1000px) {
  #s16-amenities-52,
  #s16-amenities-52 .mk-amenities52__frame,
  #s16-amenities-52 .mk-amenities52__col {
    /* B05's actual requirement — one screen, so the map is not yet visible.
       Replaces css/rhythm.css §2's --mk-band-12 (1.2 screens) for this section
       only. `max(900px, …)` keeps the authored Figma frame as the floor on a
       short laptop, exactly as --mk-band-1 does. */
    min-height: max(900px, 100svh);
  }
}

/* The breath, at both edges, at EVERY width — this rule is deliberately not
   inside a media query. It replaces §3's `padding-block: var(--mk-space-96)
   var(--mk-space-12)`, which was 96/12 on desktop, 62.55/12 at 834 and 40/12 at
   390: a fixed pair that was neither symmetric nor viewport-proportional, and
   the second half of what R7-09 means by "consistent across breakpoints".
   Same specificity as §3's rule (0,1,0); it wins on source order, later in the
   same file. */
.mk-amenities52__col {
  padding-block: var(--mk-breath, clamp(96px, 20vmin, 208px));
}

/* 2026-09-02 — MOBILE: nine visible amenities do not fit one Pixel 7 screen
   ("maybe on mobile you can reduce this list a little bit ... put the shared
   saltwater infinity pool outdoor into the see-all"). Under 1000px the pool
   row folds into the expanded list: hidden while collapsed, shown by the same
   `.is-expanded` the 38 extra rows already use. The button keeps saying 47 —
   the total did not change, only what is visible before the tap. `:has()` is
   the one honest selector: the row's identity is the Figma node on its
   heading, and nothing else on the row is unique. */
@media (max-width: 999px) {
  #s16-amenities-52:not(.is-expanded) .nectar-post-grid-item:has(.post-heading[data-mk-node="2925:458"]) { display: none; }
}
