/* ═══════════════════════════════════════════════════════════════════════════════════════════
   The site's "event" kit (owner 2026-10-09: notifications, tips and reminders should feel like the
   house games' win moment — "14b. Win card" in originals-ui.css). Components: src/components/ui/fx/.
   Tones: success = money in (the win green), process = in progress (blue), waiting = amber,
   error = red, neutral = crystal (no glow). Everything moves with transform / opacity only and is
   over in 900 ms (sweep .16 + .68 s, sparks ≤ .1 + .72 s, glow .9 s; the active-step pulse is the one slow
   loop); reduced motion = a plain fade.
   ═══════════════════════════════════════════════════════════════════════════════════════════ */

/* ── Tones: --fx / --fx-rgb ── */
.fx-tone--success { --fx: var(--success); --fx-rgb: var(--success-rgb); }
.fx-tone--process { --fx: var(--info, #38bdf8); --fx-rgb: var(--info-rgb, 56, 189, 248); }
.fx-tone--waiting { --fx: var(--warning); --fx-rgb: var(--warning-rgb); }
.fx-tone--error   { --fx: var(--danger); --fx-rgb: var(--danger-rgb); }
.fx-tone--neutral { --fx: #8fd6ff; --fx-rgb: 143, 214, 255; }

/* ── The card surface (optional: a component can keep its own and use the pieces below) ──
   Tinted edge, a light from the top in the tone, the win card's inset highlight; success adds the
   soft green glow around it. */
.fx-card {
  position: relative;
  isolation: isolate;
  border: 1px solid rgba(var(--fx-rgb, 143, 214, 255), .42);
  border-radius: var(--radius-lg);
  background:
    radial-gradient(120% 110% at 18% 0%, rgba(var(--fx-rgb, 143, 214, 255), .16) 0%, rgba(var(--fx-rgb, 143, 214, 255), 0) 62%),
    linear-gradient(180deg, rgba(var(--bg-elevated-rgb), .42) 0%, rgba(var(--bg-secondary-rgb), .98) 100%),
    var(--bg-secondary);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .08),
    0 18px 40px -14px rgba(0, 0, 0, .62);
}
.fx-card.fx-tone--success {
  border-color: rgba(var(--success-rgb), .55);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .09),
    0 0 0 1px rgba(var(--success-rgb), .1),
    0 18px 40px -14px rgba(0, 0, 0, .62),
    0 0 40px -10px rgba(var(--success-rgb), .34);
}
.fx-card.fx-tone--neutral { border-color: rgba(143, 214, 255, .2); }

/* ── Entrances ── */
/* Good news and progress: the win card's pop (a little overshoot, 0.28 s). No fill after the end, so a
   swipe's inline transform still works. */
.fx-pop { animation: fx-pop .28s cubic-bezier(.34, 1.5, .64, 1) backwards; }
/* Warnings / errors: crisp, no overshoot, no shake. */
.fx-enter { animation: fx-enter .18s cubic-bezier(.33, 1, .68, 1) backwards; }
@keyframes fx-pop {
  from { opacity: 0; transform: translateY(6px) scale(.9); }
}
@keyframes fx-enter {
  from { opacity: 0; transform: translateY(4px); }
}
/* A moment's end (useMoment, owner 2026-10-10: "it should show quickly then go away"): the last 0.4 s it fades and
   drifts up 4 px, then it is gone. !important: it must win over a card's own entrance rule in any stylesheet (e.g.
   .acc-field-msg.ok:not(:empty)); only the reduced-motion rule below replaces it. */
.fx-leave {
  animation: fx-leave .4s cubic-bezier(.4, 0, 1, 1) forwards !important;
  pointer-events: none;
}
@keyframes fx-leave {
  to { opacity: 0; transform: translateY(-4px); }
}

/* ── Glow: a halo behind the card that swells once, then rests (success) ── */
.fx-glow {
  position: absolute;
  inset: -40% -12%;
  z-index: -1;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(var(--fx-rgb, 45, 221, 30), .24), rgba(var(--fx-rgb, 45, 221, 30), 0));
  opacity: 0;
  pointer-events: none;
  animation: fx-glow .9s cubic-bezier(.22, 1, .36, 1) forwards;
}
@keyframes fx-glow {
  0% { opacity: 0; transform: scale(.6); }
  30% { opacity: 1; transform: scale(1.04); }
  100% { opacity: .45; transform: scale(1); }
}

/* ── Sweep: one light band across the card ── */
.fx-sweep {
  position: absolute;
  inset: 0;
  overflow: hidden;
  border-radius: inherit;
  pointer-events: none;
}
.fx-sweep::before {
  content: "";
  position: absolute;
  top: -25%;
  bottom: -25%;
  left: 0;
  width: 38%;
  background: linear-gradient(100deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, .16) 50%, rgba(255, 255, 255, 0) 100%);
  transform: translateX(-130%) skewX(-14deg);
  animation: fx-sweep .68s var(--fx-sweep-delay, .16s) cubic-bezier(.4, 0, .2, 1) forwards;
}
@keyframes fx-sweep {
  to { transform: translateX(360%) skewX(-14deg); }
}

/* ── Sparks: drift out and fade ── */
.fx-sparks {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.fx-sparks--edge { z-index: -1; }
.fx-sparks > i {
  position: absolute;
  width: 6px;
  height: 6px;
  margin: -3px 0 0 -3px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--fx, var(--success)) 65%, #fff);
  box-shadow: 0 0 8px rgba(var(--fx-rgb, 45, 221, 30), .85);
  opacity: 0;
  animation: fx-spark .72s var(--d, 0s) cubic-bezier(.2, .7, .3, 1) forwards;
}
.fx-sparks > i:nth-child(even) { width: 4px; height: 4px; margin: -2px 0 0 -2px; }
/* every third spark is gold: money (the site's one gold) */
.fx-sparks > i:nth-child(3n) { background: color-mix(in srgb, var(--gold, #ffd54a) 80%, #fff); box-shadow: 0 0 8px rgba(var(--gold-rgb, 255, 213, 74), .8); }
@keyframes fx-spark {
  0% { opacity: 0; transform: translate(0, 0) scale(.4); }
  25% { opacity: 1; transform: translate(calc(var(--dx) * .4), calc(var(--dy) * .4)) scale(1); }
  100% { opacity: 0; transform: translate(var(--dx), var(--dy)) scale(.3); }
}

/* ── Count: the final text (hidden) and the counting one share one cell: no size jumps ── */
.fx-count { display: inline-grid; font-variant-numeric: tabular-nums; }
.fx-count > .fx-count__room,
.fx-count > .fx-count__live { grid-area: 1 / 1; }
.fx-count__room { visibility: hidden; }
.fx-count__live { justify-self: start; }
.fx-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ── Steps (process): done = filled dot, active = a dot that pulses gently, to come = hollow ── */
.fx-steps {
  display: flex;
  align-items: center;
  gap: 0;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 11px;
  font-weight: 700;
  line-height: 14px;
  letter-spacing: .02em;
}
.fx-step {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--text-dim);
  white-space: nowrap;
}
.fx-step + .fx-step::before {
  /* the line between two steps: filled when the step before it is done */
  content: "";
  width: 14px;
  height: 1px;
  margin: 0 6px;
  background: rgba(255, 255, 255, .14);
}
.fx-step.is-done + .fx-step::before,
.fx-step.is-done + .fx-step.is-active::before { background: rgba(var(--fx-rgb, 56, 189, 248), .7); }
.fx-step__dot {
  position: relative;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  box-shadow: inset 0 0 0 1.5px rgba(255, 255, 255, .28);
  flex: none;
}
.fx-step.is-done { color: var(--text-muted); }
.fx-step.is-done .fx-step__dot { background: var(--fx, var(--info)); box-shadow: none; }
.fx-step.is-active { color: var(--text-primary); }
.fx-step.is-active .fx-step__dot { background: var(--fx, var(--info)); box-shadow: none; }
.fx-step.is-active .fx-step__dot::after {
  /* the gentle pulse: a ring that grows and fades (transform / opacity) */
  content: "";
  position: absolute;
  inset: -3px;
  border-radius: 50%;
  border: 1.5px solid var(--fx, var(--info));
  opacity: 0;
  animation: fx-step-pulse 1.8s cubic-bezier(.2, .7, .3, 1) infinite;
}
@keyframes fx-step-pulse {
  0% { opacity: .7; transform: scale(.6); }
  70%, 100% { opacity: 0; transform: scale(1.8); }
}

/* ── Coin mark: the coin's icon (or the cash mark), popping in on its own a moment after the card ── */
/* Sized in pixels, not 100% of a cell: some coin SVGs (BTC, ETH, DAI) say width="100%" and so have no size of
   their own — in a grid cell they grew to the browser default (300 x 150) and were drawn oversized. */
.fx-coin {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: var(--fx-coin, 32px);
  height: var(--fx-coin, 32px);
}
.fx-coin > img {
  display: block;
  flex: none;
  width: var(--fx-coin, 32px);
  height: var(--fx-coin, 32px);
  max-width: none;
  object-fit: contain;
  border-radius: 50%;
  filter: drop-shadow(0 4px 10px rgba(0, 0, 0, .45));
}
.fx-pop .fx-coin > img { animation: fx-coin-in .42s .06s cubic-bezier(.34, 1.56, .64, 1) backwards; }
@keyframes fx-coin-in {
  from { opacity: 0; transform: translateY(-8px) scale(.6) rotate(-25deg); }
}

/* A receipt lands with a drawn check. Pending, declined and refunded states
   use the same small mark with restrained motion; no new event/timer stream. */
.fx-receipt {
  display: inline-flex;
  flex: none;
  width: 36px;
  height: 36px;
  color: var(--fx, var(--success, #2DDD1E));
}
.fx-receipt svg { display: block; width: 100%; height: 100%; overflow: visible; }
.fx-receipt__ring { stroke: currentColor; stroke-width: 1.4; opacity: .45; }
.fx-receipt__symbol { stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.fx-receipt--animate .fx-receipt__ring { animation: fx-receipt-ring .4s .12s ease-out backwards; }
.fx-receipt--received.fx-receipt--animate .fx-receipt__symbol {
  animation: fx-receipt-check .3s .38s cubic-bezier(.2, .7, .3, 1) backwards;
}
.fx-receipt--processing.fx-receipt--animate svg { animation: fx-receipt-arrive .24s ease-out backwards; }
.fx-receipt--declined.fx-receipt--animate,
.fx-receipt--refunded.fx-receipt--animate,
.fx-receipt--updated.fx-receipt--animate { animation: fx-receipt-arrive .2s ease-out backwards; }
@keyframes fx-receipt-ring { from { stroke-dasharray: 1; stroke-dashoffset: 1; opacity: 0; } to { stroke-dasharray: 1; stroke-dashoffset: 0; opacity: .45; } }
@keyframes fx-receipt-check { from { stroke-dasharray: 1; stroke-dashoffset: 1; opacity: 0; } to { stroke-dasharray: 1; stroke-dashoffset: 0; opacity: 1; } }
@keyframes fx-receipt-arrive { from { opacity: 0; transform: translateY(3px); } }

/* ── Reduced motion: a plain fade, resting glow, no sweep / sparks / pulse / pop ── */
@media (prefers-reduced-motion: reduce) {
  .fx-pop,
  .fx-enter { animation: fx-fade .2s ease backwards; }
  .fx-leave { animation: fx-fade-out .4s ease forwards !important; }
  .fx-glow { animation: none; opacity: .45; }
  .fx-sweep,
  .fx-sparks { display: none; }
  .fx-step.is-active .fx-step__dot::after { animation: none; opacity: 0; }
  .fx-pop .fx-coin > img { animation: none; }
  .fx-receipt--animate,
  .fx-receipt--animate svg,
  .fx-receipt--animate .fx-receipt__ring,
  .fx-receipt--animate .fx-receipt__symbol { animation: none; }
}
@keyframes fx-fade {
  from { opacity: 0; }
}
@keyframes fx-fade-out {
  to { opacity: 0; }
}
