/* Everything here is gated: .js is set by head.js, .fx by effects.js once observers exist,
   and the reduced-motion block at the bottom flattens it all. */

/* ----- Hero: the one orchestrated entrance ----- */
.js .hero__line-in { transform: translateY(105%); animation: rise 900ms var(--ease-out) forwards; animation-delay: calc(var(--i, 0) * 110ms + 80ms); }
.hero__line:nth-child(2) .hero__line-in { --i: 1; }
.hero__line:nth-child(3) .hero__line-in { --i: 2; }
@keyframes rise { to { transform: none; } }

.js .avail, .js .hero__sub, .js .hero__proof, .js .hero__cta, .js .hero__links {
  opacity: 0;
  transform: translateY(14px);
  animation: fade-up 700ms var(--ease-out) forwards;
}
.js .avail { animation-delay: 40ms; }
.js .hero__sub { animation-delay: 520ms; }
.js .hero__proof { animation-delay: 620ms; }
.js .hero__cta { animation-delay: 720ms; }
.js .hero__links { animation-delay: 820ms; }
@keyframes fade-up { to { opacity: 1; transform: none; } }
@keyframes ping { 0% { transform: scale(0.6); opacity: 0.8; } 80%, 100% { transform: scale(1.8); opacity: 0; } }

/* The price-flash burst sways gently so the availability stays noticed. */
.js .flash { animation: sway 6s ease-in-out infinite; }
@keyframes sway { 0%, 100% { transform: rotate(-9deg) scale(1); } 50% { transform: rotate(-3deg) scale(1.06); } }

/* The envelope on Hire me nudges every few seconds. */
.js .btn--hire .btn__mail { animation: nudge 5s ease-in-out 3s infinite; }
@keyframes nudge { 0%, 88%, 100% { transform: none; } 92% { transform: rotate(-14deg); } 96% { transform: rotate(10deg); } }
.js .btn--hire:hover .btn__mail { animation: none; }

/* ----- "Detected": hero.js adds is-ready, is-corners, is-scan, is-box, is-label, is-named in order ----- */
.js .viewfinder__photo { opacity: 0; transform: scale(1.04); transition: opacity 600ms var(--ease-out), transform 900ms var(--ease-out); }
.js .viewfinder.is-ready .viewfinder__photo { opacity: 1; transform: none; }
.js .viewfinder__corner { opacity: 0; transform: scale(1.5); transition: opacity 300ms var(--ease-out), transform 500ms var(--ease-out); }
.js .viewfinder.is-corners .viewfinder__corner { opacity: 1; transform: none; }
.js .viewfinder.is-scan .viewfinder__scan { animation: scan 700ms linear forwards; }
@keyframes scan { from { top: 0; opacity: 1; } to { top: 100%; opacity: 0; } }
.js .viewfinder__box rect { stroke-dasharray: 100; stroke-dashoffset: 100; transition: stroke-dashoffset 600ms var(--ease-out); }
.js .viewfinder.is-box .viewfinder__box rect { stroke-dashoffset: 0; }
.js .viewfinder__label { opacity: 0; transform: translateY(4px); transition: opacity 200ms var(--ease-out), transform 200ms var(--ease-out); }
.js .viewfinder.is-label .viewfinder__label { opacity: 1; transform: none; }

/* ----- Scroll: panels pop in, everything else rises a little. Armed by effects.js. ----- */
.fx .item[data-reveal] { opacity: 0; transform: translateY(24px) scale(0.95); transition: opacity 500ms var(--ease-out), transform 700ms var(--ease-out), box-shadow 320ms var(--ease-out); transition-delay: calc(var(--i, 0) * 80ms), calc(var(--i, 0) * 80ms), 0ms; }
.fx .item[data-reveal].is-in { opacity: 1; transform: none; }
.fx .item[data-reveal].is-in:hover { transform: translateY(-5px); transition-delay: 0ms; }

.fx .step[data-reveal], .fx .timeline__item[data-reveal], .fx .skills__group[data-reveal], .fx .beyond__text [data-reveal], .fx .prose [data-reveal] {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 600ms var(--ease-out), transform 700ms var(--ease-out), background-color 200ms;
  transition-delay: calc(var(--i, 0) * 70ms);
}
.fx [data-reveal].is-in { opacity: 1; transform: none; }

/* ----- Theme change: circular wipe via View Transitions ----- */
::view-transition-old(root), ::view-transition-new(root) { animation: none; mix-blend-mode: normal; }
::view-transition-old(root) { z-index: 1; }
::view-transition-new(root) { z-index: 2; }
html { transition: background-color 300ms var(--ease-in-out), color 300ms var(--ease-in-out); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-delay: 0ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0ms !important;
  }
  html { scroll-behavior: auto; }
  .js .hero__line-in, .js .avail, .js .hero__sub, .js .hero__proof, .js .hero__cta, .js .hero__links,
  .js .viewfinder__photo, .js .viewfinder__corner, .js .viewfinder__label, .js .flash, .js .btn--hire .btn__mail { animation: none !important; opacity: 1 !important; transform: none !important; }
  .js .flash { transform: rotate(-9deg) !important; }
  .js .viewfinder__scan { display: none; }
  .fx [data-reveal] { opacity: 1 !important; transform: none !important; }
}
