/* ============================================================================
   SECTION 04 · "3.0 Ecology" · Figma 2761:2089 · 1280 x 900
   ----------------------------------------------------------------------------
   Spec   ../../figma-truth/04-ecology.spec.md      (all § references below)
   Pixels ../../figma-truth/sections-en/04-ecology.png  (@2x)
   Lift   ../../salient-truth/resort/index.html     (the founder-noted demo)

   READ THIS FIRST — the vendored CSS does NOT contain the simple-slider rules.
   Salient serves the whole `.nectar-simple-slider` / `.nectar-drag-indicator
   [data-type="solid"]` block from the page's INLINE <style id="dynamic-css-
   inline-css">, not from a <link>ed stylesheet, so `vendor/` has none of it
   (verified: 0 hits for `nectar-simple-slider` layout rules, `data-type="solid"`,
   `sizing-aspect-ratio`, `pagination-color-light`, `drag-indicator-only` across
   every file in vendor/). §A below is therefore a VERBATIM copy of those rules
   out of salient-truth/resort/assets/inline/inline-style-3.css, scoped to this
   section and otherwise byte-unchanged. It is a lift, not a reimplementation.
   See NOTES.md — the shell should eventually vendor that inline block wholesale.
   ========================================================================== */

/* ==========================================================================
   §0.0  THE TRACK  ·  founder C01 / C02 / C03, lane `r3:scroll-feel` 2026-08-19
   --------------------------------------------------------------------------
   HISTORY OF THIS BOX, IN ONE PLACE.

   (a) Figma-derived: "No height is declared. 277 (header) + 623 (media) = 900
       exactly (§1.1)."
   (b) D19/G1 made the media band the free term: `min-height: 100svh`, header
       hugs at 277, media takes the remainder. At the 900-tall parity viewport
       that is still exactly 277 + 623 = 900.
   (c) NOW (C02): the section is a TRACK and the thing that used to BE the
       section is a sticky STAGE inside it. (b)'s arithmetic is untouched — it
       simply moved down one level, onto `.mk-ecology__stage`. At progress 0 the
       rendered composition is identical to (b), which is why the Figma rest
       frame still measures.

   WHY A TRACK. C02, verbatim: scrolling in, "ecological considerations" slides
   LEFT and DISAPPEARS, then you see the images with text over them AS FULL
   SCREEN; once you reach the last one, you continue to the next section. A
   full-screen moment that PERSISTS while you keep scrolling (C03) needs scroll
   distance to persist across, and the only way to buy that without taking the
   wheel away from the user is to make the section taller than its stage. The
   page then scrolls 1:1 the whole way through; what stays still is the stage,
   because it is pinned.

   THE SAME PATTERN IS ALREADY IN THIS BUILD. sections/09-recovery-42.css §2
   pins a `position: sticky; top: 0; height: 100svh` rail inside a section that
   renders 1800 tall against 912 authored, under founder D24. 10, 11, 12 and 13
   do the same (2700 against 1366). This is that, not a new mechanic.

   `--myk-hold-screens` is read from the `data-myk-hold` attribute's intent and
   declared here so the number is visible in CSS rather than buried in a script.
   2.4 screens of hold at a 900-tall viewport is 2,160px of pinned scrolling:
   ~0.22 of it opens the frame (headline out, band collapsed), and the three
   slides take ~720px each — about one unhurried trackpad swipe per slide. The
   founders' complaint was that the section arrived in ONE 441px jerk and then
   ate six wheel ticks; this spends the same gesture budget on travel the user
   can see and stop in the middle of.
   ========================================================================== */
.mk-ecology {
  --myk-hold-screens: 2.4;
  height: calc(100svh + var(--myk-hold-screens) * 100svh);
  background: var(--mk-surface-haze);      /* #e6eef2 — §4.2, verified y 0..276 */
  position: relative;                      /* containing block for §G's scroller */
  /* D18 travels the headline out past both section edges. `clip` rather than
     `hidden` so no scroll container is created — and that distinction is now
     load-bearing for a second reason: `overflow: hidden` on this box would make
     it a scroll container, and a `position: sticky` child resolves against its
     nearest scroll container, so the stage below would pin to a box that never
     scrolls and therefore never pin at all. Only on the x axis, for the same
     reason the original author wrote here: "so a future sticky child is not
     trapped." That future child is `.mk-ecology__stage`. */
  overflow-x: clip;
}

/* --------------------------------------------------------------------------
   §0.1  THE STAGE — the frame that persists.
   This is (b) above, verbatim: flex column, header hugs at 277, media band
   takes the remainder of one screen. Nothing about the Figma composition
   changed; it is the same box with `position: sticky` on it.

   `top: 0` and not a header inset: the nav is transparent and overlays, exactly
   as sections/09-recovery-42.css §2 records for the recovery rail.
   -------------------------------------------------------------------------- */
.mk-ecology__stage {
  position: sticky;
  top: 0;
  height: 100svh;
  display: flex;
  flex-direction: column;                  /* header hugs, media band takes the rest */
  /* Containing block for §G's `position: absolute; inset: 0` scroller, which
     MUST be stage-sized and not track-sized: Salient's own controller computes
     `winH/2 - $el.outerHeight()/2`, and that term is 0 only while the animated
     column is exactly one viewport tall. Sized to the 3,060px track instead, it
     would be -1,080 and the headline would sit 378px right of Figma at rest.
     The arithmetic is in §G1; `position: sticky` above is what keeps it true —
     sticky is a POSITIONED value, so this box is the containing block for the
     scroller's `inset: 0` without needing a second declaration. Removing the
     sticky would silently re-parent the scroller to the 3,060px track. */
}

/* ==========================================================================
   §0. THE MERRIWEATHER OPTICAL-SIZE PIN IS WRONG FOR THIS SECTION.
   ----------------------------------------------------------------------------
   tokens.css pins `font-optical-sizing: none; font-variation-settings: "wdth"
   100, "opsz" 18` on every h1/h2/h3/.mk-serif, and CONVENTIONS §8.4 calls that
   "a fidelity requirement". MEASURED IN THE BROWSER AGAINST THE FIGMA RENDER,
   it is off by 12% here, and releasing it lands within a pixel:

     "Ecological considerations", Merriweather 300 @ 96px, in this shell
       opsz 18 (the tokens.css pin) ......... 1151.48px
       opsz 96 / font-optical-sizing: auto .. 1026.92px
       Figma's hug box (§2 row 4) ...........    1028px   <- auto wins by 1.08px

   The body copy agrees independently. Figma wraps line 1 as "Located in Costa
   Rica's Blue Zone, Nicoya" with ink at x 297..983 (§2). Centred in the 860
   measure, an advance of 690.13 (opsz 36 = auto) predicts ink at ~297; an
   advance of 705.88 (opsz 18) predicts ~289. Line 2 checks out the same way.

   So Merriweather in THIS Figma file is rendering at opsz = font-size. The pin
   is released for this section only — changing tokens.css is not this section's
   call, but the shell owner should re-measure it against every Merriweather
   node on the page. Logged for NOTES.md.

   The three-class selector below is deliberate. tokens.css sets the pin with
   `.mk-page :is(h1, h2, h3, .mk-serif)`, and `:is()` takes the specificity of
   its most specific argument, so that rule is (0,2,0) — it outranks a plain
   `.mk-ecology__title` (0,1,0) and the release silently does nothing. Measured:
   the headline stayed 1040 wide and wrapped to two lines until this was raised.
   ========================================================================== */

.mk-page .mk-ecology .mk-ecology__title,
.mk-page .mk-ecology .mk-ecology__copy,
.mk-page .mk-ecology .mk-ecology__copy p {
  font-optical-sizing: auto;            /* opsz tracks font-size, as Figma does */
  font-variation-settings: normal;      /* release the "opsz" 18 pin; wdth 100 and
                                           wght 300/400 are the fvar defaults and
                                           still come from font-weight */
}

/* ==========================================================================
   §0b. FIRST-BASELINE CORRECTION — Chrome paints every text run in this
   section exactly 1.000 CSS px ABOVE where Figma paints it, in an IDENTICAL
   box. This is a paint-level renderer disagreement, not a layout error, and
   it is corrected at paint level so that every box stays on its spec
   coordinate.

   HOW IT WAS ESTABLISHED (three independent instruments, no inference):

   1. LAYOUT IS ALREADY EXACT. Live DOM, probed in the capture's own headless
      Chrome via `_tools/probe.py`, section-relative:
        head    0..277           eyebrow 96..120  L120  W1040
        title   144..265  L126.531  W1026.922     media   277..900
        inner   325..852  L120 R1160              copy    325..798  L210 W860
        cta     812..852  L837.781 R1160          disc    337..433  L1124 R1220
      Every one of those is the §2 table. Nothing is mispositioned.

   2. FIGMA AGREES ABOUT THE BOXES. `get_node_full(["2761:2091","2761:2092"])`
      re-read live from the Figma MCP returns
        eyebrow bounds {x 120, y 96, w 1040, h 24}
        h1      bounds {x 126, y 144, w 1028, h 121}
      — the same boxes the build lays out. So the disagreement cannot be the
      padding, the gap, or the auto-layout arithmetic.

   3. THE OFFSET IS A CONSTANT, MEASURED SUB-PIXEL. The section was captured
      at raster scale 2 (`Page.captureScreenshot` clip.scale 2 — Figma's own
      @2x pipeline) and cross-correlated against `sections-en/04-ecology.png`
      at 0.5px steps with a parabolic sub-pixel refine:

        element      best dy    MAE @dy=0 -> @best
        eyebrow      -1.000      13.89 ->  1.03
        h1           -0.996      15.02 ->  6.43
        body line 1  -0.973      11.95 ->  3.49
        body line 2  -0.930      12.87 ->  6.06
        body line 3  -0.920      13.44 ->  6.76
        pill label   -0.939      21.12 -> 14.95
        dots         +0.002       0.76 ->  0.76   <- non-text: zero
        chevrons     -0.002       2.06 ->  2.06   <- non-text: zero

      A flat 1px across Poppins 16, Merriweather 36 and Merriweather 96 is NOT
      a metrics ratio (that would scale with font-size) and NOT a raster
      snapping artefact (it survives at scale 2 unchanged). Every non-text
      element in the same section is at 0.00.

   MECHANISM — NOT MINE. I measured the offset but could not attribute it;
   `repair:00-hero` isolated it independently on a different section and its
   model reproduces these numbers: Chrome rounds the font's ascent and descent
   to whole pixels and then TRUNCATES the fractional half-leading, while Figma
   keeps both fractional. Worked for this section's four runs:

     run        lh     unrounded content   CSS half-lead   truncated to   predicted dy
     eyebrow    24     22.4  (Poppins 16)      0.8              0             -0.8
     h1        121    120.672 (Merri 96)       0.164            0             -0.63*
     body      64.8    45.252 (Merri 36)       9.774            9             -1.20
     cta lbl    24     22.4  (Poppins 16)      0.8              0             -0.8

     * with ascent/descent rounded to 94/26 first, which is the same rounding
       step; that is what turns 0.164 into a lost 0.5.

   That predicts 0.6-1.2px — i.e. "about a pixel, and NOT proportional to
   font-size", which is exactly the signature measured. It also explains why a
   run whose leading is already integral lands exact: `repair:00-hero` reports
   00-hero's lockup (30-28) and body (36-28) at dy 0 with no correction.

   NOT A SECTION-04 DEFECT — the same -1.00 was measured on the eyebrows of
   01-who-why, 05-ecology-b and 06-ecology-c, i.e. on the shared `.mk-eyebrow`
   component. The shell-level fix is written up as REQ-BASELINE-01 in
   review/findings/SHARED-REQUESTS.md. **If that request lands, DELETE this
   block** — the two corrections would otherwise stack into a 2px error.

   MECHANISM: the independent `translate` property, deliberately not
   `transform` — Salient's own rules animate `transform` on descendants of this
   section and a shorthand here would clobber them, whereas `translate`
   composes with `transform` instead of replacing it.

   HONEST CAVEAT: `translate` is paint-only for LAYOUT (nothing reflows, no
   sibling moves, the header band stays 277), but it DOES move the element's
   own `getBoundingClientRect`. A probe of this section now reads eyebrow
   97..121 and h1 145..266, i.e. the §2 numbers PLUS this 1px. That is the
   correction showing up, not a regression — the CSS layout boxes are still
   96..120 and 144..265. `position: relative; top: 1px` would report exactly
   the same way; there is no CSS mechanism that moves painted glyphs while
   leaving the measured box behind.
   ========================================================================== */

.mk-page .mk-ecology .mk-ecology__eyebrow,
.mk-page .mk-ecology .mk-ecology__title,
.mk-page .mk-ecology .mk-ecology__copy p,
.mk-page .mk-ecology .mk-ecology__cta > span {
  translate: 0 1px;
}

/* ==========================================================================
   §A. LIFTED VERBATIM — Salient `nectar-simple-slider` + `nectar-drag-indicator`
   Source: salient-truth/resort/assets/inline/inline-style-3.css
   Only change: every selector is prefixed `.mk-ecology ` so the rules cannot
   leak into another section before the shell vendors the inline block.
   The `>= 1000px` variants are used (the demo's own desktop branch).
   ========================================================================== */

.mk-ecology .nectar-flickity.nectar-simple-slider { position: relative; }
.mk-ecology .nectar-flickity.nectar-simple-slider .flickity-viewport { margin: 0; }
.mk-ecology .nectar-simple-slider.min-height-475px { min-height: 475px; }

.mk-ecology .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-ecology .nectar-flickity.nectar-simple-slider[data-parallax="true"] .flickity-slider .cell { width: 101%; }
.mk-ecology .nectar-flickity.nectar-simple-slider:not([data-arrows="true"]) .flickity-slider .cell { padding: 0 min(8%, 90px); }

.mk-ecology .nectar-simple-slider .cell > .bg-layer-wrap,
.mk-ecology .nectar-simple-slider .cell > .bg-layer-wrap .bg-layer,
.mk-ecology .nectar-simple-slider .cell > .bg-layer-wrap .color-overlay {
  position: absolute; left: 0; top: 0; width: 100%; height: 100%;
}
.mk-ecology .nectar-flickity.nectar-simple-slider .cell > .bg-layer-wrap .bg-layer { background-size: cover; background-position: center; }
.mk-ecology .nectar-simple-slider[data-parallax="true"] .cell > .bg-layer-wrap .bg-layer { will-change: transform; }
.mk-ecology .nectar-flickity.nectar-simple-slider[data-parallax="true"] .cell > .bg-layer-wrap { top: auto; bottom: 0; }

.mk-ecology .nectar-simple-slider .cell > .inner { z-index: 10; position: relative; flex: 1; }
.mk-ecology .nectar-flickity.nectar-simple-slider .flickity-slider .cell .inner > div:last-child { margin-bottom: 0; }

.mk-ecology .nectar-simple-slider .flickity-page-dots {
  position: absolute; bottom: 0; left: 0;
  padding: 0 3% 3%;
  padding: 0 max(3.45%, 27px) max(3.45%, 27px);
  width: 100%;
  pointer-events: none;
}
.mk-ecology .nectar-simple-slider .flickity-page-dots .dot {
  opacity: 1; width: 36px; height: 36px; padding: 5px; margin: 0;
  pointer-events: all; mix-blend-mode: difference;
}
.mk-ecology .nectar-simple-slider.pagination-color-light .flickity-page-dots .dot { mix-blend-mode: initial; }

/* D16 DELETED the static `.mk-ecology__disc` and with it the group of inert
   Salient solid-disc rules that used to sit here. They are not "commented out"
   or left at zero opacity — the element is gone, so the rules are gone.
   The live equivalents, repainted to the Mykrobial token, are in §E. */

/* ==========================================================================
   §B. HEADER BAND — 2761:2090 · 1280 x 277 @ y 0
   ========================================================================== */

.mk-ecology__head {
  padding-block: var(--mk-space-96) var(--mk-space-12);   /* 96 / 12 — §1.1 */

  /* -- C02, THE COLLAPSE -----------------------------------------------------
     "then you see the images with text over them AS FULL SCREEN."
     The media band is the flex remainder (§C), so the ONLY thing standing
     between it and a full screen is this band's 277px. Collapsing this to 0
     grows the media to 100svh with no rule of its own — the same arithmetic
     that already gives it 623 at the parity viewport, run to its other end.

     `height` is a var and not `auto` because `auto` is not an animatable
     value: a transition from `auto` does not run at all. The reader script
     MEASURES this band once at init and publishes the result as
     `--myk-eco-head-h`, so the rest state is whatever the band actually hugs
     to at THIS width — 277 at 1280, something else once §F re-scales the
     headline. Hard-coding 277 here is the exact failure §C already records for
     `calc(100svh - 277px)`: correct at the parity viewport, quietly wrong
     everywhere else.

     `auto` is the fallback in the var, so before the script runs — and if it
     never runs — the band is the Figma 277 and the section renders exactly as
     it did before this change. Every fidelity capture is taken at progress 0,
     where the band is open regardless.

     900ms / cubic-bezier(.22,.61,.36,1) — "smooth as I'm going into that
     section" (C01). Time-anchored, not scroll-scrubbed, for the reason the
     script's header records: `r3:research-bgfade` measured Salient's own
     colour-change donor as an 800ms time-anchored `ease`, and a time-anchored
     curve cannot inherit the stutter of the gesture that triggered it. */
  height: var(--myk-eco-head-h, auto);
  flex: 0 0 auto;
  /* REQUIRED, not defensive. This band carries `padding-block: 96 12`. Under
     `content-box` a declared `height: 0` still leaves 108px of padding standing
     and the "full screen" never arrives; and the measured rest value would be
     385 (277 + 108) instead of 277, so the band would GROW when the script
     published it. Both failures are silent. */
  box-sizing: border-box;
  overflow: hidden;                       /* the eyebrow is clipped, not squashed */
  transition:
    height        900ms cubic-bezier(.22, .61, .36, 1),
    padding-block 900ms cubic-bezier(.22, .61, .36, 1);
  will-change: height;
}
/* THE PADDING HAS TO GO TOO, AND THIS IS NOT BELT-AND-BRACES — MEASURED.
   Under `box-sizing: border-box` a specified `height` SMALLER than
   padding + border does not shrink the box below padding + border; the content
   box floors at 0 and the used height stays 108 (96 + 12). Measured on the
   first build of this rule: `head=108  media=792` at every phase past the
   opening, i.e. the "full screen" was 108px short of the screen and nothing in
   the CSS said so. Collapsing the padding on the same curve is what actually
   reaches 0 / 900. */
[data-myk-eco="open"] .mk-ecology__head {
  height: 0;
  padding-block: 0;
}

/* >>> THE OVERLINE'S EXIT FADE IS DELETED · R7-13 · lane `r7:ecology` <<<
   It was:
       .mk-ecology__eyebrow            { transition: opacity 520ms cubic-bezier(.22,.61,.36,1); }
       [data-myk-eco="open"] .mk-ecology__eyebrow { opacity: 0; }

   TWO reasons, and the first one is that it had ALREADY STOPPED WORKING.
   MEASURED on the served page before this change, at every one of the five
   widths (review/r7/r7-ecology/BEFORE-*.json, shot `opening`): the eyebrow
   computed `opacity: 1.00` with `data-myk-eco="open"` set. css/myk-motion.js
   adopts `.mk-eyebrow` into the vocabulary, and `html.mv [data-mv].mv-in`
   (0,3,1) outranks `[data-myk-eco="open"] .mk-ecology__eyebrow` (0,2,0). The
   only thing hiding the overline was the band's own `overflow: hidden` once
   the height reached 0 — i.e. the rule was decorative and the CLIP was doing
   the work. A rule that has silently lost its cascade fight is worse than no
   rule, because it reads as an intent that is being honoured.

   The second reason is that R7-13 retires the intent: "Then BOTH stay put and
   move up naturally with the page into the blue-zone section." Nothing fades
   out here any more. Both ride up and are clipped by the band, which is what
   "moves up with the page" looks like. The overline now carries `data-mv-skip`
   in the HTML, so the vocabulary is out of this element entirely and §H owns
   its whole life. */

/* --------------------------------------------------------------------------
   R7-12 · THE LOCKSTEP RIDE-UP — the fix for "it JUMPS off and DOWN, OVER the
   next section".
   --------------------------------------------------------------------------
   THE DEFECT, IN NUMBERS, BEFORE THIS RULE (review/r7/r7-ecology/BEFORE-*.json):
   the h1 sat out of the flow in an `inset: 0` column on the STICKY stage, so
   its viewport top was NAILED at 145.0px for the entire open — while this band
   collapsed 277 -> 0 and `.mk-ecology__media`'s top swept 277 -> 0 with it.
   The blue-zone photograph therefore travelled UP THROUGH the headline and the
   headline finished painted ON it. Relative displacement, per width:

       1280x900   277px      1440x900   277px      1750x980   277px
        834x1112  244px       390x844   245px

   That is what "jumps off and DOWN over the next section" is: the title never
   moved down in absolute terms, the SECTION moved up past it. Both readings
   are the same defect and both are fixed by the same rule.

   THE RULE. The band's content now travels up by exactly as much as the band's
   bottom edge does, so the gap between the headline and the top of the
   photograph is CONSTANT for the whole collapse and the two can never cross.

     content top(c) = padTop*(1-c)  -  S*c
     media  top(c) = H0*(1-c)
     constant separation  <=>  S = H0 - padTop

   `--myk-eco-head-shift` is that S, and the reader script MEASURES it
   (S = the .mk-container's own height + this band's rest padding-bottom, both
   of which survive the collapse) rather than hard-coding 181. Hard-coding is
   the exact failure §C already records for `calc(100svh - 277px)`: right at the
   parity viewport, quietly wrong at 834 (S = 148) and 390 (S = 149).

   Same 900ms / cubic-bezier(.22,.61,.36,1) clock as the height and the padding
   above, because "lockstep" is a property of the CURVE as well as the distance:
   three properties on three different declarations, one clock, or the
   separation is only constant at the endpoints. */
.mk-ecology__head > .mk-container {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: var(--mk-space-24);                                /* itemSpacing 24 — §1.1 */
  transition: transform 900ms cubic-bezier(.22, .61, .36, 1);
}
[data-myk-eco="open"] .mk-ecology__head > .mk-container {
  transform: translateY(calc(-1 * var(--myk-eco-head-shift, 181px)));
}

/* eyebrow · 2761:2091 · 1040 x 24 @ (120, 96).
   .mk-eyebrow already carries Poppins 300 / 16 / 24 / 3px / uppercase. */
.mk-ecology__eyebrow {
  margin: 0;
  padding: 0;                             /* Salient's style.css puts padding-bottom:
                                             24px on <p>; measured, it doubled this
                                             box to 48 and the band to 301 */
  color: var(--mk-ink-strong);            /* #000000 — §4.1, NOT --mk-ink-body */
  text-align: left;                       /* textAlignHorizontal LEFT */
}

/* h1 · 2761:2092 · 1028 x 121 @ (126, 144).
   TWO corrections to §8's build checklist, both pixel-proven against the @2x
   render, both of which produce a WRONG headline if taken from the payload:

   (a) THE #ffffff FILL DOES NOT RENDER. §4.1 reports `fill: #ffffff`, but the
       glyph interiors in sections-en/04-ecology.png read (230,238,242) — the
       section ground, exactly — and a colour census of the whole headline band
       (x 120..1160, y 150..270) returns ZERO pure-white pixels out of 499k.
       The headline is a hollow outline: transparent fill + the 1px black stroke.
       This is the same hidden-paint trap as CONVENTIONS §8.1.
   (b) x = 126, not 120. That 6px is Figma's counter-axis CENTER inset of a
       1028-wide hug box inside the 1040 content box (§1.1). `width: fit-content`
       + `margin-inline: auto` reproduces the RULE rather than the literal, so it
       stays correct if the rendered measure differs from Figma's 1028 by a
       fraction. §6 offers x = 120 (the ES frame's MIN rule) as an alternative;
       it is NOT taken here because the parity gate is the EN render. */
.mk-ecology__title {
  width: fit-content;
  margin: 0 auto;                         /* see the HUG-WIDTH DRIFT block in §E2 —
                                             at >=1280 the auto centring is replaced
                                             by Figma's literal 6px inset */
  font-weight: var(--mk-w-light);         /* Merriweather Light 300 — §4.1 */
  font-size: var(--mk-size-hero);         /* 96 */
  line-height: var(--mk-lh-hero);         /* 121px, box height 121 */
  color: transparent;                     /* see (a) above */
  -webkit-text-stroke: 1px var(--mk-ink-strong);   /* weight 1, align CENTER — §4.4 */
  text-align: left;
}

/* ==========================================================================
   §C. MEDIA BAND — 2761:2094 · 1280 x 623 @ y 277
   ========================================================================== */

.mk-ecology__media {
  position: relative;                     /* positioning context for the nav disc */
}
/* >>> `position: absolute; inset: 0` — MEASURED, NOT PREFERRED. <<<
   The band's height is now the flex remainder rather than a literal 623, so it
   has to reach the cell down five wrappers: media -> .nectar-carousel ->
   .nectar-flickity -> .flickity-viewport -> .flickity-slider -> .cell. The
   obvious `height: 100%` on each link DOES NOT WORK, and the reason is worth
   writing down because it will bite the next section that goes immersive.

   `.mk-ecology__media` is a flex item with `flex: 1 1 auto`. Its USED height is
   623, but its COMPUTED `height` is still `auto`, and a percentage height
   resolves against the computed value. So `height: 100%` on the carousel
   resolved to `auto`, and the failure then cascaded:

     COLD, measured on the composed page before this rule:
       .mk-ecology__media   623   <- correct
       .nectar-carousel     475   <- 100% of auto -> auto -> its child's min-height
       .mk-ecology__slider  475   <- Salient's .min-height-475px floor, nothing else
       .flickity-viewport     0   <- 100% of a computed-auto parent
       .flickity-slider       0
       .cell                 96   <- just its own 48+48 padding
       .cell .inner           0
     and the section rendered as a 623px HOLE: header, page dots and scrim
     painted, photograph and copy and CTA absent.

   Absolutely positioning the carousel against the (position: relative) band
   gives it a DEFINITE height, and every percentage below it resolves from
   there. `display: grid; grid-template-rows: 100%` was tried first and has the
   same percentage-resolution problem one level down. */
.mk-ecology .nectar-carousel { position: absolute; inset: 0; }

/* NOT an aspect ratio: the band is 623 at 1280 AND at 1440 (§3.1 "Media band
   height ... invariant"), which is why Salient's `sizing-aspect-ratio
   aspect-2-1` (padding-bottom: 50%) was dropped.

   D19/G1 changed the 623 from a literal into a REMAINDER, and the remainder is
   taken by the flex box in §G rather than by arithmetic. `calc(100svh - 277px)`
   was tried first and rejected: it hard-codes a header height that stops being
   277 the moment §F re-scales the headline below 1280, so it would have been
   correct at the parity viewport and quietly wrong everywhere else. With
   `flex: 1` the media band is whatever the header leaves, at every width, and
   at the 900-tall parity viewport the header still hugs to exactly 277 so the
   band is exactly 623 — the previous build's geometry reproduced rather than
   approximated. Salient's `.min-height-475px` (§A) is still the floor. */
.mk-ecology__media { flex: 1 1 auto; min-height: 0; }
.mk-ecology__slider { height: 100%; }    /* §2 row 5, now inherited from the band */

/* Cell box. Two changes to the lifted rule, both required by Figma and both
   measured in a real render rather than reasoned:

   1. THE 101% IS DROPPED. §A's `[data-parallax="true"] .cell { width: 101% }`
      widens the cell so the horizontal drag-parallax never exposes an edge. But
      Salient initialises Flickity with `cellAlign: "center"` and
      `percentPosition: true`, so a 1292.8px cell in a 1280px track is CENTRED at
      x = -6.4 — and every child inherits that offset. Measured with Flickity
      live: cell L-6.40, inner L113.60, copy L203.60, CTA right 1153.60, i.e. the
      whole content column 6.4px left of Figma. At 100% the section is correct in
      BOTH states — before Flickity runs (cell at L0) and after it centres the
      cell — which is the deciding argument; see the note under the rule.
   2. vertical padding 48 (Figma's inner Text frame, §1.1) — Salient's is 0 — and
      horizontal padding 120 (Figma's margin) instead of min(8%, 90px).

   The `:not([data-arrows="true"])` is NOT decoration: §A's rule carries it and
   therefore outranks a plain descendant selector (0,6,0 vs 0,5,0). Without it
   this override silently loses and the cell keeps Salient's min(8%, 90px) —
   which is exactly what happened on the first render. */
.mk-ecology .nectar-flickity.nectar-simple-slider:not([data-arrows="true"]) .flickity-slider .cell {
  align-items: stretch;
  padding: var(--mk-space-48) var(--mk-page-x);
}
.mk-ecology .nectar-flickity.nectar-simple-slider[data-parallax="true"] .flickity-slider .cell { width: 100%; }
/* NOT COMPENSATED ELSEWHERE, deliberately. Two alternatives were tried and
   rejected against the render:
     a) keep 101% and pad by an extra symmetric 0.5% — lands exactly once
        Flickity has centred the cell, but is 6.4px wrong BEFORE it initialises,
        and Salient defers init behind a user gesture, so the cold state (which
        is what a parity probe captures) would be wrong;
     b) move the overshoot onto .bg-layer (`width:102%; left:-1%`) — but the
        layer is `background-size: cover`, so widening its box re-crops the
        photograph by 2% and breaks the plate, which §4.3 pins to an exact
        cover/center crop of a 2274x1704 source in a 1280x623 box.
   Cost of dropping it: at the extreme of a horizontal drag the parallaxed
   background can expose an edge for the duration of the drag. Recorded as
   lossiness rather than paid for in rest-state pixels. */

/* Scrim. §4.3 fill index 3, SOLID #0d1d23 @ opacity 0.4. §10.3 recorded its
   visibility as UNDETERMINED; it is now RESOLVED as VISIBLE by two independent
   proofs: (1) the SVG export of 2761:2094 emits
   `<rect width="1280" height="623" fill="#0D1D23" fill-opacity="0.4"/>` and
   emits NEITHER gradient (Figma's SVG exporter omits invisible paints), and
   (2) compositing the recovered source bitmap at cover/center and applying the
   40% scrim reproduces the render to within +/-2 on 9 of 11 sample points.
   Salient would normally emit a generated `.color-overlay-1-rgba(...)` class for
   this; the paint is a token here instead. */
.mk-ecology .nectar-simple-slider .cell > .bg-layer-wrap .color-overlay {
  background-color: var(--mk-scrim-deep);              /* #0d1d23 @ 40% */
}

.mk-ecology .nectar-simple-slider .cell.text-color-ffffff .inner { color: var(--mk-ink-inverse); }

/* Content well. Figma's inner Text frame is VERTICAL / primary MAX / counter
   CENTER (§1.1) with body(473) + 24 + slector(30) = 527 = 623 - 96. The slector
   is NOT rebuilt in this flow — Flickity owns the indicator (§D) — so with the
   copy box's own fixed 473 height, `flex-start` reproduces Figma's band-local
   48..521 exactly, where `flex-end` would put it at 102..575.
   max-width 1040 + auto margins keeps the well aligned with .mk-container above
   1280, where the band is full-bleed but the container caps at --mk-frame.

   >>> R8-03 · 2026-08-21 · lane `r8:ecology-bluezone` <<<
   `justify-content` CHANGED flex-start -> center. "Can you make that text more
   center aligned? It actually is a little awkward that it's so high up on the
   page." She does not review the 623px REST band (never seen full-screen); she
   reviews the OPEN/full-screen stage, where the band is ~viewport-tall (900 at
   the parity viewport, more at 1750x980) while the 527px content block (copy +
   gap + dots) keeps its Figma-derived height. `flex-start` pins that block to
   the top and dumps 100% of the slack at the bottom — MEASURED before this
   change: copy centreY 284.56 against a 450/490 viewport centre at 1280/1440/
   1750, i.e. 165.4 / 165.4 / 205.4px high. `flex-start` and `center` are
   BYTE-IDENTICAL at rest: MEASURED, the rest band (623) exactly equals
   48(pad) + 527(content) + 48(pad) — zero slack — so this is a no-op on the
   Figma-graded closed frame and only changes the OPEN state, where the slack is
   real. (The <1280 breakpoint already reads `center` here — see the
   max-width:1279px block below — this brings the desktop band the reviewed
   >=1441 width sits in to the same rule already proven safe at mobile.) */
.mk-ecology .nectar-simple-slider .cell > .inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  max-width: calc(var(--mk-frame) - 2 * var(--mk-page-x));   /* 1040 at 1280 */
  margin-inline: auto;
}

/* body copy · 2761:2096 · 860 x 473 @ abs (210, 325).
   .mk-measure-860 supplies width 860 + auto margins; .mk-serif supplies the
   Merriweather family (its opsz pin is released in §0). */
.mk-ecology__copy {
  height: 473px;                          /* §2 row 6 — hand-set, not content-derived */
  display: flex;
  align-items: center;                    /* textAlignVertical CENTER — derived, §9.3 */
  justify-content: center;
}
.mk-ecology__copy p {
  margin: 0;
  padding: 0;                             /* see the eyebrow note */
  font-weight: var(--mk-w-regular);       /* Merriweather Regular 400 — §4.1 */
  font-size: var(--mk-size-h2);           /* 36 */
  line-height: var(--mk-lh-h2);           /* 64.8px = 179.99999523162842% */
  text-align: center;
  color: var(--mk-ink-inverse);
  text-shadow: 0 4px 14px var(--mk-shadow-50);   /* DROP_SHADOW #00000080 (0,4) r14 — §4.1 */
}

/* CTA pill · 2767:2219 · 322 x 40, box y 812..852, right edge on the margin.
   myk-btn / myk-btn--outline supply 8/18 padding, the 40px box, the stadium
   radius, the 1px white stroke and the shell's teal-wipe hover (site.css, lifted
   from resort/rooms "Book Now", 00-hero §7.4). Figma declares no hover for this
   node (§7.5) — reusing the page's existing outline-pill behaviour rather than
   inventing one, and the teal it wipes to happens to be the very fill that sits
   hidden on this node. */
.mk-ecology__cta {
  position: absolute;
  right: 0;                               /* .inner right edge = 1160 = W - 120 */
  bottom: 0;                              /* .inner bottom edge = band-local 575 */
  /* Every difference from the base button is a TOKEN, per the component
     contract in css/myk-btn.css §1. */
  --myk-btn-weight: var(--mk-w-medium);   /* Poppins Medium 500 — §4.1 */
  --myk-btn-blur: none;                   /* this node declares NO effects (§4.4),
                                             unlike the nav buttons which blur */
  --myk-btn-track-trim: var(--mk-track-nav);  /* CSS hangs 1px of tracking off the
                                             last character; Figma's hug does not */
  /* The ring itself is `myk-btn--ring-layer`, on the element — it has to be a
     class rather than a token because it swaps the RENDERER (a ::after layer
     instead of a box-shadow), not a value. Required because this button is
     absolutely positioned; the measurement is in css/myk-btn.css §4. */
}
/* THE RING — now `myk-btn--ring-layer`, in css/myk-btn.css §4.
   The measurement that earned it (Chrome's round-half-up snap on absolutely
   positioned elements, MAE 16.91/16.16 dropping to 3.10/2.52 under a synthetic
   +0.5/+0.5 shift) moved into that file with the renderer, because the next
   section that needs it will look for it there and not here.
   `--ring-layer` reads `--myk-btn-border` for its colour, and the component's
   own `:hover` already retargets that token to `--myk-btn-hover-border`, so
   the hover ring follows with no rule in this file. */

/* ==========================================================================
   §D. INDICATOR — Flickity's page dots, wearing Figma's shape
   Figma's `slector` (2761:2105) is three LINE nodes: 36x4 active #ffffff and
   two 6x4 at 50%, cap ROUND, 15px apart, group centred on the frame, bottom
   edge at y 852 = band-local 575 = 48 from the band's bottom (§2 rows 7/7a-c).
   Salient's stock dot is an 8px round dot plus an SVG countdown ring; §7.4 says
   keep Salient's behaviour and build Figma's shape, and translates the ring's
   `.7s cubic-bezier(.25,.25,.1,1)` onto the bar's width. Both are done here.
   ========================================================================== */

.mk-ecology .nectar-simple-slider .flickity-page-dots,
.mk-ecology .mk-ecology__dots {
  position: absolute;
  left: 0;
  bottom: var(--mk-space-48);             /* 48 */
  width: 100%;
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  justify-content: center;                /* group centred on the frame */
  align-items: flex-end;
  gap: 15px;                              /* slector itemSpacing 15 — §1.1 */
  pointer-events: none;
}
/* The static fallback yields the instant Flickity's real dots appear. */
.mk-ecology__media:has(.nectar-flickity .flickity-page-dots) .mk-ecology__dots { display: none; }

.mk-ecology .nectar-simple-slider .flickity-page-dots .dot,
.mk-ecology .mk-ecology__dots .dot {
  position: relative;
  width: 6px;                             /* inactive marks 2 and 3 — §2 rows 7b/7c */
  height: 4px;                            /* LINE strokeWeight 4 */
  padding: 0;
  margin: 0;                              /* flickity.css ships `.dot{margin:0 5px}`;
                                             left in, it ADDS to the 15px gap and the
                                             group measures 98 instead of 78 (measured) */
  border: 0;
  border-radius: 2px;                     /* strokeCap ROUND on a 4px stroke */
  background: var(--mk-ink-inverse);
  opacity: 0.5;                           /* #ffffff @ 0.5 — §4.2 */
  transition: width 0.7s cubic-bezier(.25, .25, .1, 1),
              opacity 0.7s cubic-bezier(.25, .25, .1, 1);   /* §7.4 */
}
.mk-ecology .nectar-simple-slider .flickity-page-dots .dot.is-selected,
.mk-ecology .mk-ecology__dots .dot.is-selected {
  width: 36px;                            /* active mark — §2 row 7a */
  opacity: 1;
}
/* Salient paints its dot through :before and appends an SVG countdown ring on
   init; Figma has neither. */
.mk-ecology .nectar-simple-slider .flickity-page-dots .dot:before,
.mk-ecology .mk-ecology__dots .dot:before,
.mk-ecology .nectar-simple-slider .flickity-page-dots .dot svg { display: none; }
/* A 4px-tall bar is not a pointer target. Restore Salient's ~36px hit area
   without changing a rendered pixel. The inline inset matches half the 15px gap,
   so adjacent targets meet and never overlap. */
.mk-ecology .nectar-simple-slider .flickity-page-dots .dot::after {
  content: "";
  position: absolute;
  inset: -16px -7.5px;
}

/* ==========================================================================
   §E. THE MOUSE-HOVER CURSOR — founder defects D15 + D16
   ----------------------------------------------------------------------------
   >>> REWRITTEN 2026-08-18 by lane `fix:ecology`. Read helix/D15.md + D16.md.

   D16 deleted the STATIC disc. Figma node 2767:2243 was never a control: it is
   the general-interactivity CURSOR (review/branding/media-misc.md §3.3), left
   in the frame where the designer parked it. §3.1 of that document states the
   rule for the whole class in the founders' own artboard: "its position in the
   board is just where Jehnean parked it to show the component — it is not a
   layout position." So there is no `.mk-ecology__disc` any more, and none of
   its rules survive. This section's carousel opts into the REAL follow-cursor
   the same way section 14 does, through `data-touch-indicator="true"` +
   `data-indicator-bg` on the slider.

   D15 repaints that real cursor. Salient builds exactly one
   `.nectar-drag-indicator` per page, on <body>
   (init.q-a3a00a7bf4.js, `$t.prototype.createMarkup`):
       if (0 == t(".nectar-drag-indicator").length) { …append…; this.dragRAF(); }
       else this.$dragEl = t(".nectar-drag-indicator");
   and its SKIN, before this block, was Salient's stock one — lifted verbatim
   and unnamespaced into sections/07-building.css lines 386-397:

       .nectar-drag-indicator[data-type="solid"]              { left:-47px; top:-47px; width:94px; height:94px }
       .nectar-drag-indicator[data-type="solid"] .color-circle{ background-color:#000 }   <-- OPAQUE
       .nectar-drag-indicator[data-type="solid"] i            { font-size:21px; top:-13px } <-- Font Awesome

   That is precisely the founders' D15: "wrong colour and opacity". Salient's
   disc is 100 % black with no blur and Font Awesome chevrons; the Mykrobial
   token is 50 % black with a 4px backdrop blur and Material `arrow_back_ios`.

   THE BRAND TOKEN, from review/branding/media-misc.md §3.3 and §7 rule 1
   (Figma `3333:136` / `3333:169`, render-measured at 4x):

     | size        | 96 x 96, full circle                                    |
     | fill        | #000000 @ 50%                                           |
     | effect      | backdrop-filter: blur(4px)   (BACKGROUND_BLUR radius 4)  |
     | stroke      | none                                                     |
     | glyphs      | 2 x Material arrow_back_ios, #FFFFFF, 11.775 x 20 each   |
     | left glyph  | x 24.25 -> 35.5,  y 38.25 -> 57.5                        |
     | right glyph | x 60.5  -> 71.5,  y 38.25 -> 57.5                        |
     | glyph gap   | ~24.75 — a deliberately WIDE-set pair, not tight-centred  |

   §7 rule 1 also fixes WHICH class this is. Two cursor classes exist and they
   are distinguished by FILL alone: turquoise #1EB2BC 110px starts playback or
   begins a flow (primary-action, D09); black-at-50 %-plus-blur 96px moves you
   through content (general-interactivity). A carousel moves you through
   content, so this is the black one. Nothing in the system uses turquoise for
   navigation.

   >>> SCOPE, AND WHY THIS BLOCK IS NOT SCOPED. <<<
   `.nectar-drag-indicator` is a BODY-LEVEL SINGLETON. It is not inside
   `.mk-ecology`, so a scoped selector cannot reach it, and there is no version
   of this fix that is local to one section. That is not a defect in the fix —
   it is the finding: a page-global component was being skinned from a section
   file, which is how the wrong paint reached every carousel on the page at once
   (D15 here, D22 in 3.0 Building, D28 in 5.0 Amenities are ONE defect wearing
   three numbers — media-misc.md §9 says so explicitly).

   The correct home is a shared component sheet, `css/myk-cursor.css`, built the
   myk-btn way: one primitive, variants as tokens. That is filed as REQ-ECO-1 in
   founder-trace/SHARED-REQUESTS.md together with the deletion of
   sections/07-building.css lines 386-397. It is a shared surface and this lane
   does not own it.

   Until that lands, the token ships here with ONE added `body ` on each
   selector. The `body` prefix is not style — it is the minimum specificity that
   beats 07-building.css, which compose.py emits AFTER this file, so at the tie
   specificity source order would otherwise hand the page back to Salient's
   opaque disc. Every selector below is (0,n,1) against 07's (0,n,0).
   DELETE THIS WHOLE BLOCK the moment css/myk-cursor.css exists.
   ========================================================================== */

/* --------------------------------------------------------------------------
   WHAT THIS BLOCK DOES AND DOES NOT CLAIM — read before adding to it.

   A SIBLING LANE IS ALSO FIXING THIS CURSOR. `fix:amenities` owns D28 and has
   already tokenised the same component in sections/14-amenities.css
   (`--myk-cursor-gi-size/-blur/-glyph/-inset`, plus the `.blurred-bg` retarget
   from Salient's 12px to the branded 4px). Duplicating that here would be two
   section files fighting over one page-global element, which is the disease,
   not the cure. So this block is deliberately the SMALLEST set that closes D15
   and nothing more:

     · the FILL and its OPACITY  — the two properties D15 actually names, and
       the two 14-amenities.css does NOT set. It relies on Salient's
       server-generated `data-indicator-bg` rule, which this build has no
       equivalent of, so the fill still came from 07-building.css's verbatim
       `background-color: #000`. Opaque. That is the defect.
     · the `:before` OUTLINE RING — Salient's `data-type="default"` variant
       paints a 2px white ring instead of a filled disc. Suppressed here
       unconditionally, see the variant note below.
     · a variant-agnostic BOX FALLBACK — `var(…, fallback)` so the disc is
       still 96px if 14-amenities.css is ever retired.

   THE GLYPHS ARE NOT TOUCHED HERE. The artboard (media-misc §3.3) specifies
   Material `arrow_back_ios`, 11.775 x 20, at x 24.25 and x 60.5; 14-amenities
   renders Salient's icomoon `fa-angle-*` at `font-size: 20px` instead. Both are
   defensible and it is one decision, not two — reconciling them is REQ-ECO-2.

   >>> WHY NOTHING HERE IS SCOPED ON `[data-type="solid"]`. <<<
   Salient decides the singleton's `data-type` from whichever slider it
   initialises FIRST (`$t.prototype.createMarkup`: `data-indicator-bg` present
   => "solid", otherwise "default"), and with several sliders on the page that
   order is not stable across builds. Measured, in two runs of the same probe
   an hour apart: `data-type="solid"` in one and
   `class="nectar-drag-indicator blurred-bg visible"` in the other, because a
   sibling lane changed section 14's attributes in between. A `[data-type]`-
   scoped fix is therefore a fix that works on some builds. This one does not
   depend on it.

   >>> WHY `body ` IS ON EVERY SELECTOR. <<<
   Not style — specificity. compose.py emits 07-building.css AFTER this file,
   so at the tie source order would hand the fill back to Salient's opaque disc.
   Each selector below is (0,n,1) against 07's (0,n,0). DELETE the prefix and
   this block the moment css/myk-cursor.css exists (REQ-ECO-1).
   -------------------------------------------------------------------------- */

:root {
  /* The one token 14-amenities.css does not declare. Same source: the branding
     artboard's general-interactivity cursor, `#000000` @ 50%. */
  --myk-cursor-gi-fill: rgba(0, 0, 0, 0.5);
}

/* THE FIX. `background-color` was `#000` — 100% opaque — and D15 reads
   "Mouse-hover state: wrong colour and opacity."

   >>> THE BOX IS HERE TOO, AND THAT IS NOT DUPLICATION — IT IS A RESCUE. <<<
   `.color-circle` is created by init.js as a bare `<div>`; every geometric
   property it has comes from CSS. In this build the ONLY file that supplied
   them was sections/07-building.css, which had lifted Salient's inline block
   verbatim. The `fix:building-recovery` lane removed that block while closing
   D22, and nothing replaced it — measured live at that moment:

       .color-circle  getBoundingClientRect -> 96 x 0
       computed       width 96px · height 0px · background rgba(0,0,0,.5)

   i.e. correctly PAINTED and zero pixels tall. The disc vanished from the page
   and only the two chevrons rendered; an 80-pixel diff between a hovering and a
   non-hovering capture is what caught it. So this rule restores Salient's own
   box and entrance contract — `.color-circle` is a 100%-square absolutely
   positioned disc that scales in from 0.2 on `.visible` — with the branded
   paint instead of Salient's opaque `#000`. Nothing here is a Mykrobial
   invention; the values other than the fill are Salient's.

   This is the sharpest possible argument for REQ-ECO-1: a page-global element
   whose definition is spread across three section files will lose half of
   itself the first time one of those sections is edited by someone else. */
body .nectar-drag-indicator .color-circle {
  position: absolute;
  left: 0;                                  /* Salient offsets -2px against its 94
                                               box; the branded box is 96, so the
                                               fudge is not carried forward */
  top: 0;
  width: 100%;
  height: 100%;
  display: block;
  border-radius: 50%;
  background-color: var(--myk-cursor-gi-fill);
  /* Salient only applies its blur through `.blurred-bg`, which needs
     `data-indicator-blur="true"` on the slider that CREATED the singleton.
     Declared here too so the blur survives whichever slider wins that race. */
  -webkit-backdrop-filter: blur(var(--myk-cursor-gi-blur, 4px));
          backdrop-filter: blur(var(--myk-cursor-gi-blur, 4px));
  /* Salient's entrance, verbatim: hidden until the pointer enters a slider
     viewport, then scale in. `style-non-critical.css` gates `:before` and the
     glyphs this way but its `.color-circle` gate is scoped to
     `.nectar-view-indicator`, so the drag indicator needs its own. */
  transform: scale(0.2);
  opacity: 0;
  transition: transform 0.45s ease, opacity 0.3s ease;
}
body .nectar-drag-indicator.visible .color-circle { transform: scale(1); opacity: 1; }
/* Salient's press mechanic, verbatim. */
body .nectar-drag-indicator.visible.pointer-down .color-circle { transform: scale(0.15); }

/* Box fallback — only reachable if 14-amenities.css's `[data-type="solid"]`
   rule does not match (i.e. the singleton came up as "default"). */
body .nectar-drag-indicator {
  width:  var(--myk-cursor-gi-size, 96px);
  height: var(--myk-cursor-gi-size, 96px);
  left: calc(var(--myk-cursor-gi-size, 96px) / -2);
  top:  calc(var(--myk-cursor-gi-size, 96px) / -2);
  mix-blend-mode: normal;         /* Salient's base is `difference`, which turns
                                     a 50%-black disc into an inverted smear */
}

/* The `default` variant's 2px white outline ring. The Mykrobial cursor is a
   filled disc in both classes (media-misc §7 rule 1), so the ring never
   applies. `[data-type="solid"]` already hides it in 07-building.css; this
   covers the other variant. */
body .nectar-drag-indicator:before { display: none; }

/* ==========================================================================
   §E2. HUG-WIDTH DRIFT — two boxes hug text that this build renders very
   slightly narrower than Figma does, and both hugs feed a centring/right-pin
   that turns the width error into a HORIZONTAL POSITION error on every glyph.
   Measured at raster scale 2 against sections-en/04-ecology.png:

     element      dx of built vs truth    region MAE @dx=0 -> @best
     h1 left third      +0.50               7.41 -> 1.51
     h1 middle third    +0.50               5.90 -> 1.78
     h1 right third     +0.50               6.06 -> 2.32
     pill label         -0.50              12.37 -> 4.17

   ROOT CAUSE, not a guess: the vendored Merriweather measures the headline at
   1026.922px where Figma measures 1028 (0.105% narrow — the build ships the
   VARIABLE Merriweather, upem 2000, and the Figma file is set in the family
   Figma calls "Merriweather" / style "Light"; confirmed by re-reading
   `get_node_full("2761:2092")` live, which returns bounds {x 126, w 1028}).
   `width: fit-content; margin: 0 auto` then centres a 1026.922 box in the 1040
   content box and lands at L = 126.531 instead of Figma's 126 — so every glyph
   in the headline is half a pixel right. The pill does the mirror image of it:
   it hugs a 286.219px label, is right-pinned to the 120 margin, and therefore
   starts at 837.781 instead of 838.

   The proper fix is the font binary and it is SHELL-OWNED (fonts/ + the
   @font-face block in css/tokens.css) — filed as REQ-MERRIWEATHER-01 in
   review/findings/SHARED-REQUESTS.md. Until that lands, both boxes are pinned
   to the geometry §2 measured, which is the parity gate:

     h1        L = 126  (= 120 margin + Figma's 6px counter-axis CENTER inset)
     CTA pill  W = 322, right edge 1160  =>  L = 838

   Both pins are scoped to >= 1280 so §F's responsive rules (which re-scale the
   headline and re-flow the pill) are untouched. If the font is ever corrected,
   DELETE this block: `margin: 0 auto` and the natural hug then land on 126/838
   by themselves, and these pins would start fighting a correct measurement.
   ========================================================================== */

/* 2026-09-02 — WAS `(min-width: 1280px)`. Below 1280 the base rule's
   `width: fit-content; margin: 0 auto` CENTRED the title; the English
   "Ecological considerations" is as wide as its box so it still read as
   left-aligned, but the shorter Spanish "Factores ecológicos" sat 121px right
   of its own overline at 1200 (measured). The founder: it must land
   left-aligned with "¿Por qué este lugar?". Same rule, every desktop width. */
@media (min-width: 1000px) {
  .mk-page .mk-ecology .mk-ecology__title {
    margin-inline: 6px auto;              /* Figma's literal L = 126 (§2 row 4) */
  }
  .mk-ecology .mk-ecology__cta {
    width: 322px;                         /* §2 row 8 — hug replaced by the measured width */
    --myk-btn-justify: center;            /* myk-btn defaults to MIN/flex-start, which is
                                             right for a hugging box; in a now-FIXED box the
                                             label has to be centred instead */
  }
}

/* TRAILING LETTER-SPACE — the pill label is the one place in this section where
   `letter-spacing` changes a POSITION and not just a width. CSS puts a
   letter-space after the LAST character as well as between characters, so the
   label's advance is 1px wider than the glyph run it draws; centring that
   advance in the pill therefore starts the glyphs half a pixel early. Measured
   at scale 2 after the 322px pin was in: the label still wanted dx -0.5
   (region MAE 10.29 -> 2.83), while the pill box itself was already exactly
   838..1160. Pulling the phantom trailing space back off the flex item's
   margin box re-centres the glyph run on Figma's 999 centre instead of 998.5.
   Not scoped to >= 1280: the phantom space is there at every width.
   Now expressed as `--myk-btn-track-trim: var(--mk-track-nav)` on the button
   (§C above) — the component applies it to whatever element carries the label,
   so the rule that used to live here is gone rather than duplicated. */

/* ==========================================================================
   §F. BELOW 1280 — INFERRED. No Figma frame exists under 1280 (§6.2); every
   rule here states the constraint it is reasoned from and none of it is read.
   ========================================================================== */

@media (max-width: 1279px) {
  /* §6.2: all heights in this section are hand-set, so the only self-consistent
     responsive rule is to preserve the media band's aspect.
     `width: 100%` is required, not tidy-up: `aspect-ratio` combined with the
     lifted `.min-height-475px` resolves the box the OTHER way and inflates the
     width to 475 x (1280/623) = 975.9px. Measured — it produced a 976px
     horizontal overflow at every viewport below 768. */
  /* >>> REPLACED 2026-08-18 (D19/G1). The old rule was
         `height: auto; width: 100%; aspect-ratio: 1280 / 623;`
     — the only self-consistent responsive rule while the band height was a
     hand-set 623. It is no longer self-consistent: G1 says "sections should
     fill the viewport at EVERY breakpoint", and an aspect-locked band under a
     hugging header does not. The band is now the flex remainder at every width
     (§G), so there is nothing to declare here and the overflow trap the old
     comment described (aspect-ratio resolving against `.min-height-475px` and
     inflating the width to 976px) cannot arise: no aspect-ratio is set. */

  /* §6.2: at 96px the headline is 1028 wide and cannot fit a content box below
     ~1030, so it must scale or wrap; scaling keeps it on one line, which §6.1
     reads as the intent. */
  .mk-ecology__title { font-size: clamp(48px, 7.5vw, 96px); line-height: 1.26; }

  /* The 473px copy box is taller than the band once the band follows the
     viewport, so it hugs and the well centres instead. */
  .mk-ecology__copy { height: auto; }
  .mk-ecology .nectar-simple-slider .cell > .inner { justify-content: center; }
  .mk-ecology__copy p { font-size: clamp(20px, 2.6vw, 36px); line-height: 1.8; }
}

@media (max-width: 640px) {
  .mk-ecology__title { font-size: clamp(32px, 11vw, 48px); }
  /* §6.2: the pill and the centred indicator collide once the row is narrower
     than pill + indicator + gap. Drop the pill out of the corner and give the
     dots their own band. */
  /* >>> `relative`, NOT `static` — found and fixed 2026-08-21, lane `r7:ecology`.
     NOT a founder item; found while sweeping R7-10's mobile rung and fixed
     because it is one line in this lane's own file and it is the largest thing
     on the mobile screen.

     THE DEFECT, MEASURED at 390x844 on the served page before the change:
       button box            305.3 x 44   at (42.4, 600.8)
       its ::after ring box  343.2 x 564  at (23.4, 256.8)   <- the whole content well
     `.myk-btn--ring-layer::after` is `position: absolute; inset: -0.5px`
     (myk-btn.css §4, RING RENDERER C). `static` here removed the anchor's own
     containing block, so the ring resolved against the nearest positioned
     ancestor — `.cell > .inner` — and painted a 343x564 rounded rectangle over
     the photograph. Visible in review/r7/r7-ecology/BEFORE-390x844-rest.png,
     gone in AFTER-390x844-rest.png.

     `relative` with no offsets keeps everything this rule wanted — the pill
     leaves the bottom-right corner and re-enters the flow under the copy, which
     is what §6.2 asks for below 640 — and restores the containing block the
     ring renderer needs. It does not move the button by a pixel. */
  .mk-ecology__cta { position: relative; margin-top: var(--mk-space-24); }
  .mk-ecology .nectar-flickity.nectar-simple-slider .flickity-slider .cell { padding-bottom: 72px; }
}


/* ==========================================================================
   §G. THE FOLD — founder defects D14, D17, D18, D19
   ----------------------------------------------------------------------------
   Added 2026-08-18 by lane `fix:ecology`. Everything above this banner predates
   the fold and was written for a single-slide section; everything the fold
   needed is here so the diff is readable and so a reviewer can see exactly what
   the founders' six defects cost in CSS.
   ========================================================================== */

/* --------------------------------------------------------------------------
   §G1. D18 IS RETIRED · R7-11 / R7-12 / R7-13 · lane `r7:ecology`, 2026-08-21
   --------------------------------------------------------------------------
   WHAT USED TO BE HERE, so the deletion is readable rather than mysterious:

     .mk-ecology__title-slot   a zero-ink 121px box that reserved the h1's
                               place in the header band's arithmetic
     .mk-ecology__scroller     `position: absolute; inset: 0` on the stage,
                               carrying Salient's `data-scroll-animation`
                               attributes so init.js wrote
                               `translateX = -(scrollTop - $el.offset().top) * 0.35`
                               on `> .vc_column-inner` every frame
     .mk-ecology__title-rail   our own exit: `transform: translate3d(-100%,0,0)`
                               + `opacity: 0` over 980ms / 560ms

   All three are gone, with their HTML. The founders retired the gesture they
   implemented:

     R7-11  "The 'Ecological considerations' title motion is TOO MASSIVE (it
             flies in from off-screen right). Make it SUBTLE."
     R7-13  "no off-screen travel on the title ... Then BOTH stay put and move
             up naturally with the page into the blue-zone section."

   AND THE APPARATUS WAS PRODUCING R7-12 ON ITS OWN. Two measured mechanisms,
   both from review/r7/r7-ecology/DIAG-BEFORE-1750x980.json and
   FILM-BEFORE-1750x980.json, neither reachable by retuning `intensity`:

     1. AN OUT-OF-FLOW TITLE ON A STICKY STAGE CANNOT RIDE WITH THE PAGE. Its
        viewport top measured 145.0px at every sample from p=0.04 to p=0.96
        while the header band collapsed under it. See the LOCKSTEP RIDE-UP
        block in §B for the full arithmetic and the per-width numbers.
     2. SALIENT'S CONTROLLER SAWTOOTHS AGAINST A PINNED BOX. `$el.offset().top`
        is cached and re-read on its own schedule; against a box that is being
        held at the viewport top it goes stale and snaps. Measured per animation
        frame: the title's left ran -1021.0 -> -959.9 between t=474ms and
        t=483ms — a +61.1px RIGHTWARD JUMP mid-exit, while the rail was still at
        opacity 0.23, i.e. visible. That is the literal "JUMP" in R7-12. The
        controller is not wrong; it was written for static columns, and D18 fed
        it a sticky one.

   The replacement is §H: a one-shot, self-owned entrance with no scroll
   coupling at all. Nothing in this section now asks Salient's scroll-animation
   controller for anything, and `[data-scroll-animation]` appears zero times in
   sections/04-ecology.html.

   THE HEADER BAND'S ARITHMETIC IS REAL AGAIN. With the h1 back in the flow,
   96 + 24 (eyebrow) + 24 (gap) + 121 (h1) + 12 = 277 is MEASURED rather than
   reserved by a spacer, which is why `--myk-eco-head-h` (and now
   `--myk-eco-head-shift`) can be trusted at widths where §F re-scales the
   headline.
   -------------------------------------------------------------------------- */

/* ==========================================================================
   §G1b. THE GENERIC HOLD — for the other two full-screen moments (C03)
   --------------------------------------------------------------------------
   C03 names three: the ecology slider (above), the amenities GALLERY and the
   closing CTA. "be smooth as I go into it, but once I get to it I want that
   full screen thing to PERSIST a little even as I continue scrolling, and then
   let go also very smoothly."

   The mechanic has nothing ecology-specific in it, so it is written here
   section-agnostically and the reader script binds `[data-myk-hold]` generally.
   A section adopts it with TWO attributes and no CSS and no JS of its own:

       <section ... data-myk-hold="1.2" data-myk-stage-on=".its-inner-wrap">
       <div class="its-inner-wrap" data-myk-stage> ... </div>

   `sections/14-amenities.*` and `sections/18-cta-expand.*` belong to other
   lanes this round, so they are NOT edited from here. The adoption patch for
   each is written out in founder-trace/SHARED-REQUESTS.md as REQ-HOLD-1 and
   REQ-HOLD-2. The moment either adds the attribute this rule set is already on
   the page and picks it up.

   WHY THIS IS NOT A SNAP. There is no `scroll-snap-type` here and there must
   never be one: `scroll-snap-type` on a scroll container is what makes the
   viewport jump to a boundary you did not ask for, and it appears ZERO times
   across all five Salient donors. `scroll-snap-align` on 07-building and
   09-recovery-42 is inert without it and stays inert (REQ-SCROLL-01 item 5).
   ========================================================================== */
[data-myk-hold] { position: relative; }
[data-myk-hold] > [data-myk-stage],
[data-myk-hold] [data-myk-stage] {
  position: sticky;
  top: 0;
}

/* --------------------------------------------------------------------------
   §G2. D14 — the two folded-in slides.
   Slide 1's plate is inline on its own .bg-layer (Salient's lazy-bg form, kept
   from the previous build because it is the LCP-adjacent image on this
   section). Slides 2 and 3 are painted here so the `image-set()` art direction
   the retired files carried survives the fold instead of being flattened to a
   single jpeg.
   -------------------------------------------------------------------------- */

/* SLIDE 2 — Figma 2956:1260, imageHash 7aab7eba221d2003b66ed209a49f0628a0683153.
   All seven Figma filters are 0, so the plate ships ungraded. scaleMode FILL ==
   `background-size: cover; background-position: center` — that reproduces the
   payload's imageTransform to 5 decimals (derivation in the retired
   sections/_retired/05-ecology-b.css). The plain url() is the fallback for
   engines without image-set().

   NOT USED, and recorded so the next reader does not "restore" it:
   img/04-ecology/slide-2-valley--e7c79a8d.jpg. That file is the SECOND, occluded
   image fill on 04's own media node 2761:2094 (1554x2000). It is a different
   photograph from 05's band plate — perceptual hashes bdbf36e6 vs 4544d3db —
   so the fold had to choose. It chose the frame the founders pointed at: D14
   folds "slides 2 and 3", and slide 2 IS Figma frame 2956:1256, whose band
   carries 7aab7eba. The occluded fill on 2761:2094 is an authoring leftover. */
.mk-ecology .mk-ecology__bg--valley {
  background-image: url("../img/05-ecology-b/ecology-valley.jpg");
  background-image: image-set(
    url("../img/05-ecology-b/ecology-valley-1280-q95.webp") type("image/webp") 1x,
    url("../img/05-ecology-b/ecology-valley.jpg") 2x);
}

/* SLIDE 3 — Figma 2956:1247. The bytes are NOT a plain Figma export; read the
   header of img/06-ecology-c/_recover-photo.py before touching them. */
.mk-ecology .mk-ecology__bg--coast {
  background-image: url("../img/06-ecology-c/slide-3-coast--75f225cd.webp");
}

/* Salient's lazy-bg loader sets `opacity: 0` on `[data-nectar-lazy-bg]` until it
   runs, and it only walks the first two rows of the page (nectar-delay-
   javascript.js `lazyLoadCriticalMedia`). This section is well below that, so
   without this release the two folded slides render EMPTY until the visitor
   interacts — and a cold parity capture would grade a black band. Exactly the
   trap the retired 06-ecology-c.html documented and avoided by using an inline
   background-image; the paint is in CSS here, so the release is explicit. */
.mk-ecology .nectar-simple-slider .cell > .bg-layer-wrap .bg-layer[data-nectar-lazy-bg] {
  opacity: 1;
}

/* --------------------------------------------------------------------------
   §G3. D17 — "the bottom-right button must CHANGE per slide."
   No new rule is needed for the mechanism: `.mk-ecology__cta` is positioned
   against `.cell > .inner`, and every cell now has its own, so the label is a
   property of the slide rather than of the section. What IS needed is the pin
   below, because §E2 pinned a 322px width for slide 1's string and slide 3's
   is shorter — a fixed 322 would have stretched "Toxins avoidance" into a
   pill Figma never drew (2956:1254 is 322 wide in the EN frame per 06 spec
   §2.1, but that is the frame's own hug of a DIFFERENT string). Each slide
   hugs its own label; only the RIGHT edge is locked, which is what all three
   Figma frames constrain (MAX/MAX) and what lets the ES strings reflow without
   moving the anchor (05 spec §5.3 rule 5).
   -------------------------------------------------------------------------- */
@media (min-width: 1280px) {
  /* Slide 1 keeps §E2's measured 322px pin — it is the parity gate.
     Slides 2 and 3 hug. Slide 2's string is identical to slide 1's, so it lands
     on 322 by itself; asserting it would only hide a future divergence. */
  .mk-ecology__cell--2 .mk-ecology__cta,
  .mk-ecology__cell--3 .mk-ecology__cta {
    width: auto;
    --myk-btn-justify: flex-start;        /* back to the component default: a
                                             hugging box centres its own label */
  }
}

/* --------------------------------------------------------------------------
   §G4. D19 / G1 / G2 — immersive + snap-and-flick.
   The height work is in `.mk-ecology` and `.mk-ecology__media` above. What is
   left is making the flick READ as a flick.
   -------------------------------------------------------------------------- */

/* G2: "a *flick* — whole-slide, never a half-visible in-between". Flickity's
   default is a spring simulation whose tail is long and visibly elastic, which
   is what makes a wheel-driven advance look like a drag.

   >>> R16-01 CORRECTION · 2026-08-28 · lane `r16:sliders` <<<
   This comment used to claim "`.is-flicking` is set by the inline controller
   in the fragment for the length of one advance" — grepped during R16-01:
   ZERO hits for `is-flicking` anywhere in 04-ecology.html. No such mechanism
   exists; that line described an intent that was never built. Corrected here
   rather than left standing, per this project's own doc-authoring discipline.
   `transition: none` is real and load-bearing on its own, for the reason
   directly above: Flickity already writes `.flickity-slider`'s `transform`
   inline on every rAF via its physics loop (`animate()`/`positionSlider()`,
   flickity.q-2dcbd74a85.js). A CSS transition on the SAME property would
   re-trigger under those writes rather than replace them — R14-03
   (founder-trace/helix/R14-03.md) measured exactly this "compounding chase"
   on 07-building and used it DELIBERATELY there to slow a drag-release snap.
   Adding the same trick here would be the wrong fix for a DIFFERENT trigger
   (scroll-derived `select()`, not drag-release) and was correctly avoided.

   The section's real defect ("jumping", "bouncing", a bar on the opposite
   edge) was `.mk-ecology__slider`'s own `data-wrap="true"` (04-ecology.html,
   fixed to `"no-wrap"` at the carousel markup — see that file's own comment
   for the full mechanism and the live measurement). Not this rule. Verified
   this rule needs no change: with the wrap fix landed, a single realistic
   transition settles in 950-1150ms at every one of the five mandated widths
   (review/r16/r16-sliders/eco-settle-time.py; settle duration is governed by
   `selectedAttraction`/`friction`, which are width-independent, so the near-
   identical ms figures across a 390-1750px span are the EXPECTED shape for
   this physics model, not a coincidence) — already inside, or past the slow
   end of, this codebase's own "slow, premium" range (R14-03 cites 0.55-1s).
   Deliberately NOT adding a matching CSS-transition slowdown here, and NOT
   touching `selectedAttraction`/`friction` (Salient hardcodes both, no
   supported per-instance override) — the timing this section already had was
   never the defect; the wrap-driven overshoot was. Full trace:
   founder-trace/helix/R16-01.md. */
.mk-ecology .flickity-slider {
  transition: none;
}

/* The follow-cursor is the affordance that says "this is draggable", and it is
   the only affordance on a slider with no arrows. It must not be suppressed by
   a `cursor: grab` further up the cascade. */
.mk-ecology .flickity-viewport {
  cursor: none;
  height: 100%;
}

/* prefers-reduced-motion: the inline controller already refuses to lock the
   scroll, so the slider must stay reachable by its dots and by keyboard. This
   restores the pointer the rule above removed. */
@media (prefers-reduced-motion: reduce) {
  .mk-ecology .flickity-viewport { cursor: default; }
  /* `.mk-ecology__scroller > .vc_column-inner { transform: none !important }`
     used to be here. Its element no longer exists — §G1. §H's own reduced-motion
     guard replaces it and is written the safe way round: content SHOWN, travel
     dropped. */
}


/* ==========================================================================
   §H. THE R7 ENTRANCE GRAMMAR — founder items R7-11, R7-13, R7-14
   ----------------------------------------------------------------------------
   Lane `r7:ecology`, 2026-08-21. This section owns EVERY entrance inside it.
   That is a deliberate structural choice, not a style: the overline carries
   `data-mv-skip` and so do the three `.mk-ecology__copy` blocks, so
   css/myk-motion.js's page-wide vocabulary adopts nothing in here and there is
   no cross-file cascade to lose. R7-07 reached the founder as "it does look
   like you ignored my feedback" precisely because a fix landed in a file that
   then lost the cascade at a width nobody measured. One owner, one file, five
   widths measured.

   THE FAIL-OPEN CONTRACT, and it is the same one css/myk-motion.css publishes:
   NOTHING here is hidden except under `.mk-eco-anim`, and the inline reader
   adds that class only when `html.mv` is present — i.e. only
   when JavaScript ran AND `prefers-reduced-motion` is not set. No script, no
   start state, no blank section, and every cold fidelity capture is untouched.

   --------------------------------------------------------------------------
   H1. THE HEAD PAIR — "welcome home to the extraordinary", measured.
   --------------------------------------------------------------------------
   R7-11: "Make it SUBTLE: fade + a small leftward settle, matching Omai's
   'welcome home to the extraordinary'. MEASURE that element's CSS live."

   MEASURED, from Omai's own shipped bundle rather than from an impression —
   review/omai/src/main-CZCy3EJJ.js, function `zm()` at byte ~74,700, which is
   the timeline that drives `[data-hero-title]`, the element that renders the
   string "Welcome home to the extraordinary":

       De.set(l, { autoAlpha: 0, x: -20 });                  // words start 20px off, invisible
       const u = De.timeline({ defaults: { ease: "power2.out" } });
       u.to(l, { x: 0, autoAlpha: 1, duration: 1, stagger: .1 });

   Four facts come out of that, and all four are reproduced below:
     · TRAVEL       20px, horizontal. Not 40, not 400. Twenty.
     · DURATION     1000ms.
     · EASING       GSAP `power2.out`. GSAP's power2 is the CUBIC curve, so
                    power2.out is easeOutCubic = cubic-bezier(.215,.61,.355,1).
     · THE FADE RUNS *WHILE* IT MOVES — `autoAlpha` and `x` are properties of
       the SAME tween, one duration, one ease. R7-11 calls this out by name
       ("the fact that it fades WHILE moving"). A fade that finishes before the
       travel does reads as two events; this reads as one gesture.
     · A 100ms STAGGER between successive elements. R7-13 names ~120ms for our
       pair, so 120 is what is used — the founder's number, on the donor's
       mechanism.

   DIRECTION. Omai's own sign is `x: -20 -> 0`, i.e. their words settle to the
   RIGHT. R7-13 asks for the mirror: "the overline ... animates RIGHT-TO-LEFT",
   and R7-11 for "a small leftward settle". So ours starts at +20px and settles
   to 0. The GESTURE is the donor's; the AXIS DIRECTION is the founder's, and
   they are different claims — recorded here so neither is later "corrected"
   into the other.

   WHY `transform` AND NOT `translate`. §0b puts `translate: 0 1px` on both of
   these elements as a first-baseline correction. `transform` composes with it
   instead of destroying it — the same reasoning §0b itself gives, applied the
   other way round. Measured after: the 1px correction is intact at rest.

   NO `will-change`. The h1 is `color: transparent` + `-webkit-text-stroke: 1px`,
   and a permanent compositing hint on a stroked-glyph box can change how that
   hairline rasterises. The transform promotes the layer for the duration of
   the transition by itself and drops it again at `transform: none`, which is
   the state every fidelity capture grades.
   ========================================================================== */

.mk-ecology {
  /* Omai's measured welcome-home gesture. See H1 above for the source lines. */
  --myk-eco-in-travel:  20px;
  --myk-eco-in-dur:     1000ms;
  --myk-eco-in-ease:    cubic-bezier(.215, .61, .355, 1);   /* GSAP power2.out */
  --myk-eco-in-stagger: 120ms;                              /* R7-13's number  */
  /* The blue-zone band runs the PAGE's entrance clock, not Omai's hero clock:
     R7-14 names the black-dress section's grammar, which is this build's
     system-A vocabulary (css/myk-motion.css §1). Two named references, two
     curves, on purpose. */
  --myk-eco-media-ease: cubic-bezier(.4, 0, .2, 1);
}

.mk-eco-anim .mk-ecology__eyebrow,
.mk-eco-anim .mk-ecology__title {
  opacity: 0;
  transform: translate3d(var(--myk-eco-in-travel), 0, 0);
  transition:
    opacity   var(--myk-eco-in-dur) var(--myk-eco-in-ease),
    transform var(--myk-eco-in-dur) var(--myk-eco-in-ease);
}
/* R7-13: "'Ecological considerations' does the SAME, timed slightly AFTER the
   overline (~120ms)." One delay, on both properties, so the pair stays one
   gesture offset in time rather than two gestures. */
.mk-eco-anim .mk-ecology__title {
  transition-delay: var(--myk-eco-in-stagger), var(--myk-eco-in-stagger);
}
.mk-eco-anim[data-myk-eco-in] .mk-ecology__eyebrow,
.mk-eco-anim[data-myk-eco-in] .mk-ecology__title {
  opacity: 1;
  transform: none;
}

/* ==========================================================================
   H2. THE BLUE-ZONE BAND — R7-14.
   ----------------------------------------------------------------------------
   "The blue-zone full-screen section (located in Costa Rica's blue zone /
   microbial wellness / ideal for recovery + the slider) has NO entrance
   animation — her words: 'you skipped any animations.' Apply the same grammar
   the black-dress section now has: text, buttons AND slider fade in and rise
   slightly on entry."

   SHE IS RIGHT, AND HERE IS WHAT WAS ACTUALLY THERE. Measured on the served
   page before this change (review/r7/r7-ecology/FILM-BEFORE-1750x980.json,
   `entrance`), walking the whole section at 120px steps:

       .mk-ecology__cell--1 .mk-ecology__cta     opacity 1.00 at every sample
       .mk-ecology__slider                       opacity 1.00 at every sample
       .mk-ecology__cell--1 .bg-layer            opacity 1.00 at every sample

   The buttons and the slider had no entrance AT ALL — `.myk-btn` is in
   js/myk-motion.js's `SKIP` list by design, and the `media` role is declared in
   the vocabulary but deliberately never adopted. The only thing that DID move
   was the slide copy, at the vocabulary's `body` speed: 200ms, 0 delay. At the
   scale of a full-screen photograph that is a blink, and "blink" and "skipped"
   are the same observation.

   FOUR LAYERS, ONE PER ROLE — Omai's "resolve in layers" (PACING.md §2), which
   is the cheapest way to buy cadence without a scripted stagger:

     photograph + scrim   opacity ONLY, 1000ms, delay   0
     slide copy           opacity + 24px rise, 700ms, delay 120ms
     slide CTA            opacity + 24px rise, 700ms, delay 240ms
     pagination dots      opacity + 16px rise, 700ms, delay 300ms

   THE PHOTOGRAPH DOES NOT RISE, and that is measured doctrine rather than
   taste: PACING.md §2 records Omai's image rule as `opacity` ONLY, 1000ms, no
   transform. A full-bleed background layer that translates has to expose its
   own edge to do it. R7-14's "rise slightly" is honoured by everything drawn
   ON the photograph; the photograph itself fades.

   THE SCRIM RIDES WITH THE PHOTOGRAPH. `.bg-layer-wrap` carries both the
   `.bg-layer` and the `.color-overlay` (the "dip color overlay" the founder
   names), so fading the WRAP keeps the image and its scrim locked together.
   Fading the `.bg-layer` alone would reveal a bare #0d1d23-at-40% wash over the
   section ground on the way in.
   ========================================================================== */

.mk-eco-anim .mk-ecology__cell > .bg-layer-wrap {
  opacity: 0;
  transition: opacity 1000ms var(--myk-eco-media-ease);
}
/* >>> 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" —
   referencing 09-recovery-42.css's own from-white image fade (`opacity`
   only, `.mk-rplan-arrive` -> `.is-arrived`) and 00-hero.css's `mykHeroImg`
   keyframe (opacity 0->1, 1000ms, cubic-bezier(.4,0,.2,1)) as the site's
   established grammar for this. This section already uses exactly that
   curve/duration for cell 1's OWN photograph (`--myk-eco-media-ease:
   cubic-bezier(.4,0,.2,1)`, immediately above in §H2's own token block) —
   R17-09 is "give cells 2 and 3 the SAME treatment cell 1 already has,"
   not a new constant.

   BEFORE THIS CHANGE the rule below matched EVERY cell unconditionally the
   moment `data-myk-eco-media-in` fired once for the section — so cells 2
   and 3, still off-screen at that instant, were already sitting at full
   opacity by the time Flickity ever translated them into view. Nothing
   ever faded on arrival; the "fade in" only ever played for cell 1, and
   only once, at the section's own entrance.

   THE FIX splits this into the two cases that were previously conflated:
     · cell 1 keeps its EXISTING, separately-tuned (R9-08/R10-03) trigger —
       `data-myk-eco-media-in`, fired by the media band's own viewport-
       intersection IO, which times the photo to the SECTION's arrival, not
       to any per-slide selection. Touching that risks reopening timing this
       item was not asked to retune.
     · EVERY cell, cell 1 included, ALSO gets `.mk-hold-media-in` — a
       permanent marker sections/04-ecology.html's shared read() adds to
       `f.slides[want].cells[0].element` the first time that slide is ever
       selected (its own R17-09 comment). This is what actually answers the
       ask for cells 2/3: their FIRST arrival now plays the identical
       1000ms/cubic-bezier(.4,0,.2,1) fade, on the SAME layer (the wrap, so
       the scrim rides with the photograph exactly as §H2's own comment
       above already establishes for cell 1).
   PERMANENT, NEVER REMOVED — "persists" per her own word: once a slide has
   faded in it simply holds at opacity 1 from then on, the same one-shot-
   then-hold discipline `data-myk-eco-media-in` itself already uses; a later
   re-visit shows it already-arrived rather than replaying the fade, which
   avoids re-fading a cell mid-flight through Flickity's own push transition
   (fading the OUTGOING cell's photograph, rather than only ever fading the
   incoming one in, would expose this section's `#e6eef2` ground through the
   departing plate while it is still on screen — not asked for and not
   fixed here).

   `[data-myk-eco-allcells]` IS ALSO LOAD-BEARING HERE, not carried over by
   habit. LIVE-CAUGHT while verifying this item (not assumed): at a mobile
   viewport, `.mk-ecology__slider`'s own Flickity instance can take many
   seconds to construct — sometimes past this drive's own patience — because
   `nectar-delay-javascript.js`'s promotion and `init.js`'s own `new
   Flickity(...)` call are two separate lazy steps. Before this line was
   added, cells 2 and 3 had NO Flickity-independent path to `opacity: 1` —
   only `.mk-hold-media-in`, which Flickity itself has to be alive to ever
   write — so on any load where Flickity is slow or never wakes, cells 2
   and 3 would sit at `opacity: 0` forever, permanently invisible. This is
   the SAME fail-open signal H2b above already uses for the copy (`state.
   syncCells()` sets `data-myk-eco-allcells` once the band has been seen and
   nothing is Flickity-selected yet), extended here so the photograph gets
   the identical guarantee the text already had: content is never hidden
   waiting on JavaScript that might not run. This exact path (Flickity
   present but slow/never-ready) is what this drive actually hit live at
   390x844 and again at 1440x900/1750x980 — see founder-trace/helix/
   R17-sliders.md for the full account, including the widths where the
   dead-band/head-tail mapping itself got a live sweep versus where only
   this fail-open was directly exercised. */
.mk-eco-anim[data-myk-eco-media-in] .mk-ecology__cell--1 > .bg-layer-wrap,
.mk-eco-anim .mk-ecology__cell.mk-hold-media-in > .bg-layer-wrap,
.mk-eco-anim[data-myk-eco-allcells] .mk-ecology__cell > .bg-layer-wrap {
  opacity: 1;
}

/* ----------------------------------------------------------------------------
   H2b. THE PER-SLIDE LAYER — keyed on `.is-selected`, with a measured
   fail-open fallback.
   ----------------------------------------------------------------------------
   Slides 2 and 3 are horizontally off-screen when the band enters, so a
   one-shot reveal of all three cells would play their entrance while they are
   invisible and they would arrive static — "no entrance" for two thirds of the
   component. The reveal is therefore keyed on Flickity's own `.is-selected`,
   which is the same discipline sections/14-amenities.css §4 already uses under
   founder A08 ("animate in" for a slider has to mean EVERY time a slide
   arrives).

   `[data-myk-eco-allcells]` IS THE FAIL-OPEN HALF OF THAT DEPENDENCY, and it
   exists because the dependency was MEASURED to fail. Salient defers init.js
   behind nectar-delay-javascript.js, which promotes only on a TRUSTED gesture;
   on a cold load with no trusted input `window.Flickity` stays undefined and NO
   cell ever carries `.is-selected` (measured directly — see the block above
   `syncCells()` in the fragment). A reveal that required that class would then
   hide the blue-zone copy for ever.

   So the reader watches: band seen + nothing selected -> `data-myk-eco-allcells`
   reveals every cell; Flickity answers -> the attribute is removed and the
   per-slide behaviour takes over, with cell 1 held revealed by `.is-selected`
   and cells 2 and 3 (off-screen right at that instant) re-hidden so they get
   their entrance on arrival. Neither state can strand content, and slide 1
   gets its entrance no matter which order the two arrive in.

   THE OUT IS FAST AND THE IN IS SLOW. A cell that loses `.is-selected` falls
   back to the base rule, so the base rule's 240ms is the LEAVING clock and the
   revealed rule's 700ms is the ARRIVING one. A slide should not spend 700ms
   fading out underneath the slide replacing it.

   `transform` for the copy (it owns `translate: 0 1px` from §0b) and `translate`
   for the CTA (its `.myk-btn--ring-layer::after` owns `translate`, the anchor
   itself does not, and `transform` on an absolutely positioned button is the
   one thing §E2's half-pixel ring correction is sensitive to). Two properties,
   chosen per element by what that element already uses — the same test
   js/myk-motion.js's `travelProp()` applies.
   -------------------------------------------------------------------------- */

.mk-eco-anim .mk-ecology__cell .mk-ecology__copy p {
  opacity: 0;
  transform: translateY(24px);
  transition:
    opacity   240ms var(--myk-eco-media-ease),
    transform 240ms var(--myk-eco-media-ease);
}
.mk-eco-anim[data-myk-eco-media-in] .mk-ecology__cell.is-selected .mk-ecology__copy p,
.mk-eco-anim[data-myk-eco-allcells] .mk-ecology__cell .mk-ecology__copy p {
  opacity: 1;
  transform: none;
  transition:
    opacity   700ms var(--myk-eco-media-ease) 120ms,
    transform 700ms var(--myk-eco-media-ease) 120ms;
}

/* --------------------------------------------------------------------------
   H2c. R8-12 · THE BLUE-ZONE TEXT'S OWN EXIT — "fade up and out", not fade
   back down.
   --------------------------------------------------------------------------
   "Apply the black-dress enter/persist/exit choreography to the blue-zone
   text block: load in -> persist for a while -> as the user continues
   scrolling past, fade UP and OUT, releasing into the next section." Cross-
   referenced against `02-who-why-b.css` §8 (data-myk-hold, the hold-then-
   release pattern) per her explicit pointer, NOT re-derived from scratch.

   LOAD IN and PERSIST already exist and are UNCHANGED by this rule: the base
   pair above (H2b) already rises 24px and fades in over 700ms the first time
   slide 1 is selected, and then holds at opacity 1 / transform none for as
   long as `.is-selected` stays true — which, at the parity viewport, is
   roughly the first half of the 2.4-screen hold track (measured via
   `--myk-hold-p`: slide 1 keeps `.is-selected` from p~0 to p~0.51, i.e.
   ~1,101px of a 2,160px track at 900-tall — a full trackpad swipe of persist,
   not a blink).

   EXIT is what was missing, and what was there was the WRONG DIRECTION: the
   only rule matching a de-selected cell was H2b's OWN pre-entrance base rule
   (`.mk-eco-anim .mk-ecology__cell .mk-ecology__copy p` — opacity 0,
   translateY(+24px)), because losing `.is-selected` simply drops out of the
   higher-specificity "revealed" rule and falls back to it. That base rule is
   correct as a PRE-entrance state (content not yet arrived, waiting 24px
   below rest) and wrong as a POST-exit state (content already left, and the
   founder's own words for that direction are "fade up and out" — the opposite
   sign). Reusing one rule for both meant slide 1's copy, on leaving, sank back
   DOWN into the position it started from instead of rising up and out of the
   frame with the section, which is why "you kinda nailed that parallax vibe
   fading in, fading out" (02-who-why-b) and "no animation" (this element) were
   simultaneously true statements about the same build.

   SCOPED TO SLIDE 1 ONLY — `.mk-ecology__cell--1`, exactly what she named
   ("the blue-zone text block", i.e. the "located in Costa Rica's Blue Zone…"
   slide). Slides 2 and 3 keep H2b's existing behaviour untouched; neither was
   named in this item and changing them here would be scope creep into a
   choreography nobody has reviewed yet.

   THE `:not([data-myk-eco-allcells])` GUARD IS LOAD-BEARING, not decoration.
   Without it this rule's higher specificity would ALSO win over H2b's
   fail-open fallback (deferred Flickity -> reveal every cell) whenever cell 1
   is not the technically-`.is-selected` one, defeating the exact safety net
   H2b §"THE PER-SLIDE GATE" describes. Excluding the attribute outright means
   the two rules can never both try to own the same element: this one only
   ever fires once Flickity is live and genuinely driving slide selection.

   TIMING: 240ms, `var(--myk-eco-media-ease)` — H2b's own documented "the OUT
   is fast, the IN is slow" convention ("A slide should not spend 700ms fading
   out underneath the slide replacing it"), carried forward rather than
   invented. Only the SIGN of the travel changes, from +24px (down, entrance's
   starting point) to -24px (up, the founder's "fade up and out"). */
.mk-eco-anim[data-myk-eco-media-in]:not([data-myk-eco-allcells])
  .mk-ecology__cell--1:not(.is-selected) .mk-ecology__copy p {
  opacity: 0;
  transform: translateY(-24px);
  transition:
    opacity   240ms var(--myk-eco-media-ease),
    transform 240ms var(--myk-eco-media-ease);
}

/* `var(--myk-btn-transition)` is restated FIRST and it is required, not
   defensive: myk-btn.css §1 declares the button's colour/border/ring hover
   clock in a `transition` shorthand at (0,1,0), and this selector is (0,3,0).
   Declaring `transition` here without carrying that value forward would win the
   cascade and silently delete the button's hover glide — trading a founder fix
   for a founder regression on the same element. */
.mk-eco-anim .mk-ecology__cell .mk-ecology__cta {
  opacity: 0;
  translate: 0 24px;
  transition:
    var(--myk-btn-transition),
    opacity   240ms var(--myk-eco-media-ease),
    translate 240ms var(--myk-eco-media-ease);
}
.mk-eco-anim[data-myk-eco-media-in] .mk-ecology__cell.is-selected .mk-ecology__cta,
.mk-eco-anim[data-myk-eco-allcells] .mk-ecology__cell .mk-ecology__cta {
  opacity: 1;
  translate: none;
  transition:
    var(--myk-btn-transition),
    opacity   700ms var(--myk-eco-media-ease) 240ms,
    translate 700ms var(--myk-eco-media-ease) 240ms;
}

/* The dots. BOTH selectors are needed and they are not duplicates: the authored
   `.mk-ecology__dots` is Figma's rest-state copy that removes itself once
   Flickity builds the real `<ol class="flickity-page-dots">`, and which of the
   two is on the page depends on whether init.js has been promoted yet. */
.mk-eco-anim .mk-ecology__media .flickity-page-dots {
  opacity: 0;
  translate: 0 16px;
  transition:
    opacity   700ms var(--myk-eco-media-ease) 300ms,
    translate 700ms var(--myk-eco-media-ease) 300ms;
}
.mk-eco-anim[data-myk-eco-media-in] .mk-ecology__media .flickity-page-dots {
  opacity: 1;
  translate: none;
}

/* ==========================================================================
   H3. REDUCED MOTION — written the SAFE way round.
   ----------------------------------------------------------------------------
   The classes are never added under `prefers-reduced-motion` (js gate), so this
   block is a second belt on top of that: it can only ever SHOW content and drop
   travel, never hide it. css/reduced-motion.css is linked after every section
   sheet and can still beat anything here, and everything here is written so
   that being beaten is harmless.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  /* EVERY element gets its opacity back. R8-12's exit rule is included here —
     same belt-and-suspenders reasoning as the rest of this block: `.mk-eco-anim`
     is only ADDED under normal motion, but the media query is live, so a visitor
     who flips the OS setting mid-scroll must not see slide 1's copy vanish
     upward instead of standing still. */
  .mk-eco-anim .mk-ecology__eyebrow,
  .mk-eco-anim .mk-ecology__title,
  .mk-eco-anim .mk-ecology__cell > .bg-layer-wrap,
  .mk-eco-anim .mk-ecology__cell .mk-ecology__copy p,
  .mk-eco-anim[data-myk-eco-media-in]:not([data-myk-eco-allcells])
    .mk-ecology__cell--1:not(.is-selected) .mk-ecology__copy p,
  .mk-eco-anim .mk-ecology__cell .mk-ecology__cta,
  .mk-eco-anim .mk-ecology__media .flickity-page-dots {
    opacity: 1;
    transition: none;
  }

  /* THE TRAVEL IS RESET PER PROPERTY, AND THIS IS NOT PEDANTRY.
     A blanket `transform: none; translate: none` here would delete §0b's
     `translate: 0 1px` first-baseline correction from the overline, the
     headline and the slide copy — a one-pixel fidelity regression that only
     appears for reduced-motion users, i.e. in the one configuration nobody
     screenshots. Each element is reset ONLY on the property §H actually put
     travel on. */
  .mk-eco-anim .mk-ecology__eyebrow,
  .mk-eco-anim .mk-ecology__title,
  .mk-eco-anim .mk-ecology__cell .mk-ecology__copy p,
  .mk-eco-anim[data-myk-eco-media-in]:not([data-myk-eco-allcells])
    .mk-ecology__cell--1:not(.is-selected) .mk-ecology__copy p { transform: none; }

  .mk-eco-anim .mk-ecology__cell .mk-ecology__cta,
  .mk-eco-anim .mk-ecology__media .flickity-page-dots { translate: none; }

  /* The band still collapses (it is the section's structure, not its motion),
     but the ride-up arrives instantly with it rather than gliding. */
  .mk-ecology__head > .mk-container { transition: none; }
}

/* ==========================================================================
   §I. R8-02 — THE BG-FADE ARRIVAL CUE
   ----------------------------------------------------------------------------
   "I do see that you did a good job with transitioning the background to the
   grayer colour once I scroll down. I'm having a difficult time... determining
   exactly what point that happens... I'm gonna reload it." She was explicit
   she does NOT want different colours — "she did NOT ask for different
   colours — do not change the palette" is this build's own instruction for
   this item. So nothing here touches `--mk-page-bg`, `--mk-bgfade-dur`, or any
   value in the shared `css/mk-bgfade.css` / `js/mk-bgfade.js` pair (single-
   owner files this lane does not touch — SHARED-REQUESTS.md discipline).
   Instead: a SECOND, INDEPENDENT signal that the ground has changed hands,
   entirely local to this section.

   MEASURED, so the fix is aimed at a real number and not an impression
   (`_progress/LEDGER.jsonl`, unit R8-02): the two seams either side of this
   section are WCAG contrast ratios of 1.11 (`#f4f9fb` -> `#e6eef2`, the seam
   into this section) and 1.26 (`#e6eef2` -> `#cbd6dc`, the seam out of it) —
   both far below anything the eye reliably catches in a single glance, which
   is the whole reason "reload and check a couple times" happened. The colours
   are UNCHANGED by this rule; only the cue's own contrast against them is a
   new number, and it is chosen to be clearly visible without reading as a
   design element in its own right (§I2).

   THE TRIGGER is read from `.mk-ecology__stage` crossing 50% of the viewport
   in `04-ecology.html`'s reader script (`ioBg`, next to the existing R7-13/14
   entrance observer) — see that script's own comment for why the STAGE and
   not the SECTION is the observed element, and why threshold 0.5 approximates
   `review/bgfade/MECHANIC.md`'s measured donor trigger ("whichever enrolled
   section owns more of the viewport, floored at 40%" — at the viewport
   midpoint for two similarly-tall adjacent sections). That script sets/clears
   `[data-myk-eco-bgcue]` on the SECTION; everything below just paints it. */

.mk-ecology__bgcue {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;                    /* stage's own bottom edge — MEASURED clear of
                                    both the CTA and the dots at every width and
                                    in both rest/open states: `.cell`'s 48px
                                    top/bottom padding holds `.inner` (and
                                    everything anchored to it) 48px off this
                                    edge regardless of the media band's height. */
  height: 2px;
  z-index: 1;                   /* r8fix:ecology-cue · 2026-08-21 · WITHOUT this
                                    the cue paints 0 pixels: `.mk-ecology__stage`
                                    (position: sticky) is the stacking context;
                                    both this element (position: absolute) and
                                    `.mk-ecology__media` (position: relative) are
                                    z-index:auto positioned descendants, so per
                                    CSS2.1 Appendix E step 6 they paint in TREE
                                    ORDER — media is later in the DOM (line ~284
                                    vs this element's ~217) so its own content
                                    (the carousel's opaque bg-layer, filling the
                                    band down to the stage's bottom edge because
                                    the band's height is calc(100svh - 277px), i.e.
                                    flush with this bar) painted directly over
                                    this 2px strip every time, regardless of its
                                    opacity. A real A/B pixel-diff toggling
                                    [data-myk-eco-bgcue] live and diffing RGB at
                                    the bottom rows measured maxRGBdelta=0 at
                                    every sampled row before this line existed —
                                    see review/r8/r8fix-ecology-cue/. z-index:1
                                    moves this element to CSS2.1 Appendix E step 7
                                    (positive z-index), which always paints after
                                    step 6, so it now paints above media without
                                    needing to move it later in DOM order (moving
                                    DOM order was the other option on the table;
                                    this one touches zero other selectors and
                                    cannot alter any accessibility/DOM-order-
                                    dependent behaviour elsewhere in this file).
                                    pointer-events: none below means this can
                                    never intercept a click even though it now
                                    paints on top. */
  background: var(--mk-ink-strong);     /* #000000 — the section's own eyebrow/
                                            title ink; NOT a new colour token */
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--mk-bgfade-dur, 0.8s) ease;
  /* Deliberately the SAME duration token the real ground fade uses (falls
     back to the measured 0.8s literal if that shared custom property is ever
     absent) — the cue is meant to read as riding WITH the real transition,
     not as a separate, differently-timed effect competing for attention. */
}
[data-myk-eco-bgcue] .mk-ecology__bgcue {
  opacity: 0.18;                /* §I2 — visible at a glance, not a stripe */
}

/* §I2. WHY 0.18 AND 2px. Sampled by eye against both this section's colour
   (#e6eef2) and its neighbours (#f4f9fb, #cbd6dc): a 2px `--mk-ink-strong`
   line at 0.18 opacity is unmistakably present on any of the three grounds
   without reading as a rule, a border, or a piece of content — it sits below
   the visual weight of the page's real hairlines (the dots' own 0.5 opacity,
   §D) so it cannot be mistaken for a UI control. PERSISTENT rather than a
   flash, on purpose (§ above the reader script) — it is the presence/absence
   itself that marks the zone, not a moment to be caught mid-scroll. */

@media (prefers-reduced-motion: reduce) {
  /* The cue still lands (still tells her where the ground handed off), it
     just lands instantly rather than fading — same "show the end state,
     drop the travel" rule the rest of this file's reduced-motion block
     follows. */
  .mk-ecology__bgcue { transition: none; }
}

/* ==========================================================================
   2026-09-02 — SOFT EDGE ON THE SLIDE CHANGE (founder, desktop + Pixel 7):
   "the left/right animation's a little abrupt and a little fast with that
   hard edge" — make it consistent with 14-amenities, whose second frame
   "does appear to fade in". MEASURED before this change (_tools/eyes probe,
   one select() on both devices): 04 travels 99% in 713ms on Salient's stock
   physics (.022/.28), 14 in 197ms on its retuned pair — so speed is not the
   difference she sees; the HARD VERTICAL EDGE between two bright photos is.
   The fix is a crossfade riding on the slide: the cell losing `.is-selected`
   fades out while it leaves, the cell gaining it fades in while it arrives
   (Flickity writes `.is-selected` at the START of travel, so the fade and the
   travel share one clock). Physics untouched. Text choreography untouched.
   During a finger/pointer drag both neighbours stay visible
   (`.is-pointer-down` / `.is-dragging` are Flickity's own classes) so a drag
   never shows an empty stage. Reduced motion: no crossfade, as before. */
@media (prefers-reduced-motion: no-preference) {
  /* The dissolve happens THROUGH the viewport's ground. Rendered first with
     the section's pale ground: both cells at half opacity over light grey
     read as a white flash mid-travel (_tools/_scratch/eyes/xfade-p7 f95).
     Dark ink behind the cells makes the same crossfade read as a dip to
     black — the register 14-amenities' scrimmed photos already sit in. Only
     ever visible during the ~½s the cells are translucent. */
  .mk-ecology .nectar-flickity.nectar-simple-slider.flickity-enabled .flickity-viewport {
    background: var(--mk-ink, #111);
  }
  .mk-ecology .nectar-flickity.nectar-simple-slider.flickity-enabled .flickity-slider .cell {
    transition: opacity 550ms var(--myk-eco-media-ease, cubic-bezier(.22, .61, .36, 1));
  }
  .mk-ecology .nectar-flickity.nectar-simple-slider.flickity-enabled:not(.is-pointer-down):not(.is-dragging) .flickity-slider .cell:not(.is-selected) {
    opacity: 0;
  }
}
