/* ROOT VPN site motion (2026-09-25). Pairs with /js/motion.js.

   Rules of the road:
   - Everything here is behind html.motion-ready, which only /js/motion.js adds
     (and only when IntersectionObserver exists and reduced motion is off).
     With no JS, a crawler, or reduced motion, every rule below is inert.
   - Only opacity, transform and stroke-dashoffset move. No layout properties.
   - Timings come from the v2 tokens: 420ms fades, 900ms rises on the
     "enter" curve, 180ms hover. Stagger 70ms (40ms in dense lists), capped.
   The selector lists are mirrored from HERO and ITEMS in motion.js. */

/* ── Hidden start states ── */
html.motion-ready :is(
  .hero-v2 .hero-copy > *, .hero-v2 .hero-product,
  .page-intro > *,
  .download-hero > .wrap:first-child > div:first-child > *, .download-hero-art,
  .seo-hero .wrap > *
):not(.mo-in):not(.mo-split) {
  opacity: 0; transform: translate3d(0, 14px, 0);
}
html.motion-ready :is(
  .v2 .section-head > *, .v2 .section-note, .v2 .loc-note, .v2 .segmented-row,
  .list-3 > div, .feature-cards > div, .v2 .plans > .plan, .loc-grid > a,
  .download-strip > .os, .platform-grid > .platform-card, .proof > div, .trust > span,
  .network-facts > div, .network-callout, .network-globe, .honest-media, .cafe,
  .demo-grid > *, .v2 .table-scroll, .v2 .faq > details, .closing .wrap > *,
  .device-lineup, .verify > *, .sharing-grid > *,
  .section-head.reveal > *, .grid.reveal > *, .linkgrid.reveal > li, .faq.reveal > details,
  .reveal:not(.section-head):not(.grid):not(.linkgrid):not(.faq)
):not(.mo-in) {
  opacity: 0; transform: translate3d(0, 20px, 0);
}
/* Large media rises less and settles from a hair smaller: reads as weight, not bounce. */
html.motion-ready :is(.cafe, .honest-media, .network-globe, .device-lineup, .hero-v2 .hero-product, .download-hero-art):not(.mo-in) {
  transform: translate3d(0, 16px, 0) scale(.985);
}

/* ── Entering ── */
html.motion-ready .mo-in:not(.mo-settled) {
  transition: opacity var(--rv-dur-420) var(--rv-easing-standard) var(--mo-d, 0ms),
              transform var(--rv-dur-900) var(--rv-easing-enter) var(--mo-d, 0ms);
}
/* The hero is one short, quick sequence: everything lands inside 900ms. */
html.motion-ready :is(.hero-v2, .page-intro, .download-hero, .seo-hero) .mo-in:not(.mo-settled) {
  transition-duration: var(--rv-dur-420), 640ms;
}
html.motion-ready .mo-instant { transition: none !important; }

/* Multi-line hero headlines rise line by line from behind a mask. The padding
   and matching negative margin keep descenders unclipped with zero layout change. */
.mo-line { display: block; overflow: hidden; padding-bottom: .14em; margin-bottom: -.14em; }
.mo-line__in { display: block; }
html.motion-ready .mo-split:not(.mo-in) .mo-line__in { transform: translate3d(0, 110%, 0); }
html.motion-ready .mo-split.mo-in .mo-line__in {
  transition: transform 640ms var(--rv-easing-enter) var(--mo-d, 0ms);
}

/* Hero product window: the ring fills to Protected, then the route line draws,
   as the window settles. The payoff of the load sequence, and the only one. */
html.motion-ready :is(.hero-v2, .download-hero) .rv-dial[data-static] .rv-dial__progress {
  animation: mo-fill 620ms var(--rv-easing-enter) 300ms both;
}
html.motion-ready :is(.hero-v2, .download-hero) .rv-route__path {
  animation-duration: 520ms; animation-delay: 420ms;
}
@keyframes mo-fill { from { stroke-dashoffset: 100; } to { stroke-dashoffset: 0; } }

/* Hairline grids: the rule above each item draws left to right as it arrives. */
html.motion-ready .list-3 > div { position: relative; border-top-color: transparent; }
html.motion-ready .list-3 > div::after {
  content: ''; position: absolute; top: -1px; left: 0; right: 0; height: 1px;
  background: var(--rv-border-subtle); transform-origin: left center;
  transform: scaleX(0);
}
html.motion-ready .list-3 > div.mo-in::after {
  transform: scaleX(1);
  transition: transform var(--rv-dur-900) var(--rv-easing-enter) calc(var(--mo-d, 0ms) + 80ms);
}
html.motion-ready .list-3 > div.mo-instant::after { transition: none; }

/* Count-up numbers never change width mid-count. */
[data-count] { font-variant-numeric: tabular-nums; }

/* ── Hover and press (all pages, JS or not) ──
   Cards lift 2px and firm up their border; press settles back. Same curve and
   duration everywhere so it reads as one system. */
.feature-cards > div, .v2 .plan, .platform-card, .download-strip a.os, .card.hoverable, .linkgrid a {
  transition: transform var(--rv-dur-180) var(--rv-easing-standard),
              border-color var(--rv-dur-180) var(--rv-easing-standard),
              box-shadow var(--rv-dur-240) var(--rv-easing-standard),
              background-color var(--rv-dur-180) var(--rv-easing-standard);
}
@media (hover: hover) {
  .feature-cards > div:hover, .v2 .plan:hover, .platform-card:hover, .download-strip a.os:hover, .card.hoverable:hover, .linkgrid a:hover {
    transform: translateY(-2px);
    border-color: var(--rv-border-strong);
    box-shadow: 0 18px 36px -24px color-mix(in srgb, var(--rv-neutral-1000) 45%, transparent);
  }
  .v2 .plan.recommended:hover { box-shadow: 0 22px 44px -22px color-mix(in srgb, var(--rv-neutral-1000) 60%, transparent); }
  /* Country rows: the flag nudges toward the click. */
  .loc-grid > a .rv-flag { transition: transform var(--rv-dur-180) var(--rv-easing-standard); }
  .loc-grid > a:hover .rv-flag { transform: translateX(3px); }
}
.feature-cards > div:active, .v2 .plan:active, .platform-card:active, .download-strip a.os:active, .card.hoverable:active, .linkgrid a:active {
  transform: translateY(0) scale(.995);
}
/* FAQ: the answer eases in when a question opens. */
.faq details[open] > .a { animation: mo-open var(--rv-dur-240) var(--rv-easing-enter); }
@keyframes mo-open { from { opacity: 0; transform: translate3d(0, -4px, 0); } }

/* ── Reduced motion: nothing moves (motion.js also never arms itself). ── */
@media (prefers-reduced-motion: reduce) {
  html.motion-ready :is(.mo-in, .mo-line__in) { transition: none !important; }
  .feature-cards > div:hover, .v2 .plan:hover, .platform-card:hover, .download-strip a.os:hover, .card.hoverable:hover, .linkgrid a:hover,
  .loc-grid > a:hover .rv-flag,
  .feature-cards > div:active, .v2 .plan:active, .platform-card:active, .download-strip a.os:active, .card.hoverable:active, .linkgrid a:active { transform: none; }
  .faq details[open] > .a { animation: none; }
}
@media print {
  html.motion-ready :is(.mo-line__in, [style*="--mo-d"]) { transform: none !important; opacity: 1 !important; }
}
