/* =============================================================
   uv-ambient.css — theme-driven ambient scenery layer
   ------------------------------------------------------------
   Fills the empty canvas around and behind the invitation with
   the theme's world: foliage climbing the side gutters, clouds
   drifting, petals falling, a pterodactyl gliding across as you
   scroll. Built by chassis.js from theme.json's `ambient` block.

   Design rules:
   - position:fixed, pointer-events:none, painted BEHIND the
     scene content (hosts get z-index:1) — decor can never block
     a tap or cover copy.
   - Same scenery on every screen size: pieces scale with the
     viewport (clamp) and hug the edges, so phones get a slim
     peek of the world while tablets/desktops get full gutters.
   - All motion is transform/opacity only (GPU-cheap) and fully
     disabled under prefers-reduced-motion.
   ============================================================= */

#uv-ambient {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
}

/* Scene hosts paint above the ambient layer. (.cinema already has
   z-index:1 in the base chassis; cover the other two host classes.) */
.cinema, .scroll-stage, .evermore {
  position: relative;
  z-index: 1;
}

#uv-ambient img {
  position: absolute;
  display: block;
  max-width: none;
  height: auto;
  user-select: none;
  -webkit-user-select: none;
}

/* ---- side pieces (gutter foliage / peeking characters) ---- */
.uv-amb__side { will-change: transform; }
.uv-amb__side--sway {
  animation: uvAmbSway 9s ease-in-out infinite alternate;
}
@keyframes uvAmbSway {
  from { rotate: -2.2deg; }
  to   { rotate:  2.4deg; }
}

/* ---- drifters (clouds crossing very slowly) ---- */
.uv-amb__drift {
  animation: uvAmbDrift linear infinite;
}
@keyframes uvAmbDrift {
  from { transform: translateX(-22vw); }
  to   { transform: translateX(118vw); }
}

/* ---- flyers (fly-across: pterodactyl, bird, bee) ----
   A dead-straight, steady horizontal glide from one edge of the invite to
   the other, then a pause off-screen before the next pass. The flight path
   never rises, dips, or banks — the ONLY motion on the body is the
   wingbeat (the rig flaps its wings in place). Constant-speed (linear) so
   it reads as a calm, even glide. Per-pass speed jitter is set in
   chassis.js so multiple flyers don't lock into the same rhythm. */
.uv-amb__flyer {
  animation: uvAmbFly var(--fly-dur, 26s) linear infinite;
}
@keyframes uvAmbFly {
  0%   { transform: translateX(-26vw); }   /* enter from the left edge   */
  78%  { transform: translateX(118vw); }   /* exit past the right edge   */
  100% { transform: translateX(118vw); }   /* hold off-screen = the pause */
}
/* The glide wrapper only carries the horizontal flip now — no vertical
   motion of its own, so the path stays perfectly straight. */
.uv-amb__glide { display: block; }
.uv-amb__glide > img,
.uv-amb__glide > .uv-amb__flapper,
.uv-amb__glide > .uv-amb__rig { position: static; }
.uv-amb__flyer--flip .uv-amb__glide > * { scale: -1 1; }

/* 2-frame wing flap: both frames stacked, opacity square-wave in
   antiphase (frame B runs the same steps() animation offset by half a
   cycle). --flap-dur is one full wingbeat: slow + majestic for the
   pterodactyl, quick for the bird, a blur-fast buzz for the bee. */
.uv-amb__flapper { position: relative; display: block; }
.uv-amb__flapper img { position: static; display: block; width: 100%; height: auto; }
.uv-amb__flapper img + img { position: absolute; inset: 0; }
.uv-amb__flapper img:first-child {
  animation: uvAmbFlap var(--flap-dur, 0.5s) steps(1, end) infinite;
}
.uv-amb__flapper img + img {
  animation: uvAmbFlap var(--flap-dur, 0.5s) steps(1, end) infinite;
  animation-delay: calc(var(--flap-dur, 0.5s) / -2);
}
@keyframes uvAmbFlap {
  0%, 49.9% { opacity: 1; }
  50%, 100% { opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .uv-amb__flapper img { animation: none; }
  .uv-amb__flapper img + img { display: none; }
}

/* Rigged flyer: a static body layer with separate wing layers that
   ROTATE smoothly about their shoulder pivot (transform-origin), like a
   2D puppet rig — real flapping with zero frame-popping. All geometry is
   in % of the rig canvas so it scales with the flyer size. The body
   counter-bobs a touch in sync so the downstroke visibly lifts it. */
.uv-amb__rig { position: relative; display: block; }
.uv-amb__rig img { position: absolute; display: block; height: auto; }
.uv-amb__rig .uv-rig__body {
  animation: uvAmbRigBody var(--wing-dur, 0.7s) ease-in-out infinite alternate;
}
@keyframes uvAmbRigBody {
  from { translate: 0 1.5%; }
  to   { translate: 0 -2.5%; }
}
.uv-amb__wing {
  transform-origin: var(--wpx, 50%) var(--wpy, 50%);
  animation: uvAmbWing var(--wing-dur, 0.7s) ease-in-out infinite alternate;
}
@keyframes uvAmbWing {
  from { rotate: var(--wing-from, -12deg); }
  to   { rotate: var(--wing-to, 16deg); }
}
.uv-amb__wing--back { animation-delay: calc(var(--wing-dur, 0.7s) * -0.14); }
@media (prefers-reduced-motion: reduce) {
  .uv-amb__rig img { animation: none; }
}

/* ---- fallers (petals / leaves / sparkles) ----
   Leaves don't drop straight: they pendulum side to side as they sink.
   ease-in

/* ---- phones: keep the world but slim + quieter so copy wins ---- */
@media (max-width: 600px) {
  .uv-amb__side { opacity: var(--uv-amb-mob-op, 0.5) !important; }
}

/* ---- accessibility ---- */
@media (prefers-reduced-motion: reduce) {
  #uv-ambient * { animation: none !important; }
  .uv-amb__flyer { display: none; }   /* a static flyer mid-screen looks wrong */
  .uv-amb__fall  { display: none; }
}
