/* Orbita — motion layer.

   Every rule that hides something is scoped under html.motion. That class is
   set by a two-line inline script in <head>, and only when the reader has not
   asked for stillness — so if the script is blocked, or prefers-reduced-motion
   is on, none of this applies and the page is simply the page.

   Nothing animates for its own sake. Each section reveals in the order it is
   meant to be read, and the pieces that carry meaning (a route on the map, a
   bar in the chart, a stage in the engine) assemble in the order the machine
   would actually do the work. */

:root {
  --rise: cubic-bezier(.16, .86, .28, 1);
  --soft: cubic-bezier(.22, .7, .3, 1);
  --back: cubic-bezier(.2, 1.28, .34, 1);
}

/* ── When the page cannot animate ──────────────────────────────────────── */

/* A CSS transition does not advance while the document is hidden, and an
   embedded browser view can report hidden the entire time it is on screen. Both
   cases used to end the same way: the reveal class lands, the transition never
   runs, and the section stays at opacity 0 for good — a blank page.

   So for as long as the document says it is hidden, transitions are removed
   outright. It has to be transition-property, not a zero duration: a hidden
   document's transitions are pending rather than running, and shortening a
   clock that is not ticking changes nothing — only taking the property out of
   the transition resolves it to its target. Anything revealed during the
   blackout is therefore already at rest when the page comes back.

   Animations are deliberately left alone: the satellites ride an offset-path,
   and cancelling that would park all three at 0%. */
html.motion.still,
html.motion.still *,
html.motion.still *::before,
html.motion.still *::after { transition: none !important; }

/* ── The generic traveller ─────────────────────────────────────────────── */

html.motion [data-rise] {
  opacity: 0;
  transform: translate3d(var(--rx, 0px), var(--ry, 34px), 0) scale(var(--rs, 1));
  transition: opacity .6s var(--soft), transform .88s var(--rise);
}

html.motion [data-rise].in { opacity: 1; transform: none; }

/* Eyebrows arrive from wide tracking and settle — the label tightening into
   place reads as the section locking on. */
html.motion .eyebrow[data-rise] { letter-spacing: .38em; transition: opacity .6s var(--soft), transform .88s var(--rise), letter-spacing 1s var(--rise); }
html.motion .eyebrow[data-rise].in { letter-spacing: .1em; }

/* ── Headings, line by line ────────────────────────────────────────────── */

/* A flex column so the negative margins that pay for the mask's padding do not
   collapse into each other and quietly loosen the leading. */
html.motion .lines { display: flex; flex-direction: column; }
html.motion .lines .ln { display: block; overflow: hidden; padding: .2em 0; margin: -.2em 0; }
html.motion .lines .ln > i { display: block; font-style: normal; transform: translate3d(0, 135%, 0); transition: transform .95s var(--rise); }
html.motion .lines.in .ln > i { transform: none; }

/* ── Nav ───────────────────────────────────────────────────────────────── */

nav { position: sticky; top: 0; z-index: 9; background: var(--cream); transition: height .3s var(--soft), background .3s, box-shadow .3s; }
/* The bar now covers the top of the viewport, so a jump to #bench has to stop
   short of it or the heading lands underneath. */
main > section[id] { scroll-margin-top: 104px; }
html.motion nav.stuck { height: 66px; background: color-mix(in srgb,var(--cream) 91%,transparent); backdrop-filter: blur(11px); box-shadow: 0 1px 0 var(--line), 0 10px 30px color-mix(in srgb,var(--ink) 5%,transparent); }
.nav-links a { position: relative; opacity: .62; transition: opacity .25s; }
.nav-links a:after { content: ""; position: absolute; left: 0; right: 0; bottom: -7px; height: 2px; background: var(--coral); border-radius: 2px; transform: scaleX(0); transform-origin: left; transition: transform .4s var(--rise); }
.nav-links a:hover { opacity: 1; }
.nav-links a.on { opacity: 1; }
.nav-links a.on:after { transform: scaleX(1); }

.scroll-rail { position: fixed; left: 0; right: 0; top: 0; height: 2px; z-index: 11; pointer-events: none; }
.scroll-rail i { display: block; height: 100%; width: 100%; background: linear-gradient(90deg, var(--coral), var(--yellow)); transform: scaleX(0); transform-origin: left; }

/* ── Hero ──────────────────────────────────────────────────────────────── */

html.motion .cosmos .planet { opacity: 0; transform: scale(.16); transition: opacity .5s .1s, transform 1.05s var(--back) .1s; }
html.motion .cosmos.in .planet { opacity: 1; transform: none; }

html.motion .cosmos .ring,
html.motion .cosmos .ring-front { opacity: 0; transform: translate(-50%, -50%) rotate(-25deg) scale(.58); transition: opacity .7s, transform 1.25s var(--rise); }
html.motion .cosmos.in .ring,
html.motion .cosmos.in .ring-front { opacity: 1; transform: translate(-50%, -50%) rotate(-25deg); }
html.motion .cosmos .ring-one { transition-delay: .3s; }
html.motion .cosmos .ring-two { transition-delay: .42s; }
html.motion .cosmos .ring-three { transition-delay: .54s; }
html.motion .cosmos .ring-front { transition-delay: .3s; }

html.motion .cosmos .orbiters,
html.motion .cosmos .well { opacity: 0; transition: opacity .9s .95s; }
html.motion .cosmos.in .orbiters,
html.motion .cosmos.in .well { opacity: 1; }

html.motion .cosmos .star { opacity: 0; transform: scale(.2); transition: opacity .6s var(--soft), transform .8s var(--back); }
html.motion .cosmos.in .star { opacity: 1; transform: none; }
html.motion .cosmos .s1 { transition-delay: .78s; }
html.motion .cosmos .s2 { transition-delay: .88s; }
html.motion .cosmos .s3 { transition-delay: .98s; }
html.motion .cosmos .s4 { transition-delay: 1.08s; }

/* The cards keep their tilt through the entrance; the floating loop in
   script.js is delayed past this so the two never fight over transform. */
html.motion .cosmos .result-card { opacity: 0; transition: opacity .7s var(--soft), transform 1s var(--rise); }
html.motion .cosmos .r-one { transform: rotate(-6deg) translate(34px, 26px) scale(.9); transition-delay: .78s; }
html.motion .cosmos .r-two { transform: rotate(5deg) translate(-34px, 26px) scale(.9); transition-delay: .92s; }
html.motion .cosmos.in .r-one { opacity: 1; transform: rotate(-6deg); }
html.motion .cosmos.in .r-two { opacity: 1; transform: rotate(5deg); }

html.motion .cosmos .orbit-label { opacity: 0; transform: translateY(16px) scale(.88); transition: opacity .6s 1.06s, transform .8s var(--back) 1.06s; }
html.motion .cosmos.in .orbit-label { opacity: 1; transform: none; }

/* ── Why ───────────────────────────────────────────────────────────────── */

html.motion .why-sun { opacity: 0; transform: translate(-50%, -50%) scale(.1); transition: opacity .5s, transform 1s var(--back); }
html.motion .why-art.in .why-sun { opacity: 1; transform: translate(-50%, -50%); }
html.motion .why-orbit { opacity: 0; transform: translate(-50%, -50%) rotate(-33deg) scale(.6); transition: opacity .7s, transform 1.2s var(--rise); }
html.motion .why-art.in .why-orbit { opacity: 1; transform: translate(-50%, -50%) rotate(-33deg); }
html.motion .why-art .o1 { transition-delay: .16s; }
html.motion .why-art .o2 { transition-delay: .28s; }
html.motion .why-dot { opacity: 0; transform: scale(.2); transition: opacity .5s, transform .75s var(--back); }
html.motion .why-art.in .why-dot { opacity: 1; transform: none; }
html.motion .why-art .d1 { transition-delay: .5s; }
html.motion .why-art .d2 { transition-delay: .62s; }
html.motion .why-art .d3 { transition-delay: .74s; }

/* ── Cards ─────────────────────────────────────────────────────────────── */

/* The mark in each card assembles after the card lands, so you read the number
   and the title first and the ornament second. */
html.motion .cards .symbol > * { opacity: 0; transform: scale(.35); transition: opacity .5s var(--soft), transform .8s var(--back); }
html.motion .cards article.in .symbol > * { opacity: 1; transform: none; }
html.motion .cards .loops i { transform: rotate(-30deg) scale(.35); }
html.motion .cards article.in .loops i { transform: rotate(-30deg); }
html.motion .cards .pulse b { transform: rotate(-15deg) scaleX(0); transform-origin: left; }
html.motion .cards article.in .pulse b { transform: rotate(-15deg); }
html.motion .cards .symbol > :nth-child(1) { transition-delay: .34s; }
html.motion .cards .symbol > :nth-child(2) { transition-delay: .42s; }
html.motion .cards .symbol > :nth-child(3) { transition-delay: .5s; }
html.motion .cards .symbol > :nth-child(4) { transition-delay: .58s; }
html.motion .cards .symbol > :nth-child(5) { transition-delay: .66s; }

/* ── Engine ────────────────────────────────────────────────────────────── */

/* Dots and hand-off arrows arrive after their compact pipeline cards. */
html.motion .stages li:before { transform: scale(0); transition: transform .5s var(--back); }
html.motion .stages li:after { opacity: 0; scale: .7; transition: opacity .35s var(--soft), scale .5s var(--back); }
html.motion .stages li.in:before { transform: none; }
html.motion .stages li.in:after { opacity: 1; scale: 1; }

/* ── API ───────────────────────────────────────────────────────────────── */

html.motion .api-orb i { opacity: 0; transition: opacity .6s, transform 1.1s var(--rise); }
html.motion .api-orb i:nth-child(1) { transform: rotate(-30deg) scale(.55); }
html.motion .api-orb i:nth-child(2) { transform: rotate(30deg) scale(.55); transition-delay: .12s; }
html.motion .api-orb i:nth-child(3) { transform: rotate(38deg) scale(.55); transition-delay: .24s; }
html.motion .api-orb b { opacity: 0; transform: scale(.2); transition: opacity .5s .36s, transform .8s var(--back) .36s; }
html.motion .api-orb.in i:nth-child(1) { opacity: 1; transform: rotate(-30deg); }
html.motion .api-orb.in i:nth-child(2) { opacity: 1; transform: rotate(30deg); }
html.motion .api-orb.in i:nth-child(3) { opacity: 1; transform: rotate(38deg); }
html.motion .api-orb.in b { opacity: 1; transform: none; }

/* The call types itself out a line at a time. Each line is wiped in from the
   left rather than rendered character by character — same read, one paint. */
html.motion .api-code code.typed { display: block; }
html.motion .api-code code.typed .cl { display: block; min-height: 1.55em; clip-path: inset(0 100% 0 0); transition: clip-path .42s linear; }
html.motion .api-code code.typed.in .cl { clip-path: inset(0 0 0 0); }
html.motion .api-code code.typed .caret { display: inline-block; width: 8px; height: 1em; background: var(--yellow); vertical-align: -.14em; margin-left: 2px; opacity: 0; }
html.motion .api-code code.typed.in .caret { opacity: 1; animation: caret-blink 1.05s steps(1) infinite; }
@keyframes caret-blink { 0%, 49% { opacity: 1 } 50%, 100% { opacity: 0 } }

/* ── Reach map ─────────────────────────────────────────────────────────── */

/* The map builds the way the question travels: the ground first, then the
   distance rings, then the bearings, then each route out to its city. */
html.motion #reach-map .r-land { opacity: 0; transition: opacity 1.1s var(--soft); }
html.motion #reach-map.on .r-land { opacity: 1; }

html.motion #reach-map .r-ring { transform: scale(0); transform-origin: 270px 270px; transition: transform .9s var(--rise) var(--d, 0s); }
html.motion #reach-map.on .r-ring { transform: none; }
html.motion #reach-map .r-ms { opacity: 0; transition: opacity .5s calc(var(--d, 0s) + .35s); }
html.motion #reach-map.on .r-ms { opacity: 1; }

html.motion #reach-map .r-spoke { stroke-dasharray: 210; stroke-dashoffset: 210; transition: stroke-dashoffset .8s var(--rise) var(--d, 0s); }
html.motion #reach-map.on .r-spoke { stroke-dashoffset: 0; }

html.motion #reach-map .r-route { stroke-dasharray: var(--len, 260); stroke-dashoffset: var(--len, 260); transition: stroke-dashoffset .72s var(--rise) var(--d, 0s), stroke-opacity .25s, stroke-width .25s; }
html.motion #reach-map.on .r-route { stroke-dashoffset: 0; }
html.motion #reach-map .r-dot { transform: scale(0); transform-box: fill-box; transform-origin: center; transition: transform .6s var(--back) calc(var(--d, 0s) + .5s), r .25s; }
html.motion #reach-map.on .r-dot { transform: none; }
html.motion #reach-map .r-lab,
html.motion #reach-map .r-city polyline { opacity: 0; transition: opacity .5s calc(var(--d, 0s) + .62s); }
html.motion #reach-map.on .r-lab,
html.motion #reach-map.on .r-city polyline { opacity: 1; } /* the leader's own fade lives in stroke-opacity */
html.motion #reach-map .r-home { transform: scale(0); transform-box: fill-box; transform-origin: center; transition: transform .8s var(--back) .3s; }
html.motion #reach-map.on .r-home { transform: none; }

/* The read-out under the copy fills the same way the bar does. */
html.motion .reach-bar i { transition: width .55s var(--rise); }

/* ── Bench ─────────────────────────────────────────────────────────────── */

html.motion .bench-pick li { opacity: 0; transform: translateX(-14px); transition: opacity .5s var(--soft), transform .7s var(--rise); }
html.motion .bench-pick.in li { opacity: 1; transform: none; }
html.motion .bench-pick li:nth-child(1) { transition-delay: .06s }
html.motion .bench-pick li:nth-child(2) { transition-delay: .13s }
html.motion .bench-pick li:nth-child(3) { transition-delay: .2s }
html.motion .bench-pick li:nth-child(4) { transition-delay: .27s }
html.motion .bench-pick li:nth-child(5) { transition-delay: .34s }

/* Columns leave downward before the next metric draws, so switching reads as
   one chart changing its mind rather than two charts cross-fading. */
.chart-plot { --cols: 5; grid-template-columns: repeat(var(--cols), 1fr); }
.chart-plot.out .bar { height: 0 !important; transition: height .22s cubic-bezier(.5, 0, .75, 0); }
.chart-plot.out .v, .chart-plot.out .nm { opacity: 0; transition: opacity .16s; }
.col .bar { transform-origin: bottom; }
.col .nm { transition: opacity .4s .25s; }

/* ── Machine ───────────────────────────────────────────────────────────── */

html.motion .machine-art .field i { opacity: 0; scale: .25; transition: opacity .45s var(--soft), scale .6s var(--back); animation-play-state: paused; }
html.motion .machine-art .field.in i { opacity: 1; scale: 1; animation-play-state: running; }

/* ── Price ─────────────────────────────────────────────────────────────── */


html.motion .mode-card { transition: opacity .6s var(--soft), transform .85s var(--rise), translate .25s, border-color .25s, box-shadow .35s; }
html.motion .mode-card:nth-child(1) { transition-delay: .03s }
html.motion .mode-card:nth-child(2) { transition-delay: .10s }
html.motion .mode-card:nth-child(3) { transition-delay: .17s }
html.motion .mode-card:nth-child(4) { transition-delay: .24s }
html.motion .mode-card:nth-child(5) { transition-delay: .31s }
html.motion .mode-card:nth-child(6) { transition-delay: .38s }
html.motion .price-proof { transition: opacity .6s var(--soft), transform .8s var(--rise); }

/* ── Language swap ─────────────────────────────────────────────────────── */

/* The existing .swapping fade covers the exchange; headings then replay their
   line reveal in the new language, which is the point of the pause. The fade
   has to be re-stated: [data-rise] gives translated nodes a .6s opacity ramp,
   and the swap only holds them hidden for 175 ms. */
html.motion.swapping [data-i18n] { transition: opacity .16s ease; }
html.swapping .lines .ln > i { transform: translate3d(0, 135%, 0); transition: none; }

@media (max-width: 800px) {
  html.motion nav.stuck { height: 60px; }
}

/* The header should float cleanly over the page: no permanent rule and no
   sticky-state hairline at the viewport edge. */
nav { border-bottom: 0 !important; }
html.motion nav.stuck { box-shadow: none; }

/* A sticky navigation shadow, not a rectangular glass panel. The full-width
   fade has no visible side or bottom edge and dissolves into the page. */
html.motion nav.stuck {
  background: transparent;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  box-shadow: none;
  isolation: isolate;
}
html.motion nav.stuck::before {
  content: "";
  position: absolute;
  z-index: -1;
  top: -10px;
  left: 50%;
  width: 100vw;
  height: calc(100% + 38px);
  pointer-events: none;
  transform: translateX(-50%);
  background: linear-gradient(to bottom,
    color-mix(in srgb,var(--cream) 96%,transparent) 0%,
    color-mix(in srgb,var(--cream) 78%,transparent) 48%,
    transparent 100%);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  -webkit-mask-image: linear-gradient(to bottom,#000 0 58%,transparent 100%);
  mask-image: linear-gradient(to bottom,#000 0 58%,transparent 100%);
}
html.motion nav:not(.stuck)::before { content: none; }

/* Never restore the old coloured top rule on the final CTA. */
.cta::before { content: none !important; }
