/* SolaryxDev motion layer: the states js/motion.js moves between, on the home and every generated
   page. Loaded after site.css (and page.css). The particle field (field/field.css) and the header
   (the lockup, the island, the actions) are not touched here.

   Every hidden starting state is scoped to html.mo, which motion.js sets only when it runs and the
   reader has not asked for reduced motion, and only on screen: without script, with a script that
   failed, with reduced motion, or in print, every word and figure shows exactly as authored.
   Nothing here changes layout: only opacity, transform, translate, filter, clip-path and paint-only
   layers, so the engine measures the same page it always did.

   Motion tokens: --mo-out is an exponential ease-out for arrivals; springs reuse site.css --spring.
   The effects, where they live, and what they are modelled on (re-implemented, not copied):
     section headings   .mo-float, .mo-ch      letters float up out of their word as the heading
                                               arrives, scrubbed (React Bits ScrollFloat)
     the title          [data-mo="title"]      words resolve from a soft blur as the stars leave for
                                               the rails (React Bits BlurText / GSAP SplitText)
     lead paragraphs    .mo-sw                 each section's first paragraph sharpens and brightens
                                               word by word, scrubbed (React Bits ScrollReveal)
     arrivals           [data-mo="rise"]       cards, list items, rows, buttons and the footer's
                                               columns rise out of a blur in turn (SplitText + BlurText)
     key phrases        .mo-shine              a light sweeps across the trust row, the footer line,
                                               a page's lede, and each kicker once (React Bits ShinyText)
     kickers            [data-mo="scramble"]   the label over a section decrypts once as it arrives
                                               (React Bits DecryptedText)
     the stack          .mo-vel                the marquee follows the scroll's speed and direction
                                               (React Bits ScrollVelocity)
     figures            [data-mo="count"]      proof figures and countdowns count up once (CountUp)
     the chain          [data-mo="chain"]      quote to ledger: the links draw in order
     the footer         .mo-pin                the page holds still at its end while the footer slides
                                               up over it (moveuras.com's footer); motion.js cuts the
                                               held page at the footer's top edge, so the footer's
                                               see-through band (site.css) shows only the night sky
     the index          --mo-p                 a fill along the section index's rail follows the reading
     cards              .mo-card               a light follows the cursor on the border (Aceternity card
                                               spotlight, Magic UI MagicCard); product cards tilt a little
                                               (React Bits TiltedCard)
     primary buttons    .mo-mag                lean toward the cursor, spring back (React Bits Magnet)
     text links         .mo-sweep              the underline fills from the left, leaves to the right
     key cards          .mo-beam               a short light runs round the border while on screen
                                               (Magic UI BorderBeam)
     the white section  --sx, --sy             a soft light and a fine dot grid follow the cursor (site.css;
                                               Aceternity spotlight)
                        [data-mo="wh-*"]       its own arrivals: headings resolve word by word from a blur
                                               (BlurText), rules draw, groups, rows and chart cards come
                                               in turn (SplitText's stagger)
   Smooth wheel scrolling is Lenis (vendor/lenis@1.3.26, MIT), stepped by motion.js. */

:root { --mo-out: cubic-bezier(0.16, 1, 0.3, 1); }

/* the browser's own scrollbar, in the page's colours (colour only: its width, and so the layout,
   stays the platform's) */
html { scrollbar-color: rgba(245, 245, 242, 0.22) #000; }

/* the starting states are applied without transitions (motion.js holds html.mo-init for one style
   pass), so nothing animates away before the reader arrives */
html.mo-init [data-mo], html.mo-init [data-mo] *, html.mo-init [data-mo] *::after { transition: none !important; }

/* split words and letters sit inline as atomic boxes; motion.js keeps a split only if the text's
   box is unchanged by it (each letter keeps the advance it had in the shaped word) */
.mo-w, .mo-fw, .mo-ch { display: inline-block; }
.mo-ch { transform-origin: 50% 0; }
.mo-num { display: inline-block; text-align: right; }

@media screen and (prefers-reduced-motion: no-preference) {
  /* ── the title block ─────────────────────────────────────────────────────────────────────── */
  html.mo [data-mo="title"]:not(.mo-in) .mo-w { opacity: 0; filter: blur(12px); transform: translate3d(0, 0.3em, 0); }
  html.mo [data-mo="title"] .mo-w {
    transition: opacity 0.9s var(--mo-out), filter 1.1s var(--mo-out), transform 1.2s var(--mo-out);
    transition-delay: calc(var(--d, 0ms) + var(--i, 0) * 55ms);
  }
  html.mo [data-mo="title"]:not(.mo-in) > [data-mo-rise] { opacity: 0; transform: translate3d(0, 14px, 0); }
  html.mo [data-mo="title"] > [data-mo-rise] { transition: opacity 0.8s var(--mo-out) var(--d, 0ms), transform 1s var(--mo-out) var(--d, 0ms); }

  /* ── section headings: each word masks its own letters while they float up (the mask reaches
     a little above the word for the overshoot and below it for descenders); at rest it is off ── */
  html.mo .mo-float:not(.mo-rest) .mo-fw { clip-path: inset(-0.6em -0.35em -0.28em -0.35em); }

  /* ── arrivals: hidden until they arrive; the rise itself is a Web Animation (motion.js) ─────── */
  html.mo [data-mo="rise"]:not(.mo-in) { opacity: 0; }

  /* ── figures: the whole figure waits, then arrives counting ─────────────────────────────── */
  html.mo [data-mo="count"]:not(.mo-in) { opacity: 0; }
  html.mo [data-mo="count"] { transition: opacity 0.35s var(--mo-out); }

  /* ── the chain: the home's connectors draw in order, left to right (top to bottom when the
     chain is a column) ──────────────────────────────────────────────────────────────────────── */
  html.mo .art .chain[data-mo="chain"] > li::after {
    transform-origin: 0 50%;
    transition: transform 0.8s var(--mo-out) calc(200ms + var(--i, 0) * 140ms);
  }
  html.mo .art .chain[data-mo="chain"]:not(.mo-in) > li::after { transform: scaleX(0); }
  /* the pages' chain: each card lights in turn, and the hairline after it draws across the gap */
  html.mo .cp .chain[data-mo="chain"] > li:not(:last-child)::after {
    transition: opacity 0.5s var(--mo-out) calc(260ms + var(--i, 0) * 140ms), transform 0.7s var(--mo-out) calc(260ms + var(--i, 0) * 140ms);
  }
  html.mo .cp .chain[data-mo="chain"]:not(.mo-in) > li:not(:last-child)::after { opacity: 0; transform: scaleX(0); }
  html.mo .cp .chain[data-mo="chain"].mo-in > li { animation: mo-pass 1.2s var(--mo-out) calc(var(--i, 0) * 140ms); }

  /* ── the stack: motion.js moves the rows with the scroll, in place of the steady CSS loop ───── */
  html.mo .marq.mo-vel .marq-list { animation: none; }

  /* ── the footer comes over the page: <main> holds still once its foot reaches the foot of the
     screen (motion.js writes --mo-pin, the screen's height less the page's, never above 0) ──── */
  html.mo .mo-pin { position: sticky; top: var(--mo-pin, 0px); }
}
@media screen and (prefers-reduced-motion: no-preference) and (max-width: 899px) {
  html.mo .art .chain[data-mo="chain"] > li::after { transform-origin: 50% 0; }
  html.mo .art .chain[data-mo="chain"]:not(.mo-in) > li::after { transform: scaleY(0); }
}
@keyframes mo-pass { 30% { border-color: rgba(255, 255, 255, 0.42); } }

/* ── key phrases: the text's own colour, with a white band passing through it (paint only; left
   out in forced colours, where a clipped background would hide the text) ─────────────────────── */
@media screen and (prefers-reduced-motion: no-preference) and (forced-colors: none) {
  html.mo .mo-shine {
    background-image: linear-gradient(120deg, var(--mo-sh) 0%, var(--mo-sh) 35%, #fff 50%, var(--mo-sh) 65%, var(--mo-sh) 100%);
    background-size: 200% 100%;
    background-position: 150% 50%;
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
  }
  html.mo .mo-shine-once { animation: mo-shine 1.6s cubic-bezier(0.37, 0, 0.63, 1) both; }
  html.mo .mo-shine-loop { animation: mo-shine-loop 7s linear var(--mo-sh-d, 0s) infinite paused; }
  html.mo .mo-shine-loop.mo-shine-run { animation-play-state: running; }
}
@keyframes mo-shine { from { background-position: 150% 50%; } to { background-position: -50% 50%; } }
@keyframes mo-shine-loop { 0% { background-position: 150% 50%; } 26%, 100% { background-position: -50% 50%; } }

@media (prefers-reduced-motion: no-preference) {
  /* ── the section index: the reading, as a fill along its rail ────────────────────────────── */
  html.mo :is(.art-index, .cp-toc) ol { position: relative; }
  html.mo :is(.art-index, .cp-toc) ol::before {
    content: "";
    position: absolute;
    left: -1px;
    top: 0;
    width: 1px;
    height: 100%;
    background: rgba(245, 245, 242, 0.5);
    transform: scaleY(var(--mo-p, 0));
    transform-origin: 50% 0;
    pointer-events: none;
  }

  /* ── cards: a light under the cursor, on the border and faintly inside; it sits between the
     card's own surface and its text, so the text keeps its contrast ────────────────────────── */
  html.mo .mo-card { position: relative; isolation: isolate; }
  html.mo .mo-spot {
    position: absolute;
    inset: -1px;
    z-index: -1;
    border-radius: inherit;
    pointer-events: none;
    opacity: 0;
    background: radial-gradient(360px circle at var(--mx, 50%) var(--my, 50%), rgba(255, 255, 255, 0.055), transparent 62%);
    transition: opacity 0.45s var(--settle);
  }
  html.mo .mo-spot::before {
    content: "";
    position: absolute;
    inset: 0;
    padding: 1px;
    border-radius: inherit;
    background: radial-gradient(240px circle at var(--mx, 50%) var(--my, 50%), rgba(255, 255, 255, 0.55), transparent 70%);
    -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
    mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
  }
  html.mo .mo-card.mo-hot > .mo-spot { opacity: 1; }
  /* cards lift a little and lean toward the cursor (1.5 degrees, product cards 2.5), and spring back */
  html.mo .mo-tilt { transition: transform 0.9s var(--spring), translate 0.9s var(--spring), background-color 0.2s, border-color 0.2s; }
  html.mo .mo-tilt.mo-hot { translate: 0 -3px; transition: transform 0.3s var(--mo-out), translate 0.35s var(--mo-out), background-color 0.2s, border-color 0.2s; }

  /* ── primary buttons: a lean toward the cursor (translate, so the press scale still applies) ─ */
  html.mo .mo-mag { transition: background-color 0.2s, color 0.2s, box-shadow 0.2s, transform 0.2s var(--settle), opacity 0.2s, translate 0.8s var(--spring); }
  html.mo .mo-mag.mo-hot { transition: background-color 0.2s, color 0.2s, box-shadow 0.2s, transform 0.2s var(--settle), opacity 0.2s, translate 0.25s var(--mo-out); }

  /* ── text links: the resting underline stays; a bright one fills it from the left on hover and
     leaves to the right, one line only (no arrows anywhere, 2026-09-25) */
  html.mo .mo-sweep { position: relative; }
  html.mo .mo-sweep::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    top: 18px;
    height: 1px;
    background: currentColor;
    transform: scaleX(0);
    transform-origin: 100% 50%;
    transition: transform 0.5s var(--mo-out);
    pointer-events: none;
  }
  html.mo .cp-more.mo-sweep::after { top: 20px; }
  html.mo .mo-sweep:hover::after { transform: scaleX(1); transform-origin: 0 50%; }
  html.mo .more.mo-sweep:hover, html.mo .cp-more.mo-sweep:hover { text-decoration-color: rgba(255, 255, 255, 0.3); }
}

/* ── kickers: hidden until they arrive, then they decrypt (motion.js) ─────────────────────────── */
@media screen and (prefers-reduced-motion: no-preference) {
  html.mo [data-mo="scramble"]:not(.mo-in) { opacity: 0; }
  html.mo [data-mo="scramble"] { transition: opacity 0.3s var(--mo-out); }
}

/* ── the beam: a short light runs round the border of a key card while it is on screen ─────────── */
@property --mo-beam { syntax: "<angle>"; inherits: false; initial-value: 0deg; }
@media screen and (prefers-reduced-motion: no-preference) {
  html.mo .mo-beam { position: relative; isolation: isolate; }
  html.mo .mo-beam::after {
    content: "";
    position: absolute;
    inset: -1px;
    padding: 1px;
    border-radius: inherit;
    pointer-events: none;
    background: conic-gradient(from var(--mo-beam), transparent 0 74%, rgba(255, 255, 255, 0.1) 82%, rgba(255, 255, 255, 0.9) 89%, transparent 91%);
    -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
    mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
    animation: mo-beam 7s linear infinite;
    animation-play-state: paused;
  }
  html.mo .mo-beam.mo-beam-run::after { animation-play-state: running; }
}
@keyframes mo-beam { to { --mo-beam: 360deg; } }

/* ── the white section: its own arrivals (motion.js initWhite), once each, as each part arrives ──── */
@media screen and (prefers-reduced-motion: no-preference) {
  .mo-bw { display: inline-block; }
  /* a part's head: the kicker slides in and its rule draws, the heading's words resolve out of a
     blur one after another, the lead follows the last word */
  html.mo [data-mo="wh-head"]:not(.mo-in) .kicker { opacity: 0; transform: translate3d(-12px, 0, 0); }
  html.mo [data-mo="wh-head"] .kicker { transition: opacity 0.6s var(--mo-out), transform 0.8s var(--mo-out); }
  html.mo [data-mo="wh-head"] .wh-n::after { transform-origin: 0 50%; transition: transform 0.9s var(--mo-out) 0.25s; }
  html.mo [data-mo="wh-head"]:not(.mo-in) .wh-n::after { transform: scaleX(0); }
  html.mo [data-mo="wh-head"]:not(.mo-in) .mo-bw { opacity: 0; filter: blur(12px); transform: translate3d(0, 0.34em, 0); }
  html.mo [data-mo="wh-head"] .mo-bw {
    transition: opacity 0.8s var(--mo-out), filter 1s var(--mo-out), transform 1.1s var(--mo-out);
    transition-delay: calc(140ms + var(--i, 0) * 65ms);
  }
  html.mo [data-mo="wh-head"]:not(.mo-in) .wh-lead { opacity: 0; filter: blur(6px); transform: translate3d(0, 16px, 0); }
  html.mo [data-mo="wh-head"] .wh-lead {
    transition: opacity 0.9s var(--mo-out), filter 1s var(--mo-out), transform 1.1s var(--mo-out);
    transition-delay: calc(300ms + var(--n, 6) * 65ms);
  }
  /* Solutions: the four groups in turn; each group's rule and accent draw, then its rows follow */
  html.mo [data-mo="wh-sol"]:not(.mo-in) .sol-h { opacity: 0; transform: translate3d(0, 12px, 0); }
  html.mo [data-mo="wh-sol"] .sol-h { transition: opacity 0.6s var(--mo-out), transform 0.8s var(--mo-out); transition-delay: calc(var(--g, 0) * 120ms); }
  html.mo [data-mo="wh-sol"] .sol-h::after { transform-origin: 0 50%; transition: transform 1s var(--mo-out) calc(var(--g, 0) * 120ms + 160ms); }
  html.mo [data-mo="wh-sol"]:not(.mo-in) .sol-h::after { transform: scaleX(0); }
  html.mo [data-mo="wh-sol"]:not(.mo-in) .sol-group li { opacity: 0; filter: blur(6px); transform: translate3d(0, 18px, 0); }
  html.mo [data-mo="wh-sol"] .sol-group li {
    transition: opacity 0.7s var(--mo-out), filter 0.8s var(--mo-out), transform 0.9s var(--mo-out);
    transition-delay: calc(var(--g, 0) * 120ms + 200ms + var(--i, 0) * 70ms);
  }
  /* By industry: row by row, the right-hand row a beat after the left */
  html.mo [data-mo="wh-rows"]:not(.mo-in) > li { opacity: 0; transform: translate3d(0, 16px, 0); }
  html.mo [data-mo="wh-rows"] > li { transition: opacity 0.7s var(--mo-out), transform 0.9s var(--mo-out); transition-delay: calc(var(--i, 0) * 80ms); }
  /* a chart card rises into focus; its chart then plays (js/charts.js) */
  html.mo [data-mo="wh-card"]:not(.mo-in) { opacity: 0; filter: blur(5px); transform: translate3d(0, 44px, 0) scale(0.98); }
  html.mo [data-mo="wh-card"] {
    transition: opacity 0.8s var(--mo-out) var(--d, 0ms), filter 0.9s var(--mo-out) var(--d, 0ms), transform 1.15s var(--mo-out) var(--d, 0ms),
      translate 0.35s var(--settle), box-shadow 0.35s var(--settle);
  }
  html.mo [data-mo="wh-fade"]:not(.mo-in) { opacity: 0; transform: translate3d(0, 10px, 0); }
  html.mo [data-mo="wh-fade"] { transition: opacity 0.6s var(--mo-out) 0.25s, transform 0.8s var(--mo-out) 0.25s; }
}

/* the white section's cards (Solutions, By industry): the light under the cursor is the accent,
   faint inside and brighter on the border; the lift and the lean keep their shadow in step */
@media (prefers-reduced-motion: no-preference) {
  html.mo .art > .sec--white .mo-spot { background: radial-gradient(320px circle at var(--mx, 50%) var(--my, 50%), rgba(44, 90, 134, 0.07), transparent 62%); }
  html.mo .art > .sec--white .mo-spot::before { background: radial-gradient(220px circle at var(--mx, 50%) var(--my, 50%), rgba(44, 90, 134, 0.62), transparent 70%); }
  html.mo .art > .sec--white .mo-tilt { transition: transform 0.9s var(--spring), translate 0.9s var(--spring), box-shadow 0.45s var(--settle), border-color 0.25s; }
  html.mo .art > .sec--white .mo-tilt.mo-hot { transition: transform 0.3s var(--mo-out), translate 0.35s var(--mo-out), box-shadow 0.35s var(--mo-out), border-color 0.2s; }
}

/* the index's reading fill over the white section */
html[data-astra-white] :is(.art-index) ol::before { background: rgba(11, 11, 12, 0.5); }

@media print {
  .mo-sw, .mo-ch, .mo-bw { opacity: 1 !important; filter: none !important; transform: none !important; }
  .mo-spot { display: none; }
}
