/* ============================================================
   stage.css - the set itself: backdrop, curtains, sparkle FX
   ============================================================ */

.stage {
  position: fixed;
  inset: 0;
  overflow: hidden;
  /* clips anything running past the edges */
}

/* ---------- backdrop ---------- */
.bg {
  position: absolute;
  inset: 0;
  background-image: url('../assets/images/stage_bg.jpg');
  background-size: cover;
  background-position: center 70%;
  filter: saturate(1.05);
}

/* vignette + top/bottom shading so the UI stays readable over the art */
.bg::after {
  content: '';
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse at 50% 105%,
      rgba(0, 0, 0, 0) 0%, rgba(5, 3, 12, 0.55) 60%, rgba(5, 3, 12, 0.85) 100%),
}

/* ---------- curtains ---------- */
/* They always run the full height of the stage and are never squashed or
   cropped: the height drives the box and the width just follows the art's
   own proportions. When the window gets too narrow to hold that width, the
   art slides outward past the screen edge instead of shrinking. */
.curtain {
  /* the art's own width once it is as tall as the stage (420/908 of it) */
  --curtain-w: 47.7vh;
  /* how much of that may stay on screen before it starts sliding out */
  --curtain-peek: 27vw;
  /* Never push more than this much of the art off the edge: at the very
     bottom the fabric only runs to about 57% of its width, so sliding
     further would take the hem off screen and the curtain would stop
     looking like it reaches the floor. */
  /* the -6px ceiling keeps a sliver of bleed at all times, so the sway
     can never leave an edge sitting exactly on the viewport boundary */
  --curtain-slide: clamp(calc(var(--curtain-w) * -0.42),
      calc(var(--curtain-peek) - var(--curtain-w)),
      -6px);

  position: absolute;
  top: -1%;
  height: 103%;
  width: auto;
  /* natural proportions, never cropped */
  transform-origin: top center;
  filter: drop-shadow(0 10px 24px rgba(0, 0, 0, 0.5));
  pointer-events: none;
  z-index: var(--z-curtain);
}

/* Three waves on three different clocks, so the loop never lands on an
   obvious beat: the shear on `transform`, the breath on `scale`, the
   drift on `translate`. They are separate CSS properties, which is what
   lets them run at different durations and still compose.
   Nothing here rotates and nothing ever moves INWARD from the screen
   edge - a rotation would swing the bottom corner in and open a gap
   along the side, now that the curtains reach all the way down. */
.curtain.left {
  left: var(--curtain-slide);
  animation:
    swayLeft 5s ease-in-out infinite,
    breathe 19s ease-in-out infinite,
    driftLeft 23s ease-in-out infinite;
}

/* mirrored, and offset in time so the two sides never sway in lockstep */
.curtain.right {
  right: var(--curtain-slide);
  transform: scaleX(-1);
  animation:
    swayRight 5s ease-in-out infinite,
    breathe 19s ease-in-out infinite,
    driftRight 23s ease-in-out infinite;
  animation-delay: -6.2s, -11s, -14s;
}

/* the fabric leaning: a vertical shear about the top of the drape */
@keyframes swayLeft {

  0%,
  100% {
    transform: skewY(1.4deg);
  }

  50% {
    transform: skewY(-1.1deg);
  }
}

@keyframes swayRight {

  0%,
  100% {
    transform: scaleX(-1) skewY(-1.4deg);
  }

  50% {
    transform: scaleX(-1) skewY(1.1deg);
  }
}

/* the drape filling out and settling back */
@keyframes breathe {

  0%,
  100% {
    scale: 1 1;
  }

  50% {
    scale: 1.05 1.012;
  }
}

/* and the whole thing drifting, always outward, never off the edge */
@keyframes driftLeft {

  0%,
  100% {
    translate: 0 0;
  }

  50% {
    translate: -1.4% -0.4%;
  }
}

@keyframes driftRight {

  0%,
  100% {
    translate: 0 0;
  }

  50% {
    translate: 1.4% -0.4%;
  }
}

/* ---------- static twinkling stars ---------- */
.sparkle {
  position: absolute;
  color: var(--gold);
  opacity: 0.75;
  font-size: clamp(10px, 1.4vw, 18px);
  animation: twinkle 2.6s ease-in-out infinite;
  z-index: var(--z-sparkle);
  pointer-events: none;
}

@keyframes twinkle {

  0%,
  100% {
    opacity: .2;
    transform: scale(0.8) rotate(0deg);
  }

  50% {
    opacity: .9;
    transform: scale(1.15) rotate(20deg);
  }
}

/* ---------- drifting glitter (spawned by js/particles.js) ---------- */
.particles {
  position: absolute;
  inset: 0;
  z-index: var(--z-particle);
  pointer-events: none;
  overflow: hidden;
}

.particle {
  position: absolute;
  border-radius: 50%;
  pointer-events: none;
  animation-name: drift;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
  /* size, colour, position and timing are set inline per particle */
}

@keyframes drift {
  0% {
    transform: translateY(0) scale(0.5);
    opacity: 0;
  }

  12% {
    opacity: 1;
  }

  50% {
    transform: translateY(-46px) scale(1);
    opacity: 0.9;
  }

  88% {
    opacity: 0.25;
  }

  100% {
    transform: translateY(-96px) scale(0.4);
    opacity: 0;
  }
}