/* ============================================================================
   SECTION 14 · "5.0 + 5.1 Amenities" — ONE CAROUSEL, TWO SLIDES
   Figma 2931:565 (slide 1) + 2956:1276 (slide 2)
   ----------------------------------------------------------------------------
   Specs:  figma-truth/14-amenities.spec.md   (slide 1)
           figma-truth/15-amenities-51.spec.md (slide 2)
   Pixels: figma-truth/sections-en/14-amenities.png     (2560x1800, @2x)
           figma-truth/sections-en/15-amenities-51.png  (2560x1800, @2x)
   Lift:   salient-truth/MECHANIC-carousel-cursor.md — the component anatomy,
           extracted by DRIVING the live mirror at 127.0.0.1:5010, not by reading
           markup. Read it before changing anything below.
           salient-truth/tether/fragment.star-rating.html + the inline <style>
           blocks of salient-truth/tether/index.html (the star pill).

   This file supersedes the former 14-amenities.css + 15-amenities-51.css pair.
   Both are preserved verbatim under sections/_retired/. Every measured literal
   they carried is carried forward here with its provenance intact; nothing was
   re-derived from memory.

   ----------------------------------------------------------------------------
   THE ONE THING THIS FILE DELIBERATELY DOES NOT STYLE

   `.nectar-drag-indicator` — the custom follow-cursor. The founder's instruction
   was "the component already does it, just grab the component", and MECHANIC §3
   proves the two data attributes on the slider (`data-indicator-bg="#141414"`,
   `data-indicator-icon="#ffffff"`) reproduce the dark pill with white chevrons
   drawn in the comp. Adding CSS here would fork a component the founder asked us
   to adopt. Verified on the running page rather than assumed — 94px disc,
   `.color-circle` rgb(20,20,20), arrows rgb(255,255,255) in `icomoon` at 21px
   with glyphs \e608 / \e607, `left:23px` / `right:27px`, `scale(0.15)` = 14.10px
   rendered on pointer-down: measured/carousel/drive-report.json.

   >>> WHERE THAT CSS ACTUALLY COMES FROM, and it is NOT where you would guess.
   >>> vendor/…/style-non-critical.q-40f8116f6d.css ships only the BASE class
   >>> (52px, `mix-blend-mode: difference`). Every `[data-type="solid"]` rule —
   >>> the 94px box, the -47/-47 centring offsets, the `.color-circle`, the
   >>> 0.45s/0.3s enter transitions, the arrow offsets, the pointer-down collapse
   >>> — is published UNNAMESPACED, page-wide, by **sections/07-building.css**
   >>> (12 rules; that section lifted them verbatim for its own carousel).
   >>> Asked the live CSSOM which rule wins, not the file: the answer is
   >>> `07-building.css | .nectar-drag-indicator[data-type="solid"]`.
   >>>
   >>> So section 14's cursor currently depends on section 07's stylesheet. That
   >>> is an accident, and it already caused one real defect — see the SINGLETON
   >>> RELEASE block in sections/04-ecology.css. FIX (not done here, because it is
   >>> surgery on two sections this run was not asked to touch): move those 12
   >>> rules to css/salient-elements.css, whose stated purpose is exactly "Salient's
   >>> own per-element CSS which it emits inline on the demo page and which
   >>> therefore never reached vendor/", and delete them from 07-building.css. It
   >>> is behaviour-neutral today — the body-level cursor is the only element on
   >>> the page carrying that class — but it stops the cursor from silently losing
   >>> its skin the day 07 is retired or reordered.

   ----------------------------------------------------------------------------
   SPECIFICITY — WHY EVERY SALIENT SELECTOR BELOW CARRIES A LEADING .mk-amenities

   The vendored flickity sheet ships two rules that are (0,3,0) and (0,4,0) and
   that DO match this element, because unlike the retired 15 this slider now
   carries the `nectar-flickity` class:

     .nectar-flickity:not(.masonry) .flickity-viewport   { margin: 80px 0 }
     .nectar-flickity:not(.masonry) .flickity-slider .cell { width:66%; margin-right:3% }

   Salient's own `.nectar-flickity.nectar-simple-slider …` overrides for both are
   NOT in our vendor tree (they live in the resort site's non-critical sheet,
   which our capture does not include — grepped: zero `nectar-simple-slider`
   layout rules in vendor/). So they are re-authored here, namespaced, at a
   specificity that cannot lose. Same call, same reason, as sections/04-ecology.css.
   ========================================================================== */

/* ============================================================================
   R8-09 / R8-10 — READ THIS BEFORE TOUCHING §4 "the reveal" BELOW.
   ----------------------------------------------------------------------------
   R8-09, her words: "I still want ... to see the text move up and fade in ...
   for the [bubbles] where it says five out of five from reviews and the two
   guests, one bedroom, one bath." §4's `.mk-amenities__reveal` system already
   did exactly that — fade + translateY(24px), staggered 90/180ms, gated on
   Flickity's `.is-selected`. It was never visibly playing. MEASURED (not
   argued), driving this page headless with TRUSTED wheel input, served bytes
   verified == disk: Salient's delayed-JS bundle (Flickity included) wakes on
   the reader's FIRST trusted gesture ANYWHERE on the page, and Flickity marks
   cell 0 `.is-selected` synchronously in the same tick `.flickity-enabled`
   lands — both, off-screen, before a normal top-to-bottom visitor is anywhere
   near this section. No frame ever painted the hidden state, so there was
   nothing to visibly transition FROM by the time she scrolled here.
   review/r8-estate-slider/trusted-scroll-arrival.json is the walk that proved
   it: `.mk-amenities__pill` computed `opacity:1, transform:none` at every
   sample from the moment the section entered the viewport onward.

   THE FIX for that race is in `sections/14-amenities.html`'s own inline
   script (R8-09 comment block there) — a forced-reflow arm, gated on BOTH
   Flickity-ready and an IntersectionObserver actually seeing the section, so
   the hidden frame is guaranteed to paint once before §4's own transition (its
   stagger, its easing, all untouched) carries it to rest. That fix is what
   makes §4 below a real, working "simple entrance" — not a decoration.

   R8-10 is a SEPARATE, EXPLICITLY EXPERIMENTAL ask on top of that: "she is
   undecided whether THIS section's text should animate ON SCROLL ... versus a
   one-shot entrance ... implement the scroll-driven version as the live
   default, but keep the simple entrance ONE TOKEN/CLASS FLIP away." That
   variant is §4b, below §4's reduced-motion guard. It does not touch §4 — it
   OVERRIDES it, at a matched specificity broken by source order (documented
   at the top of §4b), so it can be turned off by editing ONE class.

       ┌─────────────────────────────────────────────────────────────────┐
       │  R9-03 — DECIDED. LIVE DEFAULT (as of round 9): SIMPLE ONE-SHOT  │
       │  ENTRANCE (§4 alone). `mk-amenities--motion-scroll` was REMOVED  │
       │  from `<section id="s14-amenities">` in                         │
       │  sections/14-amenities.html — she reviewed the R8-10 A/B and    │
       │  picked this one over the scroll-driven variant, her words:     │
       │  "the second option better ... 'Perfect for couples...' works   │
       │  better without the double scroll so make the first like that." │
       │  §4b below is now DEAD CODE under normal browsing (its gate     │
       │  class never matches) — kept in place, not deleted, exactly so  │
       │  the A/B stays re-derivable if she ever wants scroll-driven      │
       │  back. TO RE-ENABLE THE SCROLL-DRIVEN VARIANT: add               │
       │  `mk-amenities--motion-scroll` back to that one class list.      │
       │  Nothing in §4 or §4b needs to change either direction.          │
       └─────────────────────────────────────────────────────────────────┘

   WHY SCROLL-DRIVEN COSTS NO NEW JAVASCRIPT. `data-myk-hold="1.4"` is already
   live on this section (REQ-HOLD-1 landed, REQ-BGF-1's blank-band regression
   is fixed — see the SUPERSEDED marker in the .html). The document-wide
   reader in `sections/04-ecology.html` already writes a live, per-frame
   `--myk-hold-p` (0..1) onto `#s14-amenities` via a PASSIVE scroll listener —
   REQ-SCROLL-01 compliant, no wheel listener anywhere, nothing added here.
   §4b only reads that number in `calc()`. This is also why R8-09's arrival
   race cannot recur under the scroll variant: opacity is a live function of
   ACTUAL scroll position every frame, not a state flag set once at init.

   MEASURED, not assumed, before §4b was written (review/r8-estate-slider/
   hold-walk.json, same headless+trusted-input method): across this section's
   full 2,160px hold, the Flickity slide index changes from 0 to 1 at
   `--myk-hold-p` ≈ 0.627–0.630. §4b's two per-cell windows below split the
   0..1 range at 0.63, with a small margin (slide 1's window ends its fade-out
   at 0.58, slide 2's begins at 0.63) so neither cell's text is still moving
   the instant Flickity swaps the visible cell.

   SCOPE, STATED RATHER THAN LEFT IMPLICIT: §4b does not stagger the three
   elements the way §4 does (0 / --mk-am-reveal-step / --mk-am-reveal-step*2,
   220/440ms as of R9-04/R9-05). A per-element phase shift is
   straightforward to add here later — a small `--mk-am-lp` offset per
   `nth-child` — but it is a second new custom property on top of the two this
   already adds, and this section's own history (REQ-BGF-1, REQ-ISLAND-
   BOUNDARY-01) is two separate incidents of a new wrapper or a new rule
   quietly breaking a selector it did not look like it touched. R8-10 is
   explicitly "not a committed decision" — this ships the correct, minimal
   shape first; a stagger is a follow-up if she prefers the scroll direction.
   ========================================================================== */


/* ============================================================================
   PART 1 — SALIENT CSS, RE-AUTHORED VERBATIM (values unchanged, selector
   namespaced only). Not ours, not "improved".
   ----------------------------------------------------------------------------
   1a · the `nectar-simple-slider` cell anatomy, from the live resort page's
        computed CSSOM (MECHANIC §4.6).
   1b · the tether `flex_*_desktop_*` column utilities + `nectar-star-rating`,
        from the inline <style> blocks of salient-truth/tether/index.html. Tether
        is WP site 46; our vendor tree is site 37 (resort), so a grep of vendor/
        finds `column-link` and `screen-reader-text` (both used unchanged) but
        ZERO `nectar-star-rating` / `flex_*_desktop_*`. vendor/ is byte-locked,
        so the rules live here.

   >>> HOIST 1a AND 1b to css/salient-elements.css the moment a second section
   >>> needs them. They are generic Salient utilities, not a section-14 concern.
   ========================================================================== */

/* --- 1a · simple-slider anatomy ------------------------------------------ */
.mk-amenities .nectar-flickity.nectar-simple-slider { position: relative; }
.mk-amenities .nectar-flickity.nectar-simple-slider .flickity-viewport {
  overflow: hidden; position: relative; height: 100%; margin: 0;
}
.mk-amenities .nectar-flickity.nectar-simple-slider .flickity-slider .cell {
  width: 100%;
  padding: 0 8%;
  padding: 0 min(8%, 100px);
  position: relative;
  display: flex;
  align-items: center;
  height: 100%;
  margin-right: 0;
}
.mk-amenities .nectar-simple-slider .cell > .bg-layer-wrap,
.mk-amenities .nectar-simple-slider .cell > .bg-layer-wrap .bg-layer,
.mk-amenities .nectar-simple-slider .cell > .bg-layer-wrap .color-overlay {
  position: absolute; left: 0; top: 0; width: 100%; height: 100%;
}
.mk-amenities .nectar-flickity.nectar-simple-slider .cell > .bg-layer-wrap .bg-layer {
  background-size: cover; background-position: center;
}
.mk-amenities .nectar-simple-slider .cell > .inner { z-index: 10; position: relative; flex: 1; }
.mk-amenities .nectar-simple-slider .cell > .inner :is(h1, h2, h3, h4, h5, h6) { color: inherit; }
.mk-amenities .nectar-simple-slider .cell.text-color-ffffff .inner { color: var(--mk-ink-inverse); }
.mk-amenities .nectar-flickity.nectar-simple-slider .flickity-slider .cell .inner > div:last-child { margin-bottom: 0; }
/* The `<ol>` is inert and only the bars are hit-testable — Salient's own split,
   and it is load-bearing here: the dots sit OUTSIDE `.flickity-viewport`, which
   is exactly why the custom cursor vanishes when you reach for them
   (MECHANIC §2 point 4, measured live). A full-width hit-testable strip would
   blink the cursor out along a 1280px band instead. */
.mk-amenities .nectar-simple-slider .flickity-page-dots { pointer-events: none; }
.mk-amenities .nectar-simple-slider .flickity-page-dots .dot { pointer-events: all; }

/* NOT LIFTED, deliberately:
     .nectar-simple-slider .flickity-page-dots .dot:before
       {height:8px;width:8px;left:14px;top:14px;border-radius:50px;background:#fff}
   turns Flickity's 4px BAR into a circle. Figma draws bars (4px stroke, ROUND
   cap), which is the *base* flickity.q-458c954239.css rule that IS vendored and
   IS loaded. The base rule is left to win and only the deltas are written in §6.
   Also not lifted: `.sizing-aspect-ratio` / `.aspect-2-1` (padding-bottom:50%
   would make a 640px band at 1280 — Figma is a fixed 900), `.min-height-475px`,
   the arrow skin, and every `[data-parallax="true"]` rule (parallax is off). */

/* --- 1b · tether column utilities + star rating -------------------------- */
.flex_layout_desktop_row> .vc_column-inner > .wpb_wrapper{display:flex;flex-direction:row;}
.flex_justify_content_desktop_center> .vc_column-inner > .wpb_wrapper{justify-content:center;}
.flex_align_items_desktop_center> .vc_column-inner > .wpb_wrapper{align-items:center;}
.flex_wrap_desktop_nowrap> .vc_column-inner > .wpb_wrapper{flex-wrap:nowrap;}
.nectar-star-rating{display:flex;flex-wrap:wrap;align-items:center;}
.nectar-star-rating *{font-size:inherit;line-height:1.3;}

/* Deliberately omitted from 1b, with reasons:
     .nectar-star-rating__icon:before{font-family:icomoon;…letter-spacing:.15em}
     .nectar-star-rating__icon.size-5:before{content:"\e907 \e907 \e907 \e907 \e907"}
                        the icomoon webfont is a licensed Salient theme asset and
                        its .15em tracking would widen the run past Figma's
                        measured 90px. Inline SVG instead — see §5.
     .nectar-star-rating__content{margin-left:8px}    no __content element here
     .centered-text .nectar-star-rating{display:inline-flex}
                        we do not use Salient's `centered-text` column class
     .flex_gap_desktop_10px{gap:10px}                 Figma says 8  (2931:594)
     .wpb_column.left_padding_desktop_20px{padding-left:20px}  Figma says 18
     .wpb_column.top_padding_desktop_10px{padding-top:10px}    Figma says 8

   END VERBATIM SALIENT CSS
   ======================================================================== */


/* ============================================================================
   PART 2 — MYKROBIAL RETARGET
   Every literal below cites the spec line or the probe it came from.
   ========================================================================== */

/* ---------------------------------------------------------------------------
   2 · THE BAND
   Fixed 900 tall in BOTH design frames. Full-bleed: the photography and the two
   scrims run edge to edge; only the content is inset.
   `isolation` keeps the pills' backdrop-filter sampling this section's own paint
   rather than whatever the page has composited beneath.

   THE TWO DERIVED NUMBERS LIVE HERE AND NOWHERE ELSE.
   `--mk-am-headline-h` is Figma's 260px text box (4 x 64.8 = 259.2 ceil'd to 260
   by Figma; pinning 260 is what lands the pill's top edge on y 569.0 — the
   render steps ground -> pill between y 568.5 and 569.0 at x 534).
   `--mk-am-group-h` is the centred cluster inside Frame 1846:
       24 overline + 24 gap + 260 headline + 24 gap + 40 pill = 372
   The per-slide stack consumes it as flow (§3) and the FIXED overline layer
   consumes it as an offset (§4). One number, two consumers — change it once and
   both move together. Nothing in this file hard-codes 237 or 189.
   ------------------------------------------------------------------------ */

/* D27 (c) — FULL-SCREEN HEIGHT. Was a hard `height: 900px`.
   G1: "Sections should fill the viewport — full-screen height and width — at
   every breakpoint. You should not see the section above and below
   simultaneously."

   THIS COSTS ZERO FIDELITY, and that is measured rather than hoped. The
   per-section capture in _tools/fullpage.py runs at a 1280 x 900 viewport
   (`--window-size`, default `--height 900`), so at the instrument's own
   viewport `100svh` resolves to exactly 900 — the same number the hard literal
   produced, and the same number Figma authors. The 900 does not disappear from
   the build; it stops being a hard-coded assumption about the reader's screen
   and becomes what it always meant, "one screen".

   `min-height: 100vh` first, then `100svh`: `svh` is the SMALL viewport height,
   which is the stable one on mobile where the URL bar collapses. Browsers that
   do not know `svh` keep the `vh` line. `height` is still set (not just
   min-height) because the whole internal geometry chain below is `height: 100%`
   percentages off this box, and a percentage of `min-height` alone does not
   resolve.

   Every derived number below still holds: --mk-am-band-bottom and the chrome
   offset are computed from --mk-section-y and the group height, never from 900. */
.mk-amenities {
  height: 100vh;
  height: 100svh;                                 /* 900 at the 1280x900 capture viewport */
  overflow: hidden;
  isolation: isolate;
  color: var(--mk-ink-inverse);                   /* every text fill is #ffffff */

  --mk-am-headline-h: 260px;
  --mk-am-group-h: calc(var(--mk-lh-node)          /* 24 — overline line box   */
                      + var(--mk-space-24)         /* 24 — itemSpacing         */
                      + var(--mk-am-headline-h)    /* 260                      */
                      + var(--mk-space-24)         /* 24 — itemSpacing         */
                      + 40px);                     /* 40 — pill box            */

  /* R9-04/R9-05 — the §4 reveal's per-element stagger step. See the rule
     using it, below §4, for the founder ask and the measured retune from
     90ms. One token so the two nth-child delays can never drift apart. */
  --mk-am-reveal-step: 220ms;
  /* R11-04 — the §4 reveal's per-element DURATION, section-local. Deliberately
     its OWN token rather than reading the shared --myk-flip-dur (css/myk-btn.css
     :root) that §4 read before this item: that global also clocks the header
     search-icon hover-flip (css/myk-btn.css §8/§9), and this ask was to slow
     THIS section's reveal, not every hover-flip on the page. See the boxed
     callout below §4 for the founder ask and the live measurement behind the
     retune from .55s. */
  --mk-am-reveal-dur: 1.5s;
  /* The 750 band's bottom inset: 48 section padding + 30 indicator + 24 gap. */
  --mk-am-band-bottom: calc(var(--mk-section-y) + 30px + var(--mk-space-24));

  /* Figma BACKGROUND_BLUR radius 4 -> CSS blur(2px).
     >>> CORRECTION <<< to both specs, which map radius -> blur 1:1 "by
     convention" and flag the mapping as unverified. Two measurements agree it is
     a factor of two:
       (I)  Figma's SVG export writes, for every blurred node in both frames,
            `<div style="backdrop-filter:blur(2px);…">` under
            `data-figma-bg-blur-radius="4"`. The same exporter emits
            `stdDeviation="7"` for the headline's DROP_SHADOW radius 14 — the
            identical radius/2 = sigma rule.
       (II) fitting the @2x render: reconstruct the ground from the raw bitmap +
            both scrims, blur it, composite black@50%, and diff against the two
            glyph-free bands inside the pill. |Δ| mean by sigma —
                1.0 -> 2.23 / 1.45 | 1.5 -> 1.12 / 1.26 | 2.0 -> 1.14 / 1.31
                3.0 -> 1.50 / 1.65 | 4.0 -> 1.91 / 1.99
            Minimum at sigma 1.5-2.0; sigma 4 nearly doubles the error.
     tokens.css still publishes --mk-pill-blur: blur(4px) for this same Figma
     value. That token is wrong by a factor of two and should be fixed centrally;
     it is NOT overridden globally from a section file. */
  --mk-amenities-blur: blur(2px);
}

/* The height chain has to reach the cells or the cold render collapses.
   REQ-ISLAND-BOUNDARY-01 (filed by `r2:cascade-v34` against this exact line):
   Astro gives every hydrated island a real `<astro-island>` element with
   `display: contents`, which leaves the BOX tree but not the SELECTOR tree — so
   `>` across that boundary stops matching and V3 shipped both slides at zero
   height (99.91 %diff against Figma truth where V1 scores 2.67 %). The extra
   selector below is an ADDITION and costs V1 nothing: `astro-island` is an
   unknown element here, so it can never match in this build. */
.mk-amenities > astro-island > .nectar-carousel,
.mk-amenities > .nectar-carousel,
/* REQ-AMENITIES-STAGE-01 — the SAME `>`-across-a-new-wrapper break the comment above
   describes for V3's <astro-island>, reintroduced in V1 by the .mk-amenities__stage
   sticky wrapper I added to restore the founder-praised hold (REQ-HOLD-1). With the
   stage in between, `.mk-amenities > .nectar-carousel` stopped matching, every node
   computed height 0px, and the gallery rendered as a ~1,300px BLANK BAND — the exact
   failure this comment was written about, one wrapper later.
   The lesson is in the rule shape, not the patch: a child combinator is a claim that
   no one will ever wrap the child. Two lanes have now falsified that claim on this
   same selector. These are ADDITIVE and cost nothing when the stage is absent. */
.mk-amenities > .mk-amenities__stage > astro-island > .nectar-carousel,
.mk-amenities > .mk-amenities__stage > .nectar-carousel,
.mk-amenities .nectar-flickity.nectar-simple-slider { height: 100%; }

/* The stage must also pass a definite height down, or `height:100%` above resolves
   against `auto` and collapses again. The stage is 100svh; its flex child chain to
   the carousel needs to inherit that rather than hug content. */
.mk-amenities__stage > .nectar-carousel,
.mk-amenities__stage > astro-island { flex: 1 1 auto; min-height: 0; }

/* COLD RENDER. init.js ships as `type="salientlazyscript"` and does not run
   until the first click/scroll/touch/key/mousemove, so the page paints once with
   Flickity absent. In that state `.flickity-slider` is a plain 900px-tall
   absolute box and TWO 100%-height cells would stack to 1800 inside it. The
   viewport's `overflow: hidden` already clips slide 2, but relying on a clip is
   relying on a coincidence — this pins slide 1 as the rest state explicitly.
   `:not(.flickity-enabled)` means Flickity's own `.is-selected` machinery takes
   over the moment it initialises and this rule stops matching. The idiom is
   Salient's own (`.nectar-flickity.nectar-carousel:not(.flickity-enabled)
   .flickity-slider>div:not(:first-child){position:absolute;visibility:hidden}`
   in the vendored flickity sheet). */
.mk-amenities .nectar-flickity.nectar-simple-slider:not(.flickity-enabled) .flickity-slider > .cell:not(:first-child) {
  position: absolute; top: 0; left: 0; visibility: hidden;
}

/* ---------------------------------------------------------------------------
   2.2 · GROUND — the image fill and the two scrims
   Paint order in Figma is bottom-up: IMAGE, then #0d1d23 @40%, then #000 @20%,
   identical on BOTH frames. The two scrims are NOT collapsible: composited they
   are 0.48 x image + (4.16, 9.28, 11.2), which no single flat overlay
   reproduces. Two stacked `.color-overlay` elements in DOM paint order.

   Placement is MEASURED, not assumed. Slide 1's SVG pattern transform,
   matrix(0.00049204, 0, 0, 0.00069979, -0.129811, 0) in objectBoundingBox units
   over the 1280 x 900 frame, resolves to a 1612.317 x 900 draw at x = -166.158,
   and (1280 - 1612.317) / 2 = -166.158 exactly. That is `cover` + `center`.
   Slide 2 carries the identical transform. Reconstructing slide 1's ground from
   it and diffing against the render gives |Δ| mean 0.34 (sky), 1.59 (grass),
   1.02 (lower right) out of 255 — i.e. the model is the render. Slide 2's
   equivalent check lands at 0.81 outside the type areas.
   ------------------------------------------------------------------------ */

.mk-amenities .nectar-simple-slider .cell > .bg-layer-wrap > .color-overlay.mk-amenities__scrim-deep {
  background-color: var(--mk-scrim-deep);          /* fills[1] #0d1d23 @40% */
}
.mk-amenities .nectar-simple-slider .cell > .bg-layer-wrap > .color-overlay.mk-amenities__scrim-black {
  background-color: var(--mk-scrim-black-20);      /* fills[2] #000000 @20% — topmost */
}

/* ---------------------------------------------------------------------------
   3 · PER-SLIDE CONTENT WELL
   The cell is the 1280 x 900 frame; `.inner` is Figma's "Text" frame
   (padding 48/120/48/120, itemSpacing 24, counterAxis CENTER) and the stack is
   Frame 1846 (860 x 750, VERTICAL, justify CENTER, align CENTER, gap 24).
   `--mk-page-x` is a FIXED 120 at both 1280 and 1440 (grid.css DERIVATION 1),
   so the horizontal inset is the page's, not Salient's min(8%, 100px).
   ------------------------------------------------------------------------ */

.mk-amenities .nectar-flickity.nectar-simple-slider .flickity-slider .cell {
  padding: 0 var(--mk-page-x);
  align-items: stretch;                            /* `.inner` fills the 900 and does its own layout */
}

.mk-amenities .nectar-simple-slider .cell > .inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;                       /* primaryAxisAlignItems: MAX */
  padding-top: var(--mk-section-y);                /* 48 */
  padding-bottom: var(--mk-am-band-bottom);        /* 48 + 30 + 24 = 102 */
}

/* Frame 1846. `.mk-measure-860` (grid.css) supplies the width — a FIXED 860, not
   a 10-of-12 column span; the span reading breaks at 1440, where 10/12 would be
   993.33 and Figma still says 860. */
.mk-amenities__stack {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--mk-space-24);
}

/* SALIENT TRAP, measured not guessed (CONVENTIONS §8.6). skin-material.q-2c163bc272.css
   ships `p{padding-bottom:var(--nectar-paragraph-bottom-spacing,1.5em)}`, which
   resolved to 24px under the 16px overline and 54px under the 36px headline and
   made the stack 449.19 tall instead of 371.20 — the whole copy block sat 39px
   low. Figma has no paragraph spacing here: the 24px rhythm is the parent's
   itemSpacing. Both the padding and the <p>/<h2> margin are zeroed. */
.mk-amenities__stack > * { margin: 0; padding: 0; }

/* ---------------------------------------------------------------------------
   4 · A08 · THE OVERLINE TRAVELS WITH ITS SLIDE, AND THE STACK ANIMATES IN
   ---------------------------------------------------------------------------
   Founder A08, verbatim: *"So much more than a safe stay": the heading must MOVE
   WITH the slider text, not persist fixed. Slider text AND the 5-star review
   bubble must animate in (up + fade).*

   WHAT WAS HERE BEFORE. `.mk-amenities__chrome` — an absolutely positioned layer
   inset to the 750px band, holding ONE overline over `.flickity-viewport` for
   both slides — plus `.mk-amenities__overline-slot`, an empty 24px spacer inside
   each cell reserving the space the fixed copy occupied. Both are deleted. The
   overline is authored in flow inside each `.mk-amenities__stack` and therefore
   travels with the track.

   THE GEOMETRY DID NOT MOVE, AND THAT WAS THE ONE THING TO CHECK. The chrome
   layer derived its offset from `--mk-am-group-h`, which is the SAME number the
   flow stack centres against — at Figma's exact 900px section:
       48 + (750 - 372)/2 = 48 + 189 = 237     [flow — what ships now]
       48 + 375 - 186     = 237                [chrome — what shipped before]
   The spacer's height was `--mk-lh-node` (24) and the overline's own line box is
   `--mk-lh-node` (24), so the 24 + 24 + 260 + 24 + 40 = 372 group is untouched.

   PROVEN AS AN A/B IN ONE PAGE LOAD, not by trusting that arithmetic and not by
   diffing two screenshots (the two capture runs were at different absolute
   scroll positions because concurrent lanes had grown the page, and the section
   photograph sampled differently between them — a real difference that has
   nothing to do with this change and would have muddied a pixel diff).
   `review/r3-amenities/steps-ab.json` injects the OLD rules, swaps each cell's
   overline back to an empty slot, appends the chrome layer, and re-reads the
   geometry in the same document:
       overline top   193.50   ->   193.50     delta 0.00
       headline top   241.50   ->   241.50     delta 0.00
       pill top       525.50   ->   525.50     delta 0.00
       ink centre x   640.00   ->   640.00     delta 0.00
   (813px capture viewport, so the band is 813 - 48 - 102 = 663 and
   48 + (663 - 372)/2 = 193.5. The absolutes track the viewport; the DELTA is
   the claim, and it is zero.)
   AND AT THE CANONICAL VIEWPORT IT LANDS ON THE ARTBOARD EXACTLY. Re-measured
   with the layout viewport PINNED to 1280 x 900 via
   `Emulation.setDeviceMetricsOverride` (the `--window-size` flag gives 813, not
   900 — see REQ-FIDELITY-TABLE-04):
       overline top 237 · headline top 285 · pill top 569 · ink centre x 640.00
   which is Figma 2931:585 / 2931:567 / 2931:594, to the pixel.

   `.mk-eyebrow` (tokens.css) already carries Poppins Light 16/24, 3px tracking
   and text-transform:uppercase (textCase is not serialised by the MCP; ALL-CAPS
   was recovered from the render).
   The 3px compensation, and why `.mk-eyebrow--centred` is NOT used here: Figma's
   347 hug is ink + side bearings, with NO trailing letter-space in it. CSS always
   adds the trailing 3px, so a plain centred line lands at 638.45 and the
   fit-content + auto-margins recipe has the same 1.5px error. One tracking unit
   of left padding shifts the line-box centre to 641.5 and the INK centre back to
   640.00. (This also drops the retired 14's pinned `width: 347px`, which was an
   EN-only literal — ES 4080:341 hugs at 408.)
   ------------------------------------------------------------------------ */
.mk-amenities__overline {
  flex: 0 0 auto;
  margin: 0;
  padding: 0 0 0 var(--mk-track-eyebrow);
  text-align: center;
  color: var(--mk-ink-inverse);
}

/* --- the reveal ------------------------------------------------------------
   THE TRIGGER IS FLICKITY'S OWN `.is-selected`, NOT AN OBSERVER AND NOT A
   SCROLL HANDLER. Three reasons, in the order they decided it:

   1. IT HAS TO RE-FIRE. `js/myk-motion.js` (lane `r3:motion-vocab`) implements
      the page-wide up+fade with a one-shot IntersectionObserver, which is right
      for a section that arrives once — and its own §5 note reasons about this
      very carousel ("a carousel cell … is exactly the behaviour founder item
      A08 asks for"). But one-shot means slide 2 animates the first time it is
      ever un-clipped and is inert on every later visit. In a two-slide deck the
      reader will go back and forward repeatedly; a reveal that only works once
      is a reveal that is broken most of the time. `.is-selected` is written by
      Flickity on every `change`, so this re-fires by construction. The stack
      carries `data-mv-skip` — that lane's own documented escape hatch — so the
      two systems never both write `opacity`/`translate` on one element.

   2. IT CANNOT SEIZE THE WHEEL. REQ-SCROLL-01. There is no listener here at
      all: it is two class-keyed CSS rules. Nothing to make passive, nothing to
      preventDefault.

   3. IT IS INVISIBLE TO A COLD RENDER AND TO THE FIDELITY HARNESS. The hidden
      start state is gated on `.flickity-enabled`, which Flickity adds at init.
      With JS off — or before Salient's `salientlazyscript` init.js is promoted —
      no rule matches and the stack paints at full opacity, exactly as it does
      today. This is the trap `sections/16-amenities-52.html` documents for
      Salient's own `fade-in-from-bottom` (it paints `opacity: 0` and is only
      cleared by init.js, so a cold parity screenshot comes back blank). Not
      repeated here.

   TRAVEL IS 24px, matching `--mk-space-24`, the itemSpacing this stack is
   already built on — the same distance the type is already spaced by, so the
   entrance reads as the layout settling rather than as a separate effect.

   THE STAGGER RUNS OVERLINE -> HEADLINE -> PILL, top to bottom,
   `--mk-am-reveal-step` apart (220ms as of R9-04/R9-05 — see the boxed
   callout at the nth-child rules below for the founder ask and the live
   measurement behind the retune). It launched at 90ms, not invented: that
   was `data-animation-stagger="90"`, the value Salient's own post grid
   ships and that `sections/16-amenities-52.html` keeps verbatim two
   sections later. Kept as a single token on this page either way, so the
   two nth-child delays can never drift apart from each other.

   THE EASE is still `--myk-flip-ease` where it exists — the
   cubic-bezier(.25,1,.33,1) that css/myk-btn.css §8 establishes as this
   page's ONE hover/entrance curve, lifted from portfolio-layered. The fallback
   literal means this file does not depend on that lane having landed.

   THE CLOCK, as of R11-04, is this section's OWN `--mk-am-reveal-dur`
   (declared above, 1.5s), NOT the shared `--myk-flip-dur` §4 read through
   R9-04/R10-CARRY. See the boxed callout immediately below for the founder
   ask, the live measurement that motivated the split, and why sharing the
   global clock was no longer safe once this item asked to slow ONLY this
   section.
   ------------------------------------------------------------------------ */
.mk-amenities .nectar-flickity.flickity-enabled .cell .mk-amenities__reveal {
  opacity: 0;
  transform: translateY(24px);
  transition:
    opacity   var(--mk-am-reveal-dur, 1.5s) var(--myk-flip-ease, cubic-bezier(.25, 1, .33, 1)),
    transform var(--mk-am-reveal-dur, 1.5s) var(--myk-flip-ease, cubic-bezier(.25, 1, .33, 1));
  will-change: opacity, transform;
}

/* ┌─────────────────────────────────────────────────────────────────────┐
   │  R11-04 — RETUNED, DURATION ONLY. .55s (--myk-flip-dur) -> 1.5s       │
   │  (--mk-am-reveal-dur, section-local). Her ask, verbatim, both passes │
   │  of round 11: "the overline is already there by the time I get to   │
   │  the card... too fast, I can't actually see the animation." Order   │
   │  is R9-04/R9-05's and is UNTOUCHED here — 0 / --mk-am-reveal-step /  │
   │  --mk-am-reveal-step*2 stays exactly 0/220/440ms; this item only     │
   │  moves how long each element's own opacity/transform takes once it  │
   │  starts.                                                             │
   │                                                                       │
   │  MEASURED FIRST, NOT ASSUMED (review/r11-estate-slider-speed/        │
   │  verify-report-baseline.json, rAF-sampled live opacity, all 5        │
   │  widths, BEFORE this edit): under the OLD .55s nominal duration, the │
   │  actual time from first visible move to 99%-settled was a consistent│
   │  ~348-351ms at every width — not the nominal 550ms. cubic-bezier     │
   │  (.25,1,.33,1) is front-loaded enough that it reads as "done" well   │
   │  before the transition's own declared duration elapses (it crosses  │
   │  50% opacity in just ~73-76ms). That is HER bug, precisely: a       │
   │  550ms transition that is perceptually over in ~350ms, with the     │
   │  first half of its motion packed into the first ~75ms. Because a    │
   │  cubic-bezier's shape is normalized to [0,1] and CSS maps elapsed   │
   │  time to that normalized domain via elapsed/duration, the FRACTION  │
   │  of the duration at which any opacity threshold is crossed is a     │
   │  property of the curve alone — scaling the nominal duration scales  │
   │  every crossing time by the same factor, it does not change which   │
   │  fraction they land at. 1.5s is a ~2.7x nominal increase (.55s ->   │
   │  1.5s), chosen to land the measured 99%-settle time in the          │
   │  ~900-950ms range (up from ~350ms) — clearly, not marginally,       │
   │  slower — while keeping the three-element cascade's total time      │
   │  (440ms max delay + ~950ms duration ≈ 1.39s) inside a single         │
   │  breath, not a multi-second wait. THE EASE (--myk-flip-ease) is      │
   │  UNCHANGED — this item was about duration, not curve shape, and a   │
   │  new curve was not asked for.                                       │
   │                                                                       │
   │  SPLIT FROM `--myk-flip-dur` ON PURPOSE. That token is shared        │
   │  :root-scope (css/myk-btn.css §8/§9) and also clocks the header      │
   │  search-icon hover-flip rotation — slowing it globally would have    │
   │  slowed every button hover-flip on the page along with this         │
   │  section's reveal, which nobody asked for and which this file's own │
   │  ONE-WRITER-PER-ARTIFACT scope (css/myk-btn.css belongs to a         │
   │  different lane) does not license touching. `--mk-am-reveal-dur` is │
   │  declared once, section-local (§1 above), read here with the SAME   │
   │  literal as its fallback so deleting the declaration degrades to    │
   │  the new 1.5s rather than silently reverting to the old .55s.        │
   │                                                                       │
   │  RE-MEASURED post-change, same method, all five required widths:     │
   │  review/r11-estate-slider-speed/verify-report-afterfix.json —        │
   │  duration_ms lands 949-959ms (vs 348-351ms baseline, ~2.72x slower,  │
   │  matching the 1.5/.55=2.727 token ratio, as the elapsed/duration     │
   │  reasoning above predicts), gap_half_1_2/2_3 land 216-218ms (R9-04/  │
   │  05's 220ms nominal stagger UNDISTURBED — tighter than the 216-225ms │
   │  baseline spread, not wider), premature_paint_count and blink_count  │
   │  both 0 at every width (R10-CARRY's blink fix UNDISTURBED) — see the │
   │  VERIFY section of founder-trace/helix/R11-04.md for the full table. │
   └─────────────────────────────────────────────────────────────────────┘ */

.mk-amenities .nectar-flickity.flickity-enabled .cell.is-selected .mk-amenities__reveal {
  opacity: 1;
  transform: none;
}

/* THE STAGGER IS ON THE ENTRANCE ONLY — the delays hang off `.is-selected`, not
   off the base rule. Put them on the base rule and the LEAVING slide also exits
   in sequence, which reads as the outgoing text lagging behind its own slide.
   Out: all three at once. In: 0 / --mk-am-reveal-step / --mk-am-reveal-step*2.

   Slide 1's `.mk-amenities__pill` is a Salient column whose PAINT surface is
   `.vc_column-inner`; the outer element is the one this reveal moves, which is
   why the reveal class sits on the column and not on the inner. Stated because
   the two are easy to swap and the inner also carries a transition (§5).

   ┌───────────────────────────────────────────────────────────────────────┐
   │  R9-04/R9-05 — RETUNED, 90/180ms -> 220/440ms (founder round 9).      │
   │  Her ask, verbatim: "the so much than a safe day text, then the       │
   │  perfect or couples are solo guests... would kinda animate in         │
   │  sequentially instead of all at once... one two three animate in      │
   │  would feel really nice." Order is already hers: (1) overline "So     │
   │  much more than a safe stay", (2) headline "Vista Pacifico stands     │
   │  among...", (3) the stat pill — nth-child(1/2/3) below, top to bottom │
   │  in the stack, matches without reordering anything.                   │
   │                                                                       │
   │  MEASURED FIRST, NOT ASSUMED (review/r9-estate-slider/baseline-       │
   │  rvf.json, rAF-sampled live opacity, 1750x980): under the OLD 90/180  │
   │  delays the half-opacity crossing of each element landed at +91ms /   │
   │  +83ms relative to the one before it — i.e. the perceptual gap        │
   │  already equalled the nominal CSS delay almost exactly (a fixed       │
   │  cubic-bezier delay time-shifts a curve; it does not compress the     │
   │  gap between two copies of the same curve). So 90ms read as "all at   │
   │  once" NOT because the easing ate the gap, but because 90ms on a      │
   │  550ms duration is genuinely too tight for three short text blocks    │
   │  to register as three separate beats — confirmed by the sibling       │
   │  R9-02/10a finding that 07-building's near-identical 120ms-on-600ms   │
   │  card stagger drew the SAME "too fast / not sequential" feedback in   │
   │  this exact round, even though 120/600 (20%) is proportionally close  │
   │  to this page's own praised hero cadence (00-hero.css: 120ms step on  │
   │  700ms duration, ~17%). The hero's ratio is calibrated for a single   │
   │  above-fold sequence the eye is already fixed on; a mid-scroll        │
   │  in-viewport reveal needs a wider absolute gap to read as sequential. │
   │  Landed on 220ms/step (~40% of the 550ms duration) — under the full   │
   │  duration, so it still reads as one cascade settling rather than      │
   │  three disconnected pops, but wide enough that el[2]'s pill does not  │
   │  start moving until el[1]'s headline is most of the way through its   │
   │  own motion. RE-MEASURED post-change, same method, all five required  │
   │  widths: review/r9-estate-slider/retuned-rvf.json — gaps land at      │
   │  ~220ms / ~220ms everywhere, confirming the timeshift-preserves-gap   │
   │  reasoning above rather than re-deriving it per width.                │
   └───────────────────────────────────────────────────────────────────────┘ */
.mk-amenities .nectar-flickity.flickity-enabled .cell.is-selected .mk-amenities__reveal:nth-child(2) { transition-delay: var(--mk-am-reveal-step); }
.mk-amenities .nectar-flickity.flickity-enabled .cell.is-selected .mk-amenities__reveal:nth-child(3) { transition-delay: calc(var(--mk-am-reveal-step) * 2); }

/* GUARD A — reduced motion. The hidden start state is REMOVED rather than
   instant-transitioned: an entrance the reader has asked not to see should not
   exist, and a 1ms transition still leaves a frame at `opacity: 0`. */
@media (prefers-reduced-motion: reduce) {
  .mk-amenities .nectar-flickity.flickity-enabled .cell .mk-amenities__reveal {
    opacity: 1;
    transform: none;
    transition: none;
    will-change: auto;
  }
}

/* ---------------------------------------------------------------------------
   4b · R8-10 — THE SCROLL-DRIVEN VARIANT (live default). Read the R8-09/R8-10
   block at the top of this file first — it carries the crossover measurement,
   the rollback instructions and the reason this does not stagger yet.

   GATE. Everything below requires `.mk-amenities--motion-scroll` on the
   `<section>` (the one class the rollback removes) AND
   `(prefers-reduced-motion: no-preference)` — the positive form, not `not
   (prefers-reduced-motion: reduce)`, so this degrades on a browser that
   understands neither: no match, GUARD A above still governs, motion still
   defaults to safe. Reduced motion therefore ALWAYS gets §4's flat
   opacity:1/transform:none, never this file's continuous version of it,
   regardless of which class is on the section.

   SPECIFICITY, on purpose. `.mk-amenities.mk-amenities--motion-scroll
   .nectar-flickity.flickity-enabled .cell .mk-amenities__reveal` carries SIX
   classes — the same six as §4's `.cell.is-selected` rule just above, which
   is exactly why this beats it: equal specificity resolves by SOURCE ORDER,
   this block is physically later in the file, so it wins whether or not
   `.is-selected` is present. It does not need to fight `.is-selected` at all
   — the two per-cell windows below already make the non-selected cell's own
   `--mk-am-lp` sit at 0 or 1 (fully faded) outside its own slide's turn. */
@media (prefers-reduced-motion: no-preference) {

  /* PER-CELL LOCAL PROGRESS. `--myk-hold-p` (written every scroll frame by
     the document-wide reader in sections/04-ecology.html, generic over any
     `[data-myk-hold]` section) sweeps 0..1 across this section's WHOLE
     2,160px hold. Each cell only owns a slice of that: slide 1 until the
     measured crossover, slide 2 after it. Re-mapping each slice to its own
     0..1 local range is what lets both cells share one opacity/transform
     formula below instead of two.

     `0.58` / `0.63` are not the same number and that gap is deliberate slack
     around the measured 0.627–0.630 crossover (review/r8-estate-slider/
     hold-walk.json): slide 1's local progress reaches 1 (fully faded out) at
     global 0.58, slide 2's starts rising only from global 0.63 — a ~0.05
     dead zone spanning the actual slide change, so neither cell's text is
     mid-motion the instant Flickity swaps which cell is laid out on screen.

     Fallback `0.3` on `--myk-hold-p` is FAIL-OPEN, not a resting value: it
     only engages if `sections/04-ecology.html`'s reader never ran at all (the
     property would then be truly unset, not merely zero). At a global 0.3,
     slide 1's local progress sits inside its own plateau (opaque, at rest) —
     the safe direction to fail is visible text, matching this page's
     standing rule that nothing is ever hidden waiting on JavaScript that
     might not run. */
  .mk-amenities--motion-scroll [data-mk-node="2931:565"] {
    --mk-am-lp: clamp(0, calc(var(--myk-hold-p, 0.3) / 0.58), 1);
  }
  .mk-amenities--motion-scroll [data-mk-node="2956:1276"] {
    --mk-am-lp: clamp(0, calc((var(--myk-hold-p, 0.3) - 0.63) / 0.37), 1);
  }

  /* THE SHAPE. 20/60/20 — fade in over the first fifth of the cell's own
     local range, hold at full opacity for the middle three fifths, fade out
     over the last fifth. Same piecewise `clamp(min(...))` construction
     sections/02-who-why-b.css §11 uses for the black-dress plateau
     (`--myk-sb-p`), simplified to a symmetric split because this section's
     two windows are already asymmetric in WIDTH (0.58 vs 0.37 of the total
     hold) — giving them different in/out fractions on top of that would be a
     second axis of tuning this pass does not need.

     TRAVEL is this section's own already-established 24px (`--mk-space-24`,
     the value §4's one-shot entrance already uses), not black-dress's 120px —
     that number was tuned for a full-bleed single text block on its own
     section-height clock; this is a shorter local range and matches its
     neighbour, not a different reference. `transform`, not `translate`,
     because `.mk-amenities__reveal` carries no other transform to collide
     with — see §4 above, which already made the same choice. Passes through
     0px (rest) at local progress 0.5, the centre of the plateau, and
     continues past it to −24px by the time it is fully faded out — a
     continued upward drift on exit, not a return to the entrance position,
     matching R8-12's "fade up and move, and then move up and fade out". */
  .mk-amenities.mk-amenities--motion-scroll .nectar-flickity.flickity-enabled .cell .mk-amenities__reveal {
    opacity: clamp(0, min(calc(var(--mk-am-lp, 0) / 0.2),
                          calc((1 - var(--mk-am-lp, 0)) / 0.2)), 1);
    transform: translateY(calc(24px - 48px * var(--mk-am-lp, 0)));
    /* NONE, deliberately. This is read once per animation frame off a value
       the passive scroll reader already coalesces to one write per frame —
       adding a CSS transition on top would make the text lag the scroll
       gesture instead of tracking it, which is the "janky" complaint
       REQ-SCROLL-01 exists to keep out of this build. */
    transition: none;
    will-change: opacity, transform;
  }

  /* §4's stagger (transition-delay on nth-child 2/3) is transition-only and
     therefore already inert here — there is no transition for a delay to
     apply to. Not overridden because there is nothing to override. */
}

/* ---------------------------------------------------------------------------
   5 · TYPE + PILLS
   ------------------------------------------------------------------------ */

/* 2931:567 / 2956:1280 — Merriweather Regular 400, 36 / 179.99999523162842%
   (= 64.8px), centred, #ffffff, DROP_SHADOW #00000080 offset (0,4) radius 14.
   Figma radius = 2 sigma and CSS text-shadow blur-radius = 2 sigma, so 14 maps
   1:1 — confirmed by the SVG's own <feOffset dy="4"/><feGaussianBlur
   stdDeviation="7"/>.
   min-height, not height: Figma ceil()s the text box (4 x 64.8 = 259.2 -> 260)
   and CSS keeps 259.19; the 0.81 shortfall splits when the stack centres, putting
   the overline slot at 237.41 and the pill at 568.59 instead of 237 / 569.
   Restoring the ceil as a FLOOR lands all three boxes exactly and still lets the
   block grow if the copy does. It is a line-count-derived literal, so it is
   EN-only: the ES slide-2 body runs five lines and its box is 325.
   Both slides carry the identical role, so there is one rule for both.
   (0,2,0) is required to beat tokens.css's `.mk-page :is(h1,h2,h3,.mk-serif)`,
   which `:is()` makes (0,2,0) — a single-class override loses to it no matter
   which sheet loads last. Measured: with one class the computed font-size stayed
   36px at 1024 and 640 too, silently ignoring the responsive ladder in §7. */
.mk-amenities .mk-amenities__headline {
  width: 100%;
  min-height: var(--mk-am-headline-h);             /* 260 */
  margin: 0;
  font-family: var(--mk-font-serif);
  font-weight: var(--mk-w-regular);
  font-size: var(--mk-size-h2);                    /* 36 */
  line-height: var(--mk-lh-h2);                    /* 64.8 */
  text-align: center;
  color: var(--mk-ink-inverse);
  text-shadow: 0 4px 14px var(--mk-shadow-50);
}

/* OPTICAL SIZE. tokens.css now publishes `font-optical-sizing: auto` +
   `"wdth" 100` on `.mk-page :is(h1,h2,h3,.mk-serif)`, which is the value this
   node measured to; the local release both retired files carried is therefore
   redundant and is NOT repeated. Kept as a note because it is the reason the
   headline is 2.4 % narrower than a naive build: at the old `opsz 18` pin every
   line rendered ~3 % wide against Figma's exact vector ink —
       line 1  figma 782.5  chrome 801.5  ratio 1.0243
       line 2  figma 807.5  chrome 826.5  ratio 1.0235
       line 3  figma 787.5  chrome 807.0  ratio 1.0248
       line 4  figma 168.5  chrome 172.5  ratio 1.0237
   — and opsz = font-size (what `auto` does) fits to a 0.3px residual on an 800px
   line. If tokens.css ever re-pins opsz, this section regresses; that is the
   coupling, stated rather than re-guarded. */

/* --- slide 1 · the LIFTED tether rating pill · 2931:594 "btns" -----------
   Pill box: 480 -> 800 x 569 -> 609. 18 + 32 + 8 + 90 + 8 + 146 + 18 = 320.

   SALIENT OVERRIDE, per CONVENTIONS §8.6 — naming the rule that forced it.
   `.wpb_column:not([class*=vc_col-xs]){width:100%;margin-bottom:25px}` in
   vendor/…/grid-system.q-dcb972ee3c.css is (0,2,0); a bare `.mk-amenities__pill`
   (0,1,0) loses to it. `.mk-amenities .mk-amenities__pill` ties at (0,2,0) and
   this sheet loads after vendor, so it wins. Figma's pill HUGS its content
   (320 EN / 393 ES); 100% would make it 860. */
.mk-amenities .mk-amenities__pill {
  width: fit-content;
  max-width: 100%;
  margin-bottom: 0;                                /* kills the same rule's 25px */
}

/* The paint surface is `.vc_column-inner`, exactly as in tether, where the radius
   and border sit on it rather than on the column. Salient already gives it
   `position: relative` (`.vc_column_container>.vc_column-inner` in
   style.q-98889c766d.css), which is what makes the lifted `.column-link`
   full-cover anchor work with no CSS of ours.
   >>> CORRECTION <<< NO BORDER. The payload reports strokes[0] `#ffffff` @15%,
   1px, CENTER on BOTH pills, and tokens.css publishes it as --mk-pill-hairline.
   It does not render, twice proven on each frame:
     (I)  Figma's SVG export draws them as
          `<rect x="480" y="569" width="320" height="40" rx="20" fill="black"
           fill-opacity="0.5"/>`   (slide 1)
          `<rect x="492" y="569" width="296" height="40" rx="20" …/>` (slide 2)
          — no stroke attribute at all, while the same exporter happily emits
          `stroke=` on both indicator <line>s.
     (II) a vertical probe of the @2x render across the pill's FLAT top edge at
          x = 534 (between the score and the star run, no glyphs, no corner
          curvature) reads
              y 568.5 -> (122,103,89)   ground
              y 569.0 -> ( 58, 49, 41)  pill fill
          in a single 0.5px step. A 1px white@15% centre-aligned stroke would have
          put ~(114,…) on the 568.5-569.5 band. It is not there. The curved part
          checks out too: at x = 490 the step is at y 571.5, and the r=20 corner
          circle centred (500,589) predicts 589 - sqrt(400-100) = 571.68.
   CONVENTIONS §8.1 — build from the render, not the payload.
   Radius 54 on a 40px box clamps to a stadium; Figma's own export writes rx=20,
   the same shape. --mk-radius-pill keeps it in the page's vocabulary. */
.mk-amenities .mk-amenities__pill > .vc_column-inner {
  padding: var(--mk-pill-pad-y) var(--mk-pill-pad-x);   /* 8 / 18 — 2931:594 */
  border: 0;
  border-radius: var(--mk-radius-pill);                 /* cornerRadius 54 */
  background: var(--mk-pill-scrim-fill);                /* fills[0] #000000 @50% */
  -webkit-backdrop-filter: var(--mk-amenities-blur);
  backdrop-filter: var(--mk-amenities-blur);            /* BACKGROUND_BLUR 4 -> 2px, see §2 */
  /* Hover / focus. RECOMMENDED, NOT EXTRACTED: the served tether page inlines all
     its CSS and contains no hover or transition rule for `.column-link` or for
     the rating pill, so there is nothing to lift. Reversible, and it uses the
     page's own hover tokens rather than a new number. */
  transition:
    background-color var(--mk-motion-dur-hover) var(--mk-ease-hover),
    box-shadow       var(--mk-motion-dur-hover) var(--mk-ease-hover);
}
.mk-amenities .mk-amenities__pill:hover > .vc_column-inner {
  background: rgba(0, 0, 0, 0.6);                  /* proposal — not a Figma value */
}
.mk-amenities .mk-amenities__pill:focus-within > .vc_column-inner {
  outline: 2px solid var(--mk-ink-inverse);
  outline-offset: 3px;
}

/* The flex row itself is Salient's (PART 1b). Only the gap is retargeted:
   itemSpacing 8 on 2931:594, against tether's 10. The child margin reset kills
   `.wpb_wrapper>div{margin-bottom:24px}` from style.q-98889c766d.css, which would
   otherwise push 24px of air under all three cells. */
.mk-amenities .mk-amenities__pill > .vc_column-inner > .wpb_wrapper { gap: 8px; }
.mk-amenities .mk-amenities__pill > .vc_column-inner > .wpb_wrapper > * { margin: 0; }

/* Both text cells: Poppins 16 in a 24px line box, +1px tracking, #ffffff.
   The 24px line box is what makes the pill 8 + 24 + 8 = 40 tall. */
.mk-amenities__score p,
.mk-amenities__reviews p {
  margin: 0;
  padding-bottom: 0;                               /* same Salient <p> rule as the overline */
  font-family: var(--mk-font-sans);
  font-size: var(--mk-size-base);                  /* 16 */
  line-height: var(--mk-lh-node);                  /* 24 */
  letter-spacing: var(--mk-track-nav);             /* 1px — 2931:595 / 2931:597 */
  text-align: center;
  color: var(--mk-ink-inverse);
}

/* 2931:595 — Poppins MEDIUM. The `characters` value is "5/5 " WITH a trailing
   space and the node hugs at 32 x 24. The space is kept verbatim in the markup
   and deliberately left to HTML's normal collapsing — NOT held open with
   `white-space: pre`. Measured, headless: with the space rendering the cell is a
   36.84px box, which made the pill 325.53 instead of 320 and shifted the star run
   and the reviews text 4.8px right. Collapsed, the cell is ~31.7px and the pill
   lands at ~320.4 against Figma's 320. */
.mk-amenities__score p   { font-weight: var(--mk-w-medium); }   /* 500 */
/* 2931:597 — Poppins LIGHT, and NOT uppercased. */
.mk-amenities__reviews p { font-weight: var(--mk-w-light); }    /* 300 */

/* 2931:625 "Group 1846" — the star run. 90 x 18, five 18px boxes, zero gap.
   `display:block` on the SVG removes the inline baseline gap so the box is
   exactly 18 tall; centred in the row's 24px line box that puts the run at
   577 + 3 = 580, which is Figma's measured y.
   line-height is reset because PART 1b's `.nectar-star-rating *{line-height:1.3}`
   would otherwise make the wrapper 20.8px tall. Same specificity (0,1,0), and
   this rule is later in the same sheet. */
.mk-amenities__stars     { display: block; line-height: 0; color: var(--mk-ink-inverse); }
.mk-amenities__stars svg { display: block; }

/* --- slide 2 · the spec pill · 2956:1281 / 2956:1282 ---------------------
   Same shell, different content: 296 x 40 at x 492. Poppins Medium 16/24, 1px
   tracking, centred. The negative right margin cancels the trailing letter-space
   CSS adds after the last glyph — without it the hug width is 297 instead of 296
   and the ink sits 0.5px left. */
.mk-amenities__spec-pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: var(--mk-pill-pad-y) var(--mk-pill-pad-x);   /* 8 / 18 -> 8+24+8 = 40 tall */
  border-radius: var(--mk-radius-pill);                /* authored 54; clamps to the rx="20" the SVG exports */
  background-color: var(--mk-pill-scrim-fill);         /* #000 @50% */
  -webkit-backdrop-filter: var(--mk-amenities-blur);
  backdrop-filter: var(--mk-amenities-blur);
  /* No `border` — see the CORRECTION above; it applies to this pill too. Adding
     it lifts the pill edge from ~22 to ~57 in the 0..255 luma probe and is
     visible at 1x. */
}
.mk-amenities__spec-pill-text {
  font-family: var(--mk-font-sans);
  font-weight: var(--mk-w-medium);                 /* 500 */
  font-size: var(--mk-size-base);                  /* 16 */
  line-height: var(--mk-lh-node);                  /* 24 */
  letter-spacing: var(--mk-track-nav);             /* 1 */
  color: var(--mk-ink-inverse);
  margin-right: calc(var(--mk-track-nav) * -1);
  white-space: nowrap;
}
/* The two `|` separators are PURE BLACK on a 50%-black pill. `fills` reads
   "mixed" and no read path exposes the segments, but Figma's SVG export settles
   it: the separators are a single `<path … fill="black"/>` (two 1.824px-wide
   rects at x 597.555 and 707.539) while every word glyph is `fill="white"`.
   DESIGN FLAG, not a bug to fix silently: slide 1 uses the same pill shell with
   an all-white run and no separators, so this is probably an authoring slip in
   the comp. Reproduced as drawn; raised for the founder. */
.mk-amenities__sep { color: var(--mk-ink-strong); }

/* ---------------------------------------------------------------------------
   6 · THE INDICATOR — 2931:568 / 2956:1300 "slector"
   57 x 30 at (611.5, 822); ink bottom-aligned.
   >>> CORRECTION <<< to the specs' stroke-inflation note, which gives the ink as
   y 850..854. Both instruments say 848..852:
     (I)  the SVG export writes
          `<line x1="613.5" y1="850" x2="645.5" y2="850" stroke="white"
           stroke-width="4" stroke-linecap="round"/>` — the geometric path is 32
          long and the round caps extend it to the node's reported 36 width, and a
          4px stroke centred on y=850 inks 848..852. The inactive bar is
          `<line x1="664.5" … x2="666.5" … stroke-opacity="0.5"/>` -> 662.5..668.5.
     (II) a column probe at x = 630 of the @2x render reads pure (255,255,255)
          from y 848.0 through y 851.5 inclusive and background either side.
          A row probe at y = 850 finds two ink runs, 611.5 -> 647.5 and
          662.5 -> 668.5: 36 wide, 15 gap, 6 wide, total 57. Exact.

   Salient -> Figma delta table, re-measured:
     bar height        4px            4px           keep (base flickity rule)
     bar colour        #333           #ffffff       written
     inactive opacity  .25            .5            written
     active opacity    1              1             keep (base `.dot.is-selected`)
     bar width         30 both        36 / 6        written
     gap               margin 0 5px   15px          written as margin 0 7.5px
     caps              square         radius 2px    written (strokeCap ROUND on 4px)
     position          bottom:-60px   ink 848..852  written as bottom:48px
     transition        .1s linear     unspecified   keep Salient's
   Arithmetic check against the measured ink:
     7.5 + 36 + 7.5  +  7.5 + 6 + 7.5 = 72 wide, centred at 640 -> 604..676
     dot 1 content 604+7.5 = 611.5 .. 647.5   dot 2  655+7.5 = 662.5 .. 668.5
   `font-size:0; line-height:0` kill the inline-block baseline descender, which
   would otherwise make the holder ~5px taller than its dots and push the bars up.

   The width morph (36 <-> 6) is a Mykrobial addition — Salient's dots are equal
   width and only cross-fade — so width joins opacity on the .1s linear channel.

   TWO SELECTORS, ONE SKIN. `.mk-amenities__dots` is the authored cold-render
   copy that sits OUTSIDE the slider; `.nectar-simple-slider .flickity-page-dots`
   is the real list Flickity builds INSIDE it at init. Both are styled, and the
   `:has()` rule below retires the static one the moment the real one exists.
   ------------------------------------------------------------------------ */

.mk-amenities .nectar-simple-slider .flickity-page-dots,
.mk-amenities .mk-amenities__dots {
  position: absolute;
  left: 0;
  bottom: var(--mk-section-y);                     /* 48 -> ink 848..852 */
  width: 100%;
  height: 4px;
  margin: 0;
  padding: 0;
  list-style: none;
  text-align: center;
  line-height: 0;
  font-size: 0;
  z-index: 12;                                     /* over the chrome layer */
}
.mk-amenities .mk-amenities__dots { pointer-events: none; }

.mk-amenities .nectar-simple-slider .flickity-page-dots .dot,
.mk-amenities .mk-amenities__dots .dot {
  display: inline-block;
  position: relative;
  width: 6px;                                      /* Line 18 — 2931:571 */
  height: 4px;                                     /* strokeWeight 4 */
  margin: 0 7.5px;                                 /* itemSpacing 15 */
  padding: 0;
  opacity: .5;                                     /* stroke #ffffff @50% */
  vertical-align: top;
  transition: width .1s linear, opacity .1s linear;
}
.mk-amenities .nectar-simple-slider .flickity-page-dots .dot::before,
.mk-amenities .mk-amenities__dots .dot::before {
  content: "";                                     /* base flickity supplies it too; stated so this
                                                      rule does not depend on load order */
  display: block;
  position: absolute;
  top: 0;
  left: 0;
  height: 4px;
  width: 100%;
  border-radius: 2px;                              /* strokeCap ROUND on a 4px stroke */
  background: var(--mk-ink-inverse);
}
.mk-amenities .nectar-simple-slider .flickity-page-dots .dot.is-selected,
.mk-amenities .mk-amenities__dots .dot.is-selected {
  width: 36px;                                     /* Line 13 — 2931:569 */
  opacity: 1;
}
/* Salient's `simpleSliderStyle` appends a 65px countdown-ring <svg> into every
   `li` (it becomes an autoplay timer when `data-autoplay="true"`). This carousel
   does not autoplay — MEASURED on the reference instance,
   `Flickity.data(el).options.autoPlay === false` — and Figma draws bars, not
   rings, so the ring is suppressed rather than restyled. */
.mk-amenities .nectar-simple-slider .flickity-page-dots svg { display: none; }

/* Retire the authored copy the moment Flickity's real list exists. Scoped to
   `.nectar-flickity` so it can only ever match the generated list — the static
   `<ol>` carries `flickity-page-dots` too but lives outside the slider. */
.mk-amenities:has(.nectar-flickity .flickity-page-dots) .mk-amenities__dots { display: none; }

/* BOTH EN artboards draw slot 1 active — 5.0 and 5.1 alike — which is an artboard
   copy artefact, not a per-slide state (the ES pair draws the mirror). With the
   two frames now confirmed as ONE carousel, `.is-selected` is driven off the
   slide index by Flickity from init onward and the artboards' disagreement stops
   being a build question. The static `<ol>` still ships slot 1 active because
   that is the cold-render rest state and it is what both reference PNGs show. */


/* ============================================================================
   7 · RESPONSIVE
   The captured frames prove ONLY 1280 and 1440. Everything below is reasoned
   from the auto-layout modes and constraints the specs actually read, and it
   deliberately rides the shell's own --mk-page-x ladder in grid.css
   (1049 -> 64, 1024 -> 48, 640 -> 24) plus .mk-measure-860's collapse to 100% at
   <=1024, rather than inventing a second, conflicting ladder.

   NOTE the headline selectors carry .mk-amenities twice: the base rule is (0,2,0)
   to beat tokens.css's `.mk-page :is(h1,h2,h3,.mk-serif)`, so a single-class
   override inside a media query would silently lose to it. That is exactly what
   happened on the first pass — headless renders at 1024 and 640 both still
   reported font-size: 36px.

   `--mk-am-headline-h` is released to `auto` wherever the type changes, because
   the 260 box is a 36px-type fact. The chrome offset follows it automatically —
   that is the whole point of the token in §2.
   ========================================================================== */

/* Once the measure goes fluid the headline must come down or the cluster
   overruns Frame 1846's fixed 750 band. 36 -> 30, ratio held at 1.8.
   988 rather than grid.css's 1024: at 1024 grid.css has already released
   .mk-measure-860 to 100% and dropped --mk-page-x to 48, which gives a 928
   measure — WIDER than the authored 860 — so there is nothing for the type to do
   until 988, where the measure finally falls below 860. */
@media (max-width: 988px) {
  .mk-amenities { --mk-am-headline-h: auto; }
  .mk-amenities .mk-amenities__headline {
    font-size: 30px;
    line-height: 1.8;                              /* the authored ratio, not a new number */
    min-height: 0;
  }
  /* With the headline free to reflow, the derived chrome offset stops being
     reliable, so the overline returns to the flow it reserves a slot for. */
  .mk-amenities__chrome { display: none; }
  .mk-amenities__overline-slot { display: none; }
}

/* `primaryAxisAlignItems: CENTER` centres but does not shrink, so the fixed 750
   band has to release before the headline reflows past it. */
@media (max-width: 768px) {
  /* D27/G1 — was `height: auto; min-height: 900px`, i.e. a 900px band on a
     ~700px phone screen, which is the opposite of "fills the viewport".
     `100svh` is the small-viewport height (URL bar collapsed), so the section
     is exactly one screen with no jump when the bar hides. The `min-height`
     floor stops the centred 372px cluster from being crushed on a very short
     landscape phone; it is below every portrait phone viewport, so in practice
     `100svh` is what wins. */
  .mk-amenities { height: 100svh; min-height: 520px; }
  .mk-amenities .nectar-flickity.nectar-simple-slider:not(.flickity-enabled) .flickity-slider > .cell:not(:first-child) { display: none; }
  .mk-amenities .mk-amenities__headline { font-size: 28px; }   /* 28 / 1.8 = 50.4 */
}

/* The pill needs 320 in EN and 393 in ES, and ES is the constraining language, so
   this breakpoint is sized against 393. At 414 the available width is 334 and at
   375 it is 295 — EN overflows too. Wrap to two rows rather than change the one
   authored type size; Salient's own `.nectar-star-rating{flex-wrap:wrap}` is the
   upstream precedent, and `flex_wrap_desktop_nowrap` is by its own name a desktop
   rule, so wrapping here does not contradict the lift.
   Below both captured frames — a reasoned build-time choice, flagged for review. */
@media (max-width: 420px) {
  .mk-amenities .mk-amenities__pill > .vc_column-inner > .wpb_wrapper {
    flex-wrap: wrap;
    justify-content: center;
  }
  .mk-amenities__spec-pill-text { white-space: normal; }
}

/* The radius change is deliberately on a DIFFERENT, narrower breakpoint than the
   wrap, because 54 -> 24 is only correct once the pill is actually two rows — and
   the two conditions do not coincide. This build's gutter at <=640 is
   --mk-page-x: 24 (grid.css), so the EN pill's real wrap point is 320 + 2 x 24 =
   368, not 414. Verified in a 375-wide iframe: the pill is still one 320 x 40 row
   with 7px to spare, and an unconditional radius change there would have
   un-pilled a pill that had not wrapped. ES wraps at 393 + 48 = 441, so V2/ES
   must move BOTH numbers up. */
@media (max-width: 367px) {
  .mk-amenities .mk-amenities__pill > .vc_column-inner,
  .mk-amenities .mk-amenities__spec-pill {
    border-radius: 24px;
    text-align: center;
  }
}

/* Reduced motion: tokens.css already collapses the hover durations to 1ms and
   css/reduced-motion.css freezes transform-driven travel page-wide;
   js/mk-page-runtime.js additionally calls Flickity's own `stopPlayer()`. This
   carousel does not autoplay, so the only motion a reduced-motion user can start
   is a drag they initiated themselves — which is left working on purpose. */

/* ============================================================================
   D28 · THE MOUSE-HOVER (CURSOR-FOLLOWING) STATE — brand retarget
   Lane `fix:amenities`, 2026-08-18.
   ----------------------------------------------------------------------------
   THE FILE HEADER ABOVE SAYS "THE ONE THING THIS FILE DELIBERATELY DOES NOT
   STYLE" IS `.nectar-drag-indicator`. That was the right call on the evidence
   available at the time and it is now superseded, so read this before undoing it.

   The original reasoning was: the founder said "the component already does it,
   just grab the component", so adopting Salient's own `data-indicator-bg` /
   `data-indicator-icon` was the lift and adding CSS would fork it. Correct
   premise, missing input — the BRANDING ARTBOARD HAD NEVER BEEN OPENED. Founder
   answer Q-C in the trace is explicit: *"NO — never read it. Figma plugin now
   disconnected; this is the root cause of most hover-state failures."* So the
   build adopted the RESORT DEMO's colour (#141414, opaque) believing it was the
   design. It was not. It was the donor's.

   The artboard is now read (review/branding/media-misc.md §3.3 + §7 rule 1) and
   it defines two cursor classes, distinguished by FILL only:
       primary-action        110px, #1EB2BC,          no blur   (D09's play cursor)
       general-interactivity  96px, #000000 @ 50%, backdrop blur(4px)
   A carousel prev/next moves you through content, so it is the second one. The
   same token answers D15 and D22; D22's founder wording ("black bg, partial
   transparency, blur") is a verbatim description of it.

   WHAT IS LIFTED vs WHAT IS ALTERED — the myk-btn method, not a rewrite:
     LIFTED   `data-indicator-blur="true"` in the markup. This is SALIENT'S OWN
              blur opt-in. init.js `$t.prototype.mouseBind` does
              `e.$el.is('[data-indicator-blur="true"]') && e.$dragEl.addClass("blurred-bg")`
              and the vendored style-non-critical.q-40f8116f6d.css already ships
              `.nectar-drag-indicator.blurred-bg .color-circle{backdrop-filter:blur(12px)}`.
              The blurred cursor was in the box the whole time; nobody opened it.
     ALTERED  three numbers, and only three: 12px blur -> 4px (branding), 94px
              box -> 96px (branding), and the arrow offsets re-derived for 96.
              Fill and glyph colour are set from the markup's data-* attributes,
              not from here, so they stay on Salient's own code path.

   SPECIFICITY / CASCADE — stated, because it is load-bearing and non-obvious.
   `.nectar-drag-indicator` is a BODY-LEVEL SINGLETON that Salient appends once
   per page, so it cannot be namespaced to a section — this is a PAGE-WIDE
   surface. The `[data-type="solid"]` rules it currently gets are published
   unnamespaced by sections/07-building.css (the file header above records
   this). index.html loads 14-amenities.css AFTER 07-building.css, so the rules
   below win on cascade order at equal specificity. That is a real dependency on
   link order and it should not stay this way: a request to hoist the whole
   cursor component to css/salient-elements.css and delete both copies is filed
   in founder-trace/SHARED-REQUESTS.md. Nothing here edits 07-building.css,
   which another lane owns this run.
   ========================================================================== */

/* Branding tokens for the general-interactivity cursor, named so the hoist is a
   move rather than a rewrite. Values: media-misc.md §3.3 (render-measured at 4x)
   and §7 rule 1. */
:root {
  --myk-cursor-gi-size:  96px;                    /* was 94 (resort demo) */
  --myk-cursor-gi-blur:  4px;                     /* was 12 (Salient default) */
  /* >>> SOLVED AGAINST PIXELS, not copied across — see the GLYPH GEOMETRY
     block below for the derivation and the numbers it replaced. <<< */
  --myk-cursor-gi-glyph:   35.5px;                /* ink 11.25 x 19.50, exact  */
  --myk-cursor-gi-inset:   23.25px;               /* puts ink at -+18.12       */
  --myk-cursor-gi-glyph-y: -18.75px;              /* ink y-centred in the disc */
}

.nectar-drag-indicator[data-type="solid"] {
  width:  var(--myk-cursor-gi-size);
  height: var(--myk-cursor-gi-size);
  /* the disc is centred on the pointer, so the offsets are -size/2 */
  left: calc(var(--myk-cursor-gi-size) / -2);
  top:  calc(var(--myk-cursor-gi-size) / -2);
}

/* Salient's own `.blurred-bg` rule, retargeted from 12px to the branded 4px.
   `-webkit-` first for the same reason the vendored sheet does it. */
.nectar-drag-indicator.blurred-bg .color-circle {
  -webkit-backdrop-filter: blur(var(--myk-cursor-gi-blur));
          backdrop-filter: blur(var(--myk-cursor-gi-blur));
}

/* 07-building.css offsets `.color-circle` by `left:-2px; top:-2px` against a 94
   box — a fudge that made a 94px circle sit visually centred. With the box at
   its branded 96 the circle is already exact, so the fudge is removed rather
   than carried forward. */
.nectar-drag-indicator[data-type="solid"] .color-circle { left: 0; top: 0; }

/* ==========================================================================
   GLYPH GEOMETRY
   >>> REWRITTEN 2026-08-18 by lane `foldback:video-ecology` against
       review/branding/cursors.md §2.5, which is render-proven and which this
       block did not have when it was first written. <<<

   WHAT WAS HERE, AND WHY IT WAS WRONG — because the mistake is reusable and
   the next person will make it too.

   This block read media-misc.md §3.3's measurements —
       left  glyph bbox x 24.25 .. 35.50
       right glyph bbox x 60.50 .. 71.50
       glyph height 20
   — and wrote them straight into CSS as `left: 24.25px`, `right: 24.5px`,
   `font-size: 20px`. Those measurements are of the INK. `left`/`right` position
   an <i>'s BORDER BOX, and `font-size` sets the EM, not the ink height. An
   icomoon glyph fills neither: it sits inside its advance box with side
   bearings, and a chevron's ink is roughly 0.55em tall. So every one of the
   three numbers was applied to the wrong quantity.

   MEASURED LIVE, at 4x, inside the circle (_tools/_scratch/cursor-foldback):

       font-size 20px  ->  ink 6.50 x 11.00, centres at -19.88 / +19.75

   i.e. the chevrons rendered at 56% of the branded glyph and sat 3.4px too far
   apart. cursors.md §2.5 requires ink 11.25 x 19.50 at exactly -+18.12 from the
   disc centre, and states in as many words that this geometry does NOT scale
   with the disc — the offsets are identical at 96 and at 110 — so it can never
   be reached with `transform: scale()`.

   SOLVED, not guessed. `_tools/_scratch/cursor-foldback/calib.py` sweeps
   font-size and the two insets and measures the resulting ink from pixels:

       fs      left     right    sep      ink w    ink h    ink dy
       20.0   -19.88   +19.75   39.63     6.50     11.00    +1.25   <- shipped
       34.0   -17.38   +17.12   34.50    10.75     18.75    +1.62
       35.0   -17.12   +16.88   34.00    11.25     19.25    +2.12
       36.0   -17.00   +16.75   33.75    11.50     20.00    +1.75
       35.5   -18.12   +18.12   36.24    11.25     19.50     0.00   <- SHIPS
              (with left/right 23.25 and top -18.75)

   The winning row is exact on all six values, and its left ink box lands at
   24.25 .. 35.50 — which is media-misc §3.3's measurement CHARACTER FOR
   CHARACTER. That is the confirmation that the founders' chevron IS this
   icomoon glyph, and that the only error was applying an ink number to a box
   property.

   The two insets are now the SAME value on both sides. The old 24.25 / 24.5
   asymmetry was not a design intent: it was two independently-rounded ink
   measurements copied into two box properties. cursors.md §2.5's -+18.12 is
   symmetric, so the CSS is too.

   `top` gets its own token rather than `calc(font-size / -2)`: half the em box
   is -17.75, and the ink needs -18.75, because a chevron's ink is not centred
   in its line box. One more place where the em and the ink are different things.
   ========================================================================== */
.nectar-drag-indicator[data-type="solid"] i {
  font-size: var(--myk-cursor-gi-glyph);
  top: var(--myk-cursor-gi-glyph-y);
}
.nectar-drag-indicator[data-type="solid"] i.fa-angle-left  { left:  var(--myk-cursor-gi-inset); }
.nectar-drag-indicator[data-type="solid"] i.fa-angle-right { right: var(--myk-cursor-gi-inset); }


/* ============================================================================
   D27 · "ZOOM IN" — the outgoing plate pushes in on every advance
   ----------------------------------------------------------------------------
   Magnitude and easing are Salient's, not invented: `short_zoom` is
   `scale(1.13)` (figma-truth/09-recovery-42.spec.md §544) and the fancy-box
   rules quoted verbatim in 11-recovery-43.spec.md use
   `transition: transform 1s ease` at rest with
   `cubic-bezier(.1,.2,.7,1)` driving the zoom itself.

   WHY THE *LEAVING* CELL. The resting plate is precisely what the fidelity
   harness diffs against the Figma still. Zooming the ACTIVE slide would park it
   at scale(1.13) forever and charge this section a large, permanent pixel
   penalty for a motion the founders asked to see only in passing. Zooming the
   cell that is on its way out gives a real push-in through the whole transition
   while every slide still comes to rest at scale(1) = Figma exact.
   The class is added and removed by the script at the foot of
   sections/14-amenities.html; it is never present at rest.
   ========================================================================== */

.mk-amenities .nectar-simple-slider .cell > .bg-layer-wrap > .bg-layer {
  transform: scale(1);
  transition: transform 1s ease;                   /* Salient's own rest transition */
  will-change: transform;
}
.mk-amenities .nectar-simple-slider .cell.mk-am-leaving > .bg-layer-wrap > .bg-layer {
  transform: scale(1.13);                          /* Salient's `short_zoom` */
  transition: transform 0.64s cubic-bezier(0.1, 0.2, 0.7, 1);
}

/* ============================================================================
   R17-09 · 2026-08-28 · lane `r17:sliders`
   ----------------------------------------------------------------------------
   "Let's also do that for our left to right sliders going forward to have
   that next one fade in, and then that it persists there a little bit" —
   the same from-white image fade 09-recovery-42.css already uses (`opacity`
   only, one-shot, class-driven) and 00-hero.css's `mykHeroImg` keyframe
   (opacity 0->1, 1000ms, cubic-bezier(.4,0,.2,1)) name as the reusable
   grammar. This section had NO fade on either cell's photograph before this
   change — `.bg-layer-wrap` carried only position/sizing rules (§"1a · simple-
   slider anatomy" above); a cell was simply opaque the instant Flickity
   translated it into the viewport.

   `.mk-hold-media-in` is the SAME permanent marker sections/04-ecology.css
   uses for the identical ask on its own carousel — added once, by
   sections/04-ecology.html's shared read(), to `f.slides[want].cells[0].
   element` the first time each slide is ever selected (that file's own
   R17-09 comment). Reusing one class across both sections' stylesheets
   rather than inventing a second name for the same signal.

   OPACITY ONLY, on the WRAP (not `.bg-layer` alone), so the two stacked
   `.color-overlay` scrims (§"SLIDE 1 · Figma 2931:565" above: image + a
   #0d1d23 @40% + a #000000 @20%) fade in locked together with the
   photograph — the same reasoning sections/04-ecology.css's own §H2 gives
   for its wrap-level fade ("fading the WRAP keeps the image and its scrim
   locked together"). `transform` stays exactly as D27 above already owns
   it (`scale`, on `.bg-layer` alone) — two different properties on two
   different elements, no collision.

   PERMANENT, NEVER REMOVED, matching her own word "persists": a slide that
   has already faded in once simply holds at opacity 1 on a later re-visit
   rather than replaying — the same one-shot-then-hold discipline this
   section's D27 zoom and 04-ecology.css's own R17-09 fade both use, and it
   is what keeps the OUTGOING cell's photograph from fading to reveal this
   section's own ground through it mid-transition (not asked for here).

   THE `.mk-eco-anim` GUARD IS LOAD-BEARING, not decoration, and it is NOT
   this file reaching into ecology's naming — it is the SAME class,
   deliberately, because it is written by the SAME code: sections/
   04-ecology.html's shared reader adds `.mk-eco-anim` to EVERY `[data-myk-
   hold]` section generically (confirmed live — this section's own
   `<section>` carries it), gated on `html.mv` (JS ran AND `prefers-
   reduced-motion` is not set), exactly the fail-open contract 04-ecology.
   css's §H documents for its own identical guard. Scoping the base
   `opacity: 0` rule under it means: no JS, or reduced motion, or the
   marker never arriving for any reason -> the rule never matches at all ->
   the cell sits at its unset, fully-opaque default.

   `:not(.flickity-enabled) .cell:first-child` IS A SECOND, SEPARATE FAIL-
   OPEN, and it is not redundant with the one above — LIVE-CAUGHT while
   verifying this item (not assumed): Flickity's own construction can take
   many seconds past `html.mv` landing (`nectar-delay-javascript.js`
   promoting `init.js` and `init.js` actually calling `new Flickity(...)`
   are two separate lazy steps), and at a mobile viewport this drive
   observed it not resolve at all inside several seconds of real wait.
   `.mk-hold-media-in` can only ever be written by reading Flickity's own
   `f.slides[...]`, so on any load where Flickity is that slow the FIRST
   cell would sit at `opacity: 0` indefinitely even with `.mk-eco-anim`
   present — the exact same trap the `[data-myk-eco-allcells]` line in
   sections/04-ecology.css's own R17-09 comment fixes for that section. The
   COLD-RENDER rule immediately above this block (`:not(.flickity-enabled)
   .cell:not(:first-child){visibility:hidden}`) already establishes that,
   pre-Flickity, only `:first-child` is ever meant to be visible at all —
   so giving exactly that cell a Flickity-independent path to `opacity: 1`
   is the minimal fix, not a broader one: the SAME condition
   (`:not(.flickity-enabled)`) that hides every other cell is what reveals
   this one's photograph, and the instant Flickity does enable, `.is-
   selected`/`.mk-hold-media-in` take over exactly as they already do for
   text and every other per-slide effect on this page. This exact path
   (Flickity present but slow/never-ready) is what this drive actually hit
   live, repeatedly, at several widths — see founder-trace/helix/
   R17-sliders.md for the full account. */
.mk-eco-anim.mk-amenities .nectar-simple-slider .cell > .bg-layer-wrap {
  opacity: 0;
  transition: opacity 1000ms cubic-bezier(.4, 0, .2, 1);
}
.mk-eco-anim.mk-amenities .nectar-simple-slider .cell.mk-hold-media-in > .bg-layer-wrap,
.mk-eco-anim.mk-amenities .nectar-simple-slider:not(.flickity-enabled) .cell:first-child > .bg-layer-wrap {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  /* The script already refuses to add `.mk-am-leaving` under reduced motion;
     this is the CSS half of the same guarantee, so a stuck class cannot leave a
     plate zoomed. */
  .mk-amenities .nectar-simple-slider .cell > .bg-layer-wrap > .bg-layer,
  .mk-amenities .nectar-simple-slider .cell.mk-am-leaving > .bg-layer-wrap > .bg-layer {
    transform: none !important;
    transition: none !important;
  }
}

/* ======================================================================
   REQ-HOLD-1 — restore the founder-praised gallery immersion.

   Jehnean on 2026-08-19: "I like how you snapped the so much more than a
   safe stay image. That's a really nice one. It's really full screen. I
   feel immersed." That feeling was produced by 04-ecology's document-wide
   wheel grab, which was correctly DELETED — the founders also reported it
   as "too snappy... it grabs my screen" (C01). Removing the grab removed
   half of what made this section feel immersive.

   This restores the dwell WITHOUT capturing input, which is the whole
   point: zero of the five Salient donors install a wheel listener or
   scroll-snap-type. Sticky positioning plus generous scroll travel gives
   smooth-in / hold / smooth-out (C03) while the wheel stays the reader's.

   data-myk-hold="1.4" => ~1,260px of pinned travel at a 900-tall viewport,
   about 630px per slide: one unhurried trackpad swipe each.
   ====================================================================== */
.mk-amenities__stage {
  position: sticky;
  top: 0;
  height: 100svh;              /* svh, not vh — mobile browser chrome */
  display: flex;
  flex-direction: column;
}

/* The HOLD TRAVEL itself. REQ-HOLD-1's recipe gave the sticky stage but NOT this
   rule, so the attribute bound and nothing moved — the stage had no parent travel
   to stick through and unpinned after one frame (measured: stagePinnedFrames 1).

   Same failure shape as the 10-recovery-41 cursor: the spec described the
   destination and omitted the switch. Copied verbatim from the working donor,
   sections/04-ecology.css, which renders 3060 = 900 + 2.4*900 at a 900 viewport.

   1.4 screens => 900 + 1.4*900 = 2160px at 900 tall: ~1,260px of pinned travel,
   about 630px per slide. This also serves founder B05, "make this section a little
   bit taller so that I can't quite see the next section with the map down there yet."
   Viewport-relative per B07 — never a fixed px height.

   >>> R17-08b / R17-08c · 2026-08-28 · lane `r17:sliders` <<< 1.4 -> 2.0.
   Founder, live: "as quickly as you load the second one, you're already
   scrolling down on the page" (forward) and "sometimes it breaks out and
   starts going up to the safe long-term housing" (backward, scrolling up
   from slide 2 past this section's own start). REQ-SCROLL-01 still forbids
   a wheel lock, so — same as 04-ecology.html's own R17-07d fix — the only
   real lever for "more scroll required before release, in EITHER direction"
   is more track. The added 0.6 screens is NOT spent on the slide-to-slide
   feel R17-08a names "reference-quality, keep as-is" (the Flickity spring —
   D27 below, untouched — and R8-09's arrival reveal — untouched, both key
   off `.is-selected`/viewport IO, neither reads `--myk-hold-p` numerically):
   `data-myk-hold-head="0.3"` and `data-myk-hold-tail="0.3"` on the
   `<section>` reserve it as two ADDITIVE, pre/post zones in
   sections/04-ecology.html's shared read() (its own R17 comment), read
   OUTSIDE the SLIDE_FROM-gated interior that drives WHEN the Flickity index
   itself changes — so the interior's own relative timing is unchanged.
   VERIFIED, not assumed: sections/14-amenities.css's own §4b scroll-driven
   text variant (the ONE place on this page that reads `--myk-hold-p`
   numerically, at its hardcoded 0.58/0.63) is DEAD CODE under the live
   configuration (R9-03 above: `.mk-amenities--motion-scroll` was removed
   from this section, §4's simple one-shot entrance is what actually plays)
   — grepped and confirmed live before touching this token, so growing the
   hold has nothing coupled to it to also retune. Re-verify that grep first
   if `.mk-amenities--motion-scroll` is ever restored to this section. */
.mk-amenities {
  --myk-hold-screens: 3.0;   /* 2026-09-02 founder: a fast desktop scroll skipped slide 2 and landed in amenities; 3 screens of hold (mobile already 3.2). Must match data-myk-hold on the section. */
  height: calc(100svh + var(--myk-hold-screens) * 100svh);
  position: relative;

  /* overflow-Y MUST stay visible. An ancestor with `overflow-y: hidden` silently
     degrades `position: sticky` to static — no error, no warning, the stage simply
     never pins (measured: pinnedFrames 0 while height and capture were both
     correct). This section carried a plain `overflow: hidden` for its full-bleed
     imagery, which set BOTH axes; `overflow-x: clip` alone did not override the y.
     The working donor computes `clip visible`, and that difference is the entire
     bug. Declare both axes explicitly so no future shorthand can re-break it. */
  overflow-x: clip;
  overflow-y: visible;
}

/* ==========================================================================
   R14-03 — HORIZONTAL DRAG-RELEASE SPEED — "a little bit fast... slow down
   the horizontal scroll." (founder-trace/FT-20260823-jehnean-round14.md)

   THE MECHANISM, READ LIVE (not assumed): unlike 07-building's carousel,
   THIS slider has no CSS transition on `.flickity-slider` at all today —
   confirmed live, `getComputedStyle(...).transitionDuration === "0s"`. The
   vendored `.transition-enabled .flickity-slider{transition:...}` rule
   (flickity.q-458c954239.css) requires `.nectar-flickity.nectar-carousel`
   on ONE element; here `nectar-carousel` sits on the ANCESTOR wrapper div
   and `nectar-flickity.nectar-simple-slider` on this one (see the markup
   note in §"(A) THE CAROUSEL" above) — the selector never matches, by
   Salient's own design: `nectar-simple-slider` is its full-bleed slide
   sub-type, deliberately left ungoverned by that smoothing rule. Release/
   snap motion here is therefore driven ENTIRELY by Flickity's own physics —
   `new Flickity(...).options` confirmed live: `selectedAttraction: 0.022,
   friction: 0.28`, both Flickity's library STOCK DEFAULTS (0.022 is the
   built-in value for its "simple slider"-shaped config, not a Mykrobial
   customization either way).

   THE FIX borrows 07-building's proven mechanism rather than inventing a
   second one — same property, same duration, same easing, so both gallery
   sections now share one horizontal-carousel motion grammar site-wide, per
   the founder's own plural phrasing ("the horizontal sliders," "those
   gallery sections"). GUARDED to `:not(.is-dragging)` for the identical
   reason as 07-building's rule: `.is-dragging` lives on this same element
   (confirmed live) for the exact duration of an active drag, so the
   while-dragging 1:1 pointer-tracking feel is untouched — this rule can
   only ever affect the settle AFTER release, which is what was asked. This
   is a NEW rule, not an override (there was nothing to override), so no
   specificity fight with the vendored sheet — kept scoped to `.mk-amenities`
   to match this file's own established selector convention rather than
   reaching for an ID. */
.mk-amenities .nectar-flickity.nectar-simple-slider:not(.is-dragging) .flickity-slider {
  transition: transform 0.6s cubic-bezier(.2, .6, .3, 1);
}

/* 2026-09-02 — MOBILE HOLD 2.0 -> 3.2 screens. Founder (Pixel 7): "it's still a
   little too easy for me to accidentally, with the same amount of scrolling,
   jump out of and skip the 'perfect for couples or solo guests' [slide] and
   already be down to features and amenities." The second slide owns the last
   37% of the hold (crossover pinned at `data-myk-hold-from="0.37"`; text
   windows 0.58/0.63 above are fractions too), so a longer hold gives it more
   travel without moving the crossover. MUST match `data-myk-hold-m="3.2"` on
   the section (14-amenities.html) — the reader in 04-ecology.html takes the
   -m attribute under 1000px; this is the track's half of the same number. */
@media (max-width: 999px) {
  .mk-amenities { --myk-hold-screens: 3.2; }
}
