/* Motion is opt-in: hidden starting states exist ONLY under html.js-motion,
   so no-JS and reduced-motion visitors always see the composed page. */

html.js-motion [data-reveal] {
  opacity: 0;
  transform: translateY(26px);
  transition: opacity .7s ease, transform .7s cubic-bezier(.2, .7, .2, 1);
  transition-delay: calc(var(--reveal-i, 0) * 90ms);
}
html.js-motion [data-reveal].in-view {
  opacity: 1;
  transform: none;
}

/* Hero name wipe-in */
html.js-motion .hero-name > span {
  display: block;
  clip-path: inset(0 100% 0 0);
  transition: clip-path .9s cubic-bezier(.6, 0, .2, 1);
  transition-delay: calc(var(--line-i, 0) * 160ms);
}
html.js-motion .hero-name.in-view > span { clip-path: inset(0 0 0 0); }

/* Photo strip prints drift up as they enter */
html.js-motion .print { transition-duration: .9s; }

/* Slow Ken Burns inside the hero image letters via background position */
@keyframes drift { from { background-position: center 66%; } to { background-position: center 58%; } }
html.js-motion .hero-name .img-line { animation: drift 14s ease-in-out infinite alternate; }

/* MSP430 LEDs blink in sequence */
@keyframes led-chase { 0%, 100% { opacity: .25; } 12% { opacity: 1; } }
html.js-motion .g-leds i.on { animation: led-chase 2.4s infinite; }
html.js-motion .g-leds i.on:nth-child(2) { animation-delay: .3s; }
html.js-motion .g-leds i.on:nth-child(4) { animation-delay: .6s; }
html.js-motion .g-leds i.on:nth-child(6) { animation-delay: .9s; }
html.js-motion .g-leds i.on:nth-child(8) { animation-delay: 1.2s; }

/* Score needle sweeps on reveal */
html.js-motion .g-score .needle {
  transform: rotate(-80deg);
  transition: transform 1.4s cubic-bezier(.3, 1.2, .3, 1) .3s;
}
html.js-motion .in-view .g-score .needle,
html.js-motion .g-score.in-view .needle { transform: rotate(33deg); }

/* Spotify EQ bars — animate only while the demo is on screen (.live) */
@keyframes eq-bounce { 0%, 100% { height: 16%; } 50% { height: var(--peak, 80%); } }
html.js-motion .g-demo.live .eq i {
  animation: eq-bounce calc(.9s + var(--n) * 37ms) ease-in-out infinite;
  --peak: 40%;
}
html.js-motion .g-demo.live .eq i:nth-child(odd) { --peak: 88%; }
html.js-motion .g-demo.live .eq i:nth-child(3n) { --peak: 55%; }
html.js-motion .g-demo.live .eq i:nth-child(4n) { --peak: 70%; }

/* Skills: two rows drift in opposite directions; pause on hover */
@keyframes skill-drift { from { transform: translateX(0); } to { transform: translateX(-100%); } }
html.js-motion .skill-row .skill-track { animation: skill-drift 38s linear infinite; }
html.js-motion .skill-row.rtl .skill-track { animation-direction: reverse; }
html.js-motion .skill-row:hover .skill-track { animation-play-state: paused; }

/* PromptStrike terminal: lines appear in sequence on reveal */
html.js-motion .g-term .line { opacity: 0; }
html.js-motion .in-view .g-term .line {
  animation: term-in .3s forwards;
  animation-delay: calc(var(--l) * .45s);
}
@keyframes term-in { to { opacity: 1; } }

/* Soccer ball: slow roll back and forth past the cleats, tiny bounces */
@keyframes ball-roll {
  0%   { transform: translateX(-90px); }
  50%  { transform: translateX(90px); }
  100% { transform: translateX(-90px); }
}
@keyframes ball-spin {
  from { transform: rotate(0); } to { transform: rotate(360deg); }
}
@keyframes ball-bounce {
  0%, 100% { translate: 0 0; } 50% { translate: 0 -10px; }
}
html.js-motion .ball-track { animation: ball-roll 7s ease-in-out infinite; }
html.js-motion .soccer-scene .ball {
  animation: ball-spin 1.6s linear infinite, ball-bounce 1.1s ease-in-out infinite;
}

/* Stained glass: light sweeps through slowly */
@keyframes glass-light { 0% { transform: translateX(0); } 100% { transform: translateX(680px); } }
html.js-motion .glass .sweep { animation: glass-light 7s ease-in-out infinite; }

/* Rotating hero badge */
@keyframes badge-rotate { to { transform: rotate(360deg); } }
html.js-motion .badge-spin { animation: badge-rotate 28s linear infinite; transform-origin: 64px 64px; }

/* Parallax layers (set via --scroll-y by animations.js) */
html.js-motion .parallax { transform: translate3d(0, calc(var(--scroll-y, 0) * var(--parallax-rate, 0) * 1px), 0); }

/* Reduced motion: kill everything, belt and suspenders (JS also bails) */
@media (prefers-reduced-motion: reduce) {
  html.js-motion [data-reveal],
  html.js-motion .hero-name > span,
  html.js-motion .g-score .needle,
  html.js-motion .parallax {
    opacity: 1 !important; transform: none !important; clip-path: none !important;
    transition: none !important; animation: none !important;
  }
  html.js-motion .hero-name .img-line, html.js-motion .g-leds i.on { animation: none !important; }
  html { scroll-behavior: auto; }
}
