/* ===========================================================================
   Motion. Everything here is opt-in via a class, and everything is disabled
   wholesale by the prefers-reduced-motion block at the bottom.
   =========================================================================== */

/* ── Scroll reveal ───────────────────────────────────────────────────── */
/* js/ui.js adds .is-revealed when the element scrolls into view. */
.reveal {
  opacity: 0;
  transform: translateY(1.5rem);
  transition:
    opacity   var(--dur-reveal) var(--ease-out),
    transform var(--dur-reveal) var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
}

.reveal.is-revealed {
  opacity: 1;
  transform: none;
}

/* Fade only, no travel — for art where sliding would look wrong. */
.reveal--fade { transform: none; }

/* ── Countdown: ink wipe, then a slow gold shimmer ───────────────────── */
/* The digits start fully clipped; revealing wipes them in left-to-right like
   ink being laid down, then the gradient pans across forever. */
.countdown.is-revealed .countdown__value {
  animation:
    ink-reveal 1.1s var(--ease-out) var(--d, 0ms) forwards,
    gold-shimmer 4.5s ease-in-out calc(var(--d, 0ms) + 1.1s) infinite;
}

.countdown.is-revealed .countdown__label,
.countdown.is-revealed .countdown__sep { opacity: 0.9; }

/* Stagger: days first, then hours, minutes, seconds. (The original meant to
   do this but its selectors were missing a descendant space, so only the
   hours column ever staggered.) */
.countdown.is-revealed .countdown__unit:nth-child(1) .countdown__label { transition-delay: 0.90s; }
.countdown.is-revealed .countdown__unit:nth-child(3) .countdown__label { transition-delay: 1.08s; }
.countdown.is-revealed .countdown__unit:nth-child(5) .countdown__label { transition-delay: 1.26s; }
.countdown.is-revealed .countdown__unit:nth-child(7) .countdown__label { transition-delay: 1.44s; }

.countdown.is-revealed .countdown__sep:nth-of-type(1) { transition-delay: 0.25s; }
.countdown.is-revealed .countdown__sep:nth-of-type(2) { transition-delay: 0.43s; }
.countdown.is-revealed .countdown__sep:nth-of-type(3) { transition-delay: 0.61s; }

@keyframes ink-reveal {
  from { clip-path: inset(0 100% 0 0); }
  to   { clip-path: inset(0 0 0 0); }
}

@keyframes gold-shimmer {
  0%   { background-position: 100% 0; }
  50%  { background-position: 0% 0; }
  100% { background-position: 100% 0; }
}

/* ── Countdown: digit roll on change ─────────────────────────────────── */
/* js/countdown.js toggles .is-flipping-out, swaps the text, then flips in. */
.countdown__value {
  transition:
    transform var(--dur-flip) var(--ease-out),
    opacity   var(--dur-flip) ease;
}

.countdown__value.is-flipping-out {
  transform: translateY(-60%);
  opacity: 0;
}

.countdown__value.is-flipping-in {
  transform: translateY(60%);
  opacity: 0;
  transition: none;   /* snap to the far side, then ease back on removal */
}

/* ── Ambient loops ───────────────────────────────────────────────────── */
/* A slow bob, used on the two "scroll down" / "click to open" chevrons. */
.bob { animation: bob 1.6s ease-in-out infinite; }

@keyframes bob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(5px); }
}

/* The schedule rose slides down the timeline as the section scrolls past,
   like a bead on a thread (the original moved it 0 -> 311px). Driven by a
   scroll-linked animation where supported, so it tracks the scrollbar exactly
   and costs no JavaScript; browsers without scroll timelines just leave the
   rose parked at the top of the line, which is where it belongs anyway. */
@supports (animation-timeline: view()) {
  .timeline__rose {
    animation: rose-travel linear both;
    animation-timeline: view();
    /* Start when the list enters the viewport, finish as it leaves. */
    animation-range: entry 15% exit 60%;
  }

  /* Travels dot-to-dot, so the distance is the gaps between rows, not the
     row count: five rows means four gaps. --rows lives on .timeline and must
     match the number of <li>s — update it when an item is added or removed. */
  @keyframes rose-travel {
    from { transform: translateY(0); }
    to   { transform: translateY(calc(var(--row-h) * (var(--rows) - 1))); }
  }
}

/* A barely-there breathing scale on the large hero flowers. */
.breathe {
  animation: breathe 8s ease-in-out infinite;
  animation-delay: var(--delay, 0s);
}

@keyframes breathe {
  0%, 100% { transform: rotate(var(--rot, 0deg)) scale(1); }
  50%      { transform: rotate(var(--rot, 0deg)) scale(1.05); }
}

/* Petals drifting down past the venue illustration. Each leaf sets its own
   --fall-x/--fall-y/--dur/--delay so six of them don't move in lockstep. */
.petal {
  animation: petal-fall var(--dur, 9s) linear var(--delay, 0s) infinite;
}

@keyframes petal-fall {
  0%   { transform: rotate(var(--rot, 0deg)) translate(0, 0);          opacity: 0; }
  10%  {                                                                opacity: 0.9; }
  70%  {                                                                opacity: 0.7; }
  100% { transform: rotate(calc(var(--rot, 0deg) + 20deg))
                    translate(var(--fall-x, 20px), var(--fall-y, 260px)); opacity: 0; }
}

/* ── Reduced motion ──────────────────────────────────────────────────── */
/* Nothing moves, nothing loops, and anything that was waiting to be revealed
   is simply shown. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }

  .reveal { opacity: 1; transform: none; }

  .countdown__value { clip-path: none; }

  .countdown__label,
  .countdown__sep { opacity: 0.9; }
}
