/* Anticipation and reveal effects (play-effects.js). Durations here must
   match the constants there. None of this runs with reduced motion on:
   effects.js gives an empty plan instead. */

/* The closed box's glow, faded in by play-effects.js. Its shadow sits
   outside its own edges, so it never covers the box. */
.box { position: relative; line-height: 0; } /* No gap under the canvas. */
.box-glow {
  position: absolute;
  inset: 0;
  box-shadow: 0 0 16px 4px var(--tier-color), 0 0 4px 1px var(--tier-color);
  opacity: 0;
  pointer-events: none;
}

/* Particles: square pixels flying out from the lute's center. */
.particle {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 8px;
  height: 8px;
  margin: -4px 0 0 -4px;
  /* A dark pixel outline, so light colors show on the light stage. */
  box-shadow: 0 0 0 2px #120a05;
  pointer-events: none;
  animation: particle-fly 900ms ease-out forwards;
}

@keyframes particle-fly {
  from { transform: translate(0, 0) scale(1); opacity: 1; }
  to { transform: translate(var(--dx), var(--dy)) scale(0.3); opacity: 0; }
}

/* Light beam: falls from above onto the lute, then fades. z-index -1 puts
   it behind the page's text and button; the lute is positioned, so it
   still draws on top. */
.beam {
  position: absolute;
  left: 50%;
  bottom: 0;
  width: 140px;
  height: 100vh;
  margin-left: -70px;
  z-index: -1;
  pointer-events: none;
  transform-origin: bottom center;
  filter: blur(6px);
  animation: beam 1600ms ease-out forwards;
}

.beam-light {
  background: linear-gradient(to top, var(--tier-color), color-mix(in srgb, var(--tier-color) 40%, transparent) 60%, transparent);
}

.beam-rainbow {
  background: linear-gradient(to right, #ff0040, #ff9900, #ffee00, #33ff66, #00ccff, #6644ff, #ff00cc);
  /* Fade toward the top, like the plain beam. */
  mask-image: linear-gradient(to top, #000, #000 40%, transparent);
  -webkit-mask-image: linear-gradient(to top, #000, #000 40%, transparent);
}

@keyframes beam {
  0% { opacity: 0; transform: scaleX(0.1); }
  20% { opacity: 0.9; transform: scaleX(1); }
  70% { opacity: 0.7; }
  100% { opacity: 0; transform: scaleX(1.1); }
}

/* Screen flash: one soft pulse of the tier color. A single flash, well
   under the three-per-second limit for flashing content. */
.flash {
  position: fixed;
  inset: 0;
  background: var(--tier-color);
  pointer-events: none;
  animation: flash 500ms ease-out forwards;
}

@keyframes flash {
  0% { opacity: 0; }
  20% { opacity: 0.5; }
  100% { opacity: 0; }
}

/* Whole-page shake for the rarest tier. */
.screen-shake {
  animation: screen-shake 600ms linear;
}

@keyframes screen-shake {
  0%, 100% { transform: translate(0, 0); }
  15% { transform: translate(-8px, 4px); }
  30% { transform: translate(7px, -5px); }
  45% { transform: translate(-6px, -3px); }
  60% { transform: translate(5px, 4px); }
  75% { transform: translate(-3px, 2px); }
  90% { transform: translate(2px, -1px); }
}

/* Reveal text fades in once the box opens. It stays in the page while
   hidden so screen readers still announce the new lute. */
#reveal.pending { opacity: 0; }
