/* ============================================================================
   FanPulse shared floating reactions — paired with wireframe/assets/js/fp-reactions.js

   Two absolutely-positioned layers fill the host container: the particle canvas
   underneath, the chip layer on top. Neither takes pointer events.

   PERF: the float keyframes animate transform + opacity ONLY. Every glow is a
   static box-shadow, composited once — no animated filter/backdrop-filter, which
   would force a per-frame GPU blur pass for each chip on screen.

   color-mix() is used for the glow tints; each one is preceded by a plain
   rgba()/var() declaration so older engines still get a sane chip.
   ============================================================================ */

/* ---- layers ------------------------------------------------------------- */
.fpr-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 1;
  pointer-events: none;
}

.fpr-layer {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  overflow: hidden;
  /* containment lets the browser skip layout/paint work outside the stage */
  contain: strict;
}

/* ---- chip base ---------------------------------------------------------- */
.fpr-item {
  position: absolute;
  left: 50%;
  bottom: 40px;
  display: grid;
  place-items: center;
  transform: translate3d(-50%, 0, 0);
  will-change: transform, opacity;
  animation: fp-reax-float var(--life, 5200ms) cubic-bezier(.16, .78, .24, 1) forwards;
}

/* ---- variant: animated emoji GIF in a glow ring ------------------------- */
.fpr-img {
  width: 58px;
  height: 58px;
  padding: 7px;
  border-radius: 999px;
  overflow: hidden;
  background: linear-gradient(145deg, rgba(255, 255, 255, .18), rgba(20, 12, 48, .92));
  border: 1px solid rgba(255, 255, 255, .18);
  box-shadow:
    0 8px 16px rgba(0, 0, 0, .25),
    0 0 17px rgba(124, 60, 255, .52);
  box-shadow:
    0 8px 16px rgba(0, 0, 0, .25),
    0 0 17px color-mix(in srgb, var(--glow) 52%, transparent);
}

.fpr-img img {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: contain;
  border-radius: inherit;
}

/* ---- variant: sports word pill ------------------------------------------ */
.fpr-word {
  min-width: 72px;
  max-width: 180px;
  min-height: 34px;
  padding: 7px 15px 8px;
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  font-family: var(--font-display, 'Barlow Condensed', 'Oswald', system-ui, sans-serif);
  font-style: italic;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .03em;
  font-size: 17px;
  line-height: 1;
  white-space: nowrap;
  color: #0A0F1A;
  background:
    radial-gradient(circle at 30% 10%, rgba(255, 255, 255, .22), transparent 38%),
    linear-gradient(135deg, var(--glow, #6C3BFF), var(--glow, #6C3BFF));
  background:
    radial-gradient(circle at 30% 10%, rgba(255, 255, 255, .22), transparent 38%),
    linear-gradient(135deg,
      color-mix(in srgb, var(--glow) 90%, white 4%),
      color-mix(in srgb, var(--glow) 70%, black 18%));
  border: 1px solid rgba(255, 255, 255, .14);
  box-shadow:
    inset 0 1px 4px rgba(255, 255, 255, .18),
    0 8px 16px rgba(0, 0, 0, .25),
    0 0 22px rgba(124, 60, 255, .54);
  box-shadow:
    inset 0 1px 4px rgba(255, 255, 255, .18),
    0 8px 16px rgba(0, 0, 0, .25),
    0 0 22px color-mix(in srgb, var(--glow) 54%, transparent);
  text-shadow: 0 1px 2px rgba(0, 0, 0, .28);
}

/* Tone defaults. JS also writes --glow inline (inline wins, same value), so the
   particle trail and the pill always agree on a color. */
.fpr-word.tone-lime   { --glow: #C6FF00; color: #0A0F1A; }
.fpr-word.tone-violet { --glow: #6C3BFF; color: #ffffff; }
.fpr-word.tone-red    { --glow: #FF2D55; color: #ffffff; }
.fpr-word.tone-gold   { --glow: #FFC83D; color: #0A0F1A; }

/* ---- variant: unicode glyph disc ---------------------------------------- */
.fpr-u {
  width: 54px;
  height: 54px;
  font-size: 38px;
  line-height: 1;
  border-radius: 999px;
  background:
    radial-gradient(circle at 35% 25%, rgba(255, 255, 255, .30), transparent 35%),
    linear-gradient(145deg, var(--glow, #6C3BFF), rgba(38, 20, 78, .94));
  background:
    radial-gradient(circle at 35% 25%, rgba(255, 255, 255, .30), transparent 35%),
    linear-gradient(145deg, color-mix(in srgb, var(--glow) 72%, white 8%), rgba(38, 20, 78, .94));
  border: 1px solid rgba(255, 255, 255, .18);
  box-shadow:
    inset 0 1px 4px rgba(255, 255, 255, .25),
    0 8px 16px rgba(0, 0, 0, .25),
    0 0 24px rgba(124, 60, 255, .65);
  box-shadow:
    inset 0 1px 4px rgba(255, 255, 255, .25),
    0 8px 16px rgba(0, 0, 0, .25),
    0 0 24px color-mix(in srgb, var(--glow) 65%, transparent);
}

/* ---- float ------------------------------------------------------------- *
   transform + opacity only. Adding a filter here costs a full GPU blur pass
   per chip per frame and drops a 30-chip burst off the compositor thread. */
@keyframes fp-reax-float {
  0% {
    opacity: 0;
    transform: translate3d(calc(-50% + var(--start-x, 0px)), 12px, 0) scale(.58) rotate(var(--r0, 0deg));
  }
  10% { opacity: 1; }
  48% {
    opacity: 1;
    transform: translate3d(calc(-50% + var(--mid-x, 0px)), calc(var(--rise, 420px) * -.52), 0) scale(1) rotate(var(--r1, 0deg));
  }
  82% { opacity: .92; }
  100% {
    opacity: 0;
    transform: translate3d(calc(-50% + var(--end-x, 0px)), calc(var(--rise, 420px) * -1), 0) scale(.88) rotate(var(--r2, 0deg));
  }
}

@media (prefers-reduced-motion: reduce) {
  .fpr-item { animation-duration: calc(var(--life, 5200ms) * .5); }
}

/* ============================================================================
   Reaction bar — the button strip under a live stage.

   Sole owner of these rules: cast.php's page-local copy was deleted when the
   cast studio, events, watch parties and game rooms all moved onto this sheet.
   Rendered by includes/partials/reaction_bar.php.
   ============================================================================ */
.reax-bar{display:flex;align-items:center;gap:8px;margin-top:var(--sp-3);padding:8px;background:var(--c-surface);border:1px solid var(--c-border-2);border-radius:var(--r-lg);flex-wrap:wrap;}
.reax-emojibtn,.reax-gifbtn{flex:none;height:40px;border-radius:var(--r-md);border:1px solid var(--c-border);background:var(--c-bg-2);color:var(--c-text-2);cursor:pointer;display:grid;place-items:center;}
.reax-emojibtn{width:44px;}
.reax-gifbtn{padding:0 14px;font-weight:800;font-size:12px;letter-spacing:.05em;margin-left:auto;color:var(--c-violet);border-color:var(--c-violet);}
.reax-emojibtn:hover{border-color:var(--c-violet);color:#fff;}
.reax-gifbtn:hover{background:var(--c-violet);color:#fff;}
.reax-quick{display:flex;gap:6px;flex-wrap:wrap;}
.rq{display:inline-flex;align-items:center;gap:6px;height:40px;padding:0 12px 0 8px;border-radius:var(--r-pill);border:1px solid var(--c-border);background:var(--c-bg-2);color:var(--c-text-2);cursor:pointer;font-size:12px;font-weight:600;transition:transform .08s,border-color .15s;}
.rq:hover{border-color:var(--c-lime);color:#fff;transform:translateY(-1px);}
.rq:active{transform:scale(.94);}
.rq img{width:24px;height:24px;}
.rq .rq-u{font-size:20px;}
.reax-sports{display:flex;gap:6px;flex-wrap:wrap;}
.rchip{height:40px;padding:0 14px;border-radius:var(--r-pill);border:1px solid var(--c-violet);background:rgba(124,60,255,.10);color:#fff;cursor:pointer;font-family:var(--font-display);font-style:italic;font-weight:800;text-transform:uppercase;letter-spacing:.03em;font-size:14px;transition:transform .08s,background .15s;}
.rchip:hover{background:var(--c-violet);transform:translateY(-1px);}
.rchip:active{transform:scale(.94);}
