/* =====================================================================
   LEVEL UP
   ===================================================================== */
.levelup-kicker {
  position: relative;
  font-family: 'Orbitron', sans-serif;
  font-size: 0.78rem;
  letter-spacing: 7px;
  color: var(--cyan-bright);
  text-transform: uppercase;
}
.levelup-number {
  position: relative;
  font-family: 'Orbitron', sans-serif;
  font-weight: 700;
  font-size: clamp(3.4rem, 14vw, 6rem);
  line-height: 1;
  margin: 6px 0 18px;
  color: var(--gold-bright);
  text-shadow: 0 0 26px var(--gold), 0 0 60px rgba(255, 217, 77, 0.55), 0 5px 0 #000;
  animation: levelPop 700ms cubic-bezier(0.16, 1.1, 0.3, 1.5) both;
}
@keyframes levelPop {
  0%   { transform: scale(0.2) rotate(-12deg); opacity: 0; }
  60%  { transform: scale(1.2) rotate(4deg); opacity: 1; }
  100% { transform: scale(1) rotate(0deg); }
}

.levelup-perks {
  position: relative;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 9px;
  margin-bottom: 22px;
  text-align: left;
}
.levelup-perks li {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 11px 15px;
  border-radius: var(--radius-sm);
  background: rgba(0, 0, 0, 0.42);
  border: 1px solid var(--border-dim);
  font-family: 'Orbitron', sans-serif;
  font-size: 0.76rem;
  color: var(--panel-text);
}
/* =====================================================================
   THE BADGE
   ---------------------------------------------------------------------
   When the player has a picture, the new level rides on it: the portrait
   is the medal and the number is the stamp on its corner. Without one
   this collapses back to the bare number exactly as before, which is why
   the number keeps its own styling rather than being restyled here.
   ===================================================================== */
.levelup-badge {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin: 6px auto 14px;
}

.levelup-avatar {
  width: clamp(96px, 30vw, 132px);
  height: clamp(96px, 30vw, 132px);
  border-radius: 50%;
  object-fit: cover;
  border: 3px solid var(--gold-bright);
  box-shadow: 0 0 0 6px rgba(0, 0, 0, 0.55), 0 0 44px -6px var(--gold);
  animation: levelAvatarIn 720ms cubic-bezier(0.16, 1.1, 0.3, 1.4) both;
}
.levelup-avatar[hidden] { display: none; }

@keyframes levelAvatarIn {
  0%   { transform: scale(0.4) rotate(-8deg); opacity: 0; }
  65%  { transform: scale(1.08) rotate(3deg); opacity: 1; }
  100% { transform: scale(1) rotate(0deg); }
}

/* With a portrait the number shrinks and sits on its corner; without
   one it stays exactly the size it always was. */
.levelup-badge.has-avatar .levelup-number {
  position: absolute;
  right: -10px;
  bottom: -6px;
  margin: 0;
  font-size: clamp(1.5rem, 6vw, 2.2rem);
  padding: 4px 12px;
  border-radius: var(--radius-pill);
  background: linear-gradient(180deg, #ffd94d, #c9962f);
  color: #1a1206;
  border: 2px solid rgba(0, 0, 0, 0.6);
  text-shadow: none;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.6);
}

/* =====================================================================
   THE REWARD ROWS
   ---------------------------------------------------------------------
   Each row is one thing that was handed over, with the icon it has
   everywhere else in the game. The old list mixed gifts in with running
   totals — spin capacity, payout multiplier — and a bullet in front of
   every line made them all look equally important.
   ===================================================================== */
.levelup-perks li {
  /* Landing one after another rather than as a block, so the eye reads
     down the list instead of being handed all of it at once. --row is
     set per item from JS; the timing is entirely CSS. */
  animation: levelPerkIn 420ms cubic-bezier(0.2, 0.9, 0.3, 1) both;
  animation-delay: calc(260ms + var(--row, 0) * 90ms);
}
@keyframes levelPerkIn {
  0%   { opacity: 0; transform: translateY(10px) scale(0.97); }
  100% { opacity: 1; transform: translateY(0) scale(1); }
}

/* The old bullet is gone — every row now carries real artwork. */
.levelup-perks li::before { content: none; }

.levelup-perk-icon {
  flex: none;
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
}
.levelup-perk-icon img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  /* GAIN_ART and SHOP_CHEST_ART inject bare <img> with no sizing of
     their own; without this a 480px chest render arrives at full size. */
}
.levelup-perk-text {
  font-size: 0.86rem;
  letter-spacing: 0.02em;
}

/* The tally on a row that collapsed duplicates. Pushed to the far end by
   its own auto margin rather than by a spacer element, so a row without
   one is laid out identically to a row with one — the text does not
   shift depending on whether the player happened to win two. */
.levelup-perk-count {
  margin-left: auto;
  flex: none;
  padding: 2px 9px;
  border-radius: 999px;
  background: linear-gradient(180deg, rgba(255, 217, 77, 0.28), rgba(255, 184, 0, 0.14));
  border: 1px solid rgba(255, 217, 77, 0.55);
  color: var(--gold-bright, #ffd94d);
  font-family: 'Orbitron', sans-serif;
  font-size: 0.82rem;
  font-weight: 800;
  letter-spacing: 0.04em;
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.6);
}
@media (max-width: 480px) {
  .levelup-perk-count { font-size: 0.74rem; padding: 2px 7px; }
}

/* An unlock is the rarest line on the panel, so it is allowed to look
   like one rather than sitting flush with a coin total. */
.levelup-perks li.levelup-perk-unlock {
  background: linear-gradient(90deg, rgba(255, 217, 77, 0.16), rgba(0, 0, 0, 0.42) 60%);
  border-color: rgba(255, 217, 77, 0.5);
}
.levelup-perks li.levelup-perk-unlock .levelup-perk-text {
  color: var(--gold-bright);
  font-weight: 700;
}

@media (max-width: 480px) {
  .levelup-perk-icon { width: 28px; height: 28px; }
  .levelup-perk-text { font-size: 0.78rem; }
}

@media (prefers-reduced-motion: reduce) {
  .chest-visual, .chest-rays, .levelup-rays { animation: none; }
}

/* =====================================================================
   SPOOKY SHOWCASE — the terror family. Landing these is the game
   threatening you, so the celebratory gold is swapped for blood-red
   rays, a fog wash and a shudder.
   ===================================================================== */
.symbol-showcase.spooky .symbol-showcase-rays {
  background: repeating-conic-gradient(
    from 0deg,
    rgba(190, 20, 28, 0.42) 0deg 5deg,
    rgba(60, 0, 8, 0) 5deg 11deg
  );
  animation-duration: 260ms, 4s;
}

/* Dark vignette that closes in behind the symbol. */
.symbol-showcase.spooky::before {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse at center, rgba(60, 0, 8, 0.30) 0%, rgba(0, 0, 0, 0.88) 75%);
  animation: spookyFog 620ms ease-out both;
  pointer-events: none;
}
@keyframes spookyFog {
  from { opacity: 0; transform: scale(1.25); }
  to   { opacity: 1; transform: scale(1); }
}

.symbol-showcase.spooky .symbol-showcase-img {
  filter: drop-shadow(0 0 18px #ff2d2d) drop-shadow(0 0 46px #6b0d14);
  animation: spookyPulse 0.75s ease-in-out infinite alternate, spookyShudder 3s ease-in-out infinite;
}
@keyframes spookyPulse {
  from { filter: drop-shadow(0 0 14px #b3121c) drop-shadow(0 0 30px #3d060b); transform: scale(1); }
  to   { filter: drop-shadow(0 0 34px #ff4d4d) drop-shadow(0 0 78px #ff2d2d); transform: scale(1.07); }
}
/* Irregular, off-beat jitter — a steady shake reads as a UI glitch,
   this reads as something moving on its own. */
@keyframes spookyShudder {
  0%, 100%   { translate: 0 0; }
  4%         { translate: -5px 2px; }
  8%         { translate: 4px -3px; }
  12%        { translate: -2px 0; }
  16%        { translate: 0 0; }
  55%        { translate: 3px 2px; }
  58%        { translate: -4px -1px; }
  62%        { translate: 0 0; }
}

.symbol-showcase.spooky .symbol-showcase-label {
  color: #ff4d4d;
  text-shadow: 0 0 14px #b3121c, 0 0 34px rgba(255, 45, 45, 0.65), 0 3px 0 #000;
  animation: spookyFlicker 2.4s linear infinite;
}
/* Failing-bulb flicker. */
@keyframes spookyFlicker {
  0%, 42%, 46%, 100% { opacity: 1; }
  43%                { opacity: 0.35; }
  44%                { opacity: 0.9; }
  45%                { opacity: 0.2; }
  78%                { opacity: 1; }
  79%                { opacity: 0.45; }
  80%                { opacity: 1; }
}

.symbol-showcase.spooky .symbol-showcase-phrase {
  color: #ffd7d7;
  text-shadow: 0 0 10px #b3121c, 0 2px 6px #000;
}

@media (prefers-reduced-motion: reduce) {
  .symbol-showcase.spooky .symbol-showcase-img,
  .symbol-showcase.spooky .symbol-showcase-label { animation: none; }
  .symbol-showcase.spooky::before { animation-duration: 200ms; }
}

/* "Open all" — only rendered when a queue has built up, so it never
   competes with the single-chest tap it exists to shortcut. */
.chest-open-all {
  position: relative;
  appearance: none;
  cursor: pointer;
  display: block;
  margin: 0 auto 12px;
  padding: 10px 26px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--gold);
  background: linear-gradient(180deg, #b8860b, #7a4f10);
  color: #fff;
  font-family: 'Orbitron', sans-serif;
  font-weight: 700;
  font-size: 0.76rem;
  letter-spacing: 2px;
  transition: transform 0.15s ease, background 0.15s ease;
}
.chest-open-all:hover:not(:disabled) { transform: scale(1.05); background: linear-gradient(180deg, #e0a81c, #9a6413); }
.chest-open-all:disabled { opacity: 0.5; cursor: wait; }
.chest-open-all[hidden] { display: none; }

/* Regeneration line under the spin count. */
.hud-regen {
  font-size: 0.56rem;
  letter-spacing: 1px;
  color: var(--text-dim);
  text-transform: uppercase;
  margin-top: 2px;
}
.hud-regen.regen-full { color: var(--green); }
.hud-regen[hidden] { display: none; }

/* Holding more spins than the regen ceiling — a reward, so it reads
   gold rather than as a warning. */
.hud-stat.overflowing .hud-value { color: var(--gold-bright); }
.hud-stat.overflowing .hud-max { color: var(--gold-deep); }
.hud-stat.overflowing { border-color: var(--gold-deep); }

/* The SPIN button while free spins are running. */
.btn.spin.free {
  background: linear-gradient(180deg, #d9a418, #8a5a12);
  border-color: var(--gold-bright);
  animation: freeSpinPulse 1.4s ease-in-out infinite;
}
@keyframes freeSpinPulse {
  0%, 100% { box-shadow: 0 0 0 rgba(255, 217, 77, 0); }
  50%      { box-shadow: 0 0 22px rgba(255, 217, 77, 0.75); }
}

/* =====================================================================
   WIN MESSAGE SCRIM — the reels underneath are bright and moving, so
   large text over them was hard to read. Dims the whole scene for
   exactly as long as the message is up.
   ===================================================================== */
.win-message-container::before {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse at center, rgba(0, 0, 0, 0.55) 0%, rgba(0, 0, 0, 0.82) 100%);
  opacity: 0;
  transition: opacity 260ms ease;
  pointer-events: none;
}
.win-message-container.scrim-active::before { opacity: 1; }

/* The message itself no longer needs its own heavy plate now that the
   backdrop is doing the work. */
#winMessage {
  background: rgba(0, 0, 0, 0.45);
  backdrop-filter: blur(2px);
}

/* =====================================================================
   COIN SHOWER
   ===================================================================== */
.falling-coin {
  position: absolute;
  top: -60px;
  width: 34px;
  height: auto;
  pointer-events: none;
  filter: drop-shadow(0 3px 6px rgba(0, 0, 0, 0.6));
  animation: coinFall 2s cubic-bezier(0.35, 0.1, 0.6, 1) forwards;
}
@keyframes coinFall {
  0%   { opacity: 0; transform: translate(0, 0) rotate(0deg) scale(0.7); }
  12%  { opacity: 1; }
  85%  { opacity: 1; }
  100% {
    opacity: 0;
    transform: translate(var(--drift, 0), 105vh) rotate(var(--spin-end, 540deg)) scale(1);
  }
}

/* =====================================================================
   EDGE PULSE — light blooming inward from the screen edges.
   ===================================================================== */
.edge-pulse {
  position: fixed;
  inset: 0;
  z-index: 940;
  pointer-events: none;
  opacity: 0;
  /* Transparent centre so it frames the action instead of veiling it. */
  box-shadow: inset 0 0 120px 30px var(--pulse-color, rgba(255, 217, 77, 0.85));
}
.edge-pulse.active { animation: edgePulse 1.2s ease-out forwards; }
.edge-pulse[data-tone="gold"]    { --pulse-color: rgba(255, 217, 77, 0.85); }
.edge-pulse[data-tone="rainbow"] { --pulse-color: rgba(var(--violet-mid-rgb), 0.9); }

@keyframes edgePulse {
  0%   { opacity: 0; }
  18%  { opacity: 1; }
  100% { opacity: 0; }
}
/* The top tier cycles hue so it never reads as the same effect twice. */
.edge-pulse[data-tone="rainbow"].active { animation: edgePulse 1.2s ease-out forwards, edgeHue 1.2s linear; }
@keyframes edgeHue {
  0%   { filter: hue-rotate(0deg); }
  100% { filter: hue-rotate(320deg); }
}

/* =====================================================================
   BET HEADROOM — the ceiling rises with level AND banked spins, so it
   is easy to sit at 1x without noticing there is room above.
   ===================================================================== */
.bet-stepper.can-raise {
  border-color: var(--gold);
  box-shadow: 0 0 0 1px rgba(255, 217, 77, 0.35), 0 0 14px rgba(255, 217, 77, 0.3);
}
.bet-stepper.can-raise #betUp {
  color: var(--gold-bright);
  animation: betNudge 1.9s ease-in-out infinite;
}
@keyframes betNudge {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.18); }
}

/* Shows the ceiling right on the control, so "how high can I go" is
   answered without opening anything. */
.bet-stepper.can-raise::after {
  content: 'up to ' attr(data-max) '×';
  position: absolute;
  bottom: -16px;
  left: 50%;
  transform: translateX(-50%);
  font-size: 0.55rem;
  letter-spacing: 1px;
  color: var(--gold-bright);
  white-space: nowrap;
  text-transform: uppercase;
}
.bet-stepper { position: relative; }

/* One-off celebration when the ceiling actually goes up. */
.bet-stepper.just-raised { animation: betRaised 2.6s ease-out; }
@keyframes betRaised {
  0%   { box-shadow: 0 0 0 0 rgba(255, 217, 77, 0.9); transform: scale(1); }
  12%  { box-shadow: 0 0 0 12px rgba(255, 217, 77, 0); transform: scale(1.12); }
  24%  { transform: scale(1); }
  36%  { box-shadow: 0 0 0 0 rgba(255, 217, 77, 0.7); }
  48%  { box-shadow: 0 0 0 12px rgba(255, 217, 77, 0); }
  100% { box-shadow: 0 0 14px rgba(255, 217, 77, 0.3); }
}

@media (prefers-reduced-motion: reduce) {
  .falling-coin { animation-duration: 1s; }
  .bet-stepper.can-raise #betUp,
  .bet-stepper.just-raised,
  .edge-pulse[data-tone="rainbow"].active { animation: none; }
  .edge-pulse.active { animation: edgePulse 600ms ease-out forwards; }
}


/* =====================================================================
   THE NEW-SYMBOL REVEAL
   ---------------------------------------------------------------------
   Shown once, after the level-up panel has been dismissed, when a reel
   symbol the player has never seen becomes dealable. The spiral behind
   the art is the same idea as the Wonderland doorway: something turning,
   pulling the eye to the middle where the symbol sits.
   ===================================================================== */
.symbol-unlock {
  position: fixed;
  inset: 0;
  z-index: 12700;
  display: grid;
  place-items: center;
  background: rgba(4, 2, 12, 0.78);
  opacity: 0;
  transition: opacity 280ms ease;
}
.symbol-unlock.open { opacity: 1; }

.symbol-unlock-card {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  width: min(26rem, 90vw);
  padding: 30px 24px 22px;
  border-radius: 22px;
  border: 2px solid var(--gold, #ffd94d);
  background: linear-gradient(180deg, #241243, #0d0620);
  box-shadow: 0 26px 60px rgba(0, 0, 0, 0.7), 0 0 34px rgba(255, 217, 77, 0.28);
  transform: translateY(16px) scale(0.94);
  transition: transform 380ms cubic-bezier(0.22, 1.5, 0.36, 1);
  overflow: hidden;
}
.symbol-unlock.open .symbol-unlock-card { transform: none; }

/* The turning light behind the symbol. Sits under everything in the
   card, so the art reads against it rather than through it. */
.symbol-unlock-rays,
.symbol-unlock-ring {
  position: absolute;
  left: 50%;
  top: 96px;
  width: 300px;
  height: 300px;
  margin: -150px 0 0 -150px;
  border-radius: 50%;
  pointer-events: none;
  z-index: 0;
}
.symbol-unlock-rays {
  background: conic-gradient(from 0deg,
    rgba(255, 217, 77, 0.30) 0deg 12deg, transparent 12deg 30deg);
  animation: symbolUnlockSpin 9s linear infinite;
  opacity: 0.75;
}
.symbol-unlock-ring {
  background: radial-gradient(circle, rgba(255, 217, 77, 0.35) 0%, transparent 62%);
  animation: symbolUnlockPulse 2200ms ease-in-out infinite;
}
@keyframes symbolUnlockSpin { to { transform: rotate(360deg); } }
@keyframes symbolUnlockPulse {
  0%, 100% { transform: scale(0.92); opacity: 0.55; }
  50%      { transform: scale(1.06); opacity: 0.9; }
}

.symbol-unlock-art {
  position: relative;
  z-index: 1;
  width: 132px;
  height: 132px;
  object-fit: contain;
  filter: drop-shadow(0 0 18px rgba(255, 217, 77, 0.75));
  animation: symbolUnlockLand 620ms cubic-bezier(0.22, 1.6, 0.36, 1) both;
}
@keyframes symbolUnlockLand {
  0%   { transform: scale(0.2) rotate(-90deg); opacity: 0; }
  100% { transform: none; opacity: 1; }
}

.symbol-unlock-kicker {
  position: relative;
  z-index: 1;
  margin-top: 6px;
  font-family: "Orbitron", sans-serif;
  font-size: 0.6rem;
  letter-spacing: 0.22em;
  color: var(--gold-bright, #ffd94d);
}
.symbol-unlock-title {
  position: relative;
  z-index: 1;
  font-family: "Orbitron", sans-serif;
  font-size: 1.02rem;
  font-weight: 800;
  text-align: center;
  color: #fff;
  text-shadow: 0 2px 10px rgba(0, 0, 0, 0.7);
}
.symbol-unlock-sub {
  position: relative;
  z-index: 1;
  margin: 0;
  max-width: 22rem;
  text-align: center;
  font-size: 0.8rem;
  line-height: 1.4;
  color: var(--text-dim, #b9a8d8);
}
.symbol-unlock-btn {
  position: relative;
  z-index: 1;
  margin-top: 12px;
  min-height: 46px;
  padding: 0 30px;
  border: 0;
  border-radius: 999px;
  cursor: pointer;
  font-family: "Orbitron", sans-serif;
  font-size: 0.78rem;
  font-weight: 800;
  letter-spacing: 0.12em;
  color: #3a2a05;
  background: linear-gradient(180deg, #ffe9a3, var(--gold, #ffd94d));
  box-shadow: 0 4px 0 #b8891a;
}
.symbol-unlock-btn:active { transform: translateY(2px); box-shadow: 0 2px 0 #b8891a; }

/* The paytable row for a symbol that is not on the reels yet. */
.paytable-row.is-locked-symbol { opacity: 0.62; }
.paytable-row.is-locked-symbol .amount-single {
  color: var(--gold-bright, #ffd94d);
  font-size: 0.66rem;
  letter-spacing: 0.08em;
}

@media (prefers-reduced-motion: reduce) {
  .symbol-unlock-rays, .symbol-unlock-ring, .symbol-unlock-art { animation: none; }
  .symbol-unlock-card { transition: none; }
}
.lean-fx .symbol-unlock-rays { animation: none; }

/* The "+4 LEVELS" flag on a merged run. Sits under the big number rather
   than replacing it: the number is still where you ended up, and this is
   how far you came to get there. */
.levelup-span {
  margin-top: 2px;
  font-family: "Orbitron", sans-serif;
  font-size: 0.62rem;
  font-weight: 800;
  letter-spacing: 0.16em;
  color: var(--gold-bright, #ffd94d);
  text-shadow: 0 0 12px rgba(255, 217, 77, 0.6);
}
