/* S9 Juice/VFX (ADR-0013) placeholder styles — hand-authored, OUTSIDE the
   Sass/Rake pipeline (same precedent as style/hud.css). Linked in
   index.html AFTER style/main.css — the +N tier-colour rule below needs
   source-order to win the specificity tiebreak (guardrail 5). Only the
   rules VFXController's contract requires live here: the canvas
   coordinate-space contract, the screen-shake keyframe, the multiplier-bar
   transient FX keyframes, and the +N tier-colour override. */

/* Load-bearing, NOT cosmetic (ADR-0013 §3a, registry:
   vfx_canvas_coordinate_space). ctx.setTransform(dpr,...) carries no
   translation term, so canvas-local (0,0) equals viewport (0,0) ONLY
   under position:fixed. Under absolute, in normal page flow, every
   particle renders offset by the page-header height. */
#vfx-overlay {
  position: fixed;
  top: 0; left: 0;
  pointer-events: none;
}

/* Screen shake (ADR-0013 §5) — CSS keyframe, never per-frame JS. Duration
   is PROVISIONAL (0.15s) — the GDD's Tuning Knobs table gives SHAKE_MERGE
   as a magnitude (px) ceiling but no explicit per-merge shake duration;
   tune via a future playtest pass. */
@keyframes vfx-shake {
  0%   { transform: translate(0, 0); }
  25%  { transform: translate(var(--vfx-shake-magnitude, 0px), 0); }
  50%  { transform: translate(0, 0); }
  75%  { transform: translate(calc(var(--vfx-shake-magnitude, 0px) * -1), 0); }
  100% { transform: translate(0, 0); }
}
.game-container.vfx-shake-active {
  animation: vfx-shake 0.15s ease-in-out;
}

/* Multiplier-bar transient FX (ADR-0013 §6) — class names DISJOINT from
   HUDController's persistent tier-0..tier-4 fill classes + scaleX
   transform (guardrail 7). vfx-bar-charge/vfx-bar-cap-flash animate the
   bar fill itself (#multiplier-bar); vfx-bar-tier-pulse animates the
   surrounding #multiplier-container — a visually bigger cue for the rarer
   "tier changed" event — matching js/vfx_controller.js's own class-target
   choice (see its onEvent() and the animationend auto-clear wiring in its
   constructor). Durations/colours PROVISIONAL, tune via playtest. */
#multiplier-bar.vfx-bar-charge {
  animation: vfx-bar-charge-flash 0.2s ease-out;
}
#multiplier-container.vfx-bar-tier-pulse {
  animation: vfx-bar-tier-pulse 0.4s ease-in-out;
}
#multiplier-bar.vfx-bar-cap-flash {
  animation: vfx-bar-cap-flash 0.18s ease-out; /* ~180ms per the GDD's cap
                                                   flash spike timing */
}
@keyframes vfx-bar-charge-flash {
  0%   { filter: brightness(1); }
  30%  { filter: brightness(1.6); }
  100% { filter: brightness(1); }
}
@keyframes vfx-bar-tier-pulse {
  0%, 100% { filter: brightness(1); }
  50%      { filter: brightness(1.3); }
}
@keyframes vfx-bar-cap-flash {
  0%   { box-shadow: 0 0 0 rgba(255, 255, 255, 0); }
  40%  { box-shadow: 0 0 12px 4px rgba(255, 255, 255, 0.9); }
  100% { box-shadow: 0 0 0 rgba(255, 255, 255, 0); }
}

/* +N tier colour (ADR-0013 §7, guardrail 5) — specificity MUST match the
   base's compiled rule EXACTLY. main.scss nests .score-addition inside
   `.score-container, .best-container`, which compiles to the grouped
   selector below at style/main.css:76 — specificity (0,2,0). A bare
   `.score-addition { ... }` selector, specificity (0,1,0), would SILENTLY
   LOSE every time (the CSS cascade is specificity-first) and the colour
   would never visibly change. This file is <link>-ed AFTER style/main.css
   in index.html — specificity is equal at this exact grouped form, so
   source order is the (already-satisfied) tiebreak. */
.score-container .score-addition,
.best-container .score-addition {
  color: var(--vfx-tier-color, inherit);
}

/* Level-up celebration banner (js/vfx_controller.js showCelebration) —
   non-blocking overlay centered over the board, pointer-events:none,
   auto-clears via animationend. Colours PROVISIONAL (reuse the tier/heat
   palette). The .vfx-reduced variant (set from resolveReducedMotion()) swaps
   the scale/slide keyframe for an opacity-only fade — no strobe
   (TR-vfx-020). */
#vfx-celebration {
  position: absolute;
  top: 40%;
  left: 0;
  right: 0;
  text-align: center;
  font-weight: bold;
  font-size: 24px;
  letter-spacing: 1px;
  color: #f9f6f2;
  text-shadow: 0 2px 12px rgba(0, 0, 0, 0.5), 0 0 22px #f65e3b;
  pointer-events: none;
  opacity: 0;
  z-index: 30;
}
#vfx-celebration.vfx-celebrate-active {
  animation: vfx-celebrate 1.1s ease-out;
}
#vfx-celebration.vfx-celebrate-active.vfx-reduced {
  animation: vfx-celebrate-fade 1.1s ease-out;
}
@keyframes vfx-celebrate {
  0%   { opacity: 0; transform: translateY(12px) scale(0.85); }
  18%  { opacity: 1; transform: translateY(0) scale(1.06); }
  30%  { transform: scale(1); }
  75%  { opacity: 1; }
  100% { opacity: 0; transform: translateY(-8px) scale(1); }
}
@keyframes vfx-celebrate-fade {
  0%   { opacity: 0; }
  15%  { opacity: 1; }
  80%  { opacity: 1; }
  100% { opacity: 0; }
}

/* Run-end rank card (js/run_end_card.js) — a stat block inside the base
   .game-message overlay (shown on game-over/won). Dark text over the base's
   light-beige overlay backdrop. */
.rank-summary {
  margin: 12px auto 0;
  max-width: 220px;
  font-weight: bold;
  color: #776e65;
}
.rank-summary-row {
  display: flex;
  justify-content: space-between;
  padding: 3px 2px;
  font-size: 18px;
}
.rank-summary-label {
  opacity: 0.65;
  letter-spacing: 1px;
}
.rank-summary-newbest {
  text-align: center;
  font-size: 20px;
  letter-spacing: 2px;
  color: #d19b00;
  text-shadow: 0 0 12px rgba(237, 194, 46, 0.55);
  margin-bottom: 6px;
  animation: vfx-newbest-pulse 1.2s ease-in-out infinite;
}
@keyframes vfx-newbest-pulse {
  0%, 100% { opacity: 0.82; }
  50%      { opacity: 1; }
}
