/* Blaster fire, and the little cutscene that plays when a miniature is shot
   off the board. */

#fx {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 30;
}

/* ---------------------------------------------------------------- letterbox */

#cinema {
  position: fixed;
  inset: 0;
  z-index: 50;
  pointer-events: none;
}
#cinema[hidden] { display: none; }

#cinema .bar-top,
#cinema .bar-bottom {
  position: absolute;
  left: 0;
  right: 0;
  height: 6vh;
  background: #05090f;
  transform: scaleY(0);
  transition: transform 0.34s cubic-bezier(0.3, 0.9, 0.3, 1);
}
#cinema .bar-top { top: 0; transform-origin: top; }
#cinema .bar-bottom { bottom: 0; transform-origin: bottom; }
#cinema.rolling .bar-top,
#cinema.rolling .bar-bottom { transform: scaleY(1); }

/* Everything that is not part of the action drops back into the cold. */
.dimmed {
  filter: brightness(0.4) saturate(0.55) contrast(0.95);
  transition: filter 0.28s ease;
}
.checker.dimmed { filter: brightness(0.38) saturate(0.5); }

/* --------------------------------------------------------------- the actors */

.checker.shooter { z-index: 400 !important; }
.checker.shooter .mini {
  animation: shooter-brace 0.9s ease-out forwards;
  filter: drop-shadow(0 0 10px rgba(255, 232, 168, 0.95))
          drop-shadow(1px 0 0 rgba(8, 16, 30, 0.9))
          drop-shadow(-1px 0 0 rgba(8, 16, 30, 0.9))
          drop-shadow(0 3px 4px rgba(4, 10, 22, 0.8));
}
@keyframes shooter-brace {
  0% { transform: scale(1); }
  22% { transform: scale(1.18) translateY(-3px); }
  34% { transform: scale(1.13) translateX(-4px); }
  100% { transform: scale(1.12); }
}

/* The shooter turns to face its target for the duration of the shot, which may
   be against its usual positional facing; fx.js toggles the same .face-left
   class board.css defines and puts it back afterwards. */

.checker.victim { z-index: 390 !important; }
.checker.victim .mini {
  animation: victim-fall 0.72s cubic-bezier(0.4, 0, 0.7, 1) forwards;
}
@keyframes victim-fall {
  0% { transform: scale(1); filter: brightness(1); }
  10% { transform: scale(1.12); filter: brightness(7) saturate(0); }
  20% { transform: scale(1.02) rotate(-8deg); filter: brightness(2.6) saturate(0.4); }
  60% { transform: rotate(-62deg) translateY(6px); filter: brightness(1) sepia(0.5); }
  100% { transform: rotate(-88deg) translateY(14px); opacity: 0; filter: brightness(0.6); }
}
.checker.victim .base { animation: victim-base 0.72s ease-out forwards; }
@keyframes victim-base {
  0% { box-shadow: 0 2px 5px rgba(8, 20, 38, 0.55); }
  15% { box-shadow: 0 0 0 5px rgba(255, 120, 90, 0.9), 0 0 26px 10px rgba(255, 70, 50, 0.75); }
  100% { box-shadow: 0 2px 5px rgba(8, 20, 38, 0.4); opacity: 0.25; }
}

/* Reissued kit: the miniature reappears on the bar, ready to fight again. */
.checker.rebuilt .mini { animation: rebuilt-fade 0.4s ease-out; }
.checker.rebuilt .base { animation: rebuilt-fade 0.4s ease-out; }
@keyframes rebuilt-fade {
  0% { opacity: 0; }
  100% { opacity: 1; }
}

/* --------------------------------------------------------------- laser bolt */

.bolt {
  position: absolute;
  left: 0;
  top: 0;
  height: 8px;
  width: 27px;
  background-image: url("../images/bullet-animation 1-000.png");
  background-size: 100% 100%;
  image-rendering: pixelated;
  transform-origin: 0 50%;
  filter: drop-shadow(0 0 5px #ff5b4e) drop-shadow(0 0 12px rgba(255, 60, 40, 0.85));
  will-change: transform, opacity;
}

/* A stretched glow riding behind the bolt, so it reads at speed. */
.bolt::after {
  content: "";
  position: absolute;
  right: 100%;
  top: 50%;
  transform: translateY(-50%);
  width: 46px;
  height: 3px;
  background: linear-gradient(to left, rgba(255, 90, 70, 0.95), rgba(255, 90, 70, 0));
}

.muzzle {
  position: absolute;
  width: 34px;
  height: 34px;
  margin: -17px 0 0 -17px;
  border-radius: 50%;
  background: radial-gradient(circle, #fff 0%, #ffd08a 26%, rgba(255, 108, 60, 0.7) 52%, rgba(255, 60, 40, 0) 72%);
  animation: muzzle-pop 0.22s ease-out forwards;
  pointer-events: none;
}
@keyframes muzzle-pop {
  0% { transform: scale(0.2); opacity: 1; }
  45% { transform: scale(1.5); opacity: 1; }
  100% { transform: scale(2.1); opacity: 0; }
}

.impact {
  position: absolute;
  width: 20px;
  height: 20px;
  margin: -10px 0 0 -10px;
  border-radius: 50%;
  background: radial-gradient(circle, #ffffff 0%, #ffe08a 30%, rgba(255, 90, 60, 0.85) 55%, rgba(255, 60, 40, 0) 75%);
  animation: impact-burst 0.42s ease-out forwards;
}
@keyframes impact-burst {
  0% { transform: scale(0.3); opacity: 1; }
  40% { transform: scale(3.4); opacity: 1; }
  100% { transform: scale(5.2); opacity: 0; }
}

/* Snow kicked up where the shot lands. */
.spark {
  position: absolute;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: #fff3d0;
  box-shadow: 0 0 6px #ffb98a;
  animation: spark-fly 0.5s ease-out forwards;
}
@keyframes spark-fly {
  0% { transform: translate(0, 0) scale(1); opacity: 1; }
  100% { transform: translate(var(--dx), var(--dy)) scale(0.2); opacity: 0; }
}

/* Scorch mark left behind on the snow. */
.scorch {
  position: absolute;
  width: 44px;
  height: 18px;
  margin: -9px 0 0 -22px;
  border-radius: 50%;
  background: radial-gradient(ellipse, rgba(38, 26, 20, 0.72), rgba(38, 26, 20, 0));
  animation: scorch-fade 2.6s ease-out forwards;
}
@keyframes scorch-fade {
  0% { opacity: 0; transform: scale(0.4); }
  12% { opacity: 1; transform: scale(1); }
  100% { opacity: 0; transform: scale(1.1); }
}

/* ------------------------------------------------------------- screen shake */

#stage.shake { animation: shake 0.34s cubic-bezier(0.36, 0.07, 0.19, 0.97); }
@keyframes shake {
  10%, 90% { transform: var(--stage-scale) translate(-2px, 1px); }
  20%, 80% { transform: var(--stage-scale) translate(4px, -2px); }
  30%, 50%, 70% { transform: var(--stage-scale) translate(-7px, 2px); }
  40%, 60% { transform: var(--stage-scale) translate(7px, -1px); }
}

/* --------------------------------------------------------------- kill title

   Drawn on #cinema, which is fixed to the window, rather than on #fx, which
   rides inside the camera - a title on the board was magnified with it and ran
   off both sides of a 700px scene. Here it is measured against the window, so
   it stays whole however far the camera has pushed in. The size is capped in
   vw as well as pixels: "FOR THE EMPIRE!" at this tracking is about fourteen
   times the font size wide, so 6vw keeps the longest line inside the narrowest
   window it will be read in. */

#cinema .callout {
  position: absolute;
  left: 50%;
  top: 15vh;
  transform: translateX(-50%);
  max-width: 96vw;
  font-family: var(--font);
  font-size: clamp(17px, 6vw, 44px);
  font-weight: 800;
  letter-spacing: 0.26em;
  padding-left: 0.26em;             /* balance the trailing letter-space */
  text-transform: uppercase;
  text-align: center;
  color: #fff;
  text-shadow: 0 0 18px rgba(255, 59, 48, 0.9), 0 4px 0 rgba(0, 0, 0, 0.5);
  animation: callout-slam 0.82s cubic-bezier(0.2, 1.4, 0.4, 1) forwards;
  white-space: nowrap;
}
/* The title is white either way - it is the halo behind it that says who is
   shouting. A black halo is no halo, so the imperial one is cold steel. */
#cinema .callout.empire { text-shadow: 0 0 18px rgba(170, 212, 255, 0.85), 0 4px 0 rgba(0, 0, 0, 0.6); }

@keyframes callout-slam {
  0% { transform: translateX(-50%) scale(2.2); opacity: 0; }
  22% { transform: translateX(-50%) scale(1); opacity: 1; }
  78% { opacity: 1; }
  100% { opacity: 0; transform: translateX(-50%) scale(1.06); }
}

/* --------------------------------------------------------- reduced motion */

@media (prefers-reduced-motion: reduce) {
  .checker { transition: none; }
  #camera { transition: none; }
  #stage.shake { animation: none; }
}
