/* Battle entry/defeat particle presentation (materialize / dissolve).
   Companion of shared/battle-fx/battle-materialize.js - read the README at the top of that file.
   Every rule is scoped to `.battle.bfx-on` (added by the script unless ?battleFx=0) and to
   classes the script owns on .combatant: bfx-hidden, bfx-hold, bfx-parked, bfx-dis, bfx-dis-wait,
   bfx-dis-css, bfx-in-reduced. Sprites are only ever hidden with opacity on .sprite-flip (never display:none,
   scale(0) or a transform on .sprite-flip): recalcBattlePoints keeps measuring the real box and
   the facing flip (transform: scaleX(-1)) stays untouched. */

/* The script inserts the canvas right before #fxLayer. Same z-index as .fx-layer (4): DOM order
   paints the game's FX over the particle copy just as they paint over the real sprite
   (.combatant, z-index 3), so the copy-to-sprite hand-off is continuous. */
.battle-stage > canvas.battle-fx-canvas {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  z-index: 4;
  display: block;
  pointer-events: none;
}

/* ---- Entry ------------------------------------------------------------------------------------
   While the particles assemble the silhouette on the canvas, the DOM sprite and the combatant-level
   holo/Black Holo layers stay invisible; the script removes bfx-hidden under the finished copy. */
.battle.bfx-on .combatant.bfx-hidden .sprite-flip,
.battle.bfx-on .combatant.bfx-hidden .black-holo-aura,
.battle.bfx-on .combatant.bfx-hidden::before,
.battle.bfx-on .combatant.bfx-hidden::after {
  opacity: 0 !important;
}

/* The hold replaces the old 520 ms enc-enemy / enc-player img intro and, like that intro, parks
   the idle sheet on frame 0 (the frame the particles rebuild). Its name keeps the enc- prefix on
   purpose: the Black Holo sprinkle canvas stays blank while an enc-* animation runs (game.js). */
.battle.bfx-on .combatant.bfx-hold .sprite-flip img {
  animation: enc-bfx-hold 1000ms linear infinite !important;
}

@keyframes enc-bfx-hold {
  from { }
  to { }
}

/* Entry finished or interrupted (attack, hit, catch, faint) while .battle-intro is still on
   #battle: the hold is gone, so the legacy `.battle.battle-intro .combatant.enemy|player img`
   rule (specificity 0,4,1) would apply enc-enemy/enc-player as a NEW animation and fly the sprite
   in a second time from opacity 0 / scale(.35). Parked imgs drop it until the intro class goes.
   Specificity 0,4,2 on purpose and NOT !important / not scoped by .bfx-on: it must beat the
   enc-* rule but keep losing to the attack sheets (`.combatant.player.attacking .sprite-flip.
   battle-anim.battle-anim-attack img` 0,6,1, Black Holo attacking 0,5,1). */
.battle.battle-intro .combatant.bfx-parked span img {
  animation-name: none;
}

/* ---- Defeat -----------------------------------------------------------------------------------
   The canvas draws the breaking body on top; the DOM sprite fades out underneath in 110 ms and
   stays hidden for as long as `fainting` is present (the class is cleared by updateBattleUi when
   the side shows a living monster again). Replaces faint-drop / black-holo-sheet-faint /
   effect-bearing-monster-faint for the monsters this module dissolves. The img animations stop
   (faint-drop must not move a still under the copy); a sheet keeps the frame that was on screen
   because the script pins the computed margin-left / object-position inline at the KO. */
.battle.bfx-on .combatant.fainting.bfx-dis .sprite-flip,
.battle.bfx-on .combatant.fainting.bfx-dis .sprite-flip.battle-anim {
  animation: bfx-dis-out 110ms ease-out forwards !important;
}

.battle.bfx-on .combatant.fainting.bfx-dis .sprite-flip img,
.battle.bfx-on .combatant.fainting.bfx-dis-wait .sprite-flip img,
.battle.bfx-on .combatant.fainting.bfx-dis-css .sprite-flip img {
  animation: none !important;
}

/* Cache miss (another sheet frame than the entry's frame 0, a map-clip canvas, a resize): the
   KO'd sprite holds still on its frozen frame, fully visible, for at most 160 ms while that frame
   is sampled off the main thread. */
.battle.bfx-on .combatant.fainting.bfx-dis-wait .sprite-flip,
.battle.bfx-on .combatant.fainting.bfx-dis-wait .sprite-flip.battle-anim {
  animation: none !important;
}

@keyframes bfx-dis-out {
  from { opacity: 1; }
  to { opacity: 0; }
}

/* CSS-only fallback when the sprite cannot be sampled (tainted, vector, not decoded): a bright,
   blurred lift-and-fade. Individual translate/scale keep the wrapper's scaleX facing intact. */
.battle.bfx-on .combatant.fainting.bfx-dis-css .sprite-flip,
.battle.bfx-on .combatant.fainting.bfx-dis-css .sprite-flip.battle-anim {
  animation: bfx-dis-css 620ms ease-in forwards !important;
}

@keyframes bfx-dis-css {
  0% { opacity: 1; translate: 0 0; scale: 1; filter: brightness(1) blur(0); }
  35% { opacity: 0.9; translate: 0 -4px; scale: 1.02; filter: brightness(1.9) blur(1px); }
  100% { opacity: 0; translate: 0 -18px; scale: 1.06; filter: brightness(2.4) blur(7px); }
}

/* ---- Capture ----------------------------------------------------------------------------------
   Absorb (`in-ball`): bfx-abs-wait holds the foe at rest (no catch-absorb shrink, no radial mask)
   for the <= 160 ms its copy may need; bfx-abs hides it while the canvas copy erodes into the
   charm and keeps it hidden for as long as `in-ball` is present. Emerge (`escape`): bfx-emg stops
   catch-escape and keeps it stopped until `escape` goes away (it never restarts); bfx-hidden keeps
   the foe invisible until the motes have rebuilt it. The motes in flight are drawn on a second
   canvas right after #fxLayer (over the prism charm). */
.battle-stage > canvas.battle-fx-over {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  z-index: 4;
  display: block;
  pointer-events: none;
}

.battle.bfx-on .combatant.enemy.in-ball.bfx-abs-wait .sprite-flip,
.battle.bfx-on .combatant.enemy.in-ball.bfx-abs-wait .sprite-flip img,
.battle.bfx-on .combatant.enemy.in-ball.bfx-abs .sprite-flip,
.battle.bfx-on .combatant.enemy.in-ball.bfx-abs .sprite-flip img,
.battle.bfx-on .combatant.enemy.escape.bfx-emg .sprite-flip,
.battle.bfx-on .combatant.enemy.escape.bfx-emg .sprite-flip img {
  animation: none !important;
}

.battle.bfx-on .combatant.enemy.in-ball.bfx-abs-wait .sprite-flip {
  -webkit-mask-image: none !important;
  mask-image: none !important;
}

.battle.bfx-on .combatant.enemy.in-ball.bfx-abs .sprite-flip {
  opacity: 0 !important;
}

/* ---- Reduced motion ---------------------------------------------------------------------------
   No particles (the script never starts them). Entry: 200 ms opacity fade-in (Web Animations on
   the wrapper; bfx-in-reduced is the no-WAAPI fallback). Defeat: 300 ms opacity fade-out for
   every fainting monster, bosses included - plain monsters used to keep faint-drop here. The
   script pins the sheet frame on screen inline, so stopping the img animation never snaps it. */
@media (prefers-reduced-motion: reduce) {
  .battle.bfx-on .combatant.fainting .sprite-flip,
  .battle.bfx-on .combatant.fainting .sprite-flip.battle-anim {
    animation: bfx-reduced-out 300ms ease-out forwards !important;
  }

  .battle.bfx-on .combatant.fainting .sprite-flip img {
    animation: none !important;
  }

  .battle.bfx-on .combatant.bfx-in-reduced .sprite-flip {
    animation: bfx-reduced-in 200ms ease-out both !important;
  }
}

@keyframes bfx-reduced-out {
  from { opacity: 1; }
  to { opacity: 0; }
}

@keyframes bfx-reduced-in {
  from { opacity: 0; }
  to { opacity: 1; }
}
