/* ═══════════════════════════════════════════════════════════════════════
   MOTION SYSTEM  v2
   ═══════════════════════════════════════════════════════════════════════

   Measured on maverick-tourism.com, not guessed at. Their real setup: AOS,
   global duration 600ms, ease-in-out, delay 0, and almost no per-element
   delays. The effect list is small - 128 fade-ups, zoom-in-up on primary
   buttons, fade-right on secondary links.

   What makes theirs feel alive is that EVERY ELEMENT TRIGGERS ON ITS OWN as
   it crosses the line. Nothing waits for its section, so scrolling produces
   one continuous cascade instead of a series of block arrivals.

   v1 of this file grouped by section and gave every element in a section the
   same direction. That is exactly why it read as monotone. v2 fixes three
   things:

     1. DIRECTION VARIES PER ELEMENT, in a deliberate rhythm. Consecutive
        items arrive from different sides, so the eye is led around the page
        rather than pushed one way down it.
     2. SLOWER AND SMOOTHER. 1.35s against v1's 0.95s, on an expo-out curve
        that decelerates far more gently. Longer travel, less blur - past
        about 6px blur reads as muddy rather than soft.
     3. EARLIER TRIGGER, so an element is already moving when it arrives
        rather than starting once it is sitting still.
   ══════════════════════════════════════════════════════════════════════ */

:root{
  /* Expo-out: quick departure, very long gentle settle. Reads as a heavy
     object coming to rest rather than an element switching on. */
  --m-ease: cubic-bezier(.16,1,.3,1);
  /* Critically damped, response about 0.4s. Apple's shipped value for a
     reposition, and the reason nothing here overshoots: the user did not
     throw a button, they pressed it. */
  --m-spring: cubic-bezier(.32,.72,0,1);
  --m-dur: 1.35s;
  --m-step: 130ms;
}

[data-rv]{
  --i: 0;
  transition-property: transform, opacity, filter, clip-path;
  transition-duration: var(--m-dur);
  transition-timing-function: var(--m-ease);
  transition-delay: calc(var(--i) * var(--m-step));
}
/* The compositor hint is armed by JS one screen out and dropped on landing,
   so only a handful of layers exist at any moment. */
[data-rv].arm{ will-change: transform, opacity; }
[data-rv].done{ will-change: auto; }

/* ── directions ───────────────────────────────────────────────────────
   Travel is generous because the curve is slow. A long gentle move reads as
   premium; a short fast one reads as a UI state change. */
[data-rv="up"]    { opacity:0; transform:translate3d(0,64px,0);  filter:blur(5px); }
[data-rv="down"]  { opacity:0; transform:translate3d(0,-52px,0); filter:blur(5px); }
[data-rv="left"]  { opacity:0; transform:translate3d(-78px,0,0); filter:blur(5px); }
[data-rv="right"] { opacity:0; transform:translate3d(78px,0,0);  filter:blur(5px); }

/* Diagonals with a whisper of rotation. This is what stops a grid of cards
   feeling like a spreadsheet arriving. */
[data-rv="tilt-l"]{ opacity:0; transform:translate3d(-62px,46px,0) rotate(-1.8deg); filter:blur(5px); }
[data-rv="tilt-r"]{ opacity:0; transform:translate3d(62px,46px,0) rotate(1.8deg);   filter:blur(5px); }

[data-rv="scale"] { opacity:0; transform:translate3d(0,46px,0) scale(.94); filter:blur(6px); }

/* Buttons: Maverick's zoom-in-up, given weight and a longer settle. */
[data-rv="pop"]{ opacity:0; transform:translate3d(0,32px,0) scale(.86); transition-duration:1.1s; }

/* Media: an expanding wipe with a slow counter-zoom, so the frame opens while
   the picture settles into it. */
[data-rv="clip"]{
  clip-path: inset(16% 12% 16% 12% round 20px);
  opacity:0; transform:translate3d(0,34px,0) scale(1.07);
  transition-duration:1.7s;
}

/* Headings rise out from behind an edge, one line at a time. */
[data-rv="mask"]{ opacity:1; transform:none; filter:none; }
[data-rv="mask"] .mk{
  display:block; overflow:hidden;
  padding:.05em .12em .14em 0; margin-left:-.02em;
}
[data-rv="mask"] .mk > span{
  display:block;
  transform:translate3d(0,112%,0) rotate(2deg);
  transition:transform 1.45s var(--m-ease);
  transition-delay:calc(var(--i) * var(--m-step) + var(--mi,0) * 150ms);
}

/* ── landed ──────────────────────────────────────────────────────────── */
[data-rv].in{ opacity:1; transform:none; filter:none; }
[data-rv="clip"].in{ clip-path:inset(0 0 0 0 round 3px); }
[data-rv="mask"].in .mk > span{ transform:none; }

/* ── the gold rule that closes a heading ─────────────────────────────── */
.m-rule{
  display:block; height:2px; width:min(30%,180px); margin-top:22px;
  background:linear-gradient(90deg,var(--gold),rgba(242,201,76,0));
  transform:scaleX(0); transform-origin:left center;
  transition:transform 1.5s var(--m-ease);
  transition-delay:calc(var(--i) * var(--m-step) + 420ms);
}
[data-rv].in .m-rule, .m-rule.in{ transform:scaleX(1); }

[data-par]{ will-change:transform; }

/* ═══════════════════════════════════════════════════════════════════════
   BUTTON HOVER
   Theirs, measured: the ::after arrow runs `bounce-right 1s INFINITE` on
   hover, the background fills to 80% opacity, and :active scales to .95.

   The infinite bounce reads as restless rather than considered, and filling
   with a second colour made the button look like a different control on
   hover instead of the same one responding.

   So: the GOLD ITSELF LIFTS. A lighter gold, no change of hue, which is what
   a physical surface does when it catches more light. The arrow slides on to
   show direction, and the whole thing rises 1.5px on a contact shadow.
   ══════════════════════════════════════════════════════════════════════ */

@media (hover:hover) and (pointer:fine){
  /* THE PREMIUM HOVER (2026-10-10). Lifts a touch higher, the gradient brightens,
     and a soft warm gold bloom spreads behind the pill - classy, not neon. This is
     the motion layer and loads last, so the bloom here is the one that wins. */
  .cta:hover{
    background-image:linear-gradient(180deg,#FBE394 0%,#F4CE57 52%,#EFC64E 100%);
    transform:translateY(-2px);
    box-shadow:
      inset 0 1px 0 rgba(255,255,255,.72),
      inset 0 -1px 0 rgba(122,93,0,.26),
      0 3px 7px rgba(10,10,10,.22),
      0 20px 36px -12px rgba(10,10,10,.52),
      0 0 26px -2px rgba(242,201,76,.52);
  }
  .cta:hover svg{ transform:translateX(4px); }

  .step{ transition:transform .7s var(--m-ease); }
  .step:hover{ transform:translateX(8px); }
  .incl li{ transition:transform .6s var(--m-ease), background .6s var(--m-ease); }
  .incl li:hover{ transform:translateY(-4px); }
  .bezel{ transition:transform .9s var(--m-ease), box-shadow .9s var(--m-ease); }
  .bezel:hover{ transform:translateY(-5px); }
  /* transform, not padding: animating padding reflows every row below it. */
  .faq__q{ transition:transform .6s var(--m-ease); }
  .faq__row:hover .faq__q{ transform:translateX(9px); }
}

/* Both controls press to the same depth on the same curve, so the whole
   page answers a touch the same way. */
/* The press is the frame that matters, so it is deliberately fast. A control
   that lags the finger stops feeling like an object you touched. */
.cta:active{ transform:scale(.965); transition-duration:.09s;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.3), 0 1px 1px rgba(10,10,10,.2); }

/* ═══ NO JAVASCRIPT, NO BLANK PAGE (2026-09-17) ═══════════════════════════
   Found in the pre-go-live check, and it was site-wide rather than on one
   page: with JavaScript switched off, service-seo.html showed 33 of its 41
   text elements at opacity 0, and the journal index 31 of 33. The pages were
   not slow or degraded. They were blank.

   The cause is that the reveal states above hide [data-rv] unconditionally
   and JavaScript is the only thing that ever adds .in. The older .rv system
   in styles.css was written correctly - it hides only under `.js` - and that
   gate was not carried over when [data-rv] replaced it.

   This matters beyond tidiness. "Pages readable without JavaScript" is listed
   in BUILD-STANDARD.md as shipping with every build we sell, and our own
   audit reports it on other people's sites. Shipping a site that fails it is
   the tool failing its own test, the same way the missing security headers
   did in September.

   Every page sets the .js class from an inline script in <head>, before this
   stylesheet is parsed, so there is no flash: a browser running JavaScript
   never sees these values. The selector matches only when the script did not
   run at all. Mirrors the reduced-motion reset below deliberately - two
   resets that drift apart is how one of them stops working. */
html:not(.js) [data-rv],
html:not(.js) [data-rv] .mk > span,
html:not(.js) .m-rule{
  opacity:1 !important; transform:none !important; filter:none !important;
  clip-path:none !important; transition:none !important;
}
html:not(.js) [data-par]{ transform:none !important; }

@media (prefers-reduced-motion:reduce){
  [data-rv], [data-rv].in, [data-rv] .mk > span, .m-rule{
    opacity:1 !important; transform:none !important; filter:none !important;
    clip-path:none !important; transition:none !important;
  }
  [data-par]{ transform:none !important; }
  .cta, .cta svg{ transition:none !important; }
}
