/* ============================================================================
   reduced-motion.css — OUR ACCESSIBILITY OBLIGATION, NOT SALIENT'S
   ----------------------------------------------------------------------------
   Salient has NO `prefers-reduced-motion` handling anywhere in its code path.
   Grepped, not assumed: the string appears zero times across vendor/'s CSS and
   zero times in init.js. Every entrance, parallax and scrub on this page
   therefore runs for a visitor who has asked their OS for less motion.

   This file is loaded LAST — after every section stylesheet — so it can beat a
   section override without any of them having to know it exists.

   TWO RULES GOVERN WHAT IS IN HERE:

   1. Nothing outside `@media (prefers-reduced-motion: reduce)`. The default
      render, and therefore every fidelity measurement, is untouched. If this
      file ever grows a rule at the top level, that rule is a bug.

   2. Reduced motion means SHOW THE FINAL STATE, never "hide the content". Each
      primitive below is disabled by writing its END state, not by cancelling
      the animation and leaving the element at its authored `opacity: 0`. That
      distinction is the whole difference between an accessibility feature and
      a blank page — Salient's entrance primitives all start at opacity 0, so
      `animation: none` alone would erase the page for exactly the visitors
      this is meant to serve.

   `!important` is used deliberately and everywhere here. The values being
   beaten are (a) Salient's own `!important` declarations and (b) inline styles
   that init.js rewrites every animation frame — neither is reachable by
   specificity alone. This is the CONVENTIONS §8.6 case, and the rule being
   beaten is named on each block.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {

  /* ------------------------------------------------------------------------
     1. GLOBAL FLOOR — kill duration on transitions and keyframe animations.
     `0.01ms` rather than `none` on purpose: a zero-duration transition still
     fires `transitionend`, so any Salient handler waiting on that event still
     runs and does not strand the element mid-state. `animation-iteration-count`
     is pinned to 1 so an `infinite` loop (the hero's `ctaMinimaLArrowOuter`,
     the footer logo ticker) runs its final frame and stops rather than being
     cancelled at frame 0.
     ---------------------------------------------------------------------- */
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-delay: 0s !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0s !important;
    scroll-behavior: auto !important;
  }

  /* ------------------------------------------------------------------------
     2. SPLIT HEADINGS — the page's dominant primitive (27 instances).
     Salient's rest state is `opacity: 0` on the wrapper plus
     `transform: translateY(1.3em)` on each generated `.inner`. delay-js may
     not even have rewritten the markup yet, so BOTH the pre-rewrite wrapper
     and the post-rewrite spans have to be shown.
     Beats: css/salient-elements.css
       `[data-animation-type="line-reveal-by-space"]:not(.markup-generated){opacity:0}`
       `[data-animation-type="line-reveal-by-space"] span .inner{transform:translateY(1.3em)}`
     ---------------------------------------------------------------------- */
  .nectar-split-heading,
  .nectar-split-heading[data-animation-type="line-reveal-by-space"],
  .nectar-split-heading[data-animation-type="line-reveal-by-space"]:not(.markup-generated) {
    opacity: 1 !important;
  }
  .nectar-split-heading[data-animation-type="line-reveal-by-space"] span,
  .nectar-split-heading[data-animation-type="line-reveal-by-space"] span .inner {
    transform: none !important;
    -webkit-transform: none !important;
    opacity: 1 !important;
    filter: none !important;
  }
  /* The per-word mask is `overflow: hidden` on the generated span. With the
     letters no longer travelling, the mask has nothing to hide and can only
     clip a descender, so it is released. */
  .nectar-split-heading[data-animation-type="line-reveal-by-space"] > * > span,
  .nectar-split-heading .heading-line {
    overflow: visible !important;
  }
  .nectar-split-heading .heading-line > div {
    transform: none !important;
    -webkit-transform: none !important;
  }

  /* ------------------------------------------------------------------------
     3. BLOCK ENTRANCES — `.wpb_column.has-animation` (41 instances).
     Beats: vendor style.css `.wpb_column.has-animation{opacity:0}` and its
     per-`data-animation` transform siblings (fade-in-from-bottom 75px, etc.).
     ---------------------------------------------------------------------- */
  .wpb_column.has-animation,
  .wpb_column.has-animation[data-animation],
  [class*="animated-in"],
  .has-animation {
    opacity: 1 !important;
    transform: none !important;
    -webkit-transform: none !important;
  }

  /* ------------------------------------------------------------------------
     4. SCROLL-LINKED MOTION — the scrub. 12 `data-scroll-animation` hooks.
     init.js writes `style.transform = "translateY(<n>px) translateZ(0)"` on
     `> .vc_column-inner` on every animation frame, so this is an inline style
     being rewritten continuously; only `!important` reaches it. Scoped to the
     scroll-animation hook so no legitimate static transform is caught.
     Beats: init.js `Pe.prototype.animate` / `ta.prototype.animate`.
     ---------------------------------------------------------------------- */
  [data-scroll-animation="true"],
  [data-scroll-animation="true"] > .vc_column-inner,
  .nectar-el-parallax-scroll[data-scroll-animation="true"],
  .nectar-el-parallax-scroll[data-scroll-animation="true"] > * {
    transform: none !important;
    -webkit-transform: none !important;
    top: auto !important;
  }

  /* ------------------------------------------------------------------------
     5. BACKGROUND PARALLAX. Off on the Figma-pinned image boxes today
     (MEASUREMENT §4.2 ships it as a switch, not a deletion), so this is the
     guard that holds if the founder switches it back on.
     Beats: init.js `qe` / `Ne` parallax controllers, which set both a
     `transform` and a `top` on `.parallax-layer` / `.row-bg`.
     ---------------------------------------------------------------------- */
  .parallax-layer,
  .row-bg.using-image,
  [data-n-parallax-bg="true"] .row-bg,
  [data-n-parallax-bg="true"] .parallax-layer,
  .column-image-bg.parallax-layer {
    transform: none !important;
    -webkit-transform: none !important;
    top: 0 !important;
    height: 100% !important;
  }

  /* ------------------------------------------------------------------------
     6. THE ONE INFINITE LOOP IN THE PAGE'S OWN CSS — the hero scroll cue.
     `.nectar-next-section-wrap.minimal-arrow svg` runs `ctaMinimaLArrowOuter`
     2.5s infinite (sections/00-hero.css PART A.2). Rule 1 already stops it
     after one frame; this states the rest position explicitly so it cannot
     stop mid-travel.
     ---------------------------------------------------------------------- */
  .nectar-next-section-wrap.minimal-arrow svg,
  .nectar-next-section-wrap.minimal-arrow a:hover svg path,
  .nectar-next-section-wrap.minimal-arrow a:hover svg polyline {
    animation: none !important;
    transform: none !important;
  }

  /* ------------------------------------------------------------------------
     7. CAROUSELS AND TICKERS. The DOM keeps working — a flickity slider is
     still swipeable and its dots still work — but nothing moves on its own.
     Autoplay is a JS timer, not CSS, so js/mk-page-runtime.js stops it; this
     only removes the travel animation so a stopped slider does not sit
     mid-transition. Ken Burns is a CSS scale on the slide image.
     ---------------------------------------------------------------------- */
  .flickity-slider,
  .flickity-viewport,
  .swiper-wrapper,
  .nectar-slider-wrap .swiper-slide,
  [data-bg-animation="ken_burns"] .slide-bg-wrap,
  [data-bg-animation="ken_burns"] .image-bg {
    transition: none !important;
    animation: none !important;
  }

  /* ------------------------------------------------------------------------
     8. LAZY-LOAD FADE-IN. Salient fades a lazy image from 0 once it decodes.
     Under reduced motion the image simply appears — but it must APPEAR, which
     is why this is `opacity: 1`, not `transition: none`.
     ---------------------------------------------------------------------- */
  img.nectar-lazy,
  img[data-nectar-img-src],
  .nectar-lazy-loaded {
    opacity: 1 !important;
  }

  /* ------------------------------------------------------------------------
     9. THE EXPANDING CARD — the closing CTA's scroll-scrubbed clip-path.
     sections/18-cta-expand.html + sections/19-cta-contract.html.

     This is the one primitive on the page whose "final state" is genuinely
     ambiguous, so the choice is written down rather than left to the reader.

     THE SCRUB NEVER STARTS. js/mk-expanding-card.js checks
     `prefers-reduced-motion` before it installs and returns early, so nothing
     writes an inline clip-path in the first place. These rules are the CSS
     half — they matter because Salient's own init.js has NO reduced-motion
     handling anywhere (the string appears zero times in vendor/), so if
     init.js is promoted it WILL construct its controllers and start seeking.
     `!important` beats the inline value it writes each frame; that is the
     CONVENTIONS §8.6 case and the rule being beaten is init.js's `je`.

     THE EXPAND ROW IS SHOWN AT ITS END STATE: full bleed, no radius, copy
     centred. That is the money shot, it is Figma keyframe B exactly, and it is
     the state a visitor who asked for less motion should land on.

     THE CONTRACT ROW IS REMOVED FROM THE FLOW. It exists only to carry the
     contraction; with the scrub disabled it is a second, static, full-bleed
     copy of the same photograph directly under the first — 900 px of visual
     repetition that says nothing. "Show the final state" cannot mean "show the
     same picture twice", so this half is dropped rather than frozen.

     CONSEQUENCE, stated because it is a real one: the closing CTA is 900 px
     tall under reduced motion and 1800 px otherwise, so the page is 900 px
     shorter for these visitors. Nothing below the CTA depends on an absolute y
     position, and the fidelity harness measures the default render, so this
     changes no measurement. Recorded in HEIGHT-CHANGE-cta.md §4.
     ---------------------------------------------------------------------- */
  .mk-ctacard--expand .mk-ctacard__row,
  .mk-ctacard--expand .row-bg-wrap > .row-bg-layer {
    clip-path: none !important;
    border-radius: 0 !important;
    transition: none !important;
  }

  .mk-ctacard--contract {
    display: none !important;
  }
}
