/* Explo Contour Motion, web. Tokens come from motion-tokens.css (generated from motion/explo-motion.json), the
   behaviour from motion.js, the rules from MOTION.md. Loaded last so it can retune the earlier files.
   Five moves: LAND (arrive), STAMP (commit), PING (acknowledge), TRACE (draw, a solid wipe), DRIFT (ambient + depth).
   Colour rule: motion never adds colour. It only moves lightness: cream on night, navy on cream. */

:root { interpolate-size: allow-keywords; }

/* ───────── LAND: scroll reveals ─────────
   A reveal is never a bare fade: it arrives (offset + scale) on the Land spring, which launches fast and settles without
   a bounce. motion.js adds .in and sets --mx-d, a delay that grows with the distance from the middle of the screen. */
.js .rv:not(.in) { opacity: 0; transform: none; transition: none; }
.js .rv.in { opacity: 1; transform: none; transition: none; animation: mx-land var(--mx-spring-land-ms) var(--mx-spring-land) var(--mx-d, 0ms) backwards; }
@keyframes mx-land {
  from { opacity: 0; transform: translateY(var(--mx-land-offset)) scale(var(--mx-land-scale)); }
  to { opacity: 1; transform: none; }
}

/* ───────── TRACE: headlines draw in with a solid wipe ─────────
   A solid fill sweeps across the headline, left to right, like a route being flown. No hatching, no outline: type is
   always solid. motion.js wraps each line in .mx-t. With no JS or no @property support the text is simply solid. */
@property --mx-p { syntax: "<number>"; inherits: false; initial-value: 1; }
.mx-t { display: block; padding-bottom: 0.24em; margin-bottom: -0.24em; } /* the paint box of clipped gradient text must include descenders (g, y, p); the negative margin keeps layout unchanged */
.js .mx-t:not(.mx-done) {
  --mx-p: 0;
  color: transparent; -webkit-background-clip: text; background-clip: text;
  background-image: linear-gradient(90deg, var(--mx-ink) 0, var(--mx-ink) calc(var(--mx-p) * 140% - 40%), transparent calc(var(--mx-p) * 140%));
}
.js .mx-t.mx-run { animation: mx-trace var(--mx-trace-ms, 1100ms) var(--mx-trace) var(--mx-d, 0ms) both; }
@keyframes mx-trace { from { --mx-p: 0; } to { --mx-p: 1; } }

/* ───────── STAMP: buttons commit ─────────
   Press: down to 94% fast. Release: back up on the Stamp spring, which overshoots a hair (a thud, not a wobble).
   Flat on purpose: no glow, no sheen. motion.js adds a one-degree tick on click for the primary button. */
a.btn, button.btn { transition: transform var(--mx-spring-stamp-ms) var(--mx-spring-stamp), background-color 0.2s ease, border-color 0.2s ease; }
a.btn:active, button.btn:active { transform: scale(var(--mx-stamp-down)); transition: transform var(--mx-stamp-down-ms) var(--mx-glide), background-color 0.2s ease, border-color 0.2s ease; }
.faq summary svg { transition: transform var(--mx-spring-stamp-ms) var(--mx-spring-stamp); }

/* ───────── PING: two hairline contour rings from the point of intent ───────── */
.mx-ping { position: fixed; left: 0; top: 0; width: 0; height: 0; z-index: 95; pointer-events: none; --mx-ping-c: rgba(2, 13, 27, 0.78); }
.mx-ping.cream { --mx-ping-c: rgba(216, 216, 203, 0.9); }
.mx-ping i {
  position: absolute; left: calc(var(--mx-ping-size) / -2); top: calc(var(--mx-ping-size) / -2);
  width: var(--mx-ping-size); height: var(--mx-ping-size); border-radius: 50%;
  border: var(--mx-ping-stroke) solid var(--mx-ping-c); opacity: 0;
  animation: mx-ping-s var(--mx-ping-ms) var(--mx-ping) both, mx-ping-o var(--mx-ping-ms) linear both;
}
.mx-ping i:nth-child(2) { animation-delay: var(--mx-ping-gap); }
/* the ring travels on the Ping curve (fast out, long settle) but fades on a straight line, so it stays readable while it grows */
@keyframes mx-ping-s { from { transform: scale(var(--mx-ping-from)); } to { transform: scale(1); } }
@keyframes mx-ping-o { 0% { opacity: var(--mx-ping-alpha); } 40% { opacity: calc(var(--mx-ping-alpha) * 0.6); } 100% { opacity: 0; } }

/* ───────── GLIDE: one pill slides between the nav links on the Glider spring ───────── */
.links { position: relative; }
.links a { position: relative; z-index: 1; }
.js .links a.on { background: none; }                       /* the glider is the highlight now */
.js .links a.on:hover { background: rgba(216, 216, 203, 0.07); }
.mx-glider { position: absolute; left: 0; top: 0; z-index: 0; border-radius: 999px; pointer-events: none; background: rgba(216, 216, 203, 0.11);
  opacity: 0; transform: translate(var(--gx, 0px), var(--gy, 0px)) scale(0.86); width: var(--gw, 0px); height: var(--gh, 0px);
  transition: transform var(--mx-spring-glider-ms) var(--mx-spring-glider), width var(--mx-spring-glider-ms) var(--mx-spring-glider), opacity var(--mx-dur-base) var(--mx-glide); }
.mx-glider.on { opacity: 1; transform: translate(var(--gx, 0px), var(--gy, 0px)) scale(1); }
.mx-glider.still { transition: none; }

/* ───────── DRIFT: depth. Cards stack, phones lag the page ───────── */
.story { transform: scale(calc(1 - var(--mx-depth, 0) * 0.045)); transform-origin: 50% 0; }
.story::after { content: ""; position: absolute; inset: 0; z-index: 4; border-radius: inherit; pointer-events: none; background: rgba(1, 9, 19, 0.62); opacity: calc(var(--mx-depth, 0) * 0.7); }
.phone-wrap { transform: translateY(calc(var(--mx-dy, 0) * 1px)); }

/* ───────── DRIFT: the altimeter. The page is a descent: cruising height at the top, touchdown at the footer ───────── */
.mx-alt { position: fixed; z-index: 40; right: 16px; top: 50%; width: 96px; height: min(300px, 38vh); transform: translateY(-50%); pointer-events: none; opacity: 0; transition: opacity var(--mx-dur-scene) var(--mx-glide); color: #020d1b; font-variant-numeric: tabular-nums; display: none; }
.mx-alt.on { opacity: 1; }
.mx-alt.night { color: #d8d8cb; }
.mx-alt-rail { position: absolute; right: 0; top: 0; bottom: 0; width: 14px; }
.mx-alt-rail::before { content: ""; position: absolute; right: 0; top: 0; bottom: 0; width: 1px; background: currentColor; opacity: 0.22; }
.mx-alt-rail i { position: absolute; right: 0; height: 1px; width: 5px; background: currentColor; opacity: 0.3; }
.mx-alt-rail i.maj { width: 12px; opacity: 0.55; }
.mx-alt-mark { position: absolute; right: 0; top: 0; display: flex; align-items: center; justify-content: flex-end; gap: 8px; height: 0; will-change: transform; }
.mx-alt-mark::after { content: ""; width: 20px; height: 1.5px; background: currentColor; }
.mx-alt-mark b { font-weight: 500; font-size: 12px; letter-spacing: 0.02em; white-space: nowrap; }
.mx-alt-mark small { font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase; opacity: 0.55; margin-left: 3px; }
.mx-alt.landed .mx-alt-mark b { letter-spacing: 0.1em; text-transform: uppercase; font-size: 11px; }
@media (min-width: 1440px) and (hover: hover) { .mx-alt { display: block; } }

/* ───────── FAQ: answers open and close on the Glide curve (progressive: where interpolate-size is missing they just toggle) ───────── */
.faq details::details-content { block-size: 0; overflow: clip; transition: block-size var(--mx-dur-slow) var(--mx-glide), content-visibility var(--mx-dur-slow) allow-discrete; }
.faq details[open]::details-content { block-size: auto; }

/* ───────── HERO: the promise, in motion ─────────
   Both lines are solid and land on the same spring as everything else (the old fade-up is the one thing Rule 1 forbids). */
.js .hero .eyebrow, .js .hero .lead, .js .hero .cta-row { animation-name: mx-land; animation-duration: var(--mx-spring-land-ms); animation-timing-function: var(--mx-spring-land); animation-fill-mode: backwards; }
.js .hero h1 .h-been { animation: mx-land var(--mx-spring-land-ms) var(--mx-spring-land) 0.12s backwards; }
.js .hero h1 .h-next { animation: mx-land var(--mx-spring-land-ms) var(--mx-spring-land) 0.5s backwards; }

/* ───────── GUIDE: picking a country is a View Transition (native, 0 KB; motion.js turns it on only for a deliberate pick) ─────────
   Each card keeps its place. The old card lifts away on Take-off, the new one lands on the Land spring, a beat apart. */
@supports (view-transition-name: none) {
  #g-info { view-transition-name: g-info; } #g-move { view-transition-name: g-move; } #g-wx { view-transition-name: g-wx; }
  #g-visa { view-transition-name: g-visa; } #g-hol { view-transition-name: g-hol; } #g-best { view-transition-name: g-best; }
  ::view-transition-group(root) { animation: none; }
  ::view-transition-old(root), ::view-transition-new(root) { animation: none; mix-blend-mode: normal; }
  ::view-transition-group(g-info), ::view-transition-group(g-move), ::view-transition-group(g-wx),
  ::view-transition-group(g-visa), ::view-transition-group(g-hol), ::view-transition-group(g-best) { animation-duration: var(--mx-dur-slow); animation-timing-function: var(--mx-glide); }
  ::view-transition-old(g-info), ::view-transition-old(g-move), ::view-transition-old(g-wx),
  ::view-transition-old(g-visa), ::view-transition-old(g-hol), ::view-transition-old(g-best) { animation: mx-vt-out var(--mx-dur-base) var(--mx-takeoff) both; mix-blend-mode: normal; }
  ::view-transition-new(g-info), ::view-transition-new(g-move), ::view-transition-new(g-wx),
  ::view-transition-new(g-visa), ::view-transition-new(g-hol), ::view-transition-new(g-best) { animation: mx-land var(--mx-spring-land-ms) var(--mx-spring-land) both; mix-blend-mode: normal; }
  ::view-transition-new(g-move), ::view-transition-new(g-best) { animation-delay: 60ms; }
  ::view-transition-new(g-wx), ::view-transition-new(g-hol) { animation-delay: 120ms; }
  ::view-transition-new(g-visa) { animation-delay: 180ms; }
}
@keyframes mx-vt-out { to { opacity: 0; transform: translateY(-14px) scale(0.985); } }

/* ───────── reduced motion: arrive and fade, nothing travels ───────── */
@media (prefers-reduced-motion: reduce) {
  .js .rv.in { animation: mx-fade 160ms linear backwards; }
  @keyframes mx-fade { from { opacity: 0; } }
  .mx-ping, .mx-alt { display: none !important; }
  .story { transform: none; }
  .story::after { display: none; }
  .phone-wrap { transform: none; }
  .mx-glider { transition: none; }
}
