/* Card visuals + pack-open animation. Shared by the overlay and the collection
   page. The card art (553x832) already includes the themed argyle background;
   we layer a rarity frame, a holographic sheen, a name plate and stats on top. */

.tcg-card {
  --accent: #d4356a;
  --rarity: #9b9b9b;
  position: relative;
  width: var(--card-w, 220px);
  aspect-ratio: 553 / 832;
  border-radius: 18px;
  perspective: 1200px;
  flex: 0 0 auto;
}

.tcg-card-inner {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  -webkit-transform-style: preserve-3d;
  /* NO transition here: the flip is driven solely by the packFlip animation
     (forwards-fill), so nothing can transition the card back to its back face. */
}

/* Idle-sway wrapper (overlay only). Sits BETWEEN the outer (perspective + rise)
   and the inner (flip), carrying a slow continuous ±7deg Y-sway. Because it's a
   separate layer from the flipped inner, and ±7deg can never bring the back face
   to the viewer, it adds the gold-standard "cardTilt" life without any blink risk. */
.tcg-sway {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  -webkit-transform-style: preserve-3d;
}
.tcg-card.in-overlay .tcg-sway {
  animation: cardTilt 5s ease-in-out 2s infinite;  /* starts after the flip settles */
}
@keyframes cardTilt {
  0%   { transform: rotateY(0deg) rotateX(0deg); }
  25%  { transform: rotateY(-7deg) rotateX(1.5deg); }
  50%  { transform: rotateY(0deg) rotateX(0deg); }
  75%  { transform: rotateY(7deg) rotateX(-1.5deg); }
  100% { transform: rotateY(0deg) rotateX(0deg); }
}

.tcg-face {
  position: absolute;
  inset: 0;
  border-radius: 18px;
  background-size: cover;
  background-position: center;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  overflow: hidden;
  box-shadow:
    0 0 0 3px var(--rarity),
    0 0 18px -2px var(--rarity),
    0 10px 26px rgba(0, 0, 0, 0.35);
}

.tcg-back {
  background-image: var(--back-img);
  box-shadow: 0 0 0 3px #2a2560, 0 10px 26px rgba(0, 0, 0, 0.35);
}

.tcg-front {
  transform: rotateY(180deg);
}

/* card art as a real element (reliable paint on flipped faces) */
.tcg-art {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 18px;
}
/* character parallax float (overlay only) — echoes the gold-standard characterTilt.
   base scale 1.06 so the small translate never reveals card edges. */
.tcg-card.in-overlay .tcg-art {
  transform: scale(1.06);
  animation: artFloat 5s ease-in-out 2s infinite;
}
@keyframes artFloat {
  0%   { transform: scale(1.06) translate(0, 0); }
  50%  { transform: scale(1.06) translate(6px, 5px); }
  100% { transform: scale(1.06) translate(0, 0); }
}

/* legendary gets an animated gold shimmer ring */
.tcg-card.rarity-legendary .tcg-front {
  box-shadow:
    0 0 0 3px var(--rarity),
    0 0 26px 1px var(--rarity),
    0 10px 26px rgba(0, 0, 0, 0.4);
  animation: legendaryPulse 1.8s ease-in-out infinite;
}
@keyframes legendaryPulse {
  0%, 100% { filter: brightness(1); }
  50% { filter: brightness(1.12); }
}

/* holographic light sweep across the art */
.tcg-sheen {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    115deg, transparent 30%, rgba(255, 255, 255, 0.55) 48%,
    rgba(255, 255, 255, 0.0) 60%);
  transform: translateX(-120%);
  pointer-events: none;
}
.tcg-card.revealing .tcg-sheen {
  animation: sheenSweep 0.9s ease-out 0.45s 1;
}
@keyframes sheenSweep {
  to { transform: translateX(120%); }
}

/* rarity stars top-center */
.tcg-stars {
  position: absolute;
  top: 6%;
  left: 0;
  right: 0;
  text-align: center;
  font-size: calc(var(--card-w, 220px) * 0.085);
  color: var(--rarity);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.55);
  letter-spacing: 1px;
}

/* name plate near the bottom */
.tcg-nameplate {
  position: absolute;
  left: 8%;
  right: 8%;
  bottom: 13%;
  text-align: center;
  padding: 4px 8px;
  border-radius: 999px;
  background: rgba(20, 16, 40, 0.78);
  border: 2px solid var(--rarity);
  font-family: 'Playfair Display', Georgia, serif;
  font-weight: 700;
  color: #fff;
  font-size: calc(var(--card-w, 220px) * 0.095);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
}

/* atk / def footer */
.tcg-stats {
  position: absolute;
  left: 8%;
  right: 8%;
  bottom: 4.5%;
  display: flex;
  justify-content: space-between;
  font-family: 'DM Sans', sans-serif;
  font-weight: 700;
  font-size: calc(var(--card-w, 220px) * 0.062);
  color: #fff;
}
.tcg-stats span {
  background: rgba(20, 16, 40, 0.7);
  padding: 2px 8px;
  border-radius: 8px;
}
.tcg-stats .atk { color: #ff9c9c; }
.tcg-stats .def { color: #9cc8ff; }

/* NEW! / duplicate badge */
.tcg-badge {
  position: absolute;
  top: -10px;
  right: -10px;
  z-index: 5;
  padding: 5px 12px;
  border-radius: 999px;
  font-family: 'DM Sans', sans-serif;
  font-weight: 800;
  font-size: 14px;
  color: #fff;
  background: #d4356a;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
  transform: scale(0);
}
.tcg-badge.dup { background: #786d71; }
.tcg-card.revealing .tcg-badge {
  animation: badgePop 0.4s cubic-bezier(0.2, 1.4, 0.4, 1) 0.7s forwards;
}
@keyframes badgePop {
  to { transform: scale(1) rotate(-8deg); }
}

/* --- overlay reveal sequence --- */
.tcg-card.in-overlay {
  --card-w: 240px;
  opacity: 0;
  transform: translateY(40px) scale(0.9);
}
.tcg-card.in-overlay.entering {
  animation: cardRiseUp 0.6s cubic-bezier(0.2, 0.9, 0.3, 1) forwards;
}
@keyframes cardRiseUp {
  0% { opacity: 0; transform: translateY(40px) scale(0.9); }
  100% { opacity: 1; transform: translateY(0) scale(1); }
}
/* THE FLIP + WOBBLE — ONE animation, forwards-fill, settles at 180deg.
   It flips to the front then does a damped oscillation (overshoot/undershoot
   around 180) before settling. Because it's a single animation (no transition,
   no class-swap, all keyframes stay between 172°–190° so the back never faces
   the viewer) it physically cannot blink back to the card back. */
.tcg-card.flip .tcg-card-inner {
  animation: packFlipWobble 1.7s ease 0.25s forwards;
}
@keyframes packFlipWobble {
  0%   { transform: rotateY(0deg); }     /* back (during the 0.25s delay) */
  35%  { transform: rotateY(180deg); }   /* flipped to front */
  48%  { transform: rotateY(190deg); }   /* overshoot */
  61%  { transform: rotateY(172deg); }   /* wobble back */
  73%  { transform: rotateY(185deg); }
  84%  { transform: rotateY(177deg); }
  93%  { transform: rotateY(181deg); }
  100% { transform: rotateY(180deg); }   /* settle */
}
.tcg-card.exiting {
  animation: cardExitDown 0.5s ease-in forwards;
}
@keyframes cardExitDown {
  to { opacity: 0; transform: translateY(60px) scale(0.85); }
}

/* row of cards revealed together in the overlay */
.tcg-pack-row {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}
/* the collection strip hangs below the reveal — lift the whole composition
   so banner + grid stay on screen even on smaller OBS canvases */
.tcg-pack-row.with-collection {
  top: 42%;
}
.tcg-pack-row {
  display: flex;
  gap: 22px;
  align-items: center;
  justify-content: center;
}

/* the sealed pack: a shiny foil WRAPPER (deliberately not card art — it must
   read as the plastic packet the cards come out of). Pops in centered over
   the row, shakes with anticipation, the crimped top strip tears off at the
   perforation, then the body slides below the row (.dispensing) so the cards
   can rise out of the mouth. The body stays opaque and ABOVE the travelers
   (z-index) — that's what hides a card while it's still "inside" the pack. */
.tcg-pack {
  position: absolute;
  left: calc(50% - 130px);  /* half of the 260px width */
  top: calc(50% - 196px);   /* 440px tall, sat slightly low of center so the
                               top teeth clear the rip banner's lane */
  z-index: 4;
  width: 260px;
  height: 440px;
  filter: drop-shadow(0 10px 30px rgba(0, 0, 0, 0.45));
  /* idle motion is the 3D sway (below); the 2D shake is just one short
     shiver right before the tear (ends at 2.2s = the tear moment in JS) */
  animation: packPop 0.35s ease-out both,
             packShake 0.3s ease-in-out 1.6s 2;
  transition: top 0.7s ease-in-out;
}
.tcg-pack.dispensing {
  top: calc(100% + 6px);    /* mouth (torn edge) ends up 40px below the row */
}
/* idle 3D sway while the pack waits to tear — a filled pouch catching light */
.tcg-pack-sway {
  position: absolute;
  inset: 0;
  animation: packSway 1.8s ease-in-out 0.35s infinite;
}
@keyframes packSway {
  0%, 100% { transform: perspective(520px) rotateY(-5deg); }
  50%      { transform: perspective(520px) rotateY(5deg); }
}
.tcg-pack.tearing .tcg-pack-sway { animation: none; }
.tcg-pack-body,
.tcg-pack-top {
  position: absolute;
  left: 0;
  right: 0;
  overflow: hidden;
  /* metallic foil plastic (visible whenever no wrapper art is uploaded) */
  background:
    linear-gradient(120deg,
      #b93a63 0%, #d4356a 22%, #a874e8 48%, #66a2cc 72%, #8a5fd0 100%);
}
/* factory crimp seams: metallic silver ridged bands (they sit in the flared
   seam zone, just inside the sawtooth teeth — like the reference's mylar) */
.tcg-pack-top::before,
.tcg-pack-body::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 15px;
  z-index: 3;
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.35), rgba(0, 0, 0, 0.12)),
    repeating-linear-gradient(90deg,
      #ffffff 0 2px, #b9b3c6 2px 4px, #e9e5f0 4px 6px);
  box-shadow: inset 0 0 6px rgba(31, 10, 40, 0.3);
}
.tcg-pack-top::before { top: 9px; }
.tcg-pack-body::after { bottom: 9px; }
/* pillowy pouch silhouette: sides bulge to full width mid-body and pinch in
   at the crimped seams; sawtooth teeth at the factory edges. Fixed px polygon
   — the pack is a fixed 190x262, keep these in sync if it's ever resized. */
.tcg-pack-body {
  top: 44px;
  bottom: 0;
  clip-path: polygon(8px 0px, 252px 0px, 249.0px 17.6px, 246.0px 35.2px, 246.4px 52.8px, 247.5px 70.4px, 249.2px 88.0px, 251.2px 105.5px, 253.4px 123.1px, 255.4px 140.7px, 257.0px 158.3px, 258.1px 175.9px, 258.5px 193.5px, 258.1px 211.1px, 257.0px 228.7px, 255.4px 246.3px, 253.4px 263.9px, 251.2px 281.5px, 249.2px 299.0px, 247.5px 316.6px, 246.4px 334.2px, 246.0px 351.8px, 250.9px 369.4px, 256.0px 387.0px, 252.8px 396px, 249.7px 387px, 246.5px 396px, 243.4px 387px, 240.2px 396px, 237.1px 387px, 233.9px 396px, 230.8px 387px, 227.6px 396px, 224.5px 387px, 221.3px 396px, 218.2px 387px, 215.0px 396px, 211.9px 387px, 208.7px 396px, 205.6px 387px, 202.4px 396px, 199.3px 387px, 196.1px 396px, 193.0px 387px, 189.8px 396px, 186.7px 387px, 183.5px 396px, 180.4px 387px, 177.2px 396px, 174.1px 387px, 170.9px 396px, 167.8px 387px, 164.6px 396px, 161.5px 387px, 158.3px 396px, 155.2px 387px, 152.0px 396px, 148.9px 387px, 145.7px 396px, 142.6px 387px, 139.4px 396px, 136.3px 387px, 133.1px 396px, 130.0px 387px, 126.8px 396px, 123.7px 387px, 120.5px 396px, 117.4px 387px, 114.2px 396px, 111.1px 387px, 107.9px 396px, 104.8px 387px, 101.6px 396px, 98.5px 387px, 95.3px 396px, 92.2px 387px, 89.0px 396px, 85.9px 387px, 82.7px 396px, 79.6px 387px, 76.4px 396px, 73.3px 387px, 70.1px 396px, 67.0px 387px, 63.8px 396px, 60.7px 387px, 57.5px 396px, 54.4px 387px, 51.2px 396px, 48.1px 387px, 44.9px 396px, 41.8px 387px, 38.6px 396px, 35.5px 387px, 32.3px 396px, 29.2px 387px, 26.0px 396px, 22.9px 387px, 19.7px 396px, 16.6px 387px, 13.4px 396px, 10.3px 387px, 7.1px 396px, 4.0px 387px, 9.1px 369.4px, 14.0px 351.8px, 13.6px 334.2px, 12.5px 316.6px, 10.8px 299.0px, 8.8px 281.5px, 6.6px 263.9px, 4.6px 246.3px, 3.0px 228.7px, 1.9px 211.1px, 1.5px 193.5px, 1.9px 175.9px, 3.0px 158.3px, 4.6px 140.7px, 6.6px 123.1px, 8.8px 105.5px, 10.8px 88.0px, 12.5px 70.4px, 13.6px 52.8px, 14.0px 35.2px, 11.0px 17.6px);
}
.tcg-pack-top {
  top: 0;
  height: 44px;
  border-bottom: 2px dashed rgba(255, 255, 255, 0.35); /* tear perforation */
  clip-path: polygon(4px 9px, 7.2px 0px, 10.3px 9px, 13.5px 0px, 16.6px 9px, 19.8px 0px, 22.9px 9px, 26.0px 0px, 29.2px 9px, 32.3px 0px, 35.5px 9px, 38.6px 0px, 41.8px 9px, 44.9px 0px, 48.1px 9px, 51.2px 0px, 54.4px 9px, 57.5px 0px, 60.7px 9px, 63.8px 0px, 67.0px 9px, 70.1px 0px, 73.3px 9px, 76.5px 0px, 79.6px 9px, 82.8px 0px, 85.9px 9px, 89.1px 0px, 92.2px 9px, 95.4px 0px, 98.5px 9px, 101.7px 0px, 104.8px 9px, 108.0px 0px, 111.1px 9px, 114.3px 0px, 117.4px 9px, 120.6px 0px, 123.7px 9px, 126.9px 0px, 130.0px 9px, 133.2px 0px, 136.3px 9px, 139.5px 0px, 142.6px 9px, 145.8px 0px, 148.9px 9px, 152.1px 0px, 155.2px 9px, 158.4px 0px, 161.5px 9px, 164.7px 0px, 167.8px 9px, 171.0px 0px, 174.1px 9px, 177.3px 0px, 180.4px 9px, 183.6px 0px, 186.7px 9px, 189.9px 0px, 193.0px 9px, 196.2px 0px, 199.3px 9px, 202.5px 0px, 205.6px 9px, 208.8px 0px, 211.9px 9px, 215.1px 0px, 218.2px 9px, 221.4px 0px, 224.5px 9px, 227.7px 0px, 230.8px 9px, 234.0px 0px, 237.1px 9px, 240.3px 0px, 243.4px 9px, 246.6px 0px, 249.7px 9px, 252.9px 0px, 256.0px 9px, 252px 44px, 8px 44px);
}
/* her uploaded wrapper design, printed across the whole pouch (strip + body
   show their slice of one 190x262 image); empty = the foil gradient shows */
.tcg-pack-art {
  position: absolute;
  inset: 0;
  background-repeat: no-repeat;
  background-size: 100% 440px; /* full pack height; width tracks the pack */
  background-position: 0 -44px;
}
.tcg-pack-top .tcg-pack-art { background-position: 0 0; }
/* custom mode: uploaded art IS the pack — silhouette comes from the image's
   own alpha, all built-in pouch chrome disappears. The 44px strip still
   tears off the top, slicing the image at its crimp zone. */
.tcg-pack.custom .tcg-pack-body,
.tcg-pack.custom .tcg-pack-top {
  clip-path: none;
  background: transparent;
}
.tcg-pack.custom .tcg-pack-top { border-bottom: none; }
.tcg-pack.custom .tcg-pack-top::before,
.tcg-pack.custom .tcg-pack-body::after { display: none; }
.tcg-pack.custom .tcg-pack-depth,
.tcg-pack.custom .tcg-pack-shine,
.tcg-pack.custom .tcg-pack-label { display: none; }
/* depth: radial center highlight + darker curved-edge falloff = filled pouch */
.tcg-pack-depth {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    /* glossy edge sheens */
    linear-gradient(90deg, transparent 3%, rgba(255, 255, 255, 0.3) 6.5%, transparent 11%),
    linear-gradient(90deg, transparent 89%, rgba(255, 255, 255, 0.3) 93.5%, transparent 97%),
    /* soft foil creases (paired light/dark lines at slightly-off angles) */
    linear-gradient(96deg, transparent 28%, rgba(255, 255, 255, 0.09) 30.5%, rgba(26, 8, 36, 0.1) 32.5%, transparent 35.5%),
    linear-gradient(85deg, transparent 54%, rgba(26, 8, 36, 0.09) 57%, rgba(255, 255, 255, 0.08) 59%, transparent 62%),
    linear-gradient(101deg, transparent 69%, rgba(255, 255, 255, 0.07) 72%, rgba(26, 8, 36, 0.08) 74.5%, transparent 78%),
    linear-gradient(92deg, transparent 13%, rgba(26, 8, 36, 0.07) 15%, rgba(255, 255, 255, 0.06) 17%, transparent 20%),
    /* broad vertical undulation — the bag's surface isn't optically flat */
    repeating-linear-gradient(88deg,
      transparent 0 26px, rgba(255, 255, 255, 0.035) 26px 34px, transparent 34px 58px),
    /* stress wrinkles pulling toward the crimped seams */
    linear-gradient(180deg, rgba(255, 255, 255, 0.1) 0.5%, rgba(31, 10, 40, 0.16) 3%, transparent 9%),
    linear-gradient(0deg, rgba(255, 255, 255, 0.08) 0.5%, rgba(31, 10, 40, 0.18) 3%, transparent 10%),
    /* two offset highlights read as a puffed, slightly uneven surface */
    radial-gradient(48% 34% at 46% 36%, rgba(255, 255, 255, 0.2), transparent 70%),
    radial-gradient(40% 30% at 60% 64%, rgba(255, 255, 255, 0.1), transparent 70%),
    linear-gradient(90deg, rgba(31, 10, 40, 0.34) 0, transparent 12%, transparent 88%, rgba(31, 10, 40, 0.34) 100%),
    linear-gradient(180deg, rgba(31, 10, 40, 0.16) 0, transparent 10%, transparent 84%, rgba(31, 10, 40, 0.26) 100%);
}
.tcg-pack-top .tcg-pack-depth {
  background:
    linear-gradient(90deg, rgba(31, 10, 40, 0.34) 0, transparent 16%, transparent 84%, rgba(31, 10, 40, 0.34) 100%),
    linear-gradient(180deg, transparent 40%, rgba(0, 0, 0, 0.22) 100%);
}
/* moving light streak so it reads as glossy plastic */
.tcg-pack-shine {
  position: absolute;
  inset: -40%;
  background: linear-gradient(115deg,
    transparent 42%, rgba(255, 255, 255, 0.55) 50%, transparent 58%);
  animation: packShine 1.6s ease-in-out infinite;
}
@keyframes packShine {
  from { transform: translateX(-45%); }
  to   { transform: translateX(45%); }
}
.tcg-pack-label {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  text-align: center;
  text-shadow: 0 2px 8px rgba(0, 0, 0, 0.55);
}
.tcg-pack-emblem {
  font-size: 66px;
  filter: drop-shadow(0 3px 6px rgba(0, 0, 0, 0.4));
}
.tcg-pack-title {
  font-family: 'Playfair Display', serif;
  font-weight: 800;
  font-size: 36px;
  letter-spacing: 3px;
  color: #fff;
}
.tcg-pack-sub {
  font-family: 'DM Sans', system-ui, sans-serif;
  font-weight: 700;
  font-size: 15px;
  letter-spacing: 5px;
  text-transform: uppercase;
  color: #ffe3ee;
}
.tcg-pack.tearing .tcg-pack-top {
  animation: packTear 0.8s ease-in forwards;
}
@keyframes packPop {
  from { opacity: 0; transform: translateY(26px) scale(0.85); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
@keyframes packShake {
  0%, 100% { transform: rotate(0); }
  25% { transform: rotate(-2deg); }
  75% { transform: rotate(2deg); }
}
@keyframes packTear {
  30% { transform: translate(14px, -8px) rotate(6deg); opacity: 1; }
  to  { transform: translate(120px, -160px) rotate(30deg); opacity: 0; }
}
/* emptied pack drops away after the last card lands */
.tcg-pack.depart {
  animation: packDepart 0.5s ease-in forwards;
}
@keyframes packDepart {
  to { transform: translateY(120px) rotate(-5deg); opacity: 0; }
}

/* the camper's collection, pinned UNDER the reveal (reference-tool style).
   Fades in as the tear finishes; a fresh pull's thumb flips like the big
   card above it. */
.tcg-collection-strip {
  position: absolute;
  top: calc(100% + 74px); /* clears the "new to collection" banner's lane */
  left: 50%;
  transform: translateX(-50%) translateY(14px);
  opacity: 0;
  transition: opacity 0.45s ease-out, transform 0.45s ease-out;
  padding: 12px 16px 14px;
  border-radius: 16px;
  background: rgba(20, 16, 40, 0.92);
  border: 2px solid #a970ff;
  box-shadow: 0 8px 40px rgba(169, 112, 255, 0.35);
  font-family: 'DM Sans', system-ui, sans-serif;
}
.tcg-collection-strip.show {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}
.tcg-collection-strip.exiting {
  opacity: 0;
  transform: translateX(-50%) translateY(14px);
}
.tcs-title {
  color: #e9ddff;
  font-weight: 800;
  font-size: 14px;
  letter-spacing: 0.4px;
  margin-bottom: 9px;
  text-align: center;
  white-space: nowrap;
}
.tcs-grid {
  display: grid;
  grid-template-columns: repeat(10, 34px);
  gap: 6px;
  justify-content: center;
}
.tcs-thumb {
  position: relative;
  width: 34px;
  height: 47px;              /* the cards' 5:7 */
  border-radius: 5px;
  border: 1.5px solid rgba(255, 255, 255, 0.14);
  background: rgba(255, 255, 255, 0.04);
  perspective: 300px;
}
.tcs-inner {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  transition: transform 0.7s cubic-bezier(0.3, 1.4, 0.4, 1);
}
.tcs-thumb.flipped .tcs-inner { transform: rotateY(180deg); }
.tcs-face {
  position: absolute;
  inset: 0;
  border-radius: 3.5px;
  backface-visibility: hidden;
  background-size: cover;
  background-position: center;
}
.tcs-back { filter: saturate(0.55) brightness(0.55); } /* still-to-find slots */
.tcs-thumb.pending .tcs-back {
  filter: none;              /* a fresh pull waits face-up-bright to flip */
  box-shadow: 0 0 8px rgba(255, 255, 255, 0.3);
}
.tcs-front { transform: rotateY(180deg); }

/* invisible flex placeholder that reserves a card's final slot in the row */
.tcg-card.tcg-ghost {
  visibility: hidden;
}

/* card back in transit: rises out of the pack mouth (below the pack's
   z-index, so the part still inside is hidden by the opaque body), then
   flies to its slot. left/top/width + transitions are set inline by JS;
   height follows via the card aspect-ratio. */
.tcg-traveler {
  position: absolute;
  z-index: 2;
  aspect-ratio: 553 / 832;
  border-radius: 18px;
  background-image: var(--back-img);
  background-size: cover;
  background-position: center;
  box-shadow: 0 0 0 3px #2a2560, 0 10px 26px rgba(0, 0, 0, 0.35);
}

/* a card swapped in where its traveler landed: already visible and in place,
   so it settles with a tiny squash instead of the rise-from-below entrance */
.tcg-card.in-overlay.from-pack {
  opacity: 1;
  transform: none;
}
.tcg-card.in-overlay.from-pack.entering {
  animation: cardLandSettle 0.3s cubic-bezier(0.2, 0.9, 0.3, 1);
}
@keyframes cardLandSettle {
  from { transform: scale(1.05); }
  to   { transform: scale(1); }
}

/* "<user> is ripping a pack!" banner floating above the card row */
.tcg-rip-banner {
  position: absolute;
  left: 50%;
  bottom: calc(100% + 26px);
  transform: translateX(-50%);
  white-space: nowrap;
  padding: 10px 26px;
  border-radius: 999px;
  background: rgba(20, 16, 40, 0.92);
  border: 2px solid #ffce47;
  box-shadow: 0 6px 30px rgba(255, 206, 71, 0.45);
  color: #fff;
  font-family: 'DM Sans', system-ui, sans-serif;
  font-weight: 800;
  font-size: 24px;
  animation: ripBannerIn 0.4s ease-out both;
}
@keyframes ripBannerIn {
  from { opacity: 0; transform: translateX(-50%) translateY(14px); }
  to   { opacity: 1; transform: translateX(-50%) translateY(0); }
}

/* "new to the collection" pill under the card row — like the rip banner but
   smaller and gold/pink. Pops in after the last flip, exits with the row. */
.tcg-new-banner {
  position: absolute;
  left: 50%;
  top: calc(100% + 22px);
  z-index: 5;
  transform: translateX(-50%);
  white-space: nowrap;
  padding: 7px 18px;
  border-radius: 999px;
  background: rgba(20, 16, 40, 0.92);
  border: 2px solid #ffce47;
  box-shadow: 0 6px 24px rgba(255, 77, 184, 0.45);
  color: #ffe3ee;
  font-family: 'DM Sans', system-ui, sans-serif;
  font-weight: 800;
  font-size: 18px;
  animation: newBannerPop 0.45s cubic-bezier(0.2, 1.4, 0.4, 1) both;
}
@keyframes newBannerPop {
  from { opacity: 0; transform: translateX(-50%) scale(0.6); }
  to   { opacity: 1; transform: translateX(-50%) scale(1); }
}
.tcg-new-banner.exiting {
  animation: newBannerOut 0.5s ease-in forwards;
}
@keyframes newBannerOut {
  to { opacity: 0; transform: translateX(-50%) translateY(24px); }
}

/* --- high-rarity reveal drama (epic/legendary) --- */
.tcg-burst {
  position: absolute;
  inset: -45%;
  border-radius: 50%;
  background: radial-gradient(circle, var(--rarity) 0%, transparent 62%);
  opacity: 0;
  transform: scale(0.3);
  pointer-events: none;
  z-index: 0;
}
.tcg-card.has-burst.revealing .tcg-burst {
  animation: rarityBurst 1.3s ease-out 0.9s 1;
}
@keyframes rarityBurst {
  0%   { opacity: 0;    transform: scale(0.3); }
  30%  { opacity: 0.85; }
  100% { opacity: 0;    transform: scale(1.3); }
}
.tcg-spark {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--rarity);
  box-shadow: 0 0 8px var(--rarity);
  opacity: 0;
  pointer-events: none;
  z-index: 6;
}
.tcg-card.has-burst.revealing .tcg-spark {
  animation: sparkFly 1s ease-out 0.95s 1;
}
@keyframes sparkFly {
  0%   { opacity: 1; transform: translate(-50%, -50%) scale(1); }
  100% { opacity: 0; transform: translate(calc(-50% + var(--dx)), calc(-50% + var(--dy))) scale(0.3); }
}

/* --- foil / holographic variant --- */
.tcg-card.foil .tcg-front::after {
  content: "";
  position: absolute; inset: 0; border-radius: 18px; pointer-events: none;
  background: linear-gradient(120deg, rgba(255,77,184,0.30), rgba(122,92,255,0.30), rgba(54,197,255,0.30), rgba(255,210,63,0.30));
  background-size: 300% 300%;
  mix-blend-mode: screen;
  opacity: 0.6;
  animation: foilShift 3s linear infinite;
}
@keyframes foilShift { 0% { background-position: 0% 50%; } 100% { background-position: 300% 50%; } }
.tcg-foil-tag {
  position: absolute; top: -10px; left: -10px; z-index: 6;
  padding: 4px 11px; border-radius: 999px; font-family: 'DM Sans', sans-serif; font-weight: 800; font-size: 12px; color: #fff;
  background: linear-gradient(90deg, #ff4db8, #7a5cff, #36c5ff, #ffd23f); background-size: 300% 100%;
  animation: foilShift 3s linear infinite; box-shadow: 0 3px 10px rgba(0, 0, 0, 0.3);
}
.tcg-foil-mark { position: absolute; top: -6px; left: -6px; z-index: 5; font-size: 16px; filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.3)); }

/* --- collection grid card (static) --- */
.tcg-card.locked .tcg-front { display: none; }
.tcg-card.locked .tcg-back { transform: none; }
.tcg-card.owned .tcg-back { display: none; }
.tcg-card.owned .tcg-front { transform: none; }
.tcg-card.grid { --card-w: 150px; }
.tcg-count {
  position: absolute;
  bottom: -8px;
  right: -8px;
  z-index: 5;
  min-width: 26px;
  height: 26px;
  padding: 0 6px;
  border-radius: 999px;
  background: var(--rose, #d4356a);
  color: #fff;
  font-family: 'DM Sans', sans-serif;
  font-weight: 800;
  font-size: 13px;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 3px 8px rgba(0, 0, 0, 0.25);
}
