/* ==========================================================================
   Motion layer
   --------------------------------------------------------------------------
   Everything here is gated on html.motion, which the inline head script adds
   only when the reader has not asked for reduced motion (and main.js takes
   away again if the animation libraries fail to load). Without it the page
   is the complete static layout in site.css.

   Almost nothing is hidden by CSS: while main.js sets the starting states,
   the loader covers the page. If the scripts never run, the loader removes
   itself after twelve seconds and the resting layout shows.
   ========================================================================== */

/* ----- Lenis (the parts of lenis.css the page relies on) ---------------- */

html.lenis, html.lenis body { height: auto; }
.lenis.lenis-stopped { overflow: clip; }

/* ----- Loader ----------------------------------------------------------- */

.loader { display: none; }

html.motion .loader {
  position: fixed; inset: 0; z-index: 150;
  display: grid; place-items: center;
  pointer-events: none;
  animation: loader-failsafe 0s linear 12s forwards;
}
html.motion.is-loaded .loader { animation: none; }
@keyframes loader-failsafe { to { visibility: hidden; } }

.loader-curtain {
  position: absolute; inset: 0; z-index: -1;
  background: var(--stage);
}
.loader-inner { position: relative; display: grid; place-items: center; }
.loader-mark { width: clamp(6rem, 12vw, 9rem); height: auto; overflow: visible; }
.loader-mark text {
  font-family: var(--font-serif);
  font-size: 132px;
  fill: transparent;
  stroke: var(--bronze);
  stroke-width: 1;
  stroke-dasharray: 520;
  stroke-dashoffset: 520;
}
.loader-count {
  position: fixed; right: var(--gutter); bottom: 1.25rem;
  font-family: var(--font-serif);
  font-size: clamp(3rem, 8vw, 6rem);
  line-height: 1;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}

/* ----- Grain drifts ----------------------------------------------------- */

html.motion .grain { animation: grain .9s steps(6) infinite; }
@keyframes grain {
  0%   { transform: translate(0, 0); }
  20%  { transform: translate(-4%, 3%); }
  40%  { transform: translate(3%, -5%); }
  60%  { transform: translate(-6%, -2%); }
  80%  { transform: translate(5%, 4%); }
  100% { transform: translate(0, 0); }
}

/* ----- Hero: the headline arrives centred, over the dissolve ------------ */

html.motion .hero-headline {
  left: 50%; right: auto; top: 50%; bottom: auto;
  width: min(92vw, 13ch);
  max-width: none;
  transform: translate(-50%, -50%);
  font-size: var(--t-display);
  line-height: 1.02;
  letter-spacing: -.03em;
  text-align: center;
  text-shadow: 0 4px 40px rgba(var(--stage-rgb), .9);
  opacity: 0;
}
html.motion .hero-cue { display: flex; }

@media (max-width: 860px) {
  html.motion .hero-headline { font-size: clamp(2.4rem, 11vw, 3.5rem); }
}

/* ----- Systems: a horizontal track on wide screens ---------------------- */

@media (min-width: 900px) {
  html.motion .systems-pin {
    position: relative;
    height: 100svh;
    display: flex; flex-direction: column; justify-content: center;
    overflow: hidden;
  }
  html.motion .systems-track {
    display: flex; align-items: stretch;
    gap: 1.25rem;
    width: max-content; max-width: none;
    height: min(38rem, 76svh);
    margin: 0;
    padding: 0 var(--gutter);
    will-change: transform;
  }
  html.motion .sys-group {
    flex: 0 0 min(24rem, 30vw);
    flex-direction: column; align-items: flex-start; justify-content: flex-end;
    gap: 1rem;
    padding: 0 2rem 0 2rem;
    border-bottom: 0;
    border-left: 1px solid var(--rule-strong);
  }
  html.motion .sys-group-name { font-size: var(--t-h2); line-height: 1.02; letter-spacing: -.02em; }
  html.motion .sys-card { flex: 0 0 clamp(21rem, 27vw, 26rem); }
  html.motion .sys-end {
    flex: 0 0 min(32rem, 40vw);
    justify-content: center;
    padding: 0 0 0 2rem;
    border-left: 1px solid var(--rule-strong);
  }
  html.motion .systems-meter {
    display: block;
    position: absolute; left: var(--gutter); right: var(--gutter); bottom: 2.25rem;
    height: 1px; background: var(--rule);
  }
  html.motion .systems-meter i {
    position: absolute; inset: 0;
    background: var(--bronze);
    transform: scaleX(0); transform-origin: 0 50%;
  }
}

/* Card arrival: the icon draws, the old way is struck out, the new way
   slides in, the stack follows. .is-in is added once by main.js. */
html.motion .sysicon svg * {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  transition: stroke-dashoffset 1.3s var(--ease-out);
}
html.motion .sys-card.is-in .sysicon svg * { stroke-dashoffset: 0; }

html.motion .delta-from::after {
  transform: scaleX(0);
  transition: transform .7s var(--ease-io) .45s;
}
html.motion .sys-card.is-in .delta-from::after { transform: scaleX(1); }

html.motion .delta-to {
  opacity: 0; transform: translateX(-.75rem);
  transition: opacity .7s var(--ease-out) .75s, transform .9s var(--ease-out) .75s;
}
html.motion .sys-card.is-in .delta-to { opacity: 1; transform: none; }

html.motion .sys-card .stack li {
  opacity: 0; transform: translateY(.5rem);
  transition: opacity .5s var(--ease-out), transform .6s var(--ease-out);
  transition-delay: calc(.9s + var(--i, 0) * 70ms);
}
html.motion .sys-card.is-in .stack li { opacity: 1; transform: none; }

/* Hover mechanics: each mark runs only while its card is hovered. Dash
   values are in pathLength units (main.js sets pathLength="1"). */
html.motion .sys-card.is-in:hover .sysicon--dial .hand { animation: dial 2.4s var(--ease-io) infinite; transform-origin: 20px 20px; }
html.motion .sys-card.is-in:hover .sysicon--scan .scanline { animation: scan 1.8s var(--ease-io) infinite alternate; }
html.motion .sys-card.is-in:hover .sysicon--bars .bar { animation: bars 1.1s var(--ease-io) infinite alternate; transform-origin: 50% 100%; transform-box: fill-box; }
html.motion .sys-card.is-in:hover .sysicon--wave .bar { animation: bars 1.1s var(--ease-io) infinite alternate; transform-origin: 50% 50%; transform-box: fill-box; }
html.motion .sys-card.is-in:hover .sysicon--bars .bar:nth-of-type(2n),
html.motion .sys-card.is-in:hover .sysicon--wave .bar:nth-of-type(2n) { animation-delay: -.55s; }
html.motion .sys-card.is-in:hover .sysicon--slide .rail { animation: rail 2.6s linear infinite; }
html.motion .sys-card.is-in:hover .sysicon--merge .lens-a { animation: lensA 2s var(--ease-io) infinite alternate; }
html.motion .sys-card.is-in:hover .sysicon--merge .lens-b { animation: lensB 2s var(--ease-io) infinite alternate; }
html.motion .sys-card.is-in:hover .sysicon--flow .hot,
html.motion .sys-card.is-in:hover .sysicon--hub .hot,
html.motion .sys-card.is-in:hover .sysicon--draw .hot { stroke-dasharray: .12 .08; animation: flow .9s linear infinite; transition: none; }

@keyframes dial  { to { transform: rotate(360deg); } }
@keyframes scan  { from { transform: translateY(0); } to { transform: translateY(17px); } }
@keyframes bars  { from { transform: scaleY(1); } to { transform: scaleY(.45); } }
@keyframes rail  { to { transform: translateX(-13px); } }
@keyframes lensA { to { transform: translateX(6px); } }
@keyframes lensB { to { transform: translateX(-6px); } }
@keyframes flow  { from { stroke-dashoffset: 0; } to { stroke-dashoffset: -.4; } }

/* ----- Process: one step open at a time, as the scroll reaches it ------- */

html.motion .network-stage, html.motion .network-inner { height: 100svh; min-height: 36rem; }
html.motion .step { --fill: 0; }
html.motion .step-copy { opacity: .42; }
html.motion .step.is-done .step-copy { opacity: .72; }
html.motion .step.is-active .step-copy { opacity: 1; }
html.motion .step-more { grid-template-rows: 0fr; opacity: 0; }
html.motion .step.is-active .step-more { grid-template-rows: 1fr; opacity: 1; }
html.motion .step-n { border-color: rgba(var(--bronze-rgb), .4); color: var(--ink-subtle); }
html.motion .step.is-active .step-n {
  border-color: var(--bronze);
  background: rgba(var(--bronze-rgb), .16);
  color: var(--glow);
  box-shadow: 0 0 0 6px rgba(var(--bronze-rgb), .08), 0 0 26px rgba(var(--bronze-rgb), .45);
}
html.motion .step.is-done .step-n { border-color: var(--bronze); background: var(--bronze); color: var(--stage); }

/* ----- Marquees run on one line ----------------------------------------- */

html.motion .mq-track {
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
}

/* ----- Sub-page arrivals (ui.js adds .is-in once) ------------------------ */

html.motion [data-io] {
  opacity: 0;
  transform: translateY(2rem);
  transition: opacity .9s var(--ease-out), transform 1.1s var(--ease-out);
  transition-delay: calc(var(--d, 0) * 90ms);
}
html.motion [data-io].is-in { opacity: 1; transform: none; }

/* SplitText output */
.split-mask { display: inline-block; overflow: hidden; vertical-align: top; padding-bottom: .08em; margin-bottom: -.08em; }
.split-line { display: block; }
