/* Motion layer: staggered reveals, a gold shimmer, photo light sweeps and
   a rising-rocket fireworks show. Everything here yields to reduced motion. */

@keyframes gold-shimmer {
  0% { background-position: 100% 0; }
  100% { background-position: 0 0; }
}
@keyframes reveal-up {
  from { opacity: 0; transform: translateY(30px); filter: blur(5px); }
  to { opacity: 1; transform: none; filter: blur(0); }
}
@keyframes photo-sweep {
  0% { transform: translateX(-140%) skewX(-18deg); opacity: 0; }
  20% { opacity: .85; }
  100% { transform: translateX(240%) skewX(-18deg); opacity: 0; }
}
@keyframes trail-glow {
  0% { opacity: .9; }
  100% { opacity: 0; }
}

/* The gradient text carries its own shimmer instead of a flat fade. */
.motion-enabled .gold-text {
  background-image: linear-gradient(110deg, #7662c0 0%, #b57bbb 30%, #d9a6d6 45%, #b78cc6 60%, #7662c0 100%);
  background-size: 220% 100%;
  animation: gold-shimmer 7s linear infinite;
}

/* A section's children arrive one after another, not all at once.
   Decorations and the tilted envelope keep their own transforms and loops. */
.motion-enabled .reveal.is-visible > :not(.envelope, .letter-aura, .letter-orbit, .letter-floating-star, .photo-button) {
  animation: reveal-up 1.1s var(--ease) both;
}
.motion-enabled .reveal.is-visible > :not(.envelope, .letter-aura, .letter-orbit, .letter-floating-star, .photo-button):nth-child(2) { animation-delay: .1s; }
.motion-enabled .reveal.is-visible > :not(.envelope, .letter-aura, .letter-orbit, .letter-floating-star, .photo-button):nth-child(3) { animation-delay: .2s; }
.motion-enabled .reveal.is-visible > :not(.envelope, .letter-aura, .letter-orbit, .letter-floating-star, .photo-button):nth-child(4) { animation-delay: .3s; }
.motion-enabled .reveal.is-visible > :not(.envelope, .letter-aura, .letter-orbit, .letter-floating-star, .photo-button):nth-child(5) { animation-delay: .4s; }
.motion-enabled .reveal.is-visible > :not(.envelope, .letter-aura, .letter-orbit, .letter-floating-star, .photo-button):nth-child(6) { animation-delay: .5s; }

/* The timeline line draws itself, then the moments step in. */
.motion-enabled .timeline.is-visible .timeline-item {
  animation: reveal-up 1s var(--ease) both;
}
.motion-enabled .timeline.is-visible .timeline-item:nth-child(2) { animation-delay: .35s; }
.motion-enabled .timeline.is-visible .timeline-item:nth-child(3) { animation-delay: .7s; }

/* A band of light crosses a photograph the moment it appears. */
.motion-enabled .photo-frame::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background: linear-gradient(90deg, transparent, #ffffffcc 50%, transparent);
  transform: translateX(-140%) skewX(-18deg);
  opacity: 0;
}
.motion-enabled .photo-card.reveal.is-visible .photo-frame::before {
  animation: photo-sweep 1.4s var(--ease) .25s both;
}

/* The closing line becomes the night sky the fireworks rise into. */
.closing { position: relative; overflow: hidden; }
#fireworks-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 0;
}
.closing > .icon,
.closing > p,
.closing > .closing-kicker,
.closing > .firework-trigger { position: relative; z-index: 1; }

/* Transient fireworks must stay out of the flex flow; otherwise every
   rocket becomes a flex item and pushes the cards below down. */
.closing > .firework-rocket,
.closing > .firework-burst {
  position: absolute;
  z-index: 0;
}

/* A firework climbs, then blooms. The trail fades behind it. */
.firework-rocket {
  position: absolute;
  z-index: 0;
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: #b77ad0;
  box-shadow: 0 0 10px 3px #d9a6e8, 0 0 2px 1px #fff;
  pointer-events: none;
  animation: rocket-rise 1.05s cubic-bezier(.2, .6, .3, 1) forwards;
}
.firework-rocket::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 100%;
  width: 2px;
  height: 46px;
  transform: translateX(-50%);
  background: linear-gradient(#c28ad9, transparent);
  border-radius: 2px;
  animation: trail-glow 1.05s linear forwards;
}
@keyframes rocket-rise {
  from { transform: translate(-50%, 0) scale(.6); opacity: 1; }
  to { transform: translate(-50%, var(--rise, -260px)) scale(1); opacity: 1; }
}

/* The burst is a ring of sparks that fly outward and fall. */
.firework-burst {
  position: absolute;
  z-index: 0;
  width: 0;
  height: 0;
  pointer-events: none;
}
.firework-spark {
  position: absolute;
  left: 0;
  top: 0;
  width: var(--size, 4px);
  height: var(--size, 4px);
  border-radius: 50%;
  background: var(--spark, #fff);
  /* A tight ring of the spark's own colour, then a wider soft halo, so it
     reads as coloured light instead of a white dot on the pale sky. */
  box-shadow: 0 0 0 1px var(--spark, #fff), 0 0 10px 2px var(--spark, #fff);
  filter: saturate(1.25);
  animation: spark-bloom 1.6s cubic-bezier(.1, .5, .2, 1) forwards;
}
@keyframes spark-bloom {
  0% { transform: translate(0, 0) scale(1); opacity: 1; }
  70% { opacity: 1; }
  100% { transform: translate(var(--dx), var(--dy)) scale(.3); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .gold-text,
  .reveal.is-visible > *,
  .timeline.is-visible .timeline-item,
  .photo-card.reveal.is-visible .photo-frame::before,
  .firework-rocket,
  .firework-spark { animation: none; }
  .photo-frame::before { display: none; }
}
