/* ==========================================================================
   animations.css — every moving thing. All motion is switched off for
   visitors who enable "reduce motion" in their OS (bottom of this file).
   ========================================================================== */

/* background */
.bg__spot { animation: roam 22s ease-in-out infinite; }
.bg__orb--1, .bg__orb--3 { animation: drift1 20s ease-in-out infinite; }
.bg__orb--2 { animation: drift2 26s ease-in-out infinite; }
.pulse { stroke-dasharray: 70 930; stroke-dashoffset: 1000; animation: dash 6s linear infinite; }
.pulse--2 { animation-delay: -1.5s; animation-duration: 7s; }
.pulse--3 { animation-delay: -3s; animation-duration: 5.5s; }
.pulse--4 { animation-delay: -4.2s; animation-duration: 8s; }
.pulse--5 { animation-delay: -2.4s; }
.glass::after { animation: sweep 9s ease-in-out infinite; }

/* logo: peak draws itself, then the cursor appears and blinks */
.logo-draw { stroke-dasharray: 153; stroke-dashoffset: 153; animation: draw 1.6s cubic-bezier(.6, 0, .2, 1) .3s forwards; }
.logo-cursor { opacity: 0; animation: pop .25s ease 1.9s forwards, blink 1.1s steps(1) 2.4s infinite; }

.blink { animation: blink 1.1s steps(1) infinite; }
.bob { animation: bob 2.2s ease-in-out infinite; }
.node-ping { animation: ping 2.8s ease-out infinite; }
.steps__flow { animation: flow 4s linear infinite; }
.ticker__row { animation: marquee 42s linear infinite; }
.ticker__row--alt { animation: marquee 48s linear infinite reverse; }

/* page-load entrance */
.rise { animation: rise .9s cubic-bezier(.2, .7, .2, 1) both; }
.d1 { animation-delay: .25s; } .d2 { animation-delay: .45s; } .d3 { animation-delay: .7s; }

/* typing code — starts when effects.js adds .is-typing to the editor */
.type { display: inline-block; overflow: hidden; white-space: pre; width: 0; vertical-align: bottom; }
/* jump-start: the last character is drawn at the start of the final step, so a
   tiny floating-point timing error can never leave the line one character short */
.is-typing .type { animation: type var(--d) steps(var(--n), jump-start) var(--w) forwards; }
.later { opacity: 0; }
.is-typing .later { animation: rise .6s cubic-bezier(.2, .7, .2, 1) var(--w) forwards; }

/* scroll reveal: CSS scroll-timeline where supported, JS fallback adds .is-visible */
.reveal { opacity: 0; transform: translateY(22px); transition: opacity .8s cubic-bezier(.2, .7, .2, 1), transform .8s cubic-bezier(.2, .7, .2, 1); }
.reveal.is-visible { opacity: 1; transform: none; }
@supports (animation-timeline: view()) {
  .reveal { opacity: 1; transform: none; transition: none; animation: rise linear both; animation-timeline: view(); animation-range: entry 0% cover 24%; }
}

/* terminal output line + theme icon */
.line-in { animation: rise .45s cubic-bezier(.2, .7, .2, 1) both; }
.icon-btn svg { animation: spin .5s cubic-bezier(.2, .7, .2, 1) both; }

@keyframes type { to { width: calc(var(--n) * 1ch); } }
@keyframes roam {
  0%, 100% { -webkit-mask-position: 50% 22%; mask-position: 50% 22%; }
  25% { -webkit-mask-position: 88% 8%; mask-position: 88% 8%; }
  50% { -webkit-mask-position: 66% 84%; mask-position: 66% 84%; }
  75% { -webkit-mask-position: 12% 62%; mask-position: 12% 62%; }
}
@keyframes dash { to { stroke-dashoffset: 0; } }
@keyframes ping { 0% { box-shadow: 0 0 0 0 rgba(61, 107, 255, .6); } 70%, 100% { box-shadow: 0 0 0 12px rgba(61, 107, 255, 0); } }
@keyframes drift1 { 0%, 100% { transform: translate(0, 0); } 50% { transform: translate(100px, 60px) scale(1.12); } }
@keyframes drift2 { 0%, 100% { transform: translate(0, 0); } 50% { transform: translate(-90px, 80px) scale(.92); } }
@keyframes blink { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }
@keyframes pop { to { opacity: 1; } }
@keyframes draw { to { stroke-dashoffset: 0; } }
@keyframes bob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(6px); } }
@keyframes flow { 0% { background-position: -30% 0; } 100% { background-position: 130% 0; } }
@keyframes spin { from { opacity: 0; transform: rotate(-90deg) scale(.6); } to { opacity: 1; transform: none; } }
@keyframes marquee { to { transform: translateX(-50%); } }
@keyframes rise { from { opacity: 0; transform: translateY(22px); } to { opacity: 1; transform: none; } }
@keyframes sweep { 0% { background-position: 150% 0; } 55%, 100% { background-position: -60% 0; } }

/* ---------- respect "reduce motion" ---------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; scroll-behavior: auto !important; }
  .type { width: auto; }
  .later, .logo-cursor, .reveal { opacity: 1; transform: none; }
  .logo-draw { stroke-dashoffset: 0; }
  .pulse { stroke-dasharray: none; opacity: .35; }
}
