/* Zovrel — motion.
   Timings are read from Figma get_motion_context. Figma authors everything on one looping
   12s timeline; on the real page the hero intro plays once on load and the float/spin/scroll
   parts keep running, which is what the brief specifies.
   Animations use the individual `translate` / `rotate` / `scale` properties so an intro and a
   float can compose on nested elements without fighting over `transform`. */

:root {
  --ease-bounce: cubic-bezier(.45, 1.45, .8, 1);
  --ease-out-fig: cubic-bezier(0, 0, .58, 1);
}

/* ============================================================ HERO HEADLINE (word by word) */
/* Figma: grouping WORD, order LEFT_RIGHT, 4 groups, stagger 200ms, group 400ms,
   from y +40px / opacity 0, ease cubic-bezier(0,0,.58,1). */

.word { display: inline-block; }
.word > span {
  display: inline-block;
  opacity: 0;
  translate: 0 40px;
  animation: word-in 400ms var(--ease-out-fig) both;
  animation-delay: calc(var(--i) * 200ms);
}
@keyframes word-in { to { opacity: 1; translate: 0 0; } }

.hero__eyebrow, .hero__lead, .hero__actions {
  opacity: 0;
  translate: 0 16px;
  animation: rise-in 500ms var(--ease-out-fig) both;
}
.hero__eyebrow { animation-delay: 60ms; }
.hero__lead    { animation-delay: 820ms; }
.hero__actions { animation-delay: 960ms; }
@keyframes rise-in { to { opacity: 1; translate: 0 0; } }

/* ============================================================ HERO ARTEFACTS */
/* intro: 800ms bounce, 400ms opacity, staggered 220ms apart (1100 / 1320 / 1540 / 1760).
   fill-mode `both` so each card holds its start state during its delay. */

.art__in {
  animation:
    art-fade 400ms ease-out            var(--in-delay) both,
    art-rise 800ms var(--ease-bounce)  var(--in-delay) both,
    var(--rot-kf) 800ms var(--ease-bounce) var(--in-delay) both;
}
@keyframes art-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes art-rise { from { translate: 0 70px; } to { translate: 0 0; } }

@keyframes rot-f { from { rotate: 14deg; }  to { rotate: 6deg; } }
@keyframes rot-p { from { rotate: -15deg; } to { rotate: -7deg; } }
@keyframes rot-s { from { rotate: 3deg; }   to { rotate: -5deg; } }
@keyframes rot-a { from { rotate: -4deg; }  to { rotate: 4deg; } }

.art-f .art__in { --in-delay: 1100ms; --rot-kf: rot-f; }
.art-p .art__in { --in-delay: 1320ms; --rot-kf: rot-p; }
.art-s .art__in { --in-delay: 1540ms; --rot-kf: rot-s; }
.art-a .art__in { --in-delay: 1760ms; --rot-kf: rot-a; }

/* float: y and rotation run at their own periods, exactly as Figma authored them */
.art__card {
  animation:
    float-y var(--fy) ease-in-out var(--f-delay) infinite,
    float-r var(--fr) ease-in-out var(--f-delay) infinite;
}
@keyframes float-y { 0%, 100% { translate: 0 0; } 50% { translate: 0 -10px; } }
@keyframes float-r { 0%, 100% { rotate: 0deg; } 50% { rotate: var(--amp); } }

.art-f .art__card { --fy: 2600ms; --fr: 3640ms; --amp:  1.5deg; --f-delay: 1900ms; }
.art-p .art__card { --fy: 3000ms; --fr: 4200ms; --amp: -1.5deg; --f-delay: 2120ms; }
.art-s .art__card { --fy: 3400ms; --fr: 4760ms; --amp:  1.5deg; --f-delay: 2340ms; }
.art-a .art__card { --fy: 3800ms; --fr: 5320ms; --amp: -1.5deg; --f-delay: 2560ms; }

@media (max-width: 1023px) { .art { --mock-scale: .62; } }

/* ---- dashboard bars: rise from below the clipped chart, 500ms bounce, 60ms apart ---- */
.card-forecast .bar {
  translate: 0 var(--rise);
  animation: bar-rise 500ms var(--ease-bounce) both;
  animation-delay: calc(1700ms + var(--i) * 60ms);
}
@keyframes bar-rise { to { translate: 0 0; } }

/* ---- survey: boundary, vertices, area tag ---- */
.card-survey .boundary {
  opacity: 0;
  animation: art-fade 600ms ease-out 2300ms both;
}
.card-survey .vertex {
  opacity: 0; scale: 0;
  animation: art-fade 200ms ease-out calc(2000ms + var(--i) * 70ms) both,
             pop 450ms var(--ease-bounce) calc(2000ms + var(--i) * 70ms) both;
}
.card-survey .areatag {
  opacity: 0; scale: .5;
  animation: art-fade 200ms ease-out 2480ms both,
             pop 450ms var(--ease-bounce) 2480ms both;
}
@keyframes pop { to { scale: 1; } }

/* ---- phone: messages, review card, typing ---- */
.card-phone .msg, .card-phone .review, .card-phone .typing {
  opacity: 0;
  animation: art-fade 400ms ease-out var(--d) both,
             msg-rise 400ms ease-out var(--d) both;
}
@keyframes msg-rise { from { translate: 0 12px; } to { translate: 0 0; } }
.card-phone .msg--1  { --d: 2000ms; }
.card-phone .msg--2  { --d: 2200ms; }
.card-phone .review  { --d: 2400ms; }
.card-phone .typing  { --d: 2650ms; }

.card-phone .review .approve {
  opacity: 0; scale: .5;
  animation: art-fade 200ms ease-out 2560ms both,
             pop 450ms var(--ease-bounce) 2560ms both;
}
.card-phone .typing img {
  animation: blink 1200ms ease-in-out calc(2800ms + var(--i) * 160ms) infinite;
}
@keyframes blink { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }

/* ---- architecture: boxes + sticker ---- */
.card-arch .box {
  opacity: 0; scale: .5;
  animation: art-fade 200ms ease-out calc(2000ms + var(--i) * 70ms) both,
             pop 450ms var(--ease-bounce) calc(2000ms + var(--i) * 70ms) both;
}
.card-arch .links { opacity: 0; animation: art-fade 600ms ease-out 2400ms both; }
.card-arch .sticker {
  opacity: 0;
  animation: art-fade 200ms ease-out 2500ms both,
             pop-rot 450ms var(--ease-bounce) 2500ms both;
}
@keyframes pop-rot { from { scale: .5; } to { scale: 1; } }

/* ---- Z stamp: pop in, then the ring turns slowly ---- */
.stamp {
  opacity: 0; scale: .3;
  animation: art-fade 200ms ease-out 2400ms both,
             pop 450ms var(--ease-bounce) 2400ms both;
}
.stamp .ring { animation: spin 12s linear infinite; }
@keyframes spin { to { rotate: 360deg; } }

/* ============================================================ MARQUEE (continuous loop) */

.marquee__track { animation: marquee 12s linear infinite; }
@keyframes marquee { to { translate: -50% 0; } }

/* ============================================================ SCROLL REVEALS */
/* Figma: y +16px / opacity 0 → 600ms ease-out. Plays once, on entering the viewport. */

.reveal {
  opacity: 0;
  translate: 0 16px;
  transition: opacity 600ms ease-out, translate 600ms ease-out;
  transition-delay: var(--d, 0ms);
}
.reveal.is-in { opacity: 1; translate: 0 0; }

/* ============================================================ REDUCED MOTION */
/* Final state, no movement. */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-delay: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    transition-delay: 0ms !important;
  }
  html { scroll-behavior: auto; }

  .word > span,
  .hero__eyebrow, .hero__lead, .hero__actions,
  .art__in, .card-survey .boundary, .card-survey .vertex, .card-survey .areatag,
  .card-phone .msg, .card-phone .review, .card-phone .typing,
  .card-phone .review .approve, .card-arch .box, .card-arch .links,
  .card-arch .sticker, .stamp, .reveal {
    opacity: 1 !important;
    translate: 0 0 !important;
    scale: var(--mock-scale, 1) !important;
  }
  @media (max-width: 1023px) { .art { --mock-scale: .62; } }
  .card-forecast .bar { translate: 0 0 !important; }
  .marquee__track { translate: 0 0 !important; }
}

/* ============================================================ INNER-PAGE BAND ART */
/* Figma authors these on a 6s loop: drop in at 600ms over 800ms (bounce), then
   float y 0 → -8px every 2.4s. Same split as the hero: intro once, float forever. */

.bm__in {
  rotate: var(--rot, 0deg);
  animation:
    bm-fade 500ms ease-out           var(--d, 600ms) both,
    bm-rise 800ms var(--ease-bounce) var(--d, 600ms) both;
}
@keyframes bm-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes bm-rise { from { translate: 0 60px; } to { translate: 0 0; } }

.bm .mock {
  animation: bm-float var(--fy, 2400ms) ease-in-out calc(var(--d, 600ms) + 800ms) infinite;
}
@keyframes bm-float { 0%, 100% { translate: 0 0; } 50% { translate: 0 -8px; } }

@media (prefers-reduced-motion: reduce) {
  .bm__in { opacity: 1 !important; translate: 0 0 !important; }
  .bm .mock { translate: 0 0 !important; }
}
