/* Shared plumbing for theme-package decorations (see themes/loader.js).
   Packages style the LOOK of .tfx nodes; this file only owns how they sit
   and move, so every package gets the same cheap, compositor-only motion. */

.tfx { pointer-events: none; }
.tfx-layer { position: absolute; inset: 0; }
.tfx-particles { position: absolute; inset: 0; overflow: hidden; }

/* Each particle is a full-height column that slides by its own height, so
   translateY(-100%) always means "one container height" whatever the box
   size. The visible mote is the ::before at the column's leading end. */
.tfx-p {
  position: absolute; top: 0; left: var(--x, 50%);
  width: var(--s, 3px); height: 100%;
  opacity: 0;
  will-change: transform, opacity;
  animation: tfx-rise var(--d, 9s) linear var(--dl, 0s) infinite;
}
.tfx-p::before {
  content: ''; position: absolute; left: 0;
  width: var(--s, 3px); height: var(--s, 3px); border-radius: 50%;
  animation: tfx-sway var(--sd, 2.4s) ease-in-out infinite alternate;
}
.tfx-rise .tfx-p::before { bottom: 0; }
.tfx-fall .tfx-p::before { top: 0; }
.tfx-fall .tfx-p { animation-name: tfx-fall; }

@keyframes tfx-rise {
  0%   { transform: translate3d(0, 4%, 0); opacity: 0; }
  12%  { opacity: var(--o, 0.8); }
  70%  { opacity: calc(var(--o, 0.8) * 0.75); }
  100% { transform: translate3d(var(--dx, 0), -104%, 0); opacity: 0; }
}
@keyframes tfx-fall {
  0%   { transform: translate3d(0, -4%, 0); opacity: 0; }
  10%  { opacity: var(--o, 0.8); }
  85%  { opacity: var(--o, 0.8); }
  100% { transform: translate3d(var(--dx, 0), 104%, 0); opacity: 0; }
}
@keyframes tfx-sway {
  from { transform: translateX(calc(var(--sw, 6px) * -1)); }
  to   { transform: translateX(var(--sw, 6px)); }
}

@media (prefers-reduced-motion: reduce) {
  .tfx-particles { display: none; }
}

/* ---------- Stream-effect layers every theme gets ----------
   Put on a player's element for one effect (loader.js runSlotEffect), then
   removed. Themes restyle or replace them via their own theme.json events.
   Rule for themes: never put `animation` on the player's element itself for
   an effect (it would replace the page's own entrance and turn glows); animate
   these layers instead. The engine shakes elements with the separate
   `translate` property for the same reason. */
.tfx-ev { z-index: 7; }
.tfx-flash {
  opacity: 0;
  mix-blend-mode: screen;
  animation: tfx-flash 0.8s ease-out both;
}
.tfx-flash--long { animation-duration: 1.6s; }
.tfx-flash--red   { background: radial-gradient(110% 90% at 50% 50%, rgba(255, 50, 50, 0.15), rgba(255, 30, 30, 0.55)); }
.tfx-flash--white { background: rgba(255, 255, 255, 0.55); animation-duration: 0.35s; }
.tfx-flash--green { background: radial-gradient(110% 90% at 50% 60%, rgba(80, 255, 160, 0.35), rgba(40, 200, 120, 0.15)); }
@keyframes tfx-flash {
  0% { opacity: 0; } 12% { opacity: 1; } 100% { opacity: 0; }
}
.tfx-cursed {
  background: radial-gradient(100% 80% at 50% 50%, rgba(120, 40, 200, 0.05), rgba(90, 20, 160, 0.35));
  mix-blend-mode: multiply;
  animation: tfx-cursed-pulse 2.4s ease-in-out infinite;
}
@keyframes tfx-cursed-pulse { 0%, 100% { opacity: 0.6; } 50% { opacity: 1; } }
