/* ============================================================
   PREMIUM POLISH LAYER — tactile presses, spring modals, ambient gold
   ============================================================
   The "feel" sheet: buttons compress down-and-in on press and spring
   back with overshoot, panels arrive with a back-out pop, and the lobby
   gets a whisper of drifting gold. Everything dry, tight, quiet.

   Loads LAST (after styles.css / styles-mobile.css / styles-emblems.css)
   so its deliberate upgrades of existing chrome (.modal-closing,
   .toast-enter/.toast-exit, .btn-spin-pulse, .ui-glow-hover,
   .screen-veil, .lobby-card's transition) win by source order.

   Contract (extends the styles.css house rules):
   - Animate only transform/opacity (plus the standalone `scale`
     property); depth/glow is static box-shadow, never animated.
   - Entrance animations use fill-mode `backwards`, never `both`.
   - Hover rules live inside @media (hover: hover).
   - Background sweeps declare background-repeat: no-repeat.
   - Every keyframes-driven class is silenced under .reduced-motion, and
     ambient loops also under .performance-mode — see GUARDS at the
     bottom. Transitions need no guard: styles.css clamps them globally
     under reduced-motion.
   ============================================================ */

:root {
  --prm-pop: cubic-bezier(0.175, 0.885, 0.32, 1.275); /* back-out pop (house curve) */
  --prm-snap: cubic-bezier(0.34, 1.56, 0.64, 1);      /* springy overshoot for presses */
  --prm-glide: cubic-bezier(0.22, 1, 0.36, 1);        /* house glide (sheet-up curve) */
  --prm-gold: #fbbf24;
}

/* ============================================================
   TACTILE BUTTONS — press down-and-in, spring back on release
   ============================================================ */
/* The release overshoot comes free from the --prm-snap curve — no
   keyframes needed, so no motion guard either (transitions are clamped
   globally). Composable with Tailwind color/bg utilities; JSX replaces
   any hover:scale/active:scale utilities when adding this class so the
   cascade has a single transform owner. */
/* !important because the Tailwind Play CDN injects its generated <style>
   at runtime AFTER every linked sheet — a leftover `transition-all` on
   the same element would otherwise flatten the spring to Tailwind's
   150ms ease. Color-family properties are included so those same
   `transition-all` consumers keep their eased color hovers. The
   reduced-motion clamp this shorthand would defeat is restored in
   GUARDS below. */
.prm-tactile {
  transition: transform 0.26s var(--prm-snap), box-shadow 0.26s var(--prm-snap), filter 0.2s ease,
    color 0.15s ease, background-color 0.15s ease, border-color 0.15s ease, opacity 0.15s ease !important;
}
@media (hover: hover) {
  .prm-tactile:hover:not(:disabled) {
    transform: translateY(-1px);
    filter: brightness(1.07);
  }
}
.prm-tactile:active:not(:disabled) {
  transform: translateY(1px) scale(0.96);
  filter: brightness(0.95);
}

/* SPIN button: a deeper, springier crunch layered over the existing
   idle pulse (styles.css already pauses that pulse on :active — the
   animation itself is untouched here). */
.btn-spin-pulse {
  transition: transform 0.24s var(--prm-snap), filter 0.2s ease;
}
.btn-spin-pulse:active {
  transform: scale(0.93);
  filter: brightness(0.94);
}

/* Juicy glow buttons compress on press too (hover glow stays as-is). */
.ui-glow-hover:active:not(:disabled) {
  transform: translateY(1px) scale(0.95);
}

/* ============================================================
   MODAL ENTRANCES / EXITS — spring pop in, quiet sink out
   ============================================================ */
/* Panel spring: scale 0.92 → slight overshoot → rest. Only applied (by
   JSX) to panels with NO existing animation class — two animation
   classes on one element and the cascade kills one of them. */
@keyframes prm-modal-panel {
  from { opacity: 0; transform: scale(0.92) translateY(14px); }
  62%  { opacity: 1; transform: scale(1.015) translateY(-2px); }
  to   { opacity: 1; transform: scale(1) translateY(0); }
}
.prm-modal-panel { animation: prm-modal-panel 0.34s var(--prm-glide) backwards; }

/* Backdrop just fades — opacity only, nothing for the GPU to chew on. */
@keyframes prm-backdrop-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}
.prm-backdrop-in { animation: prm-backdrop-in 0.25s ease-out backwards; }

/* Upgrade the shared modal exit (styles.css): fade + a gentle scale
   sink instead of a flat fade. Same 0.18s — <ModalFade>'s unmount timer
   is unchanged — and still swallows clicks while closing. */
@keyframes prm-modal-exit {
  from { opacity: 1; transform: scale(1); }
  to   { opacity: 0; transform: scale(0.97); }
}
.modal-closing {
  animation: prm-modal-exit 0.18s ease-in forwards !important;
  pointer-events: none !important;
}

/* ============================================================
   RESURRECTED UTILITIES — animate-* classes long referenced in JSX
   but never defined in any sheet. Given real (quiet) motion.
   ============================================================ */
@keyframes prm-fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}
.animate-fade-in { animation: prm-fade-in 0.3s ease-out backwards; }
/* Binds the overlay-fade-in keyframes that already live in styles.css
   (used there via arbitrary animate-[overlay-fade-in_*] utilities). */
.animate-overlay-fade-in { animation: overlay-fade-in 0.3s ease-out backwards; }

@keyframes prm-slide-down {
  from { opacity: 0; transform: translateY(-12px); }
  to   { opacity: 1; transform: translateY(0); }
}
.animate-slide-down { animation: prm-slide-down 0.32s var(--prm-glide) backwards; }

/* Binds the login-form-slide keyframes from styles.css. */
.animate-form-slide { animation: login-form-slide 0.3s ease-out backwards; }

/* Same motion as .ui-error-shake (styles.css), a touch quicker. */
.animate-shake { animation: ui-error-shake 0.4s cubic-bezier(0.36, 0.07, 0.19, 0.97); }

/* ============================================================
   DROPDOWNS / POPOVERS — pop out from the anchor corner
   ============================================================ */
@keyframes prm-drop-in {
  from { opacity: 0; transform: scale(0.92) translateY(-6px); }
  to   { opacity: 1; transform: scale(1) translateY(0); }
}
.prm-drop-in {
  transform-origin: top right;
  animation: prm-drop-in 0.24s var(--prm-pop) backwards;
}

/* ============================================================
   LOBBY — card press + ambient gold motes
   ============================================================ */
/* Card press uses the STANDALONE `scale` property on purpose:
   freezeParallax (LobbyScreen.js) owns the card's inline `transform`,
   and the hover lift (styles.css) owns the transform property in CSS —
   `scale` composes with both, no collision. The transition re-states
   the styles.css pair and appends scale (this sheet loads last, so it
   is the transition's single owner). */
.lobby-card {
  transition: transform 0.3s ease, box-shadow 0.3s ease, scale 0.3s var(--prm-snap);
}
.lobby-tile:active .lobby-card { scale: 0.977; }

/* Ambient layer: a handful of soft gold motes drifting through the
   lobby. Fixed, click-through, under the content (z-0). Each mote gets
   its drift vector (--mx/--my) and duration (--md) inline from JSX;
   position/size tweaks ride the same inline style. */
.prm-ambient {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  overflow: hidden;
}
@keyframes prm-mote-drift {
  0%   { opacity: 0; transform: translate3d(0, 0, 0) scale(0.8); }
  15%  { opacity: 0.32; }
  85%  { opacity: 0.32; }
  100% { opacity: 0; transform: translate3d(var(--mx, 30px), var(--my, -140px), 0) scale(1.15); }
}
.prm-mote {
  position: absolute;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(251, 191, 36, 0.9) 0%, rgba(251, 191, 36, 0) 70%);
  opacity: 0;
  animation: prm-mote-drift var(--md, 16s) linear infinite;
}

/* ============================================================
   CABINET DEPTH — static machine-frame shading via ::before
   (.cabinet-breathe already owns ::after for the breathing glow)
   ============================================================ */
/* Inset shadows + a top specular hairline make the frame read as a
   physical bezel with the reels recessed inside it. Entirely static —
   zero animation cost, painted once. */
.prm-cabinet { position: relative; }
.prm-cabinet::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2; /* over the reel edges so the bezel shading reads; click-through */
  border-radius: inherit;
  pointer-events: none;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.09),
    inset 0 10px 24px rgba(0, 0, 0, 0.38),
    inset 0 -12px 22px rgba(0, 0, 0, 0.5);
  /* Static top specular hairline — a thin catch of light on the bezel lip. */
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.06) 0%, rgba(255, 255, 255, 0.015) 3%, transparent 8%);
}

/* ============================================================
   TOGGLE KNOB — the settings-switch thumb springs across
   ============================================================ */
.prm-toggle-knob { transition: transform 0.3s var(--prm-snap); }

/* ============================================================
   SHIMMER TEXT — gold gradient sweep for premium headings
   ============================================================ */
/* background-size 200% keeps the glyphs covered at every position the
   loop visits (0%–100%), so no-repeat can never expose a gap; the
   there-and-back keyframes avoid a wrap snap. AMBIENT → killed under
   both gates in GUARDS. */
@keyframes prm-shimmer-text {
  0%, 100% { background-position: 0% center; }
  50%      { background-position: 100% center; }
}
.prm-shimmer-text {
  background: linear-gradient(105deg, #daa520 0%, #fbbf24 38%, #fff3c4 50%, #fbbf24 62%, #daa520 100%);
  background-size: 200% auto;
  background-repeat: no-repeat;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  animation: prm-shimmer-text 3.4s ease-in-out infinite;
}

/* ============================================================
   NUMBER SETTLE — a/b replay pair for AnimatedNumber
   ============================================================ */
/* Two keyframe names, one visual: JSX retriggers the pop by swapping
   a↔b instead of forcing a reflow to restart a single animation. */
@keyframes prm-num-settle-a {
  0%   { transform: scale(1); }
  45%  { transform: scale(1.14); }
  100% { transform: scale(1); }
}
@keyframes prm-num-settle-b {
  0%   { transform: scale(1); }
  45%  { transform: scale(1.14); }
  100% { transform: scale(1); }
}
/* inline-block: transforms are ignored on plain inline spans. */
.prm-num-settle-a { display: inline-block; animation: prm-num-settle-a 0.3s var(--prm-pop); }
.prm-num-settle-b { display: inline-block; animation: prm-num-settle-b 0.3s var(--prm-pop); }

/* ============================================================
   TOASTS — springier than the styles.css originals
   ============================================================ */
/* Rise + pop in; sink away out. The exit keeps the original max-height
   collapse so the stack closes up beneath a departing toast, and stays
   under the 400ms JS removal timer. */
@keyframes prm-toast-in {
  from { opacity: 0; transform: translateY(14px) scale(0.95); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
.toast-enter { animation: prm-toast-in 0.34s var(--prm-pop) backwards; }

@keyframes prm-toast-out {
  from { opacity: 1; transform: translateY(0) scale(1); max-height: 80px; margin-bottom: 0.5rem; }
  to   { opacity: 0; transform: translateY(10px) scale(0.94); max-height: 0; margin-bottom: 0; }
}
.toast-exit { animation: prm-toast-out 0.32s ease-in forwards; overflow: hidden; }

/* ============================================================
   CLOSE BUTTONS — the shared ✕ feel
   ============================================================ */
/* Quarter-turn + grow on hover, crunch (still turned) on press.
   Composes with existing color/bg utilities; JSX removes
   hover:scale-110/active:scale-95 Tailwind utilities when adding it. */
/* Same !important rationale as .prm-tactile: these buttons keep their
   Tailwind `transition-all` for color hovers, which the CDN injects
   after this sheet. */
.prm-close {
  transition: transform 0.22s var(--prm-snap),
    color 0.15s ease, background-color 0.15s ease, border-color 0.15s ease !important;
}
@media (hover: hover) {
  .prm-close:hover { transform: scale(1.08) rotate(90deg); }
}
.prm-close:active { transform: scale(0.88) rotate(90deg); }

/* ============================================================
   SEARCH MORPH — the lobby search input glides open/closed
   ============================================================ */
/* An animation, not a transition: the input MOUNTS already expanded
   (searchOpen conditional render), and transitions never fire on mount.
   Grows out of the collapsed pill's position on the left. */
@keyframes prm-search-in {
  from { opacity: 0; transform: scaleX(0.72); }
  to   { opacity: 1; transform: scaleX(1); }
}
.prm-search-in {
  transform-origin: left center;
  animation: prm-search-in 0.25s var(--prm-glide) backwards;
}

/* ============================================================
   SCREEN VEIL — deepen the flat black cross-fade into a vignette
   ============================================================ */
/* Background only — same element, same opacity keyframes and z-order
   from styles.css, so the transition mechanics are untouched. */
.screen-veil {
  background: radial-gradient(120% 100% at 50% 42%, #12100e 0%, #0c0a09 55%, #050403 100%);
}

/* ============================================================
   GUARDS — motion gates, mirroring the styles.css contract
   ============================================================ */
/* reduced-motion: every keyframes-driven class above is silenced.
   Entrances end at identity, so a plain cancel shows them at rest. */
.reduced-motion .prm-modal-panel,
.reduced-motion .prm-backdrop-in,
.reduced-motion .animate-fade-in,
.reduced-motion .animate-overlay-fade-in,
.reduced-motion .animate-slide-down,
.reduced-motion .animate-form-slide,
.reduced-motion .animate-shake,
.reduced-motion .prm-drop-in,
.reduced-motion .toast-enter,
.reduced-motion .prm-num-settle-a,
.reduced-motion .prm-num-settle-b,
.reduced-motion .prm-search-in { animation: none !important; }
/* Restore the styles.css reduced-motion transition clamp that the
   !important shorthands above would otherwise out-cascade. */
.reduced-motion .prm-tactile,
.reduced-motion .prm-close { transition-duration: 0.05s !important; }
/* Exits end AWAY from identity — snap them instead of cancelling, so a
   closing element still lands invisible while JS waits to unmount it. */
.reduced-motion .modal-closing,
.reduced-motion .toast-exit { animation-duration: 0.01s !important; }
/* Ambient loops: gone entirely under EITHER gate — the motes are pure
   decoration and the shimmer repaints text every frame. */
.reduced-motion .prm-ambient,
.performance-mode .prm-ambient { display: none; }
.reduced-motion .prm-mote,
.performance-mode .prm-mote { animation: none !important; }
.reduced-motion .prm-shimmer-text,
.performance-mode .prm-shimmer-text { animation: none !important; background-position: 0 0; }
