/* RIPPED — extracted from the original index.html. */
  /* =========================================================
     Tokens — modeled on 90scard's --color-* system
     ========================================================= */
  :root[data-theme="light"] {
    --color-bg:              #ffffff;
    --color-bg-secondary:    #f3f5f9;
    --color-bg-tertiary:     #e6eaf1;
    --color-text:            #0a0a0f;
    --color-text-secondary:  #3a4156;          /* darkened for AA contrast on white */
    --color-border:          rgba(10, 10, 15, 0.12);
    --color-border-secondary:rgba(10, 10, 15, 0.06);
    --color-border-active:   #0a0a0f;          /* dark fill on active pills */
    --color-icon:            #0a0a0f;
    --color-accent:          #ee1c25;          /* Poké red — saved for one CTA */

    /* Legacy aliases used elsewhere */
    --ink:     var(--color-text);
    --ink-dim: var(--color-text-secondary);
    --line:    var(--color-border);
    --accent:  var(--color-accent);
    --accent-2: #3b4cca;
    --gold:    #ffcb05;
  }
  :root[data-theme="dark"] {
    --color-bg:              #0a0a0f;
    --color-bg-secondary:    #14141c;
    --color-bg-tertiary:     #1c1c28;
    --color-text:            #f5f7fa;
    --color-text-secondary:  #9aa0b8;
    --color-border:          rgba(255, 255, 255, 0.10);
    --color-border-secondary:rgba(255, 255, 255, 0.05);
    --color-border-active:   #f5f7fa;
    --color-icon:            #f5f7fa;
    --color-accent:          #ee1c25;
    --ink:     var(--color-text);
    --ink-dim: var(--color-text-secondary);
    --line:    var(--color-border);
    --accent:  var(--color-accent);
    --accent-2: #6e8bff;
    --gold:    #ffcb05;
  }
  /* Default to light if data-theme missing */
  :root { color-scheme: light; }
  :root[data-theme="dark"] { color-scheme: dark; }

  :root {
    --r-common:    #9aa0b8;
    --r-uncommon:  #3aa18f;
    --r-rare:      #3a87dd;
    --r-epic:      #9b3adf;
    --r-legendary: #e89200;

    --ease-out-quint: cubic-bezier(0.22, 1, 0.36, 1);
    --ease-in-out-cubic: cubic-bezier(0.65, 0, 0.35, 1);
    --font-display: "Inter", ui-sans-serif, system-ui, sans-serif;
    --font-body:    "Space Grotesk", "Inter", ui-sans-serif, system-ui, sans-serif;
  }

  *, *::before, *::after { box-sizing: border-box; }
  html, body { margin: 0; padding: 0; }

  html {
    overscroll-behavior: none;
    touch-action: pan-x pan-y;
    -webkit-text-size-adjust: 100%;
    /* Hard lock against iOS pinch-zoom drift: html is a fixed-size
       window, body scrolls inside it. With this setup, iOS can't
       displace fixed elements when the toolbar collapses or the user
       accidentally pinches — there's no extra layout viewport to drift
       relative to. */
    height: 100%;
    overflow: hidden;
  }
  body {
    font-family: var(--font-body);
    color: var(--color-text);
    background: var(--color-bg);
    /* Body becomes the scroll container — sized to the visual viewport
       and scrolls its overflowing children. Fixed elements within body
       (topbar, mobile-nav, sidebar drawer, overlay) stay glued to the
       body's edges, not iOS's drifting layout viewport. */
    height: 100dvh;
    overflow-y: auto;
    overflow-x: hidden;
    -webkit-overflow-scrolling: touch;     /* momentum scroll on iOS */
    transition: background 0.2s ease, color 0.2s ease;
    position: relative;
    touch-action: pan-x pan-y;
    overscroll-behavior: none;
    -webkit-text-size-adjust: 100%;
  }

  /* Subtle Poké Ball wallpaper — repeating SVG pattern, very low opacity.
     The element extends 220px past every viewport edge so the GPU-driven
     translate animation never exposes a blank rim. The keyframes shift the
     element by exactly one tile period (220px) so when the animation loops
     the visual state is identical — no visible seam. transform is on the
     compositor thread, so unlike the old background-position approach this
     no longer repaints during scroll on mobile. */
  body::before {
    content: "";
    position: fixed;
    inset: -220px;
    z-index: 0;
    pointer-events: none;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='120' height='120' viewBox='0 0 120 120'><g fill='none' stroke='%230a0a0f' stroke-width='1.4' opacity='0.55'><circle cx='30' cy='30' r='14'/><path d='M16 30h28'/><circle cx='30' cy='30' r='4' fill='%230a0a0f'/></g><g fill='none' stroke='%230a0a0f' stroke-width='1.4' opacity='0.4'><circle cx='90' cy='86' r='10'/><path d='M80 86h20'/><circle cx='90' cy='86' r='3' fill='%230a0a0f'/></g></svg>");
    background-size: 220px 220px;
    opacity: 0.13;
    will-change: transform;
    animation: bgDrift 80s linear infinite;
  }
  @keyframes bgDrift {
    from { transform: translate3d(0, 0, 0); }
    to   { transform: translate3d(220px, 220px, 0); }
  }
  /* Respect users who prefer no motion. */
  @media (prefers-reduced-motion: reduce) {
    body::before { animation: none; }
  }
  :root[data-theme="dark"] body::before {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='120' height='120' viewBox='0 0 120 120'><g fill='none' stroke='%23ffffff' stroke-width='1.4' opacity='0.55'><circle cx='30' cy='30' r='14'/><path d='M16 30h28'/><circle cx='30' cy='30' r='4' fill='%23ffffff'/></g><g fill='none' stroke='%23ffffff' stroke-width='1.4' opacity='0.4'><circle cx='90' cy='86' r='10'/><path d='M80 86h20'/><circle cx='90' cy='86' r='3' fill='%23ffffff'/></g></svg>");
    opacity: 0.16;
  }
  @keyframes bgDrift { to { background-position: 720px 480px; } }

  /* Soft red+blue glow blobs in the corners — Pokemon-flag energy without being garish */
  body::after {
    content: "";
    position: fixed; inset: 0; z-index: 0;
    pointer-events: none;
    background:
      radial-gradient(700px 500px at 90% -10%, rgba(238, 28, 37, 0.06), transparent 60%),
      radial-gradient(700px 500px at -10% 110%, rgba(59, 76, 202, 0.06), transparent 60%);
  }

  /* Make sure app content sits above the wallpaper */
  .app, .mobile-nav { position: relative; z-index: 1; }

  button { font: inherit; color: inherit; cursor: pointer; }

  /* =========================================================
     App shell — sidebar + main + mobile bottom nav (90scard pattern)
     ========================================================= */
  .app {
    display: flex;
    min-height: 100dvh;
    background: transparent;   /* let body's Poké Ball wallpaper show through */
  }

  /* === Desktop sidebar === */
  .sidebar {
    width: 256px;
    flex-shrink: 0;
    border-right: 1px solid var(--color-border-secondary);
    position: sticky; top: 0;
    height: 100dvh;
    display: flex; flex-direction: column;
    background: var(--color-bg);
  }
  .sidebar-logo {
    height: 80px;
    display: flex; align-items: center; gap: 10px;
    padding: 0 16px;
    font-family: var(--font-display);
    font-weight: 900; font-size: 22px; letter-spacing: -0.01em;
    color: var(--color-text);
  }
  .sidebar-logo .pokeball {
    width: 28px; height: 28px; border-radius: 999px;
    background:
      radial-gradient(circle at 50% 50%, var(--color-bg) 0 5px, var(--color-text) 5px 6.5px, transparent 6.5px),
      linear-gradient(180deg, var(--color-accent) 0 50%, var(--color-bg) 50% 100%);
    box-shadow: inset 0 0 0 2px var(--color-text);
    flex-shrink: 0;
  }
  .sidebar-body {
    flex: 1; min-height: 0;
    display: flex; flex-direction: column; justify-content: space-between;
    padding: 16px;
    overflow-y: auto;
  }
  .sidebar-section { display: flex; flex-direction: column; gap: 12px; margin-bottom: 16px; }
  .sidebar-section-title {
    margin: 0; font-size: 13px; font-weight: 500; color: var(--color-text-secondary);
  }
  .sidebar-divider { height: 1px; background: var(--color-border); margin: 4px 0; }

  .sidebar-item {
    height: 48px;
    display: flex; align-items: center; gap: 12px;
    padding: 0 16px;
    border-radius: 12px;
    border: 0;
    background: var(--color-bg-secondary);
    color: var(--color-text);
    font-size: 15px; font-weight: 700;
    transition: background .18s ease, color .18s ease;
    text-align: left; cursor: pointer;
    width: 100%;
  }
  .sidebar-item:hover { background: var(--color-bg-tertiary); }
  .sidebar-item.is-active {
    background: var(--color-border-active);
    color: var(--color-bg);
  }
  .sidebar-item.is-active .icon { color: var(--color-bg); }
  .sidebar-item .icon {
    width: 24px; height: 24px;
    display: grid; place-items: center;
    color: var(--color-icon);
    flex-shrink: 0;
  }

  /* Theme toggle pill */
  .theme-toggle {
    margin-top: 16px;
    padding: 4px;
    background: var(--color-bg-secondary);
    border: 1px solid var(--color-border);
    border-radius: 14px;
    display: flex; gap: 0;
  }
  .theme-toggle button {
    flex: 1; height: 34px;
    display: flex; align-items: center; justify-content: center; gap: 6px;
    border: 0; border-radius: 10px;
    background: transparent; color: var(--color-text);
    font-size: 13px; font-weight: 700;
    transition: background .18s, color .18s, opacity .18s;
    opacity: 0.55;
  }
  .theme-toggle button.is-active {
    background: var(--color-border-active);
    color: var(--color-bg);
    opacity: 1;
  }

  /* === Main column === */
  .main-col {
    flex: 1; min-width: 0;
    display: flex; flex-direction: column;
    padding-bottom: 80px;             /* room for mobile bottom nav */
    background: transparent;
  }
  .topbar {
    height: 80px;
    border-bottom: 1px solid var(--color-border-secondary);
    display: flex; align-items: center; justify-content: space-between;
    padding: 0 24px;
    position: sticky; top: 0; z-index: 30;
    background: rgba(255, 255, 255, 0.7);    /* lighter so the pattern peeks through */
    -webkit-backdrop-filter: blur(14px);
    backdrop-filter: blur(14px);
  }
  :root[data-theme="dark"] .topbar { background: rgba(10, 10, 15, 0.7); }

  .topbar-left  { display: flex; align-items: center; gap: 12px; }
  .topbar-right { display: flex; align-items: center; gap: 10px; }

  .balance-pill {
    height: 44px;
    padding: 0 18px;
    border-radius: 14px;
    background: var(--color-bg-secondary);
    border: 1px solid var(--color-border);
    color: var(--color-text);
    font-size: 14px; font-weight: 700;
    display: flex; align-items: center; gap: 8px;
    transition: background .25s ease, border-color .25s ease;
  }
  .balance-pill .label { color: var(--color-text-secondary); font-weight: 500; }
  .balance-pill strong { color: var(--color-text); font-weight: 800; }
  /* Hide balance entirely when not signed in — there's no user account
     for it to belong to yet. JS sets body.auth-signed-out / signed-in. */
  body.auth-signed-out .balance-pill { display: none !important; }
  /* Red flash when a purchase is rejected for insufficient funds */
  .balance-pill.flash {
    background: rgba(238, 28, 37, 0.14);
    border-color: rgba(238, 28, 37, 0.45);
    animation: balanceShake 0.5s ease-out;
  }
  @keyframes balanceShake {
    0%, 100% { transform: translateX(0); }
    20% { transform: translateX(-4px); }
    40% { transform: translateX(4px); }
    60% { transform: translateX(-3px); }
    80% { transform: translateX(2px); }
  }

  /* Toast — bottom-center notice for things like insufficient balance */
  .toast {
    position: fixed; left: 50%; bottom: 96px;
    transform: translate(-50%, 12px);
    background: var(--color-text); color: var(--color-bg);
    padding: 12px 20px; border-radius: 999px;
    font-size: 13px; font-weight: 700;
    box-shadow: 0 10px 30px rgba(0,0,0,0.18);
    opacity: 0; pointer-events: none; z-index: 100;
    transition: opacity .25s ease, transform .25s var(--ease-out-quint);
    max-width: 90vw; white-space: nowrap;
  }
  .toast.show {
    opacity: 1;
    transform: translate(-50%, 0);
  }

  /* =========================================================
     Auth — sign-in button + account chip in the topbar
     ========================================================= */
  .auth-signin {
    height: 38px;
    padding: 0 14px;
    border-radius: 10px;
    border: 1px solid var(--color-border);
    background: var(--color-bg);
    color: var(--color-text);
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 13px;
    letter-spacing: 0.04em;
    cursor: pointer;
    transition: background .15s, transform .12s;
    display: inline-flex; align-items: center; gap: 8px;
  }
  .auth-signin::before {
    content: ""; width: 14px; height: 14px;
    background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 48'><path fill='%234285F4' d='M24 9.5c3.54 0 6.71 1.22 9.21 3.6l6.85-6.85C35.9 2.38 30.47 0 24 0 14.62 0 6.51 5.38 2.56 13.22l7.98 6.19C12.43 13.72 17.74 9.5 24 9.5z'/><path fill='%2334A853' d='M46.98 24.55c0-1.57-.15-3.09-.38-4.55H24v9.02h12.94c-.58 2.96-2.26 5.48-4.78 7.18l7.73 6c4.51-4.18 7.09-10.36 7.09-17.65z'/><path fill='%23FBBC05' d='M10.53 28.59c-.48-1.45-.76-2.99-.76-4.59s.27-3.14.76-4.59l-7.98-6.19C.92 16.46 0 20.12 0 24c0 3.88.92 7.54 2.56 10.78l7.97-6.19z'/><path fill='%23EA4335' d='M24 48c6.48 0 11.93-2.13 15.89-5.81l-7.73-6c-2.15 1.45-4.92 2.3-8.16 2.3-6.26 0-11.57-4.22-13.47-9.91l-7.98 6.19C6.51 42.62 14.62 48 24 48z'/></svg>") center/contain no-repeat;
  }
  .auth-signin:hover { background: var(--color-bg-secondary); transform: translateY(-1px); }
  .auth-signin:active { transform: translateY(0); }
  .auth-signin[hidden] { display: none; }

  .auth-chip {
    display: inline-flex; align-items: center; gap: 8px;
    height: 38px;
    padding: 4px 8px 4px 4px;
    border-radius: 999px;
    background: var(--color-bg-secondary);
    border: 1px solid var(--color-border);
    color: var(--color-text);
  }
  .auth-chip[hidden] { display: none; }
  .auth-avatar {
    width: 30px; height: 30px;
    border-radius: 999px;
    background: var(--color-bg-tertiary);
    object-fit: cover;
    flex-shrink: 0;
  }
  .auth-name {
    font-size: 13px; font-weight: 700;
    max-width: 110px;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .auth-signout {
    width: 26px; height: 26px;
    border: 0; border-radius: 999px;
    background: transparent;
    color: var(--color-text-secondary);
    cursor: pointer;
    font-size: 14px;
    display: grid; place-items: center;
    transition: background .15s, color .15s;
  }
  .auth-signout:hover { background: var(--color-bg-tertiary); color: var(--color-accent); }

  @media (max-width: 480px) {
    .auth-name { display: none; }
    .auth-chip { padding: 4px; }
    .auth-signin { height: 36px; padding: 0 10px; font-size: 12px; }
    .auth-signin::before { width: 13px; height: 13px; }
  }

  .topbar-burger {
    width: 44px; height: 44px;
    display: none;
    align-items: center; justify-content: center;
    border-radius: 12px; border: 0;
    background: transparent; color: var(--color-text);
  }

  /* Round icon button used in the topbar (sound toggle, etc.) */
  .icon-btn {
    width: 44px; height: 44px;
    display: flex; align-items: center; justify-content: center;
    border-radius: 12px; border: 1px solid var(--color-border);
    background: var(--color-bg-secondary);
    color: var(--color-text);
    transition: background .18s ease, color .18s ease, border-color .18s ease;
  }
  .icon-btn:hover { background: var(--color-bg-tertiary); }
  .icon-btn.is-active {
    background: var(--color-border-active);
    color: var(--color-bg);
    border-color: var(--color-border-active);
  }

  /* Mobile-only logo in topbar */
  .topbar-logo-mobile { display: none; align-items: center; gap: 8px; font-family: var(--font-display); font-weight: 900; font-size: 18px; }
  .topbar-logo-mobile .pokeball {
    width: 24px; height: 24px; border-radius: 999px;
    background:
      radial-gradient(circle at 50% 50%, var(--color-bg) 0 4px, var(--color-text) 4px 5.5px, transparent 5.5px),
      linear-gradient(180deg, var(--color-accent) 0 50%, var(--color-bg) 50% 100%);
    box-shadow: inset 0 0 0 2px var(--color-text);
  }

  /* === Mobile bottom nav === */
  .mobile-nav {
    display: none;
    position: fixed; bottom: 0; left: 0; right: 0; z-index: 40;
    height: calc(64px + env(safe-area-inset-bottom));
    padding-bottom: env(safe-area-inset-bottom);
    background: var(--color-bg);
    border-top: 1px solid var(--color-border);
  }
  :root[data-theme="dark"] .mobile-nav {
    background: var(--color-bg-secondary);   /* slightly lifted in dark mode */
  }
  .mobile-nav-inner { display: flex; height: 64px; }
  .mobile-nav button {
    flex: 1;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
    border: 0; background: transparent;
    color: var(--color-text-secondary);
    font-size: 10px; font-weight: 600;
    transition: background .18s, color .18s;
    position: relative;
  }
  /* Active tab indicator — soft light-grey pill that reads in both themes
     without the harsh inverted-contrast look the original had. The pill
     uses the design system's "tertiary" surface (one step elevated from
     the nav bar's secondary surface), so it feels like a gently-raised
     chip rather than a colour blast. */
  .mobile-nav button.is-active {
    background: var(--color-bg-tertiary);
    color: var(--color-text);
  }
  /* Dark mode — same approach (elevated tertiary surface), plus a thin
     red accent line at the top of the pill so the eye still picks up
     the active tab at a glance. */
  :root[data-theme="dark"] .mobile-nav button.is-active {
    background: var(--color-bg-tertiary);
    color: var(--color-text);
    box-shadow: inset 0 2px 0 var(--color-accent);
  }
  .mobile-nav button.is-active .icon { color: var(--color-text); }
  :root[data-theme="dark"] .mobile-nav button.is-active .icon { color: var(--color-accent); }
  .mobile-nav button .icon { width: 22px; height: 22px; }

  @media (max-width: 1023px) {
    .topbar-burger, .topbar-logo-mobile { display: flex; }
    .mobile-nav { display: block; }
    .topbar { height: 64px; padding: 0 12px; }
    .balance-pill { height: 38px; padding: 0 12px; font-size: 13px; }

    /* Sidebar becomes a slide-in drawer on mobile.
       NOTE on stacking: drawer (60) > topbar lifted while open (56) >
       backdrop (55) > everything else. That keeps the hamburger tappable
       when the drawer is open so the user always has a way back. */
    .sidebar {
      display: flex;
      position: fixed; top: 0; left: 0; bottom: 0;
      width: min(86vw, 320px);
      z-index: 60;
      transform: translateX(-100%);
      transition: transform 0.3s var(--ease-out-quint);
      height: 100dvh;
      background: var(--color-bg);
      box-shadow: 16px 0 50px rgba(0, 0, 0, 0.18);
      border-right: 1px solid var(--color-border);
    }
    body.menu-open .sidebar { transform: translateX(0); }

    /* Dark mode — the default --color-bg (#0a0a0f) is essentially the same
       colour as a dimmed page, so the drawer used to merge invisibly with
       the backdrop. Use the lifted secondary surface and a brighter rim. */
    :root[data-theme="dark"] .sidebar {
      background: var(--color-bg-secondary);
      box-shadow:
        16px 0 50px rgba(0, 0, 0, 0.7),
        1px 0 0 0 rgba(255, 255, 255, 0.06) inset;
      border-right: 1px solid rgba(255, 255, 255, 0.08);
    }

    /* Dim backdrop behind the open drawer — kept light so the page
       behind the drawer doesn't read as a uniform "everything greyed
       out" wash. The drawer's own elevation/shadow does the visual
       separation work; the backdrop just hints that the rest of the
       page isn't tappable. */
    .menu-backdrop {
      position: fixed; inset: 0; z-index: 55;
      background: rgba(0, 0, 0, 0.18);
      opacity: 0; pointer-events: none;
      transition: opacity 0.25s ease;
    }
    :root[data-theme="dark"] .menu-backdrop { background: rgba(0, 0, 0, 0.4); }
    body.menu-open .menu-backdrop {
      opacity: 1; pointer-events: auto;
    }
    /* Lift the topbar above the backdrop while the drawer is open so the
       hamburger stays visible and tappable as a close target. */
    body.menu-open .topbar { z-index: 56; }

    /* Slide the bottom nav out of the way when the drawer is open — it
       used to remain anchored over the bottom of the drawer (covering the
       Light/Dark and Mute/Sound toggles) since .mobile-nav lives outside
       .app at body root with z-index 40 above the drawer's containing
       block. Animate it out so the drawer reads as a clean full-height
       panel. */
    .mobile-nav {
      transition: transform 0.28s var(--ease-out-quint), background .2s;
    }
    body.menu-open .mobile-nav {
      transform: translateY(100%);
      pointer-events: none;
    }
  }

  /* Press-flash on tab buttons — immediate visible confirmation that the
     tap registered, since on iOS the drawer slide-out can otherwise mask it. */
  .tab-press-flash {
    box-shadow: 0 0 0 2px var(--color-accent), 0 0 18px rgba(238,28,37,0.4) !important;
    transform: scale(0.97);
    transition: transform .12s var(--ease-out-quint), box-shadow .12s ease;
  }

  /* Visible feedback when a tab activates — subtle fade-in on the new view
     so the user sees something happen even if they land on an empty page. */
  .view.is-on { animation: viewFade 0.28s var(--ease-out-quint); }
  @keyframes viewFade {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: translateY(0); }
  }
  @media (prefers-reduced-motion: reduce) {
    .view.is-on { animation: none; }
  }
  @media (min-width: 1024px) {
    .menu-backdrop { display: none; }
  }

  /* =========================================================
     Hero
     ========================================================= */
  .hero {
    text-align: center; padding: 72px 24px 24px;
  }
  .hero h1 {
    font-family: var(--font-display);
    font-size: clamp(40px, 8vw, 80px); line-height: 0.98; margin: 0 0 16px;
    font-weight: 900; letter-spacing: -0.035em;
    color: var(--color-text);
  }
  .hero h1 em { font-style: normal; color: var(--color-accent); }
  .hero p { color: var(--color-text-secondary); max-width: 620px; margin: 0 auto; font-size: 16px; line-height: 1.55; }
  .hero .verify {
    display: inline-block; margin-top: 18px; font-size: 12px;
    color: var(--color-text-secondary); background: var(--color-bg-secondary); border: 1px solid var(--color-border);
    padding: 8px 14px; border-radius: 999px; font-weight: 600;
  }
  .hero .verify::before { content: "✓ "; color: var(--r-uncommon); font-weight: 800; }

  /* =========================================================
     Pack carousel (3 visible at once: prev / current / next)
     ========================================================= */
  .carousel-wrap {
    padding: 16px 24px 80px;
    perspective: 1600px;
  }
  .carousel {
    position: relative;
    height: clamp(420px, 60vh, 640px);
    display: grid; place-items: center;
    transform-style: preserve-3d;
  }

  .car-track {
    position: relative; width: 100%; height: 100%;
    transform-style: preserve-3d;
  }

  /* every pack is absolutely positioned and CSS-transformed by JS-set --offset */
  .pack-card {
    --w: clamp(220px, 24vw, 320px);
    position: absolute;
    left: 50%; top: 50%;
    width: var(--w);
    aspect-ratio: 5 / 7;
    margin-left: calc(var(--w) / -2);
    margin-top: calc(var(--w) / -2 * 1.4);
    background: transparent; border: 0; padding: 0;
    transform-style: preserve-3d;
    transition:
      transform .9s var(--ease-out-quint),
      opacity .6s var(--ease-out-quint),
      filter .6s var(--ease-out-quint);
    cursor: pointer;
    will-change: transform;
  }

  /* --offset is -2..2; --abs is its absolute value. JS sets these. */
  .pack-card {
    --offset: 0;
    --abs: 0;
    transform:
      translate3d(calc(var(--offset) * 95%), 0, calc(var(--abs) * -80px))
      scale(calc(1 - var(--abs) * 0.20));
    opacity: calc(1 - var(--abs) * 0.42);
    z-index: calc(10 - var(--abs));
    pointer-events: auto;
    cursor: pointer;
    /* 95% horizontal offset + small Z push back keeps side packs cleanly
       behind the centered one with no overlap, but no rotateY/blur which
       kill mobile framerate. */
  }
  .pack-card[data-hidden="true"] { opacity: 0; pointer-events: none; }
  .pack-card.is-current:hover {
    /* Subtler hover — no rotateX (caused the "shoots out toward center" feel)
       and a smaller scale bump. */
    transform:
      translate3d(0, -6px, 0)
      scale(1.015);
  }

  /* Pack visual */
  .pack {
    position: relative; width: 100%; height: 100%;
    border-radius: 22px; overflow: hidden;
    transform-style: preserve-3d;
    box-shadow:
      0 1px 0 rgba(255,255,255,0.08) inset,
      0 -30px 60px rgba(0,0,0,0.5) inset,
      0 30px 70px rgba(0,0,0,0.55),
      0 0 0 1px rgba(255,255,255,0.06);
  }
  .pack-card.is-current .pack {
    box-shadow:
      0 1px 0 rgba(255,255,255,0.1) inset,
      0 -30px 60px rgba(0,0,0,0.5) inset,
      0 50px 100px rgba(0,0,0,0.6),
      0 0 0 1px rgba(255,255,255,0.12),
      0 0 80px var(--pack-glow, rgba(183,148,255,0.45));
  }
  /* Static subtle highlight strip — replaces the rotating conic-gradient foil
     animation, which was rendering as a "transparent overlay shooting through
     the middle" on some mobile browsers and adding GPU cost. */
  .pack::before {
    content: ""; position: absolute; left: 0; right: 0; top: 0; height: 35%;
    background: linear-gradient(180deg, rgba(255,255,255,0.10), transparent);
    pointer-events: none;
  }

  .pack-art {
    position: absolute; inset: 0;
    background: var(--pack-bg);
    display: grid; place-items: center;
  }
  .pack-art .creature {
    font-size: clamp(72px, 11vw, 130px);
    filter: drop-shadow(0 10px 30px rgba(0,0,0,0.55));
    animation: bob 5s ease-in-out infinite;
  }
  @keyframes bob { 50% { transform: translateY(-10px); } }

  .pack-meta {
    position: absolute; left: 0; right: 0; bottom: 0;
    padding: 16px 16px 18px;
    background: linear-gradient(180deg, transparent, rgba(0,0,0,0.82) 70%);
    display: flex; align-items: flex-end; justify-content: space-between;
    gap: 10px;
    color: #fff;                                /* on dark pack art, force light text */
  }
  /* On mobile the pack-meta strip overlaps the bottom nav and duplicates
     the .car-info panel rendered below the carousel — hide it on phones
     so the tile reads as a clean piece of artwork instead. */
  @media (max-width: 1023px) {
    .pack-meta { display: none; }
  }
  /* Inner column for the name+tag pair — explicit gap so the two lines
     breathe instead of squashing together, and min-width:0 so flex can
     give the name as much horizontal space as it needs. */
  .pack-meta > div:first-child {
    display: flex; flex-direction: column; gap: 4px;
    min-width: 0;
    flex: 1 1 auto;
  }
  .pack-meta .name {
    font-size: 15px; font-weight: 800;
    letter-spacing: 0.02em;
    line-height: 1.2;
    color: #fff;
    /* No ellipsis — the names are short enough to fit at 15px so we'd
       rather keep the full name visible than truncate. */
    word-break: keep-all;
  }
  .pack-meta .tag {
    font-size: 10px;
    color: rgba(255,255,255,0.78);
    text-transform: uppercase;
    letter-spacing: 0.16em;
    line-height: 1.15;
  }
  .pack-meta .price {
    background: rgba(0,0,0,0.55); border: 1px solid rgba(255,255,255,0.18);
    padding: 6px 9px; border-radius: 999px;
    color: #fff; font-size: 11.5px; font-weight: 700;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    flex-shrink: 0;
  }

  .pack-card[data-rarity="common"]    { --pack-bg: linear-gradient(160deg, #2a3045, #5b637f); --pack-glow: rgba(138,138,168,0.5); }
  .pack-card[data-rarity="rare"]      { --pack-bg: linear-gradient(160deg, #1a3a6b, #4179c1, #6ee7ff); --pack-glow: rgba(110,197,255,0.6); }
  .pack-card[data-rarity="epic"]      { --pack-bg: linear-gradient(160deg, #3a1a6b, #6c2eb9, #c77bff); --pack-glow: rgba(199,123,255,0.65); }
  .pack-card[data-rarity="legendary"] { --pack-bg: linear-gradient(160deg, #6b3a1a, #c97a1f, #ffd66e); --pack-glow: rgba(255,210,110,0.7); }

  /* Carousel chrome */
  .car-arrow {
    position: absolute; top: 50%; transform: translateY(-50%);
    width: clamp(44px, 5vw, 52px);
    height: clamp(44px, 5vw, 52px);
    border-radius: 999px;
    background: var(--color-bg);                 /* themed instead of hard white */
    border: 1px solid var(--color-border);
    color: var(--color-icon);                    /* visible on both themes */
    display: grid; place-items: center;
    font-size: 22px; z-index: 20;
    box-shadow: 0 8px 24px rgba(0,0,0,0.10);
    transition: transform .25s var(--ease-out-quint), box-shadow .25s, border-color .25s, background .2s;
    cursor: pointer;
  }
  :root[data-theme="dark"] .car-arrow {
    background: var(--color-bg-secondary);       /* lifted card surface in dark mode */
    box-shadow: 0 8px 24px rgba(0,0,0,0.4);
  }
  .car-arrow:hover {
    transform: translateY(-50%) scale(1.06);
    box-shadow: 0 12px 30px rgba(0,0,0,0.18);
    border-color: var(--color-border-active);
  }
  :root[data-theme="dark"] .car-arrow:hover { background: var(--color-bg-tertiary); }
  .car-arrow.prev { left: clamp(8px, 2vw, 24px); }
  .car-arrow.next { right: clamp(8px, 2vw, 24px); }

  .car-info {
    text-align: center; margin-top: 22px;
    display: flex; flex-direction: column; align-items: center;
    gap: 18px;
  }
  .car-info h3 {
    margin: 0;
    font-size: clamp(22px, 4.5vw, 28px);
    font-weight: 800;
    letter-spacing: -0.012em;
    line-height: 1.18;
    color: var(--ink);
  }
  .car-info p {
    margin: 0;
    color: var(--ink-dim);
    font-size: clamp(13px, 1.5vw, 15px);
    line-height: 1.5;
    max-width: 38ch;
  }
  .car-dots { display: flex; gap: 8px; }
  .car-dot {
    width: 8px; height: 8px; border-radius: 999px;
    background: rgba(20,30,60,0.15); cursor: pointer; border: 0;
    transition: width .3s var(--ease-out-quint), background .3s;
  }
  .car-dot.is-active { background: var(--accent); width: 24px; }

  .open-cta {
    margin-top: 4px;
    background: var(--color-border-active);
    color: var(--color-bg); border: 0;
    padding: clamp(13px, 1.7vw, 18px) clamp(20px, 3vw, 36px);
    border-radius: 14px;
    font-family: var(--font-display);
    font-weight: 800; font-size: clamp(13px, 1.4vw, 15px);
    letter-spacing: 0.06em;
    box-shadow: 0 12px 28px rgba(0,0,0,0.18);
    transition: transform .22s var(--ease-out-quint), filter .2s, box-shadow .22s;
    max-width: min(520px, 92vw);
    line-height: 1.3;
    text-align: center;
    min-height: 48px;          /* touch target */
  }
  .open-cta:hover  { transform: translateY(-2px); filter: brightness(0.92); box-shadow: 0 18px 38px rgba(0,0,0,0.22); }
  .open-cta:active { transform: translateY(0); }
  .open-cta:disabled,
  .open-cta[aria-disabled="true"] {
    background: var(--color-bg-tertiary);
    color: var(--ink-dim);
    cursor: not-allowed;
    box-shadow: none;
    filter: none;
    transform: none;
    opacity: 0.85;
  }
  .open-cta:disabled:hover,
  .open-cta[aria-disabled="true"]:hover { transform: none; filter: none; box-shadow: none; }

  /* =========================================================
     Odds breakdown + minimum guarantee — punchier, more visual
     ========================================================= */
  .odds-card {
    width: min(620px, 94vw);
    margin-top: 8px;
    background: var(--color-bg-secondary);
    border: 1px solid var(--color-border);
    border-radius: 18px;
    padding: clamp(18px, 2.4vw, 24px) clamp(18px, 2.4vw, 26px) clamp(16px, 2vw, 20px);
    text-align: left;
    box-shadow: 0 1px 0 rgba(255,255,255,0.04) inset, 0 12px 32px rgba(0,0,0,0.06);
  }
  .odds-card .odds-head {
    display: flex; align-items: center; justify-content: space-between;
    gap: 12px; margin-bottom: clamp(14px, 1.8vw, 18px);
  }
  .odds-card .odds-title {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: clamp(12px, 1.3vw, 14px);
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--ink);
  }
  .guarantee-chip {
    display: inline-flex; align-items: center; gap: 8px;
    background: var(--color-bg-tertiary);
    border: 1px solid var(--color-border);
    border-radius: 999px;
    padding: 7px 14px;
    font-family: var(--font-display);
    font-weight: 800;
    font-size: clamp(11px, 1.2vw, 13px);
    letter-spacing: 0.04em;
    color: var(--ink);
    white-space: nowrap;
  }
  .guarantee-chip::before {
    content: ""; width: 8px; height: 8px; border-radius: 999px;
    background: var(--gold);
    box-shadow: 0 0 0 4px rgba(255,203,5,0.22);
  }

  .odds-rows {
    display: flex; flex-direction: column;
    gap: clamp(8px, 1.1vw, 12px);
  }
  .odds-row {
    display: grid;
    grid-template-columns: 16px minmax(120px, max-content) 1fr 60px;
    align-items: center;
    gap: clamp(10px, 1.4vw, 14px);
    font-family: var(--font-body);
    font-size: clamp(14px, 1.5vw, 15px);
    color: var(--ink);
    /* Subtle per-row tint. Fallback for Safari < 16.4 (no color-mix support):
       a flat secondary surface — quieter but still distinct enough. */
    background: var(--color-bg-tertiary);
    background: color-mix(in srgb, var(--swatch, var(--ink-dim)) 8%, transparent);
    border: 1px solid var(--color-border);
    border: 1px solid color-mix(in srgb, var(--swatch, var(--ink-dim)) 14%, transparent);
    border-radius: 12px;
    padding: clamp(8px, 1.2vw, 12px) clamp(10px, 1.4vw, 14px);
  }
  .odds-row .swatch {
    width: 14px; height: 14px; border-radius: 999px;
    background: var(--swatch, var(--ink-dim));
    /* Solid-ring fallback for Safari < 16.4. Modern Safari uses the
       second declaration (translucent ring + colored shadow). */
    box-shadow: 0 0 0 4px var(--color-border-secondary);
    box-shadow:
      0 0 0 4px color-mix(in srgb, var(--swatch, var(--ink-dim)) 22%, transparent),
      0 4px 10px color-mix(in srgb, var(--swatch, var(--ink-dim)) 35%, transparent);
  }
  /* Two-line cell: rarity name on top, RM range below. */
  .odds-row .rarity-cell {
    display: flex; flex-direction: column;
    gap: 2px;
    line-height: 1.2;
    min-width: 0;
  }
  .odds-row .rarity-name {
    text-transform: capitalize;
    font-weight: 800;
    letter-spacing: 0.01em;
    font-size: clamp(14px, 1.5vw, 16px);
    color: var(--ink);
  }
  .odds-row .value-range {
    font-size: clamp(11.5px, 1.2vw, 13px);
    color: var(--ink-dim);
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.01em;
    font-weight: 600;
  }
  .odds-row[data-zero="true"] .value-range { color: var(--ink-dim); opacity: 0.55; }
  .odds-row .bar {
    position: relative;
    height: 12px;
    background: var(--color-border-secondary);
    border-radius: 999px;
    overflow: hidden;
    box-shadow: 0 1px 0 rgba(0,0,0,0.04) inset;
  }
  .odds-row .bar > i {
    position: absolute; left: 0; top: 0; bottom: 0;
    width: var(--pct, 0%);
    /* Flat-fill fallback for Safari < 16.4 — same colour, just no
       gradient + glow. */
    background: var(--swatch, var(--ink-dim));
    background: linear-gradient(90deg,
      color-mix(in srgb, var(--swatch, var(--ink-dim)) 100%, transparent) 0%,
      color-mix(in srgb, var(--swatch, var(--ink-dim)) 80%, white) 100%);
    border-radius: 999px;
    transition: width 0.45s var(--ease-out-quint);
    box-shadow: none;
    box-shadow: 0 0 12px color-mix(in srgb, var(--swatch, var(--ink-dim)) 50%, transparent);
  }
  .odds-row .pct {
    text-align: right;
    font-variant-numeric: tabular-nums;
    font-weight: 800;
    font-size: clamp(15px, 1.7vw, 17px);
    color: var(--ink);
    letter-spacing: -0.01em;
  }
  .odds-row[data-zero="true"] {
    opacity: 0.45;
    background: var(--color-border-secondary);
    border-color: var(--color-border-secondary);
  }
  .odds-row[data-zero="true"] .bar > i { width: 0 !important; }
  .odds-row[data-zero="true"] .pct { color: var(--ink-dim); }

  .odds-foot {
    margin-top: clamp(14px, 1.8vw, 18px);
    padding-top: clamp(10px, 1.4vw, 14px);
    border-top: 1px dashed var(--color-border);
    font-size: clamp(11.5px, 1.2vw, 13px);
    color: var(--ink-dim);
    line-height: 1.5;
  }

  @media (max-width: 520px) {
    .odds-card {
      width: 100%;
      max-width: 100%;
      padding: 16px 14px 14px;
      border-radius: 16px;
    }
    .odds-row {
      grid-template-columns: 14px minmax(100px, max-content) 1fr 52px;
      gap: 10px;
      padding: 10px 12px;
      font-size: 13.5px;
    }
    .odds-row .swatch { width: 12px; height: 12px; }
    .odds-row .rarity-name { font-size: 14px; }
    .odds-row .value-range { font-size: 11px; }
    .odds-row .bar { height: 10px; }
    .odds-row .pct { font-size: 15px; }
    .odds-card .odds-head { flex-wrap: wrap; gap: 8px; }
  }
  @media (max-width: 360px) {
    .odds-row { grid-template-columns: 12px minmax(86px, max-content) 1fr 46px; gap: 8px; padding: 9px 10px; font-size: 12.5px; }
    .odds-row .value-range { display: block; font-size: 10.5px; }
    .odds-row .pct { font-size: 14px; }
  }

  /* =========================================================
     Purchase-confirmation dialog
     ========================================================= */
  .confirm {
    position: fixed; inset: 0; z-index: 70;
    display: flex; align-items: center; justify-content: center;
    padding: 20px;
    background: rgba(10, 10, 15, 0.45);
    -webkit-backdrop-filter: blur(6px);
    backdrop-filter: blur(6px);
    visibility: hidden; opacity: 0;
    pointer-events: none;
    transition: opacity .2s ease, visibility .2s;
  }
  .confirm.is-open { visibility: visible; opacity: 1; pointer-events: auto; }
  :root[data-theme="dark"] .confirm { background: rgba(0, 0, 0, 0.6); }

  .confirm-card {
    /* Fluidly fills the viewport on phones, generous max on desktop. */
    width: min(560px, 100%);
    max-height: calc(100dvh - 40px);
    overflow-y: auto;
    background: var(--color-bg);
    color: var(--ink);
    border: 1px solid var(--color-border);
    border-radius: clamp(14px, 2.4vw, 22px);
    padding: clamp(18px, 3.2vw, 30px);
    box-shadow: 0 24px 70px rgba(0,0,0,0.28);
    transform: translateY(8px) scale(0.98);
    transition: transform .22s var(--ease-out-quint);
  }
  .confirm.is-open .confirm-card { transform: translateY(0) scale(1); }
  .confirm-eyebrow {
    font-family: var(--font-display);
    font-size: clamp(10px, 1.1vw, 12px);
    letter-spacing: 0.18em; text-transform: uppercase;
    color: var(--ink-dim);
    margin: 0 0 8px;
  }
  .confirm-title {
    font-family: var(--font-display);
    font-size: clamp(20px, 3.2vw, 28px);
    font-weight: 800; letter-spacing: -0.01em;
    line-height: 1.15;
    margin: 0 0 clamp(14px, 2vw, 20px);
    color: var(--ink);
  }
  .confirm-pack {
    display: flex; align-items: center;
    gap: clamp(12px, 1.6vw, 18px);
    background: var(--color-bg-secondary);
    border: 1px solid var(--color-border);
    border-radius: 14px;
    padding: clamp(12px, 1.6vw, 16px) clamp(14px, 2vw, 18px);
    margin-bottom: clamp(14px, 2vw, 18px);
  }
  .confirm-pack .pack-emoji {
    width: clamp(48px, 7vw, 64px);
    height: clamp(48px, 7vw, 64px);
    border-radius: 12px;
    display: grid; place-items: center;
    font-size: clamp(26px, 3.6vw, 34px);
    background: var(--pack-bg, var(--color-bg-tertiary));
    box-shadow: 0 6px 16px rgba(0,0,0,0.15);
    flex: 0 0 auto;
  }
  .confirm-pack .pack-info { flex: 1; min-width: 0; }
  .confirm-pack .pack-info .name {
    font-weight: 700;
    font-size: clamp(15px, 1.7vw, 18px);
    color: var(--ink);
    line-height: 1.2;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .confirm-pack .pack-info .sub {
    font-size: clamp(12px, 1.3vw, 13px);
    color: var(--ink-dim);
    margin-top: 3px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
  }
  .confirm-pack .price {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: clamp(17px, 2.1vw, 22px);
    color: var(--ink);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
  }

  .confirm-rows {
    display: grid; grid-template-columns: 1fr auto;
    row-gap: clamp(7px, 1vw, 10px);
    column-gap: clamp(12px, 2vw, 18px);
    font-size: clamp(13px, 1.4vw, 15px);
    margin-bottom: clamp(16px, 2.2vw, 22px);
    padding: 4px 2px 0;
  }
  .confirm-rows .label { color: var(--ink-dim); }
  .confirm-rows .value {
    color: var(--ink);
    font-variant-numeric: tabular-nums;
    font-weight: 700;
  }
  .confirm-rows .value.warn { color: var(--accent); }
  .confirm-rows .divider {
    grid-column: 1 / -1; height: 1px;
    background: var(--color-border-secondary);
    margin: 4px 0;
  }

  .confirm-actions {
    display: flex; gap: clamp(8px, 1.2vw, 12px);
    flex-direction: row-reverse;
  }
  .confirm-btn {
    flex: 1;
    border: 0;
    padding: clamp(13px, 1.6vw, 16px) clamp(16px, 2vw, 20px);
    border-radius: 12px;
    font-family: var(--font-display);
    font-weight: 800;
    font-size: clamp(13px, 1.4vw, 15px);
    letter-spacing: 0.06em;
    cursor: pointer;
    transition: transform .18s var(--ease-out-quint), filter .15s, box-shadow .18s;
    min-height: 48px;          /* WCAG / iOS touch target */
  }
  .confirm-btn.primary {
    background: var(--color-border-active);
    color: var(--color-bg);
    box-shadow: 0 8px 22px rgba(0,0,0,0.18);
  }
  .confirm-btn.primary:hover  { transform: translateY(-1px); filter: brightness(0.94); }
  .confirm-btn.primary:active { transform: translateY(0); }
  .confirm-btn.primary:disabled,
  .confirm-btn.primary[aria-disabled="true"] {
    background: var(--color-bg-tertiary);
    color: var(--ink-dim);
    box-shadow: none;
    cursor: not-allowed;
    transform: none; filter: none;
  }
  .confirm-btn.ghost {
    background: transparent;
    color: var(--ink);
    border: 1px solid var(--color-border);
  }
  .confirm-btn.ghost:hover { background: var(--color-bg-secondary); }

  /* Phone — give the dialog room and stack buttons full-width. */
  @media (max-width: 520px) {
    .confirm { padding: 14px; align-items: flex-end; }
    .confirm-card {
      width: 100%;
      border-radius: 18px 18px 14px 14px;  /* sheet-like feel */
      padding: 20px 18px 16px;
      max-height: calc(100dvh - 28px);
    }
    .confirm-actions { flex-direction: column-reverse; }
    .confirm-btn { width: 100%; }
    .confirm-pack { padding: 12px 14px; }
  }
  /* Tiny phones — keep emoji+price+name from crowding. */
  @media (max-width: 360px) {
    .confirm-pack { gap: 10px; }
    .confirm-pack .pack-emoji { width: 44px; height: 44px; font-size: 24px; }
    .confirm-pack .price { font-size: 16px; }
  }

  /* =========================================================
     Open overlay
     ========================================================= */
  .overlay {
    position: fixed; inset: 0; z-index: 50;
    background:
      radial-gradient(900px 700px at 50% 40%, rgba(255,255,255,0.96), rgba(248,250,255,0.92));
    -webkit-backdrop-filter: blur(20px);
    backdrop-filter: blur(20px);
    /* visibility + pointer-events instead of display:none — display toggles
       can be flaky on some mobile browsers and skip the opacity transition */
    display: flex;
    align-items: center; justify-content: center;
    visibility: hidden;
    opacity: 0;
    pointer-events: none;
    transition: opacity .25s ease, visibility .25s;
  }
  /* Dark mode — the hard-coded white radial above used to wash the entire
     page in white when a pack opened. Override with a deep, near-black
     vignette that lets the rip-stage glow read against true darkness. */
  :root[data-theme="dark"] .overlay {
    background:
      radial-gradient(900px 700px at 50% 40%, rgba(20, 22, 32, 0.92), rgba(6, 8, 14, 0.96));
  }
  .overlay.is-open {
    visibility: visible;
    opacity: 1;
    pointer-events: auto;
  }
  .overlay .close {
    position: absolute; top: 20px; right: 24px;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    width: 40px; height: 40px; border-radius: 999px;
    display: grid; place-items: center;
    color: var(--color-icon); font-size: 18px;
    box-shadow: 0 6px 18px rgba(0,0,0,0.14);
    z-index: 80;
    cursor: pointer;
  }
  :root[data-theme="dark"] .overlay .close {
    background: var(--color-bg-secondary);
    box-shadow: 0 6px 18px rgba(0,0,0,0.45);
  }
  .overlay .close:hover { transform: scale(1.06); }

  /* =========================================================
     The 3D pack — driven by GSAP (initial state only in CSS)
     ========================================================= */
  .stage {
    position: relative; width: min(360px, 82vw); aspect-ratio: 5 / 7;
    perspective: 1600px; transform-style: preserve-3d;
  }

  /* Suspense vignette — softer in light mode (focus, not blackout) */
  .vignette {
    position: fixed; inset: 0; pointer-events: none; z-index: 49;
    background: radial-gradient(55% 45% at 50% 50%, transparent 35%, rgba(8, 10, 22, 0.55) 95%);
    opacity: 0;
  }
  :root[data-theme="dark"] .vignette {
    background: radial-gradient(55% 45% at 50% 50%, transparent 30%, rgba(0, 0, 0, 0.85) 95%);
  }

  /* Bright halo behind the pack — fixed blur in CSS, GSAP only touches transform+opacity */
  .halo {
    position: absolute; left: 50%; top: 50%;
    width: 110%; aspect-ratio: 1;
    transform: translate(-50%, -50%) scale(0.4);
    background: radial-gradient(closest-side,
      rgba(255,255,255, 0.85),
      var(--pack-glow, rgba(238,28,37,0.5)) 40%,
      transparent 75%);
    pointer-events: none;
    opacity: 0;
    z-index: 0;
    will-change: transform, opacity;
  }

  .pack-3d {
    position: absolute; inset: 0;
    transform-style: preserve-3d;
    transform-origin: center center;
    touch-action: none;       /* critical for mobile swipe */
    cursor: grab;
    z-index: 1;
    user-select: none;
    -webkit-user-select: none;
    will-change: transform;
  }
  .pack-3d:active { cursor: grabbing; }

  .pack-body, .pack-top {
    position: absolute; left: 0; right: 0;
    background: var(--pack-bg);
    overflow: hidden;
    backface-visibility: hidden;
    box-shadow: 0 30px 80px rgba(0,0,0,0.45), 0 0 0 1px rgba(255,255,255,0.06);
  }
  .pack-body {
    top: 22%; bottom: 0;
    border-radius: 0 0 22px 22px;
  }
  .pack-top {
    top: 0; height: 26%;
    border-radius: 22px 22px 4px 4px;
    transform-origin: 50% 100%;
    z-index: 3;
    will-change: transform, opacity;
  }
  .pack-top::after { /* jagged tear strip on the seam */
    content: ""; position: absolute; left: -2%; right: -2%; bottom: -3px; height: 10px;
    background:
      conic-gradient(from 90deg at 50% 0%, transparent 0 35%, rgba(0,0,0,0.6) 35% 65%, transparent 65% 100%) 0 0 / 14px 10px repeat-x,
      linear-gradient(180deg, rgba(255,255,255,0.18), transparent);
    mask: linear-gradient(180deg, black 30%, transparent);
  }

  /* Light leak across the seam — fixed size, GSAP animates transform+opacity (GPU only) */
  .seam-light {
    position: absolute; left: -10%; right: -10%; top: 22%;
    height: 220px;
    transform: translateY(-50%) scaleY(0);
    transform-origin: 50% 50%;
    background: radial-gradient(60% 100% at 50% 50%, rgba(255,255,255,1), rgba(255,255,255,0) 70%);
    mix-blend-mode: screen;
    opacity: 0;
    pointer-events: none;
    z-index: 2;
    will-change: transform, opacity;
  }

  .pack-3d .creature {
    position: absolute; inset: 0; display: grid; place-items: center;
    font-size: 110px; filter: drop-shadow(0 8px 24px rgba(0,0,0,0.5));
    will-change: transform, opacity;
  }

  .burst {
    position: absolute; left: 50%; top: 50%; width: 75%; aspect-ratio: 1; border-radius: 999px;
    background: radial-gradient(closest-side,
      rgba(255,255,255, 0.9),
      var(--pack-glow, #fff) 40%,
      transparent 70%);
    transform: translate(-50%, -50%) scale(0.2);
    opacity: 0;
    mix-blend-mode: screen; pointer-events: none;
    will-change: transform, opacity;
  }

  /* Continuous shine sweep across the pack while drag is active */
  .shine {
    position: absolute; inset: 0; pointer-events: none; overflow: hidden;
    border-radius: 22px;
    z-index: 4;
    opacity: 0;
  }
  .shine::before {
    content: ""; position: absolute; top: -10%; bottom: -10%;
    width: 35%;
    background: linear-gradient(90deg, transparent, rgba(255,255,255,0.7), transparent);
    mix-blend-mode: screen;
    filter: blur(3px);
    animation: shineSweep 1.3s linear infinite;
    transform: translateX(-130%);
  }
  @keyframes shineSweep {
    0%   { transform: translateX(-130%); }
    100% { transform: translateX(330%); }
  }

  /* Light rays — GSAP fades opacity */
  .rays {
    position: absolute; left: 50%; top: 22%; width: 0; height: 0;
    pointer-events: none;
    opacity: 0;
  }
  .rays span {
    position: absolute; left: 0; top: 0;
    width: 4px; height: 280px;
    background: linear-gradient(180deg, rgba(255,255,255,0.85), transparent);
    transform-origin: top center;
    mix-blend-mode: screen;
    border-radius: 999px;
  }

  .rip-hint {
    position: absolute; bottom: -64px; left: 50%; transform: translateX(-50%);
    color: var(--ink-dim); font-size: 12px; letter-spacing: 0.22em; text-transform: uppercase;
    white-space: nowrap;
    pointer-events: none;
    opacity: 1;
    transition: opacity 0.3s ease;
    /* Belt-and-suspenders hide once the fan is showing — the GSAP
       quickSetter inline opacity:0 was sometimes outlived by a stale
       paint, leaving "swipe to tear" lingering over the reveal. */
  }

  /* Whenever the reveal fan is showing, hide the rip-hint.
     :has() is supported in Safari 15.4+ — older browsers still get
     the JS-driven hide path inside showReveal(). */
  .overlay:has(#reveal.is-on) .rip-hint {
    opacity: 0 !important;
    visibility: hidden;
  }

  /* =========================================================
     Reveal — fanned cards
     ========================================================= */
  .reveal {
    position: absolute; inset: 0; z-index: 60;
    display: none; align-items: center; justify-content: center;
    pointer-events: none;
  }
  .reveal.is-on { display: flex; pointer-events: auto; }

  .fan {
    position: relative; width: min(960px, 95vw); height: min(420px, 60vh);
    transform-style: preserve-3d;
  }

  .holo-card {
    --w: clamp(220px, 28vw, 320px);     /* bigger — single hero card */
    position: absolute; left: 50%; top: 50%;
    width: var(--w); aspect-ratio: 2.5 / 3.5;
    margin-left: calc(var(--w) / -2);
    margin-top: calc(var(--w) / -2 * 1.4);
    border-radius: 18px;
    transform-style: preserve-3d;
    /* start: tucked inside the (now-open) pack, below the fan */
    transform: translate(0, 280px) scale(0.35) rotate(0deg);
    opacity: 0;
    transition:
      transform 1.0s var(--ease-out-quint),
      opacity .35s ease;
    cursor: pointer;
  }
  .reveal.is-on .holo-card { opacity: 1; }
  /* Each card rises and fans into place with a long stagger */
  .reveal.is-on .holo-card { transform: translate(var(--tx, 0), 0) rotate(var(--rot, 0deg)) scale(1); }
  .reveal.is-on .holo-card:nth-child(1) { transition-delay: .15s; }
  .reveal.is-on .holo-card:nth-child(2) { transition-delay: .35s; }
  .reveal.is-on .holo-card:nth-child(3) { transition-delay: .55s; }
  .reveal.is-on .holo-card:nth-child(4) { transition-delay: .75s; }
  .reveal.is-on .holo-card:nth-child(5) { transition-delay: .95s; }

  .face, .back {
    position: absolute; inset: 0; border-radius: 14px;
    backface-visibility: hidden;
    box-shadow: 0 18px 40px rgba(0,0,0,0.5), 0 0 0 1px rgba(255,255,255,0.08);
    overflow: hidden;
  }
  /* Poké Ball card back */
  .back {
    background:
      radial-gradient(circle at 50% 50%,
        white 0 20%, var(--ink) 20% 23%, transparent 23%),
      linear-gradient(180deg, var(--accent) 0 50%, white 50% 100%);
    transform: rotateY(0deg);
    border: 2px solid var(--ink);
  }
  .back::before {
    content: ""; position: absolute; left: 8%; right: 8%; top: 50%;
    height: 2px; background: var(--ink); transform: translateY(-50%);
  }
  .back::after {
    content: ""; position: absolute; left: 50%; top: 50%; width: 16%; aspect-ratio: 1;
    background: white; border: 2px solid var(--ink); border-radius: 999px;
    transform: translate(-50%, -50%);
  }
  .face {
    transform: rotateY(180deg);
    background: var(--card-bg, linear-gradient(160deg, #333, #555));
    display: flex; flex-direction: column; padding: 10px;
  }
  .holo-card .inner { /* the flipper */
    position: absolute; inset: 0; transform-style: preserve-3d;
    transition: transform .9s var(--ease-out-quint);
  }
  .holo-card.flipped .inner { transform: rotateY(180deg); }

  .face .creature {
    flex: 1; display: grid; place-items: center; font-size: clamp(80px, 12vw, 140px);
    filter: drop-shadow(0 10px 22px rgba(0,0,0,0.45));
  }
  .face .nameplate {
    background: rgba(0,0,0,0.55);
    border-radius: 10px; padding: 10px 14px;
    display: flex; align-items: baseline; justify-content: space-between;
    font-size: 13px; color: #fff;
  }
  .face .nameplate strong { font-size: 16px; letter-spacing: 0.04em; color: #fff; font-weight: 800; }
  .face .nameplate .rar {
    text-transform: uppercase; letter-spacing: 0.18em; font-weight: 800; font-size: 9px;
    color: var(--rar-color, #fff);
  }

  /* Holo overlay — soft cursor-follow shine, no rainbow color-dodge ghosting */
  .face::before {
    content: ""; position: absolute; inset: 0;
    background:
      radial-gradient(180px circle at var(--mx, 50%) var(--my, 50%),
        rgba(255,255,255,0.45), transparent 60%);
    mix-blend-mode: overlay;
    opacity: var(--holo-strength, 0.6);
    pointer-events: none;
  }
  .face::after { /* glare */
    content: ""; position: absolute; inset: 0;
    background: linear-gradient(105deg, transparent 30%, rgba(255,255,255,0.25) 50%, transparent 70%);
    transform: translateX(-100%);
    pointer-events: none;
  }
  .holo-card.flipped .face::after { animation: glare 1.4s ease forwards; }
  @keyframes glare { to { transform: translateX(100%); } }

  /* Rarity tinting */
  .holo-card[data-rarity="common"]    { --rar-color: var(--r-common);    --holo-strength: 0.4; }
  .holo-card[data-rarity="uncommon"]  { --rar-color: var(--r-uncommon);  --holo-strength: 0.55; }
  .holo-card[data-rarity="rare"]      { --rar-color: var(--r-rare);     --holo-strength: 0.7; }
  .holo-card[data-rarity="epic"]      { --rar-color: var(--r-epic);     --holo-strength: 0.85; }
  .holo-card[data-rarity="legendary"] { --rar-color: var(--r-legendary); --holo-strength: 1.0; }

  /* CTAs at bottom of reveal — hidden until the user FLIPS the card,
     so the Sell-for-RM-X.XX label doesn't spoil the rarity. */
  .reveal-actions {
    position: absolute; left: 50%; bottom: 40px; transform: translateX(-50%);
    display: flex; gap: 12px; flex-wrap: wrap; justify-content: center;
    opacity: 0; pointer-events: none;
    transform: translate(-50%, 12px);
    transition: opacity .35s ease, transform .35s var(--ease-out-quint);
  }
  .reveal.is-flipped .reveal-actions {
    opacity: 1;
    pointer-events: auto;
    transform: translate(-50%, 0);
  }

  /* Subtle "tap to flip" hint that appears while the card is still face-down.
     No CSS keyframe animation — that was preventing the hint from disappearing
     once the user flipped the card (animation overrides inline/class opacity). */
  .flip-hint {
    position: absolute; left: 50%; bottom: 40px; transform: translateX(-50%);
    color: var(--color-text-secondary);
    font-size: 12px; letter-spacing: 0.22em; text-transform: uppercase;
    white-space: nowrap; pointer-events: none;
    opacity: 0; transition: opacity .35s ease;
  }
  .reveal.is-on:not(.is-flipped) .flip-hint { opacity: 1; transition-delay: 0.4s; }
  .btn {
    border: 1px solid var(--line); background: rgba(255,255,255,0.06);
    color: var(--ink); padding: 12px 20px; border-radius: 999px;
    font-weight: 700; font-size: 13px; letter-spacing: 0.06em;
    transition: transform .2s, background .2s, border-color .2s;
  }
  .btn:hover { transform: translateY(-2px); background: rgba(255,255,255,0.1); }
  .btn-primary {
    background: linear-gradient(135deg, var(--accent), var(--accent-2));
    color: #11062b; border-color: transparent;
  }
  .btn-primary:hover { filter: brightness(1.08); }

  /* =========================================================
     Card detail (tilt) overlay
     ========================================================= */
  .detail {
    position: fixed; inset: 0; z-index: 70;
    display: none; align-items: center; justify-content: center;
    background: rgba(255,255,255,0.85); -webkit-backdrop-filter: blur(24px); backdrop-filter: blur(24px);
    opacity: 0; transition: opacity .3s ease;
  }
  .detail.is-on {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 24px;
    opacity: 1;
  }
  .detail .close { position: absolute; top: 20px; right: 24px; width: 40px; height: 40px;
    border-radius: 999px; border: 1px solid var(--line); background: white;
    color: var(--ink); display: grid; place-items: center;
    box-shadow: 0 6px 18px rgba(20,30,60,0.08); }
  :root[data-theme="dark"] .detail { background: rgba(8, 10, 14, 0.85); }
  :root[data-theme="dark"] .detail .close { background: var(--color-bg-secondary); border-color: var(--color-border); color: var(--color-icon); }
  .detail .close:hover { transform: scale(1.06); }

  /* Card actions panel — shown when the detail was opened from the
     binder (so the card has a DB pk and is sellable). */
  .detail-actions {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    width: min(360px, 80vw);
  }
  .detail-actions[hidden] { display: none; }
  .detail-meta {
    display: flex; align-items: baseline; gap: 8px;
    font-family: var(--font-display);
  }
  .detail-meta .detail-value-label {
    color: var(--ink-dim);
    font-size: 12px;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    font-weight: 700;
  }
  .detail-meta .detail-value {
    color: var(--ink);
    font-size: 22px;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
  }
  .detail-btn {
    width: 100%;
    padding: 14px 24px;
    border-radius: 14px;
    border: 0;
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 14px;
    letter-spacing: 0.06em;
    cursor: pointer;
    transition: transform .18s var(--ease-out-quint), filter .15s, box-shadow .18s;
    min-height: 48px;
  }
  .detail-btn.primary {
    background: var(--color-border-active);
    color: var(--color-bg);
    box-shadow: 0 8px 22px rgba(0,0,0,0.18);
  }
  .detail-btn.primary:hover  { transform: translateY(-1px); filter: brightness(0.94); }
  .detail-btn.primary:active { transform: translateY(0); }
  .detail-btn.primary:disabled,
  .detail-btn.primary[aria-disabled="true"] {
    background: var(--color-bg-tertiary);
    color: var(--ink-dim);
    box-shadow: none;
    cursor: not-allowed;
    transform: none;
    filter: none;
  }

  .tilt-wrap {
    width: min(360px, 80vw); aspect-ratio: 2.5 / 3.5;
    perspective: 1200px;
  }
  .tilt-card {
    width: 100%; height: 100%; position: relative; transform-style: preserve-3d;
    border-radius: 20px; overflow: hidden;
    transition: transform .35s var(--ease-out-quint);
    box-shadow: 0 30px 80px rgba(0,0,0,0.6), 0 0 0 1px rgba(255,255,255,0.1);
    background: var(--card-bg, linear-gradient(160deg, #333, #555));
    display: flex; flex-direction: column; padding: 14px;
  }
  .tilt-card .creature { flex: 1; display: grid; place-items: center; font-size: 130px;
    filter: drop-shadow(0 12px 30px rgba(0,0,0,0.55)); transform: translateZ(40px); }
  .tilt-card .nameplate {
    background: rgba(0,0,0,0.55); border-radius: 10px; padding: 10px 14px;
    display: flex; align-items: baseline; justify-content: space-between;
    transform: translateZ(20px); color: #fff;
  }
  .tilt-card .nameplate strong { font-size: 16px; letter-spacing: 0.04em; color: #fff; }
  .tilt-card .nameplate .rar { text-transform: uppercase; letter-spacing: 0.2em; font-size: 10px; font-weight: 800; color: var(--rar-color, #fff); }
  .tilt-card .flavor { color: rgba(255,255,255,0.78); font-size: 12px; line-height: 1.45; padding: 8px 6px 0; transform: translateZ(20px); }
  .tilt-card::before { /* clean cursor-follow shine — no rainbow ghosting */
    content: ""; position: absolute; inset: 0;
    background:
      radial-gradient(280px circle at var(--mx, 50%) var(--my, 50%),
        rgba(255,255,255,0.55), transparent 55%);
    mix-blend-mode: overlay;
    opacity: var(--holo-strength, 0.6);
    pointer-events: none;
  }
  .tilt-card::after { /* sparkle grid */
    content: ""; position: absolute; inset: 0;
    background-image:
      radial-gradient(2px 2px at 20% 30%, rgba(255,255,255,0.7), transparent),
      radial-gradient(1px 1px at 70% 60%, rgba(255,255,255,0.55), transparent),
      radial-gradient(1.5px 1.5px at 40% 80%, rgba(255,255,255,0.45), transparent),
      radial-gradient(1px 1px at 85% 25%, rgba(255,255,255,0.6), transparent);
    mix-blend-mode: screen;
    opacity: var(--holo-strength, 0.3);
    pointer-events: none;
  }
  .tilt-card[data-rarity="common"]    { --rar-color: var(--r-common); --holo-strength: 0.05; }
  .tilt-card[data-rarity="uncommon"]  { --rar-color: var(--r-uncommon); --holo-strength: 0.18; }
  .tilt-card[data-rarity="rare"]      { --rar-color: var(--r-rare); --holo-strength: 0.32; }
  .tilt-card[data-rarity="epic"]      { --rar-color: var(--r-epic); --holo-strength: 0.5; }
  .tilt-card[data-rarity="legendary"] { --rar-color: var(--r-legendary); --holo-strength: 0.65; }

  /* =========================================================
     Particles (rarity bursts)
     ========================================================= */
  .particles {
    position: absolute; left: 50%; top: 50%; width: 0; height: 0; pointer-events: none;
  }
  .particles span {
    position: absolute; left: 0; top: 0; width: 8px; height: 8px; border-radius: 999px;
    background: currentColor;
    transform: translate(-50%, -50%) translate(var(--dx, 0), var(--dy, 0)) scale(var(--s, 1));
    opacity: 0;
    animation: pop 900ms var(--ease-out-quint) forwards;
  }
  @keyframes pop {
    0% { opacity: 0; transform: translate(-50%, -50%) scale(0); }
    20% { opacity: 1; }
    100% { opacity: 0; transform: translate(-50%, -50%) translate(var(--dx, 0), var(--dy, 0)) scale(0.4); }
  }

  /* Legendary screen flash */
  .flash {
    position: fixed; inset: 0; z-index: 65; pointer-events: none;
    background: white; opacity: 0; mix-blend-mode: screen;
  }
  .flash.go { animation: flash 600ms ease-out forwards; }
  @keyframes flash {
    0% { opacity: 0; }
    20% { opacity: 0.55; }
    100% { opacity: 0; }
  }

  /* =========================================================
     Collection
     ========================================================= */
  .view { display: none; }
  .view.is-on { display: block; }
  .collection {
    padding: 40px 24px 120px; max-width: 1200px; margin: 0 auto;
  }
  .collection h2 { margin: 0 0 8px; font-size: 28px; letter-spacing: -0.01em; }
  .collection p { color: var(--ink-dim); margin: 0 0 28px; }
  .col-grid {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 18px;
  }
  .col-card {
    aspect-ratio: 2.5 / 3.5; border-radius: 12px; padding: 8px;
    background: var(--card-bg);
    box-shadow: 0 10px 28px rgba(0,0,0,0.4), 0 0 0 1px rgba(255,255,255,0.06);
    display: flex; flex-direction: column; cursor: pointer;
    transition: transform .3s var(--ease-out-quint);
    position: relative; overflow: hidden;
  }
  .col-card:hover { transform: translateY(-4px) rotate(-1deg); }
  .col-card .creature { flex: 1; display: grid; place-items: center; font-size: 56px; }
  .col-card .nameplate {
    background: rgba(0,0,0,0.55); border-radius: 6px; padding: 4px 8px;
    display: flex; align-items: baseline; justify-content: space-between;
    font-size: 11px; color: #fff;
  }
  .col-card .nameplate strong { color: #fff; }
  .col-card .nameplate .rar { font-size: 8px; letter-spacing: 0.2em; font-weight: 800; color: var(--rar-color, #fff); }
  .col-card[data-rarity="common"]    { --rar-color: var(--r-common); }
  .col-card[data-rarity="uncommon"]  { --rar-color: var(--r-uncommon); }
  .col-card[data-rarity="rare"]      { --rar-color: var(--r-rare); }
  .col-card[data-rarity="epic"]      { --rar-color: var(--r-epic); }
  .col-card[data-rarity="legendary"] { --rar-color: var(--r-legendary); }

  .empty {
    border: 1px dashed var(--line); border-radius: 18px; padding: 64px 24px; text-align: center;
    color: var(--ink-dim);
  }

  /* Quiet footer — Privacy / Terms / copyright. Lives at the bottom of
     the main column; mobile-nav covers it when scrolled to bottom which
     is fine — it's reachable when scrolled up. */
  .site-footer {
    padding: 32px 24px clamp(80px, 14vw, 120px);
    text-align: center;
    color: var(--color-text-secondary);
    font-size: 12px;
    letter-spacing: 0.04em;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    flex-wrap: wrap;
  }
  .site-footer a {
    color: var(--color-text-secondary);
    text-decoration: none;
    font-weight: 600;
    transition: color .15s;
  }
  .site-footer a:hover { color: var(--color-accent); }
  .site-footer span { opacity: 0.55; }

  /* =========================================================
     Reduced motion
     ========================================================= */
  @media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
      animation-duration: 0.01ms !important;
      animation-iteration-count: 1 !important;
      transition-duration: 0.01ms !important;
    }
  }
