/* Ordis AI v2: motion layer (builder B). Pending looks exist only under html.js, so content never depends
   on JavaScript; the kill switch at the end turns every CSS animation and transition into its final state. */

/* Cross-document view transitions. Must sit outside @layer to take effect. */
@view-transition { navigation: auto; }

@layer motion {
  /* ---------- View transitions: root cross-fade with a small rise; the header stays put ---------- */
  .site-header { view-transition-name: site-header; }
  ::view-transition-old(root) { animation: vt-out var(--d-sm) var(--ease-ui) both; }
  ::view-transition-new(root) { animation: vt-in var(--d-sm) var(--ease-out) both; }
  @keyframes vt-out { to { opacity: 0; } }
  @keyframes vt-in { from { opacity: 0; transform: translateY(12px); } }

  /* ---------- Lenis (rules from lenis.css, Lenis by darkroom.engineering, MIT licence) ---------- */
  html.lenis, html.lenis body { height: auto; }
  .lenis:not(.lenis-autoToggle).lenis-stopped { overflow: clip; }
  .lenis [data-lenis-prevent],
  .lenis [data-lenis-prevent-wheel],
  .lenis [data-lenis-prevent-touch],
  .lenis [data-lenis-prevent-vertical],
  .lenis [data-lenis-prevent-horizontal] { overscroll-behavior: contain; }
  .lenis.lenis-smooth iframe { pointer-events: none; }
  .lenis.lenis-autoToggle { transition-property: overflow; transition-duration: 1ms; transition-behavior: allow-discrete; }

  /* ---------- data-reveal ----------
     JS adds .is-armed (transition on) and .is-pending (hidden look) to blocks below the fold only, then drops
     .is-pending at 15% visible. .is-armed comes off after the reveal so component hover transitions return. */
  html.js [data-reveal].is-armed {
    transition: opacity var(--d-md) var(--ease-out), transform var(--d-md) var(--ease-out);
  }
  html.js [data-reveal=""].is-pending,
  html.js [data-reveal="rise"].is-pending { opacity: 0; transform: translateY(24px); }
  html.js [data-reveal="fade"].is-pending { opacity: 0; }
  html.js [data-reveal="scale"].is-pending { opacity: 0; transform: scale(.96); }

  /* stagger: the children move; --i is set per child by reveal.js, --stagger-step keeps the total within .5s */
  html.js [data-reveal="stagger"].is-armed > * {
    transition: opacity var(--d-md) var(--ease-out), transform var(--d-md) var(--ease-out);
    transition-delay: calc(var(--i, 0) * var(--stagger-step, 80ms));
  }
  html.js [data-reveal="stagger"].is-pending > * { opacity: 0; transform: translateY(16px); }
  /* custom: no default look; page CSS styles its own .is-pending state */

  /* ---------- data-split: SplitText line masks. The padding keeps descenders out of the clip ---------- */
  .split-line-mask { padding-bottom: .12em; margin-bottom: -.12em; }
  .split-line { will-change: transform; }

  /* ---------- data-odo: one digit strip per digit, rolled by --n ---------- */
  .odo { display: inline-flex; align-items: flex-start; line-height: 1.1; font-variant-numeric: tabular-nums; white-space: nowrap; }
  .odo__d { display: inline-block; height: 1.1em; overflow: clip; }
  .odo__strip {
    display: flex; flex-direction: column;
    transform: translateY(calc(var(--n, 0) * -1.1em));
    transition: transform var(--d-md) var(--ease-out);
    transition-delay: calc(var(--k, 0) * 40ms);
  }
  .odo__strip > span, .odo__s { display: block; height: 1.1em; }
  .odo__s { display: inline-block; }

  /* ---------- data-scramble: glyphs still decoding are dimmer; the real text sits in a .vh twin ---------- */
  .scramble__g { color: var(--ink-3); }

  /* ---------- data-scrub-words: --w (0..1, tweened per word) mixes --ink-3 into --ink; default full ink ---------- */
  .scrub-word { color: color-mix(in srgb, var(--ink) calc(var(--w, 1) * 100%), var(--ink-3)); }

  /* ---------- data-typer: lines wipe in one by one with stepped clip (the text never leaves the DOM) ---------- */
  html.js [data-typer].is-typing .terminal__line,
  html.js [data-typer].is-typing:not(:has(.terminal__line)) > * { clip-path: inset(0 100% 0 0); }
  html.js [data-typer].is-typing .is-typed {
    clip-path: inset(0 0 0 0);
    transition: clip-path var(--typer-d, .3s) steps(var(--steps, 24), jump-end);
  }

  /* ---------- data-wave: bars scale between two heights while .is-playing ---------- */
  .wave { display: flex; align-items: center; justify-content: space-between; gap: 2px; height: var(--wave-h, 64px); color: var(--ink-3); }
  .wave__bar {
    /* bar width follows the pitch (--wave-n set by wave.js), kept between 2px and 6px */
    flex: 0 0 auto; width: clamp(2px, 100% / var(--wave-n, 48) * .4, 6px); height: 100%; border-radius: 2px; background: currentColor;
    transform: scaleY(var(--h, .3)); transform-origin: 50% 50%;
  }
  .wave.is-playing .wave__bar { animation: wave-bar var(--dur, 1s) var(--ease-inout) var(--delay, 0s) infinite alternate; }
  .wave[data-paused] .wave__bar { animation-play-state: paused; } /* page pause controls (WCAG 2.2.2) */
  @keyframes wave-bar { from { transform: scaleY(var(--h, .3)); } to { transform: scaleY(var(--h2, .8)); } }
  /* No JS (or before the module runs): a static row of bars of varied height from one stripe fill + envelope mask */
  .wave:empty {
    background: repeating-linear-gradient(90deg, currentColor 0 3px, transparent 3px 6px);
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 40' preserveAspectRatio='none'%3E%3Cpath d='M0 18L4.2 15.2L8.3 16.7L12.5 14.4L16.7 7.6L20.8 14.8L25 10L29.2 13.3L33.3 9.7L37.5 1.1L41.7 12.6L45.8 12.1L50 8.7L54.2 8.5L58.3 1.4L62.5 12.9L66.7 12.3L70.8 7.4L75 11.1L79.2 7.8L83.3 15.7L87.5 13.2L91.7 12.5L95.8 17.2L100 18L100 22L95.8 22.8L91.7 27.5L87.5 26.8L83.3 24.3L79.2 32.2L75 28.9L70.8 32.6L66.7 27.7L62.5 27.1L58.3 38.6L54.2 31.5L50 31.3L45.8 27.9L41.7 27.4L37.5 38.9L33.3 30.3L29.2 26.7L25 30L20.8 25.2L16.7 32.4L12.5 25.6L8.3 23.3L4.2 24.8L0 22Z'/%3E%3C/svg%3E") center / 100% 100% no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 40' preserveAspectRatio='none'%3E%3Cpath d='M0 18L4.2 15.2L8.3 16.7L12.5 14.4L16.7 7.6L20.8 14.8L25 10L29.2 13.3L33.3 9.7L37.5 1.1L41.7 12.6L45.8 12.1L50 8.7L54.2 8.5L58.3 1.4L62.5 12.9L66.7 12.3L70.8 7.4L75 11.1L79.2 7.8L83.3 15.7L87.5 13.2L91.7 12.5L95.8 17.2L100 18L100 22L95.8 22.8L91.7 27.5L87.5 26.8L83.3 24.3L79.2 32.2L75 28.9L70.8 32.6L66.7 27.7L62.5 27.1L58.3 38.6L54.2 31.5L50 31.3L45.8 27.9L41.7 27.4L37.5 38.9L33.3 30.3L29.2 26.7L25 30L20.8 25.2L16.7 32.4L12.5 25.6L8.3 23.3L4.2 24.8L0 22Z'/%3E%3C/svg%3E") center / 100% 100% no-repeat;
  }

  /* ---------- .dot--live: a short pulse (4 rounds, under 5s, so no pause control is needed) ---------- */
  .dot--live { animation: live-pulse 1.2s var(--ease-out) 4; }
  @keyframes live-pulse {
    0% { box-shadow: 0 0 0 0 var(--success); }
    70%, 100% { box-shadow: 0 0 0 7px transparent; }
  }

  /* ---------- Kill switch: ?motion=off, or OS reduce when JS is off (head.js sets motion on otherwise) ---------- */
  html[data-motion="off"] *,
  html[data-motion="off"] *::before,
  html[data-motion="off"] *::after {
    animation: none !important;
    transition-duration: 0s !important;
    transition-delay: 0s !important;
  }
  @media (prefers-reduced-motion: reduce) {
    html:not([data-motion="on"]) *,
    html:not([data-motion="on"]) *::before,
    html:not([data-motion="on"]) *::after {
      animation: none !important;
      transition-duration: 0s !important;
      transition-delay: 0s !important;
    }
  }
}
