/* =========================================================================
   animations.css — keyframes, entrance opening sequence, intro states,
   and prefers-reduced-motion support
   ========================================================================= */

/* ---------- Ambient keyframes ---------- */
@keyframes tapPulse {
  0%   { transform: scale(1);   opacity: .9; }
  55%  { transform: scale(1.14); opacity: 0; }
  100% { transform: scale(1);   opacity: 0; }
}

@keyframes cueDrop {
  0%   { top: -100%; }
  60%  { top: 100%; }
  100% { top: 100%; }
}

@keyframes entranceSway {
  0%, 100% { rotate: -1.1deg; }
  50%      { rotate: 1.1deg; }
}

@keyframes glowBreathe {
  0%, 100% { opacity: .78; transform: scale(1); }
  50%      { opacity: 1;   transform: scale(1.05); }
}

@keyframes ribbonShimmer {
  0%, 100% { filter: brightness(1); }
  50%      { filter: brightness(1.18); }
}

@keyframes tickUp {
  0%   { opacity: 0; transform: translateY(.45em); }
  100% { opacity: 1; transform: translateY(0); }
}

@keyframes dustBurst {
  0%   { opacity: 0; transform: translate(0, 0) scale(.4); }
  18%  { opacity: 1; }
  100% { opacity: 0; transform: translate(var(--dx, 0), var(--dy, -60px)) scale(1.2); }
}

@keyframes successPop {
  0%   { opacity: 0; transform: scale(.6); }
  100% { opacity: 1; transform: scale(1); }
}

@keyframes cardReveal {
  0%   { opacity: 0; transform: scale(.985) translateY(10px); }
  100% { opacity: 1; transform: none; }
}

/* ---------- Ambient states (while entrance is closed) ---------- */
.js .entrance:not(.is-opening) .entrance__tag {
  animation: entranceSway 7s var(--ease-soft) infinite;
  transform-origin: 50% -10%;
}
.js .entrance:not(.is-opening) .entrance__ribbon {
  animation: ribbonShimmer 5.5s ease-in-out infinite;
}
.js .entrance:not(.is-opening) .entrance__glow {
  animation: glowBreathe 6s ease-in-out infinite;
}

/* ---------- Opening sequence ---------- */
/* Panels sweep away from the centre (transform transitions live in style.css) */
.entrance.is-opening .entrance__panel--l {
  transform: translate3d(-104%, 0, 0);
}
.entrance.is-opening .entrance__panel--r {
  transform: scaleX(-1) translate3d(-104%, 0, 0);
}

/* Hanging tag lifts and dissolves as the curtains part */
.entrance.is-opening .entrance__stage {
  transform: translateY(-5vh) scale(1.14);
  opacity: 0;
}
.entrance.is-opening .entrance__tag {
  animation: none;
  pointer-events: none;
}
.entrance.is-opening .entrance__glow {
  animation: none;
  opacity: 1;
  transform: scale(1.8);
}

/* The cover itself dissolves to reveal the hero underneath */
.entrance.is-opening {
  opacity: 0;
  visibility: hidden;
  transition:
    opacity calc(var(--entrance-dur) * .42) var(--ease-soft) calc(var(--entrance-dur) * .58),
    visibility 0s linear var(--entrance-dur);
}

.entrance.is-done { display: none; }

/* ---------- Hero intro (plays once the entrance opens) ---------- */
.js .hero__content > * {
  opacity: 0;
  transform: translateY(26px);
  transition: opacity .95s var(--ease-out), transform .95s var(--ease-out);
}
.js body.is-opened .hero__content > * { opacity: 1; transform: none; }

.js body.is-opened .hero__content > *:nth-child(1) { transition-delay: .10s; }
.js body.is-opened .hero__content > *:nth-child(2) { transition-delay: .22s; }
.js body.is-opened .hero__content > *:nth-child(3) { transition-delay: .34s; }
.js body.is-opened .hero__content > *:nth-child(4) { transition-delay: .46s; }
.js body.is-opened .hero__content > *:nth-child(5) { transition-delay: .56s; }
.js body.is-opened .hero__content > *:nth-child(6) { transition-delay: .66s; }
.js body.is-opened .hero__content > *:nth-child(7) { transition-delay: .78s; }

.js .scroll-cue {
  opacity: 0;
  transition: opacity .8s var(--ease-out) 1.1s;
}
.js body.is-opened .scroll-cue { opacity: 1; }
body.has-scrolled .scroll-cue {
  opacity: 0;
  pointer-events: none;
  transition: opacity .4s var(--ease-soft) 0s;
}

/* Hero image settles with a slow cinematic zoom */
.js .hero__bg img {
  transform: scale(1.16);
  transition: transform 2.8s var(--ease-out) .2s;
}
.js body.is-opened .hero__bg img { transform: scale(1.06); }

/* ---------- Scratch reveal celebration ---------- */
.scratch__card.is-revealed .scratch__inner {
  animation: cardReveal .8s var(--ease-out) both;
}

/* ---------- Countdown tick ---------- */
.countdown__value.is-tick {
  animation: tickUp .45s var(--ease-out);
}

/* ---------- RSVP success ---------- */
.rsvp__success-icon { animation: successPop .7s var(--ease-out) both; }

/* =========================================================================
   Reduced motion — short, simple fades instead of complex motion
   ========================================================================= */
@media (prefers-reduced-motion: reduce) {
  :root { --entrance-dur: 450ms; }

  *,
  *::before,
  *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    transition-delay: 0s !important;
  }

  html { scroll-behavior: auto; }

  /* Keep a short, graceful curtain fade rather than an instant cut */
  .entrance,
  .entrance__panel,
  .entrance__stage,
  .entrance__glow {
    transition-duration: 450ms !important;
    transition-delay: 0s !important;
  }
  .entrance.is-opening {
    transition: opacity 450ms ease !important;
  }

  /* Content simply appears — no sliding */
  .js .reveal,
  .js .hero__content > * {
    opacity: 1 !important;
    transform: none !important;
  }
  .js .hero__bg img { transform: scale(1.06) !important; }
  .scroll-cue__line::after { animation: none; }
}
