*,*::before,*::after{box-sizing:border-box;margin:0;padding:0;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-rendering:optimizeLegibility}
:root{--font:'Roboto',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;--accent:rgb(95,95,148);--accent2:rgba(68,68,111,0.6);--green:rgb(88,190,140)}
::selection{background:rgba(255,255,255,0.25);color:#fff}
html{scrollbar-width:none;scroll-behavior:smooth}
html::-webkit-scrollbar{display:none}
body{background:#000;color:#fff;font-family:var(--font);letter-spacing:-0.011em;overflow-x:hidden;min-height:100vh;user-select:none;-webkit-user-select:none}
input,textarea{user-select:text;-webkit-user-select:text}
img{-webkit-user-drag:none;user-drag:none;-khtml-user-drag:none;-moz-user-drag:none;-o-user-drag:none}

#topo-canvas{position:fixed;inset:0;z-index:0;pointer-events:none;opacity:0.25}
#bg-canvas{position:fixed;inset:0;z-index:0;pointer-events:none}

header{position:fixed;top:0;left:0;right:0;z-index:100;display:flex;justify-content:center;padding:14px 24px;pointer-events:none}
.nav-inner{position:relative;display:flex;align-items:center;justify-content:space-between;width:100%;max-width:820px;height:52px;padding:0 12px 0 18px;background:rgba(10,10,10,0.88);backdrop-filter:blur(32px);-webkit-backdrop-filter:blur(32px);border:1px solid rgba(255,255,255,0.07);border-radius:18px;box-shadow:0 4px 32px rgba(0,0,0,0.5);pointer-events:all}
.nav-brand-wrap{position:relative;flex-shrink:0}
.nav-brand{font-size:15px;font-weight:700;color:#fff;letter-spacing:-0.01em}
.nav-brand-logout-btn svg{width:15px;height:15px;flex-shrink:0}
.nav-menu-btn{display:none;align-items:center;justify-content:center;width:34px;height:34px;flex-shrink:0;border:none;background:transparent;color:rgba(255,255,255,0.7);cursor:pointer;border-radius:9px;transition:background .15s,color .15s}
.nav-menu-btn:hover{background:rgba(255,255,255,0.06);color:#fff}
.nav-menu-btn svg{width:19px;height:19px}
.nav-links{display:flex;align-items:center}
.nav-link{padding:8px 16px;border-radius:10px;font-size:14.5px;font-weight:400;color:rgba(255,255,255,0.34);transition:color .15s;background:transparent;cursor:pointer;border:none;font-family:var(--font)}
.nav-link:hover{color:rgba(255,255,255,0.7)}
.nav-link.active{font-weight:500;color:#fff}
.nav-right{display:flex;align-items:center;gap:10px}
.wallet{display:flex;align-items:center;gap:8px;padding:8px 14px;border:1px solid rgba(255,255,255,0.08);border-radius:11px;background:rgba(255,255,255,0.03);transition:border-color .18s}
.wallet:hover{border-color:rgba(255,255,255,0.16)}


/* Its own backdrop/panel rather than reusing .crate-modal-backdrop — that one's built for a
   1100px-wide browse grid, and a login form riding on those same base rules is what made it
   read as an oversized, generic box. This one is sized and paced for exactly what it holds. */
.auth-modal-backdrop{position:fixed;inset:0;z-index:210;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,0);backdrop-filter:blur(0px);-webkit-backdrop-filter:blur(0px);opacity:0;pointer-events:none;transition:opacity .3s ease,background .3s ease,backdrop-filter .3s ease}
.auth-modal-backdrop.open{opacity:1;pointer-events:auto;background:rgba(4,4,6,0.72);backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px)}
.auth-modal{position:relative;width:min(300px,88vw);padding:34px 24px 24px;background:rgba(13,13,16,0.98);border:1px solid rgba(255,255,255,0.09);border-radius:18px;box-shadow:0 24px 64px rgba(0,0,0,0.55);overflow:hidden;transform:translateY(14px) scale(.96);opacity:0;transition:transform .32s cubic-bezier(.16,1,.3,1),opacity .28s ease}
.auth-modal-backdrop.open .auth-modal{transform:translateY(0) scale(1);opacity:1}
/* Soft radial glow bleeding down from the top edge, purely decorative — echoes the item-card
   rarity glow used elsewhere so the modal doesn't feel like a bare system dialog dropped in. */
.auth-modal-glow{position:absolute;top:-90px;left:50%;transform:translateX(-50%);width:260px;height:180px;background:radial-gradient(ellipse at center, rgba(120,205,145,0.22) 0%, rgba(120,205,145,0) 70%);pointer-events:none}
.auth-modal-close{position:absolute;top:12px;right:12px;width:30px;height:30px;display:flex;align-items:center;justify-content:center;border-radius:9px;border:none;background:rgba(255,255,255,0.04);color:rgba(255,255,255,0.45);cursor:pointer;transition:background .15s,color .15s}
.auth-modal-close:hover{background:rgba(255,255,255,0.08);color:rgba(255,255,255,0.85)}
.auth-modal-close svg{width:15px;height:15px}
.auth-modal-icon{position:relative;display:block;width:34px;height:34px;object-fit:contain;margin:0 auto 14px;filter:drop-shadow(0 0 14px rgba(120,205,145,0.45))}
.auth-modal-tabs{position:relative;display:flex;margin-bottom:22px;border-bottom:1px solid rgba(255,255,255,0.08)}
.auth-modal-tab{flex:1;padding:0 0 12px;border:none;background:none;color:rgba(255,255,255,0.45);font-size:13.5px;font-weight:700;font-family:var(--font);cursor:pointer;transition:color .18s}
.auth-modal-tab.active{color:#fff}
/* A single absolutely-positioned bar slides between tabs instead of each tab drawing its own
   underline — one element animating its transform reads as a deliberate motion, whereas two
   independent underlines swapping opacity just looks like a flicker. */
.auth-modal-tab-indicator{position:absolute;bottom:-1px;left:0;width:50%;height:2px;background:var(--green);border-radius:2px;transition:transform .28s cubic-bezier(.65,0,.35,1)}
.auth-modal-tabs:has(.auth-modal-tab[data-auth-tab="signup"].active) .auth-modal-tab-indicator{transform:translateX(100%)}
.auth-modal-form{position:relative;display:flex;flex-direction:column;gap:14px}
.auth-modal-field{display:flex;flex-direction:column;gap:6px}
.auth-modal-field label{font-size:11px;font-weight:700;letter-spacing:.06em;color:rgba(255,255,255,0.45);text-transform:uppercase}
.auth-modal-field input{padding:11px 13px;border-radius:10px;border:1px solid rgba(255,255,255,0.09);background:rgba(255,255,255,0.025);color:#fff;font-size:14px;font-family:var(--font);outline:none;transition:border-color .18s,background .18s}
.auth-modal-field input:focus{border-color:rgba(120,205,145,0.5);background:rgba(255,255,255,0.04)}
.auth-modal-error{display:none;padding:10px 12px;border-radius:9px;background:rgba(220,90,80,0.12);border:1px solid rgba(220,90,80,0.3);color:rgb(235,140,130);font-size:12.5px;font-weight:600;line-height:1.4;animation:authErrorIn .22s cubic-bezier(.16,1,.3,1) both}
.auth-modal-error.visible{display:block}
@keyframes authErrorIn{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}
.auth-modal-submit{margin-top:4px;padding:12.5px;border-radius:11px;border:none;background:var(--green);color:#0c1a12;font-size:14px;font-weight:800;font-family:var(--font);letter-spacing:.02em;cursor:pointer;transition:filter .16s,transform .1s}
.auth-modal-submit:hover{filter:brightness(1.1)}
.auth-modal-submit:active{transform:scale(.98)}
.auth-modal-submit:disabled{opacity:.55;cursor:default;filter:none;transform:none}
/* The icon is the tallest thing in the wallet, so its height drives the pill's height. Scaling
   it up visually with a transform instead of a bigger box keeps the layout box at 18px — the
   art renders larger without the wallet growing or anything shifting. */
.scrap-icon{width:18px;height:18px;flex-shrink:0;object-fit:contain;transform:scale(1.111)}
.wallet-amt{font-size:13.5px;font-weight:700;color:#fff;font-variant-numeric:tabular-nums;letter-spacing:0.01em}

#app{position:relative;z-index:2}
.wrap{max-width:1180px;margin:0 auto;padding:104px 32px 70px}
@keyframes fadeUp{from{opacity:0;transform:translate3d(0,14px,0)}to{opacity:1;transform:translate3d(0,0,0)}}
@keyframes fadeIn{from{opacity:0}to{opacity:1}}
.fade{animation:fadeUp .55s cubic-bezier(.22,1,.36,1) both}

.page{display:none}
.page.active{display:block}
.wrap.page-transition{animation:pageOut .18s cubic-bezier(.4,0,1,1) both}
@keyframes pageOut{from{opacity:1;transform:translate3d(0,0,0)}to{opacity:0;transform:translate3d(0,-10px,0)}}

.searchbar{position:relative;max-width:400px;margin:36px auto 0}
.searchbar input{width:100%;padding:14px 18px 14px 46px;border-radius:999px;border:1px solid rgba(255,255,255,0.09);background:rgba(255,255,255,0.03);color:#fff;font-size:14px;font-family:var(--font);outline:none;transition:border-color .18s,box-shadow .18s,background .18s}
.searchbar input::placeholder{color:rgba(255,255,255,0.3)}
.searchbar input:focus{border-color:rgba(255,255,255,0.35);box-shadow:0 0 0 4px rgba(255,255,255,0.08);background:rgba(255,255,255,0.05)}
.search-ico{position:absolute;left:17px;top:50%;transform:translateY(-50%);width:17px;height:17px;color:rgba(255,255,255,0.32);transition:color .18s;pointer-events:none}
.searchbar:focus-within .search-ico{color:rgba(255,255,255,0.75)}

.filterbar{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:28px;flex-wrap:wrap}
.filter-chips{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.chip{display:flex;align-items:center;gap:7px;padding:9px 15px;border-radius:11px;border:1px solid rgba(255,255,255,0.08);background:rgba(255,255,255,0.03);color:rgba(255,255,255,0.5);font-size:13px;font-weight:500;font-family:var(--font);cursor:pointer;transition:all .16s;white-space:nowrap}
.chip svg,.chip i{width:15px;height:15px;flex-shrink:0;color:rgba(255,255,255,0.4);font-size:14px;display:flex;align-items:center;justify-content:center;transition:color .16s}
.chip:hover{color:rgba(255,255,255,0.85);border-color:rgba(255,255,255,0.16);background:rgba(255,255,255,0.05)}
.chip.active{color:#fff;border-color:rgba(255,255,255,0.24);background:rgba(255,255,255,0.11)}
.chip.active svg,.chip.active i{color:rgb(120,205,145)}
.chip-icon-only{padding:9px 11px}
.chip-icon-only svg{width:18px;height:18px}
.chip-icon-only.active svg{color:rgb(255,165,80)}

.dropdown{position:relative;flex-shrink:0}
.dd-btn{display:flex;align-items:center;gap:9px;padding:9px 15px;border-radius:11px;border:1px solid rgba(255,255,255,0.08);background:rgba(255,255,255,0.03);color:rgba(255,255,255,0.8);font-size:13px;font-weight:500;font-family:var(--font);cursor:pointer;transition:all .16s;white-space:nowrap}
.dd-btn:hover{border-color:rgba(255,255,255,0.16);background:rgba(255,255,255,0.05)}
.dd-icon-slot{display:flex;align-items:center;justify-content:center;flex-shrink:0}
.dd-icon-slot svg{width:15px;height:15px;color:rgba(255,255,255,0.55)}
.dd-icon-slot i{font-size:14px;color:rgba(255,255,255,0.55)}
.dd-chev{width:14px;height:14px;opacity:.55;transition:transform .2s;flex-shrink:0}
.dropdown.open .dd-btn{border-color:rgba(255,255,255,0.2);background:rgba(255,255,255,0.06)}
.dropdown.open .dd-chev{transform:rotate(180deg)}
.dd-menu{position:absolute;top:calc(100% + 6px);right:0;min-width:200px;background:rgba(16,16,16,0.98);backdrop-filter:blur(24px);-webkit-backdrop-filter:blur(24px);border:1px solid rgba(255,255,255,0.1);border-radius:13px;padding:6px;box-shadow:0 16px 48px rgba(0,0,0,0.6);z-index:60;opacity:0;pointer-events:none;transform:translateY(-8px) scale(.98);transform-origin:top right;transition:opacity .2s cubic-bezier(.22,1,.36,1),transform .2s cubic-bezier(.22,1,.36,1)}
.dropdown.open .dd-menu{opacity:1;pointer-events:auto;transform:translateY(0) scale(1)}
.dd-item{display:flex;align-items:center;gap:10px;padding:9px 11px;border-radius:9px;font-size:13px;font-weight:500;color:rgba(255,255,255,0.55);cursor:pointer;transition:background .12s,color .12s;border:1px solid transparent}
.dd-item svg,.dd-item i{width:15px;height:15px;display:flex;align-items:center;justify-content:center;font-size:14px;flex-shrink:0;opacity:.65;color:rgba(255,255,255,0.7)}
.dd-item:hover{background:rgba(255,255,255,0.05);color:#fff}
.dd-item.active{background:rgba(255,255,255,0.1);color:#fff;border-color:rgba(255,255,255,0.16)}
.dd-item.active svg{opacity:1;color:#fff}

.placeholder{margin-top:18px;padding:60px 32px;border:1px dashed rgba(255,255,255,0.1);border-radius:18px;background:rgba(255,255,255,0.014);text-align:center}
.placeholder h3{font-size:16px;font-weight:600;color:rgba(255,255,255,0.5);margin-bottom:6px}
.placeholder p{font-size:13px;color:rgba(255,255,255,0.28)}

#loadMoreSentinel{height:1px}
.load-more-btn{display:block;margin:24px auto 0;padding:11px 26px;border-radius:11px;border:1px solid rgba(255,255,255,0.1);background:rgba(255,255,255,0.04);color:rgba(255,255,255,0.75);font-size:13.5px;font-weight:600;font-family:var(--font);cursor:pointer;transition:all .16s}
.load-more-btn:hover{background:rgba(255,255,255,0.08);border-color:rgba(255,255,255,0.2);color:#fff}

.case-grid{display:grid;grid-template-columns:repeat(6,1fr);gap:10px;margin-top:18px}
.case-card{--glow:120,205,145;position:relative;display:flex;flex-direction:column;align-items:center;background:rgba(255,255,255,0.03);border:1px solid rgba(255,255,255,0.08);border-radius:12px;padding:8px 8px 24px;cursor:pointer;overflow:hidden;transition:transform .6s cubic-bezier(.16,1,.3,1),border-color .3s ease,background .3s ease;animation:fadeIn .4s ease both}
.case-card:hover{transform:translateY(-3px);border-color:rgba(255,255,255,0.18);background:rgba(255,255,255,0.05);z-index:2}
.case-art{width:100%;aspect-ratio:1/1;display:flex;align-items:center;justify-content:center;position:relative;top:-8px}
.case-glow{position:absolute;left:50%;top:50%;width:115%;height:115%;transform:translate(-50%,-50%);background:radial-gradient(circle, rgba(var(--glow),0.2) 0%, rgba(var(--glow),0.1) 45%, rgba(var(--glow),0) 72%);opacity:0;transition:opacity .5s ease;pointer-events:none;z-index:0}
.case-card:hover .case-glow{opacity:1}
.case-art img{position:relative;z-index:1}
.case-art img{width:80%;height:80%;object-fit:contain}
.case-fav{position:absolute;top:6px;right:6px;width:28px;height:28px;background:none;border:none;display:flex;align-items:center;justify-content:center;cursor:pointer;opacity:0;transition:opacity .15s;z-index:5}
.case-card:hover .case-fav{opacity:1}
.case-fav.active{opacity:1}
.case-fav svg{width:22px;height:22px;color:rgba(255,255,255,0.55);transition:color .15s;filter:drop-shadow(0 1px 2px rgba(0,0,0,0.8))}
.case-fav:hover svg{color:rgba(255,255,255,0.9)}
.case-fav.active svg{color:rgb(255,165,80);fill:rgb(255,165,80)}
.case-name{font-size:15.5px;font-weight:600;color:rgba(255,255,255,0.82);margin-top:8px;position:relative;top:-18px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;text-align:center;width:100%}
.case-slider{width:65%;margin-left:auto;margin-right:auto;height:4px;display:flex;gap:3px;margin-top:8px;position:relative;top:-15px}
.case-slider .seg{flex:1;height:100%;border-radius:3px;background:rgba(255,255,255,0.12)}
.case-slider .seg.lit:nth-child(1){background:rgb(120,205,145)}
.case-slider .seg.lit:nth-child(2){background:rgb(240,160,55)}
.case-slider .seg.lit:nth-child(3){background:rgb(235,80,70)}
.case-slider .pin{position:absolute;top:-2.5px;width:3px;height:9px;border-radius:2px;background:#fff;transform:translateX(-50%)}
.case-price{display:flex;align-items:center;justify-content:center;gap:6px;width:65%;margin:auto auto 0;top:4px;position:relative;font-size:13.5px;font-weight:600;color:rgba(255,255,255,0.6);background:rgba(255,255,255,0.03);border:1px solid rgba(255,255,255,0.08);border-radius:9px;padding:6px 12px}
.case-price img{width:18px;height:18px;object-fit:contain}
@media (max-width:1300px){.case-grid{grid-template-columns:repeat(4,1fr)}}
@media (max-width:700px){.case-grid{grid-template-columns:repeat(2,1fr)}}

.case-detail-bar{display:grid;grid-template-columns:1fr auto 1fr;align-items:start;margin-top:32px}
.case-detail-back,.case-detail-demo{display:flex;align-items:center;gap:6px;padding:8px 14px;border-radius:9px;font-size:12.5px;font-weight:500;font-family:var(--font);cursor:pointer;transition:all .16s;white-space:nowrap;flex-shrink:0;margin-top:70px}
.case-detail-back{justify-self:end;margin-right:211px;padding-left:0;border:none;background:none;color:rgba(255,255,255,0.6);font-size:14.5px}
.case-detail-back:hover{color:#fff}
.case-detail-demo{justify-self:start;margin-left:246px;border:1px solid rgba(255,255,255,0.08);background:rgba(255,255,255,0.03);color:rgba(255,255,255,0.6)}
.case-detail-demo:hover{color:#fff;border-color:rgba(255,255,255,0.18);background:rgba(255,255,255,0.06)}
.case-detail-demo:disabled{opacity:.45;cursor:default;pointer-events:none}
.case-detail-back svg{width:16px;height:16px;flex-shrink:0}
.case-detail-demo svg{width:13px;height:13px;flex-shrink:0}
.case-detail-heading{grid-column:2;display:flex;flex-direction:column;align-items:center;gap:6px}
.case-detail-art{width:76px;height:76px;display:flex;align-items:center;justify-content:center}
.case-detail-art img{width:100%;height:100%;object-fit:contain;filter:drop-shadow(0 8px 24px rgba(0,0,0,0.5))}
.case-detail-name{font-size:17px;font-weight:700;color:#fff;letter-spacing:-0.01em}

.spin-wrap{position:relative;max-width:820px;margin:34px auto 0}
.spin-pointer{position:absolute;top:-2px;left:50%;transform:translateX(-50%);z-index:5;filter:drop-shadow(0 2px 6px rgba(0,0,0,0.6))}
.spin-pointer img{width:64px;height:64px;display:block;object-fit:contain}
.spin-viewport{position:relative;height:156px;overflow:hidden;border-radius:12px;border:1px solid rgba(255,255,255,0.08);background:rgba(255,255,255,0.02)}
.spin-viewport::before,.spin-viewport::after{content:"";position:absolute;top:0;bottom:0;width:70px;z-index:3;pointer-events:none}
.spin-viewport::before{left:0;background:linear-gradient(90deg,#000 0%,transparent 100%)}
.spin-viewport::after{right:0;background:linear-gradient(270deg,#000 0%,transparent 100%)}
.spin-viewport::marker{content:none}
.spin-viewport .spin-center-line{position:absolute;left:50%;top:0;bottom:0;width:2px;background:rgba(230,70,50,0.5);z-index:2;transform:translateX(-50%)}
.spin-track{position:absolute;top:0;left:0;height:100%;display:flex;align-items:center;gap:3px;padding:0 8px;will-change:transform;transform:translateZ(0);backface-visibility:hidden}
.spin-slot{flex-shrink:0;width:132px;height:132px;display:flex;align-items:center;justify-content:center;position:relative}
.spin-slot{--rarity:120,205,145}
.spin-slot .slot-box{position:absolute;inset:0;border-radius:9px;background:radial-gradient(ellipse 100% 145% at 50% 0%,rgba(var(--rarity),0.35) 0%,rgba(var(--rarity),0.03) 75%,rgba(255,255,255,0.03) 100%);background-clip:padding-box;border:1px solid rgba(255,255,255,0.07);overflow:hidden;pointer-events:none;z-index:0}
.spin-slot img{width:112px;height:112px;object-fit:contain;position:relative;z-index:1}
/* Duds read as a bit dull on the reel — mild desaturation/dim, and the slot's tint is already
   forced to flat grey via --rarity in slotHTML, so no rarity glow either. Kept subtle: fully
   grayscaling it out read as way too dead. */
.spin-slot.dud img{filter:grayscale(.45) brightness(.88);opacity:.92}
.spin-slot .slot-placeholder{width:112px;height:112px;border-radius:6px;background:rgba(255,255,255,0.08)}
.spin-slot .slot-price{position:absolute;left:0;right:0;bottom:10px;z-index:2;display:flex;align-items:center;justify-content:center;gap:6px;font-size:19px;font-weight:800;color:#fff;text-shadow:0 1px 4px rgba(0,0,0,0.9);opacity:0;transform:translateY(14px);transition:opacity .55s cubic-bezier(.22,1,.36,1),transform .55s cubic-bezier(.22,1,.36,1)}
.spin-slot .slot-price img{width:25px;height:25px;object-fit:contain}
.spin-track.settled .spin-slot{transition:opacity .3s ease,filter .3s ease,transform .3s ease}
.spin-track.settled .spin-slot:not(.landed){opacity:.35;filter:grayscale(.4);transform:scale(.97)}
.spin-slot.landed .slot-price{opacity:1;transform:translateY(0)}

/* Multi-spin (qty 2-5): ONE wide viewport (same outer chrome as the single-spin .spin-viewport
   — one arrow pair at the edges, one center line through the middle) containing N narrower
   columns side by side, one per unit. Unlike the single-spin reel (items slide horizontally
   past a fixed pointer), each column here scrolls its items downward past a fixed horizontal
   center line — same slot-machine idea, rotated 90°. Each column's track reuses .spin-slot as
   the individual item card (built via slotHTML, same as single-spin) stacked in a vertical
   flex column instead of the horizontal one the single-spin track uses. */
/* Same overall footprint as .spin-wrap/.spin-viewport (156px tall) and the same .spin-slot
   card size (132px, 112px art) as the single-spin reel — switching qty 1 <-> 2-5 must not
   resize the wheel or shrink the item art, only change what's scrolling inside it. */
.multi-spin-wrap{position:relative;max-width:820px;margin:34px auto 0}
/* Same /img/arrow.png the single-spin pointer uses (points down by default), rotated to point
   inward from each side instead of down. */
.multi-spin-arrow{position:absolute;top:50%;transform:translateY(-50%);z-index:4;filter:drop-shadow(0 2px 6px rgba(0,0,0,0.6))}
.multi-spin-arrow img{width:48px;height:48px;display:block;object-fit:contain}
.multi-spin-arrow.left{left:10px}
.multi-spin-arrow.left img{transform:rotate(-90deg)}
.multi-spin-arrow.right{right:6px}
.multi-spin-arrow.right img{transform:rotate(90deg)}
/* No top/bottom fade overlays — just the plain background tint (same rgba(255,255,255,0.02)
   wash the single-spin .spin-viewport uses) visible across the whole box. */
.multi-spin-viewport{position:relative;height:156px;overflow:hidden;border-radius:12px;border:1px solid rgba(255,255,255,0.08);background:rgba(255,255,255,0.02);display:flex;padding:0 30px}
/* Each unit's own slice of the shared viewport — a plain overflow:hidden window its column
   scrolls inside of. */
.multi-spin-unit{position:relative;flex:1;height:100%;overflow:hidden}
.multi-spin-unit .spin-track{position:absolute;top:0;left:0;width:100%;height:auto;flex-direction:column;align-items:center;gap:3px;padding:8px 0;display:flex;z-index:1}
/* One line segment per column (not one line spanning the whole wheel) — same fixed vertical
   offset on every column so, side by side, they read as one continuous horizontal line across
   the wheel. Each segment fades in/out via its own gradient rather than being a solid bar. */
.multi-spin-unit .slot-line{position:absolute;left:0;top:50%;transform:translateY(-50%);width:100%;height:1px;background:linear-gradient(90deg,transparent,rgb(205,65,43),transparent);z-index:0;pointer-events:none}
/* No boxed card here (the single-spin reel's .slot-box is a bordered rounded-rect) — a
   rarity-tinted drop-shadow glow on the item image itself instead. */
.multi-spin-unit .spin-slot .slot-box{display:none}
.multi-spin-unit .spin-slot>img{filter:drop-shadow(0 0 6px rgba(var(--rarity),0.5)) drop-shadow(0 0 12px rgba(var(--rarity),0.25));position:relative;z-index:1}
/* Duds don't glow on the 2-5 multi-spin lanes — a dud with a halo reads like something worth
   landing on. Multi-spin only; the single-spin reel's dud treatment is handled separately. */
.multi-spin-unit .spin-slot.dud>img{filter:none}
/* Columns get tight at qty 4-5 — scale the card/art down slightly so neighboring items don't
   crowd into each other, but not so much it reads as tiny. */
.multi-spin-wrap[data-qty="4"] .spin-slot,.multi-spin-wrap[data-qty="5"] .spin-slot{width:116px;height:116px}
/* ">img"/">.slot-placeholder" (direct child only) so this doesn't also catch the 25px scrap
   icon nested inside .slot-price — that was blowing it up and squeezing it invisible. */
.multi-spin-wrap[data-qty="4"] .spin-slot>img,.multi-spin-wrap[data-qty="5"] .spin-slot>img,
.multi-spin-wrap[data-qty="4"] .spin-slot>.slot-placeholder,.multi-spin-wrap[data-qty="5"] .spin-slot>.slot-placeholder{width:98px;height:98px}

.spin-controls{max-width:820px;margin:14px auto 0;display:flex;align-items:flex-start;gap:6px}
.open-btn{flex-shrink:0;display:flex;align-items:center;justify-content:center;gap:8px;padding:18px 16px;border-radius:11px;border:1px solid rgba(255,255,255,0.08);background:rgba(255,255,255,0.03);color:rgba(255,255,255,0.5);font-size:13.5px;font-weight:700;font-family:var(--font);cursor:pointer;transition:all .16s;white-space:nowrap}
.open-btn:hover{color:rgba(255,255,255,0.85);border-color:rgba(255,255,255,0.16);background:rgba(255,255,255,0.05)}
.open-btn:disabled{opacity:.45;cursor:default;pointer-events:none}
.open-btn-label{color:rgba(255,255,255,0.85);letter-spacing:.01em}
/* Price matches the label's brightness — without this it inherits the button's dimmer base. */
#openCaseCost{color:rgba(255,255,255,0.85)}
.open-btn img{width:16px;height:16px;object-fit:contain}
.qty-group{display:flex;align-items:center;gap:4px;flex-shrink:0;margin-left:2px}
.qty-btn{width:32px;height:36px;border-radius:9px;border:1px solid rgba(255,255,255,0.08);background:rgba(255,255,255,0.03);color:rgba(255,255,255,0.5);font-size:12.5px;font-weight:600;font-family:var(--font);cursor:pointer;transition:all .16s}
.qty-btn:hover{color:rgba(255,255,255,0.85);border-color:rgba(255,255,255,0.16);background:rgba(255,255,255,0.05)}
.qty-btn.active{color:#fff;border-color:rgba(255,255,255,0.24);background:rgba(255,255,255,0.11)}
.qty-btn:disabled{opacity:.35;cursor:default;pointer-events:none}
.qty-group.spinning .qty-btn{opacity:.4;pointer-events:none;transition:opacity .2s ease}
.spin-controls-right{display:flex;align-items:center;gap:8px;flex-shrink:0;margin-left:auto}
.icon-btn{width:42px;height:42px;display:flex;align-items:center;justify-content:center;border-radius:10px;border:1px solid rgba(255,255,255,0.08);background:rgba(255,255,255,0.03);color:rgba(255,255,255,0.5);cursor:pointer;transition:all .16s}
.icon-btn:hover{color:rgba(255,255,255,0.85);border-color:rgba(255,255,255,0.16);background:rgba(255,255,255,0.05)}
.icon-btn svg{width:17px;height:17px}
.icon-btn.active{color:#fff;border-color:rgba(255,255,255,0.24);background:rgba(255,255,255,0.11)}
.icon-btn.muted{color:rgb(230,70,50);border-color:rgba(230,70,50,0.35);background:rgba(230,70,50,0.1)}
.icon-btn-wrap{position:relative}
.icon-tooltip{position:absolute;bottom:calc(100% + 8px);left:50%;transform:translateX(-50%) translateY(4px);padding:6px 10px;border-radius:7px;background:rgba(14,14,20,0.98);border:1px solid rgba(255,255,255,0.1);color:rgba(255,255,255,0.85);font-size:12px;font-weight:500;white-space:nowrap;pointer-events:none;opacity:0;transition:opacity .16s ease,transform .16s ease;z-index:20}
.icon-btn-wrap:hover .icon-tooltip{opacity:1;transform:translateX(-50%) translateY(0)}

.unboxed-section{max-width:820px;margin:25px auto 0;opacity:0;transform:translateY(-8px);animation:unboxedFadeIn .5s cubic-bezier(.22,1,.36,1) both}
@keyframes unboxedFadeIn{to{opacity:1;transform:translateY(0)}}
.unboxed-header{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;flex-wrap:wrap}
.unboxed-heading{font-size:14px;font-weight:700;color:rgb(230,70,50);letter-spacing:.03em;text-transform:uppercase;margin-bottom:4px}
.unboxed-sub{font-size:13px;color:rgba(255,255,255,0.5)}
.unboxed-last-spin{display:flex;align-items:center;gap:6px;padding:8px 14px;border-radius:9px;background:rgba(120,205,145,0.15);color:rgb(150,220,170);font-size:12px;font-weight:700;letter-spacing:.02em;white-space:nowrap}
.unboxed-last-spin img{width:14px;height:14px;object-fit:contain}
.unboxed-box{margin-top:14px;padding:16px;border-radius:13px;border:1px solid rgba(255,255,255,0.08);background:rgba(255,255,255,0.03)}
.unboxed-grid{display:flex;flex-wrap:wrap;gap:10px}
.unboxed-card{--rarity:120,205,145;position:relative;display:flex;flex-direction:column;align-items:center;width:100px;padding:10px 6px 12px;border-radius:11px;border:1px solid rgba(255,255,255,0.08);background:radial-gradient(ellipse 100% 110% at 50% 0%,rgba(var(--rarity),0.35) 0%,rgba(var(--rarity),0.03) 75%,rgba(255,255,255,0.03) 100%);background-clip:padding-box;overflow:hidden;opacity:0;transform:translateY(-10px);animation:unboxedCardIn .45s cubic-bezier(.22,1,.36,1) both}
@keyframes unboxedCardIn{to{opacity:1;transform:translateY(0)}}
.unboxed-card img{width:52px;height:52px;object-fit:contain;margin:8px 0 8px}
.unboxed-card-name{font-size:11.5px;font-weight:700;color:rgb(var(--rarity));text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%;margin-bottom:4px}
.unboxed-card-price{display:flex;align-items:center;gap:4px;font-size:11.5px;font-weight:600;color:rgba(255,255,255,0.8)}
.unboxed-card-price img{width:12px;height:12px;margin:0}

.battles-promo{display:flex;align-items:center;gap:16px;max-width:820px;width:100%;margin:25px auto 0;padding:18px 20px;border-radius:13px;border:1px solid rgba(255,255,255,0.08);background:rgba(255,255,255,0.03);cursor:pointer;transition:all .16s;text-align:left;font-family:var(--font)}
.battles-promo:hover{border-color:rgba(255,255,255,0.16);background:rgba(255,255,255,0.05)}
.battles-promo img{width:50px;height:50px;object-fit:contain;flex-shrink:0}
.battles-promo-text strong{display:block;font-size:16px;font-weight:700;color:#fff;margin-bottom:3px}
.battles-promo-text p{font-size:13.5px;color:rgba(255,255,255,0.55);line-height:1.4}
.battles-promo-text p b{color:rgba(255,255,255,0.85);font-weight:700}

.case-items-section{max-width:820px;margin:32px auto 0}
.case-items-heading{font-size:14px;font-weight:700;color:rgb(230,70,50);letter-spacing:.03em;text-transform:uppercase;margin-bottom:14px}
.case-items-grid{display:grid;grid-template-columns:repeat(5,1fr);gap:12px}
.case-item-card{--rarity:120,205,145;position:relative;display:flex;flex-direction:column;align-items:center;padding:14px 10px 16px;border-radius:12px;border:1px solid rgba(255,255,255,0.08);background:radial-gradient(ellipse 100% 110% at 50% 0%,rgba(var(--rarity),0.35) 0%,rgba(var(--rarity),0.03) 75%,rgba(255,255,255,0.03) 100%);background-clip:padding-box;overflow:hidden}
.case-item-chance-wrap{position:absolute;top:10px;right:12px;height:14px;min-width:30px;overflow:visible}
.case-item-chance,.case-item-range{position:absolute;top:0;right:0;font-size:11px;font-weight:700;color:rgba(255,255,255,0.75);white-space:nowrap;transition:transform .45s cubic-bezier(.22,1,.36,1),opacity .45s cubic-bezier(.22,1,.36,1)}
.case-item-range{transform:translateY(100%);opacity:0}
.case-item-card:hover .case-item-chance{transform:translateY(-100%);opacity:0}
.case-item-card:hover .case-item-range{transform:translateY(0);opacity:1}
.case-item-card img{width:84px;height:84px;object-fit:contain;margin:14px 0 12px}
.case-item-name{font-size:13.5px;font-weight:700;color:rgb(var(--rarity));text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;width:100%;margin-bottom:6px}
.case-item-price{display:flex;align-items:center;gap:5px;font-size:13px;font-weight:600;color:rgba(255,255,255,0.8)}
.case-item-price img{width:14px;height:14px;object-fit:contain;margin:0}
@media (max-width:1000px){.case-items-grid{grid-template-columns:repeat(3,1fr)}}
@media (max-width:700px){.case-items-grid{grid-template-columns:repeat(2,1fr)}}

.live-wins-section{max-width:1180px;margin:40px auto 0;transition:none}
.live-wins-heading{font-size:14px;font-weight:700;color:#fff;letter-spacing:.03em;text-transform:uppercase;margin-bottom:14px}
.live-wins-track{display:flex;gap:10px;overflow-x:auto;overflow-y:hidden;padding-bottom:4px;scrollbar-width:none}
.live-wins-track::-webkit-scrollbar{display:none}
.live-win-card{--rarity:120,205,145;flex-shrink:0;width:175px;height:64px;display:flex;align-items:center;gap:10px;padding:8px 12px;border-radius:11px;border:1px solid rgba(255,255,255,0.08);background:linear-gradient(90deg,rgba(var(--rarity),0.28) 0%,rgba(var(--rarity),0.04) 60%,rgba(255,255,255,0.03) 100%);background-clip:padding-box;overflow:hidden}
.live-win-card img{width:42px;height:42px;object-fit:contain;flex-shrink:0}
.live-win-info{display:flex;flex-direction:column;align-items:flex-end;margin-left:auto;min-width:0}
.live-win-price{display:flex;align-items:center;gap:5px;font-size:13px;font-weight:700;color:#fff}
.live-win-price img{width:14px;height:14px;object-fit:contain;margin:0}
.live-win-case{font-size:11.5px;font-weight:500;color:rgba(255,255,255,0.55);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%;margin-top:3px}

@media (max-width:768px){
  .nav-menu-btn{display:flex}
  /* Same four .nav-link buttons as desktop (script.js wires their click handlers generically by
     class, not by container), just relocated into a panel that drops down below the pill instead
     of sitting inline — there isn't room for all four labels next to the brand and wallet once
     the nav-inner pill itself has to shrink to fit a phone-width screen. */
  .nav-links{position:absolute;top:calc(100% + 8px);left:0;right:0;display:none;flex-direction:column;align-items:stretch;gap:2px;padding:8px;background:rgba(10,10,10,0.96);backdrop-filter:blur(32px);-webkit-backdrop-filter:blur(32px);border:1px solid rgba(255,255,255,0.07);border-radius:16px;box-shadow:0 12px 32px rgba(0,0,0,0.5)}
  .nav-inner.menu-open .nav-links{display:flex}
  .nav-link{text-align:left;padding:11px 14px;border-radius:10px}
  .nav-link.active{background:rgba(255,255,255,0.06)}
  .wrap{padding:88px 18px 50px}
}

.toast-layer{position:fixed;right:20px;bottom:20px;z-index:200;display:flex;flex-direction:column-reverse;gap:10px;pointer-events:none}
.toast-layer{overflow:visible}
.toast{display:flex;align-items:center;gap:10px;padding:12px 16px;border-radius:11px;border:1px solid rgba(255,255,255,0.12);background:rgba(24,24,24,0.98);backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);box-shadow:0 12px 32px rgba(0,0,0,0.5);color:rgba(255,255,255,0.85);font-size:13.5px;font-weight:500;max-width:320px;animation:toastIn .5s cubic-bezier(.22,1,.36,1) both}
.toast.leaving{animation:toastOut .45s cubic-bezier(.5,0,.75,0) both}
.toast-icon{width:20px;height:20px;flex-shrink:0;color:rgb(108,140,168)}
.toast-error .toast-icon{color:rgb(235,80,70)}
.toast-success .toast-icon{color:rgb(120,205,145)}
.toast-titled{align-items:flex-start}
.toast-titled .toast-icon{margin-top:1px}
.toast-body{display:flex;flex-direction:column;gap:2px}
.toast-title{font-weight:700;color:rgba(255,255,255,0.95)}
.toast-message{color:rgba(255,255,255,0.7);font-weight:500}
@keyframes toastIn{from{opacity:0;transform:translateX(420px)}to{opacity:1;transform:translateX(0)}}
@keyframes toastOut{from{opacity:1;transform:translateX(0)}to{opacity:0;transform:translateX(420px)}}

/* ══ Scrap Upgrader ══ */
/* Breaks out of .wrap's 1180px cap — the right column needs more room than that leaves,
   otherwise its buttons/search bar overlap at any normal window width. Fixed 480px/750px on
   PC/desktop — do not change these; a prior attempt at making them fluid via minmax()/fr
   ended up shrinking the whole layout (crate included) even at ordinary desktop widths well
   above 1230px, which was never supposed to happen. The narrower-viewport media query below
   (max-width:1300px) is where this grid actually needs to flex — it stays a hard fixed pair
   above that width, matching PC exactly as it always has. */
.upgrader-layout{display:grid;grid-template-columns:480px 750px;gap:16px;align-items:start;margin-top:44px;width:max-content;margin-left:auto;margin-right:auto;position:relative;left:50%;transform:translateX(-50%)}
.upgrader-left{background:rgba(255,255,255,0.03);border:1px solid rgba(255,255,255,0.08);border-radius:14px;padding:40px 30px;display:flex;flex-direction:column;align-items:center;text-align:center;min-height:640px;overflow:hidden;position:relative}
.upgrader-play-label{font-size:13px;font-weight:700;letter-spacing:.05em;color:rgba(255,255,255,0.5);text-transform:uppercase}
.upgrader-play-amt{display:flex;align-items:center;gap:10px;font-size:30px;font-weight:800;color:#fff;margin-top:10px}
.upgrader-play-amt img{width:38px;height:38px;object-fit:contain}
.upgrader-preview{margin-top:65px;display:flex;flex-direction:column;align-items:center;gap:7px;height:118px;justify-content:center}
.upgrader-no-items{font-size:22px;font-weight:700;color:#fff}
.upgrader-hint{font-size:15.5px;color:rgba(255,255,255,0.45)}
.upgrader-roll-mult{font-size:18px;font-weight:700;color:#8CC2E7}
.upgrader-roll-amt{display:flex;align-items:center;gap:10px;font-size:30px;font-weight:800;color:#fff}
.upgrader-roll-amt img{width:38px;height:38px;object-fit:contain}
.upgrader-roll-text{font-size:15px;color:rgba(255,255,255,0.7);margin-top:2px}
.upgrader-roll-chance{font-size:13.5px;color:rgba(255,255,255,0.45)}
.upgrader-crate-wrap{flex:1;margin-top:12px;width:100%;max-height:220px;display:flex;align-items:center;justify-content:center;position:relative;overflow:visible;z-index:0}
/* Deliberately fixed at 500px — WIDER than .upgrader-left's 420px content box on purpose: the
   crate art is meant to bleed across the card's side padding and clip at the card's edges
   (.upgrader-left has overflow:hidden), rendering ~480px wide. A min(500px,100%) "safety cap"
   here once shrank it to 420px and visibly shrank the crate on PC — do not re-add one. */
.upgrader-crate-stack{position:relative;width:530px;top:50px;flex-shrink:0}
.upgrader-crate-img{display:block;width:100%;height:auto;object-fit:contain;position:relative;z-index:1;--shake-x:0px;--shake-y:0px}
@keyframes upgCrateShake{
  0%{transform:translate(0,0)}
  30%{transform:translate(var(--shake-x),var(--shake-y))}
  60%{transform:translate(calc(var(--shake-x) * -0.5),calc(var(--shake-y) * -0.5))}
  100%{transform:translate(0,0)}
}
/* Fixed-width, always-centered stage. Every card inside is absolutely positioned at its own
   slot, so the box never resizes as items are added or removed — which is what keeps the
   group visually centered on the crate even while outgoing cards are still fading. */
.upgrader-crate-items{position:absolute;left:50%;bottom:100px;transform:translateX(-50%);width:420px;height:110px;z-index:5;pointer-events:none}
/* will-change:transform promotes this to its own composited layer up front, so the two stacked
   drop-shadow() filters get rendered into that layer's bitmap ONCE — the infinite float
   animation below then just repositions/rescales the whole cached layer each frame instead of
   re-running both filters against the new transform every frame, which is real per-frame paint
   cost a JS rAF timing profile can't see (the float loop is pure CSS, no JS per-frame at all)
   but mobile GPUs feel heavily on an always-running animation like this one. */
.upgrader-crate-item-inner{--rarity:120,205,145;width:110px;height:110px;display:flex;align-items:center;justify-content:center;filter:drop-shadow(0 0 16px rgba(var(--rarity),0.65)) drop-shadow(0 0 32px rgba(var(--rarity),0.3));will-change:transform;animation-name:upgCrateItemFloat;animation-timing-function:ease-in-out;animation-iteration-count:infinite}
/* --slot-x is the card's resting offset from the row's center, set per-item from JS. Cards
   rest at translateX(--slot-x) and both enter and exit through the center (translateX(0))
   while scaled down and dropped into the crate — so they read as rising out of the crate on
   the way in and sinking back into it on the way out. Only transform/opacity ever animate,
   which keeps it smooth and interruptible mid-flight. */
.upgrader-crate-item{--slot-x:0px;position:absolute;left:50%;bottom:0;width:110px;margin-left:-55px;opacity:0;transform:translate(0,45px) scale(.7);transition:opacity .5s ease,transform .5s cubic-bezier(.22,1,.36,1)}
.upgrader-crate-item.in{opacity:1;transform:translate(var(--slot-x),0) scale(1)}
.upgrader-crate-item img{width:100%;height:100%;object-fit:contain}
/* Shrink item size once there are more than 2 on the crate, so 3-4 items stay inside
   the crate opening instead of spilling past its edges. Card width tracks the inner size so
   each card stays centered on its own slot (margin-left is half the width). */
.upgrader-crate-items[data-count="3"] .upgrader-crate-item{width:88px;margin-left:-44px}
.upgrader-crate-items[data-count="3"] .upgrader-crate-item-inner{width:88px;height:88px}
.upgrader-crate-items[data-count="4"] .upgrader-crate-item{width:72px;margin-left:-36px}
.upgrader-crate-items[data-count="4"] .upgrader-crate-item-inner{width:72px;height:72px}
@keyframes upgCrateItemFloat{
  0%,100%{transform:translateY(0) scale(1)}
  50%{transform:translateY(-10px) scale(1.06)}
}
.upgrader-crate-top{width:100%;height:auto;object-fit:contain;position:absolute;left:0;top:1.5%;transform:translateY(-500px);opacity:0;pointer-events:none;z-index:2;transform-origin:50% 50%}

/* Win-chance ring: a Vuetify-style v-progress-circular — two stacked SVG circles sharing
   the same center/radius. The gray track is always fully drawn; the colored fill circle
   uses the classic stroke-dasharray/stroke-dashoffset trick (dasharray = full circumference,
   dashoffset = circumference minus the filled fraction) so it visually reads as a partial
   ring proportional to win chance %. A CSS transition on stroke-dashoffset is what makes the
   fill animate smoothly on change instead of snapping. */
.upgrader-ring-wrap{position:absolute;left:50%;top:45%;transform:translate(-50%,-50%);width:78%;aspect-ratio:1/1;z-index:0;pointer-events:none;opacity:0;transition:opacity .5s ease}
.upgrader-ring-wrap.visible{opacity:1}
.upgrader-ring-svg{width:100%;height:100%;transform:rotate(-90deg)}
.upgrader-ring-track{fill:none;stroke:rgba(255,255,255,0.08);stroke-width:13}
.upgrader-ring-fill{fill:none;stroke:#A43422;stroke-width:13;stroke-linecap:butt;stroke-dasharray:565.487;stroke-dashoffset:565.487;transition:stroke-dashoffset .6s cubic-bezier(.22,1,.36,1)}
.upgrader-ring-arrow{position:absolute;top:4.5%;left:50%;transform:translate(-50%,-50%);width:17%;pointer-events:none}
/* Drop + bounce is driven by a real spring physics simulation in JS (see dropCrateTopSpring
   in script.js), not CSS keyframes — see that function for the full explanation. This class
   only marks "the lid has become visible"; JS writes translateY directly every frame. */
.upgrader-crate-top.dropping{opacity:1}
/* Wobble phase: kicks in a beat after the drop lands — a decaying rotational wobble,
   like a coin settling flat, oscillating roughly ±5° and tapering to 0. */
.upgrader-crate-top.wobbling{animation:upgCrateTopWobble 1.1s ease-out forwards}
@keyframes upgCrateTopWobble{
  0%{transform:translateY(0) rotate(0deg);opacity:1}
  10%{transform:translateY(0) rotate(5deg);opacity:1}
  24%{transform:translateY(0) rotate(-4.4deg);opacity:1}
  38%{transform:translateY(0) rotate(3.2deg);opacity:1}
  52%{transform:translateY(0) rotate(-2.2deg);opacity:1}
  66%{transform:translateY(0) rotate(1.3deg);opacity:1}
  80%{transform:translateY(0) rotate(-0.6deg);opacity:1}
  92%{transform:translateY(0) rotate(0.2deg);opacity:1}
  100%{transform:translateY(0) rotate(0deg);opacity:1}
}

/* Everything on the left card fades out once Upgrade is pressed, leaving just the crate. */
.upgrader-left.spinning .upgrader-play-label,
.upgrader-left.spinning .upgrader-play-amt,
.upgrader-left.spinning #upgPreview,
.upgrader-left.spinning .upgrader-actions{animation:upgFadeOut .35s ease forwards}
/* Reset: the play text and preview ease back in first, with the action buttons trailing so the
   card rebuilds itself top-down rather than snapping back all at once. */
.upgrader-left.resetting .upgrader-play-label,
.upgrader-left.resetting .upgrader-play-amt,
.upgrader-left.resetting #upgPreview{animation:upgFadeIn .33s ease both}
.upgrader-left.resetting .upgrader-actions{animation:upgFadeIn .33s ease .29s both}
@keyframes upgFadeIn{from{opacity:0}to{opacity:1}}
/* Ring retreats to where it came from — back down and shrinking away as it fades. */
.upgrader-ring-wrap.retreating{animation:upgRingRetreat .49s cubic-bezier(.4,0,.7,1) forwards}
@keyframes upgRingRetreat{
  0%{opacity:1;transform:translate(-50%,-50%) scale(1)}
  100%{opacity:0;transform:translate(-50%,-50%) translateY(34px) scale(.82)}
}
/* Lid dissolves while the crate is on its way back down. */
.upgrader-crate-top-wobble.dismissing{animation:upgFadeOut .39s ease forwards}
/* Roll readout drops back out of frame, in step with the ring's retreat. Doubled up on the
   class so it outranks the .shown rule further down the file, which would otherwise keep its
   much slower reveal timings and leave the readout hanging while everything else cleared. */
.upgrader-roll-result.hiding.hiding{opacity:0;transform:translateY(46px);
  transition:opacity .33s ease,transform .36s cubic-bezier(.4,0,.7,1)}
/* With the text and buttons faded out, the crate is left sitting low in the card. Sliding it
   up by the gap between its own centre and the card's centre (measured: 89px) puts the crate
   and its ring in the middle of the section. Driven by its own class rather than .spinning so
   it can be timed to the ring appearing, not to the click. The duration is set from JS to
   match the sound, and the curve mirrors the ring's own cubic ease-out so the rise decelerates
   in step with the arc and settles exactly as the sound ends. */
/* The final control point sits well below 1 so the curve keeps a little speed all the way to
   the end instead of braking early — with a hard ease-out the last pixel ate ~150ms and the
   crate looked parked before the sound finished. */
.upgrader-crate-wrap{transition:transform var(--center-dur,.55s) cubic-bezier(.45,.1,.75,.85)}
.upgrader-crate-wrap.centered{transform:translateY(-89px)}
/* Wobble wrappers. The crate body already owns its transform (impact shake) and the lid's is
   driven frame-by-frame by the drop physics, so the ascent wobble is applied to these extra
   wrapper layers instead — the transforms compose rather than fighting each other.
   The z-indexes mirror what the images themselves carry (ring 0 < body 1 < lid 2); without
   them the wrappers form their own stacking contexts and the whole crate jumps above the
   ring. */
.upgrader-crate-body-wobble,
.upgrader-crate-top-wobble{display:block;width:100%;transform-origin:50% 60%;will-change:transform}
/* Only transition once .dudded is set — during the spin these are driven frame-by-frame from
   JS, and a transition there would lag the rattle behind and smear it. The origin is pinned to
   a fixed point instead of each element's own centre: the lid wrapper is absolutely positioned
   and collapses to a fraction of the body's height, so percentage origins put the two on
   different pivots and the lid swings off the crate when it tilts. */
.upgrader-crate-stack.dudded .upgrader-crate-body-wobble,
.upgrader-crate-stack.dudded .upgrader-crate-top-wobble{
  transform-origin:50% 190px;
  transition:transform .9s cubic-bezier(.22,1,.36,1)}
.upgrader-crate-body-wobble{position:relative;z-index:1}
.upgrader-crate-top-wobble{position:absolute;left:0;top:0;z-index:2}
/* Win: the lid is blown off the crate — mirrors the entry drop in reverse, launching upward
   while fading out. Applied to the wobble wrapper because the lid image's own transform is
   still owned by the drop physics. */
/* Loss: the crate slumps over and goes semi-transparent — a dud, discarded. Applied to the
   two wobble wrappers rather than the whole stack, since the ring and arrow are siblings in
   there and shouldn't tilt or fade with it. */
.upgrader-crate-stack.dudded .upgrader-crate-body-wobble,
.upgrader-crate-stack.dudded .upgrader-crate-top-wobble{
  transform:rotate(-7deg) translateY(10px)}
/* Opacity lives on this shared wrapper rather than on each piece, so the crate and lid fade
   as one flat object. Fading them separately compounds where they overlap — the lid ends up
   showing the lit crate through it and reads as more transparent than the body.
   To revert: delete this rule and put `opacity:.45` back on the two wobble wrappers above. */
/* Needs its own stacking position, otherwise this wrapper flattens the body/lid z-indexes it
   contains and the ring ends up painting over the crate. */
.upgrader-crate-fade{display:block;position:relative;z-index:1;transition:opacity .9s ease}
.upgrader-crate-stack.dudded .upgrader-crate-fade{opacity:.55}
/* Roll readout — sits below the ring and slides up from the bottom of the card once the arc
   has settled. Absolutely positioned so it can't shift the crate/ring layout above it, and it
   starts translated down + transparent so the reveal is a single eased slide-and-fade. */
.upgrader-roll-result{position:absolute;left:0;right:0;bottom:26px;text-align:center;
  pointer-events:none;z-index:3;opacity:0;transform:translateY(52px);
  transition:opacity 1s ease,transform 1.15s cubic-bezier(.22,1,.36,1)}
.upgrader-roll-result.shown{opacity:1;transform:translateY(0)}
.upgrader-roll-value{font-size:19px;font-weight:800;color:#5b9dd9;letter-spacing:.2px;line-height:1.1}
.upgrader-roll-label{margin-top:5px;font-size:11px;font-weight:800;color:#fff;letter-spacing:1px}
.upgrader-crate-top-wobble.launched{animation:upgLidLaunch 1.25s cubic-bezier(.25,0,.5,1) forwards}
@keyframes upgLidLaunch{
  0%{transform:translateY(0) rotate(0deg);opacity:1}
  12%{transform:translateY(14px) rotate(-1.5deg);opacity:1}
  55%{opacity:0}
  100%{transform:translateY(-520px) rotate(9deg);opacity:0}
}
@keyframes upgFadeOut{to{opacity:0}}

/* Items slide/sink down into the crate's center and shrink away as they fade, instead of
   just fading in place — reads as the items dropping into the crate before it closes. */
.upgrader-crate-items.collapsing{animation:upgItemsCollapse .8s cubic-bezier(.4,0,.7,1) forwards}
@keyframes upgItemsCollapse{
  0%{opacity:1;transform:translateX(-50%) translateY(0) scale(1)}
  100%{opacity:0;transform:translateX(-50%) translateY(40px) scale(.25)}
}
/* Win payoff: the items climb back out of the open crate, each turning once on the way up.
   The container handles the rise and fade only — rotating it would swing the whole group
   around one shared centre, so the outer items would arc through the air instead of spinning.
   The turn is applied per card so each one revolves on its own axis, all at the same time. */
.upgrader-crate-items.revealing{animation:upgItemsReveal 1.15s cubic-bezier(.18,.9,.3,1) forwards}
@keyframes upgItemsReveal{
  0%{opacity:0;transform:translateX(-50%) translateY(46px) scale(.3)}
  35%{opacity:1}
  100%{opacity:1;transform:translateX(-50%) translateY(0) scale(1)}
}
/* Applied to the card, not the inner element — the inner owns the perpetual float animation
   and setting animation here would replace it, leaving the items dead still afterwards. */
.upgrader-crate-items.revealing .upgrader-crate-item{
  animation:upgItemSpin 1.15s cubic-bezier(.18,.9,.3,1)}
/* Keeps translate(var(--slot-x),0) scale(1) — the card's resting placement from .in — so the
   spin doesn't yank each item back to the row's centre while it turns. */
@keyframes upgItemSpin{
  0%{transform:translate(var(--slot-x),0) scale(1) rotate(0deg)}
  100%{transform:translate(var(--slot-x),0) scale(1) rotate(360deg)}
}

.upgrader-actions{display:flex;justify-content:center;gap:10px;width:100%;margin-top:auto;position:relative;z-index:1}
.upgrader-go-btn{width:200px;flex:none;display:flex;align-items:center;justify-content:center;gap:9px;padding:16px;border-radius:12px;border:1px solid rgba(255,255,255,0.08);background:rgba(255,255,255,0.05);color:rgba(255,255,255,0.4);font-size:15px;font-weight:800;letter-spacing:.02em;font-family:var(--font);cursor:pointer;transition:all .16s}
.upgrader-go-btn i{font-size:17px}
.upgrader-go-btn:disabled{cursor:default}
.upgrader-go-btn.ready{background:#66852F;border-color:#66852F;color:#DDF2B8}
.upgrader-go-btn.ready:hover{background:#75993a}
.upgrader-reroll-wrap{width:52px;height:52px;flex-shrink:0}
.upgrader-reroll-btn{width:100%;height:100%;display:flex;align-items:center;justify-content:center;border-radius:12px;border:1px solid rgba(255,255,255,0.08);background:rgba(255,255,255,0.03);color:rgba(255,255,255,0.6);cursor:pointer;transition:all .16s}
.upgrader-reroll-btn:hover{color:#fff;border-color:rgba(255,255,255,0.18);background:rgba(255,255,255,0.06)}
.upgrader-reroll-btn svg{width:19px;height:19px}

.upgrader-right{display:flex;flex-direction:column;gap:16px}
.upgrader-box{background:rgba(255,255,255,0.03);border:1px solid rgba(255,255,255,0.08);border-radius:14px;padding:20px}
.upgrader-header{display:flex;align-items:center;gap:12px}
.upgrader-header-icon{width:34px;height:34px;object-fit:contain;flex-shrink:0}
.upgrader-header-text{flex:1;min-width:0}
.upgrader-header-text strong{display:block;font-size:17px;font-weight:700;color:#fff}
.upgrader-header-text p{font-size:13.5px;color:rgba(255,255,255,0.5);margin-top:2px}
.upgrader-header-right{display:flex;align-items:center;gap:8px;flex-shrink:0}

.upgrader-controls{display:flex;gap:20px;flex-wrap:wrap}
.upgrader-block-label{font-size:11.5px;font-weight:700;letter-spacing:.05em;color:#fff;text-transform:uppercase;margin-bottom:9px}
.upgrader-amount-block{flex:0 0 auto}
.upgrader-amount-row{display:flex;align-items:center;gap:6px}
.upgrader-amount-input-wrap{width:160px;height:42px;box-sizing:border-box;flex:none;display:flex;align-items:center;gap:6px;padding:0 10px;border-radius:10px;border:1px solid rgba(255,255,255,0.08);background:rgba(255,255,255,0.03)}
.upgrader-amount-input-wrap img{width:20px;height:20px;object-fit:contain;flex-shrink:0}
.upgrader-amount-input-wrap input{flex:1;width:0;min-width:0;background:none;border:none;outline:none;color:#fff;font-size:14px;font-weight:600;font-family:var(--font)}
.upgrader-quick-btn{width:52px;height:42px;box-sizing:border-box;padding:0;display:flex;align-items:center;justify-content:center;border-radius:10px;border:1px solid rgba(255,255,255,0.08);background:rgba(255,255,255,0.03);color:rgba(255,255,255,0.7);font-size:12.5px;font-weight:700;font-family:var(--font);cursor:pointer;transition:all .16s;white-space:nowrap;text-align:center}
#upgHalfBtn{font-size:16px}
.upgrader-quick-btn:hover{color:#fff;border-color:rgba(255,255,255,0.18);background:rgba(255,255,255,0.06)}
.upgrader-mult-block{flex-shrink:0}
.upgrader-mult-row{display:flex;gap:6px}
.upgrader-mult-btn{width:52px;height:42px;box-sizing:border-box;padding:0;display:flex;align-items:center;justify-content:center;border-radius:10px;border:1px solid rgba(255,255,255,0.08);background:rgba(255,255,255,0.03);color:rgba(255,255,255,0.7);font-size:12.5px;font-weight:700;font-family:var(--font);cursor:pointer;transition:all .16s;text-align:center}
.upgrader-mult-btn:hover{color:#fff;border-color:rgba(255,255,255,0.18);background:rgba(255,255,255,0.06)}
.upgrader-mult-btn.active{background:#66852F;border-color:#66852F;color:#DDF2B8}
.upgrader-mult-btn.disabled{opacity:.4;cursor:not-allowed;pointer-events:none}
/* Bet controls are locked for the duration of a round — same treatment as the multiplier
   buttons so the whole betting row reads as committed. */
.upgrader-quick-btn.disabled{opacity:.4;cursor:not-allowed;pointer-events:none}
.upgrader-amount-input-wrap:has(input.disabled){opacity:.4;pointer-events:none}
.upgrader-amount-input-wrap input.disabled{cursor:not-allowed}

.upgrader-items-box{display:flex;flex-direction:column;gap:16px}
.upgrader-items-header{display:flex;align-items:flex-end;justify-content:space-between;gap:16px;flex-wrap:wrap}
.upgrader-items-sub{font-size:12.5px;color:rgba(255,255,255,0.45)}
.upgrader-items-tools{display:flex;align-items:center;gap:8px}
.upgrader-search{width:min(160px,100%);flex:1 1 130px;height:42px;padding:0 13px;border-radius:9px;border:1px solid rgba(255,255,255,0.08);background:rgba(255,255,255,0.03);color:#fff;font-size:12.5px;font-family:var(--font);outline:none;transition:border-color .16s}
.upgrader-search:focus{border-color:rgba(255,255,255,0.25)}
.upgrader-search::placeholder{color:rgba(255,255,255,0.35)}

.upgrader-items-grid{position:relative;max-height:321px;overflow-y:auto;overflow-x:hidden;padding-right:8px;will-change:scroll-position;transform:translateZ(0);contain:layout style paint;scroll-behavior:smooth}
.upgrader-items-spacer{position:relative;width:100%}
.upgrader-items-grid::-webkit-scrollbar{width:6px}
.upgrader-items-grid::-webkit-scrollbar-track{background:transparent}
.upgrader-items-grid::-webkit-scrollbar-thumb{background:rgba(255,255,255,0.15);border-radius:3px}
.upgrader-items-grid::-webkit-scrollbar-thumb:hover{background:rgba(255,255,255,0.25)}
.upgrader-items-grid{scrollbar-width:thin;scrollbar-color:rgba(255,255,255,0.15) transparent}
.upgrader-item-card{--rarity:120,205,145;position:absolute;top:0;left:0;box-sizing:border-box;display:flex;flex-direction:column;align-items:center;padding:8px 4px 8px;border-radius:9px;border:1px solid rgba(255,255,255,0.08);background:radial-gradient(ellipse 100% 145% at 50% 0%,rgba(var(--rarity),0.32) 0%,rgba(var(--rarity),0.03) 75%,rgba(255,255,255,0.03) 100%);background-clip:padding-box;cursor:pointer;transition:border-color .16s;contain:layout style paint}
.upgrader-item-hover{position:absolute;inset:0;border-radius:8px;display:flex;align-items:center;justify-content:center;padding:6px;background:rgba(0,0,0,0.55);opacity:0;pointer-events:none;transition:opacity .35s ease}
.upgrader-item-hover-name{font-size:13.5px;font-weight:700;text-align:center;line-height:1.25;transform:translateY(10px);transition:transform .45s cubic-bezier(.22,1,.36,1)}
.upgrader-item-card:hover .upgrader-item-hover{opacity:1}
.upgrader-item-card:hover .upgrader-item-hover-name{transform:translateY(0)}
.upgrader-item-card.selected{border-color:#3a6f96;background:#1c3d54}
#upgRefreshBtn.upgrader-clear-btn{background:rgba(180,50,50,0.18);border-color:rgba(220,80,80,0.4);color:rgba(255,150,150,0.9)}
#upgRefreshBtn.upgrader-clear-btn:hover{background:rgba(180,50,50,0.28);border-color:rgba(220,80,80,0.6);color:#ffb3b3}
.upgrader-item-card img{width:67.5px;height:67.5px;object-fit:contain;margin:4px 0 6px}
.upgrader-item-price{display:flex;align-items:center;gap:5px;font-size:13.5px;font-weight:700;color:#fff}
.upgrader-item-price img{width:14px;height:14px;object-fit:contain;margin:0}
.upgrader-item-card.loading{pointer-events:none}
.upgrader-item-card.loading img,.upgrader-item-card.loading .upgrader-item-price{visibility:hidden}
.upgrader-item-loading{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px}
.upgrader-item-spinner{width:16px;height:16px;border-radius:50%;border:2px solid rgba(255,255,255,0.15);border-top-color:rgba(255,255,255,0.6);animation:upgSpinnerSpin .7s linear infinite}
.upgrader-item-loading span{font-size:9.5px;font-weight:600;color:rgba(255,255,255,0.5)}
/* Grid-level refresh state — applies to whatever cards happen to be in the (virtualized,
   constantly recycled) DOM at any moment, instead of tagging specific card elements that
   might get swapped out mid-animation as the user scrolls or the list re-renders. Every
   card always carries its own hidden .upgrader-item-loading overlay; this class just
   reveals it site-wide across the grid while a refresh is in progress. */
.upgrader-item-loading{display:none}
.upgrader-items-grid.refreshing .upgrader-item-card{pointer-events:none}
.upgrader-items-grid.refreshing .upgrader-item-card img,
.upgrader-items-grid.refreshing .upgrader-item-card .upgrader-item-price{visibility:hidden}
.upgrader-items-grid.refreshing .upgrader-item-card .upgrader-item-loading{display:none}
/* While refreshing, each card runs a skeleton shimmer — a highlight sweeping across an empty
   placeholder — so the reload reads as real work happening per card. --shimmer-delay is set
   per card from JS to stagger the sweep across the grid. */
.upgrader-items-grid.refreshing .upgrader-item-card{--shimmer-delay:0ms;overflow:hidden}
.upgrader-items-grid.refreshing .upgrader-item-card::after{
  content:"";position:absolute;inset:0;border-radius:inherit;
  background:linear-gradient(100deg,rgba(255,255,255,0) 30%,rgba(255,255,255,0.13) 50%,rgba(255,255,255,0) 70%);
  background-size:220% 100%;
  animation:upgCardShimmer 1.15s ease-in-out infinite;animation-delay:var(--shimmer-delay)}
@keyframes upgCardShimmer{0%{background-position:130% 0}100%{background-position:-130% 0}}
/* Cards fade back in once their image has actually landed. */
.upgrader-item-card.refreshed{animation:upgCardRefreshed .34s cubic-bezier(.22,1,.36,1)}
@keyframes upgCardRefreshed{from{opacity:0;transform:scale(.94)}to{opacity:1;transform:none}}
@keyframes upgSpinnerSpin{to{transform:rotate(360deg)}}
#upgSortBtn svg{transition:transform .2s ease}
#upgRefreshBtn svg.spinning{animation:upgRefreshSpin 1s linear infinite}
@keyframes upgRefreshSpin{to{transform:rotate(360deg)}}
#upgraderRerollBtn svg{--spin-dir:1}
#upgraderRerollBtn svg.flipping{animation:upgRerollSpin .28s cubic-bezier(.65,0,.35,1)}
@keyframes upgRerollSpin{
  0%{transform:rotate(0)}
  100%{transform:rotate(calc(var(--spin-dir) * 180deg))}
}

/* Preview text spins a full turn on every Change Roll — a plain 2D rotate() that always
   accumulates forward (never resets to 0 or snaps backward), transitioned smoothly so it
   visibly spins through the update and eases to a stop upright again. */
#upgPreview{transition:transform 1.05s cubic-bezier(.16,1,.3,1)}

.upgrader-left.shaking{animation:upgLeftShake 1.05s cubic-bezier(.36,.07,.19,.97) both}
@keyframes upgLeftShake{
  0%,100%{transform:translate(0,0)}
  8%{transform:translate(-1.5px,1px)}
  16%{transform:translate(1.5px,-1px)}
  24%{transform:translate(-1.5px,-1px)}
  32%{transform:translate(1.2px,1px)}
  40%{transform:translate(-1px,1px)}
  48%{transform:translate(1px,-0.8px)}
  56%{transform:translate(-0.8px,-0.8px)}
  64%{transform:translate(0.8px,0.6px)}
  72%{transform:translate(-0.5px,0.5px)}
  80%{transform:translate(0.5px,-0.4px)}
  90%{transform:translate(0,0)}
}

@media (max-width:1320px){
  /* Tablet band: KEEP the two columns side by side, but let them share the viewport
     proportionally (same 480:750 ratio as the desktop fix) instead of holding the fixed
     ~1310px width that forced iPads to pan/pinch-zoom around an oversized page. The desktop
     rule's width:max-content + left:50%/translateX(-50%) centering hack is dropped here for
     plain full-width flow. PC (>1320px) renders the fixed desktop grid exactly as always. */
  .upgrader-layout{grid-template-columns:minmax(0,39fr) minmax(0,61fr);width:100%;left:auto;transform:none}
  /* The crate art deliberately overhangs its column on desktop (530px in a 420px content box,
     ~126%, clipped at the card edges) — the same proportional overhang keeps the look as the
     column shrinks. The floating-items stage scales with the column instead of a fixed 420px. */
  .upgrader-crate-stack{width:126%}
  .upgrader-crate-items{width:100%}
  .upgrader-items-grid{grid-template-columns:repeat(5,1fr)}
}
@media (max-width:700px){
  /* Phones: side-by-side genuinely can't fit — stack to a single column. */
  .upgrader-layout{grid-template-columns:1fr;max-width:600px;margin-left:auto;margin-right:auto}
  .upgrader-crate-stack{width:min(500px,120%)}
  .upgrader-items-grid{grid-template-columns:repeat(4,1fr)}
}


/* ── Spinner Battles ──────────────────────────────────────────────────────── */
/* .spinners-top-row is the whole "title + REMOVE FINISHED + CREATE A GAME" unit, always
   rendered as a single piece so the title and button stay in the same flex row no matter where
   the whole thing currently lives (see renderSpinnersYourGames in script.js, which relocates
   this exact node — not a clone — between sitting here by default, reading "Games", and sitting
   inside #spinnersYourGames reading "Your games" once at least one game exists).
   .spinners-games-title-row is a plain placeholder title, hidden by default and only shown
   (by script.js) once .spinners-top-row has moved away, so "Games" still has a heading of its
   own left behind. position:relative on .spinners-top-row is just the anchor for the create
   panel, pulled out of flow via absolute positioning so it can sit to the right of the header
   without shrinking the header's own centered width/position. */
.spinners-top-row{position:relative;margin-top:36px}
/* 940px, not 820 — matches .spinners-your-games .spinners-games-list below (widened so a 4th
   220px card fits per row: 4x220 + 3x14 gaps = 922px, which 820px can't hold). Keeping the
   title row and the grid at the same width is what keeps REMOVE FINISHED / CREATE A GAME
   (anchored off this row's right edge) lined up with the wider card grid underneath it. */
.spinners-games-title-row{width:100%;max-width:940px;margin:36px auto 0}
.spinners-header{display:flex;align-items:center;justify-content:space-between;gap:20px;flex-wrap:wrap;width:100%;max-width:940px;margin:0 auto}
/* Same 940px column as .spinners-your-games .spinners-games-list and the header row above —
   without this, the public "Games" grid had no max-width at all, so its cards (sharing the same
   .spinners-games-list grid rule, minmax(220px,1fr)) stretched to fill the full page width
   instead of the same column "Your games" cards sit in, making them visibly bigger/differently
   positioned even though it's the exact same card markup. */
.spinners-layout{margin-top:22px;max-width:940px;margin-left:auto;margin-right:auto}
.spinners-title{font-size:24px;font-weight:800;color:#fff;letter-spacing:.01em}
/* Muted/secondary styling (not the green .create-battle-btn look) — this doesn't do anything
   yet, so it shouldn't read as the page's primary action. */
.spinners-remove-finished-btn{display:flex;align-items:center;gap:8px;flex-shrink:0;padding:11px 18px;border-radius:11px;border:1px solid rgba(255,255,255,0.08);background:rgba(255,255,255,0.05);color:rgba(255,255,255,0.7);font-size:12.5px;font-weight:800;letter-spacing:.02em;font-family:var(--font);cursor:pointer;transition:all .16s;white-space:nowrap}
.spinners-remove-finished-btn:hover{color:#fff;border-color:rgba(255,255,255,0.16);background:rgba(255,255,255,0.08)}
.spinners-remove-finished-btn svg{width:15px;height:15px;flex-shrink:0}
.spinners-games-list{min-height:1px}
/* Positioned relative to the header's own centered right edge (50% + half the header's 940px
   width + the 24px gap) rather than flowing in the header's flexbox, so the header/REMOVE
   FINISHED position is completely untouched by the panel's presence. */
.spinners-create-panel{position:absolute;left:calc(50% + 494px);top:0;width:340px;background:rgba(255,255,255,0.03);border:1px solid rgba(255,255,255,0.08);border-radius:14px;padding:20px}
/* The calc(50% + 494px) offset above needs roughly 940px (the centered games column) + 340px
   (this panel) + a 24px gap either side of that math to actually have somewhere to put the
   panel that doesn't run off the edge of the page — there's no room for that on an iPad-width
   screen, which is what forced horizontal scrolling there. Below that width the panel drops
   out of absolute positioning entirely and just flows as a normal block under the header row. */
@media (max-width:1300px){
  .spinners-create-panel{position:static;width:100%;max-width:940px;margin:16px auto 0}
}
.spinners-create-title{font-size:15px;font-weight:800;letter-spacing:.03em;color:rgb(187,229,113)}
.spinners-create-desc{margin-top:8px;font-size:13.5px;line-height:1.5;color:#fff}
.spinners-create-label{display:flex;align-items:center;gap:8px;margin-top:22px;margin-bottom:10px;font-size:12px;font-weight:800;letter-spacing:.04em;color:rgb(178,214,239)}
.spinners-create-label-plain{margin-bottom:10px}
.spinners-create-label-icon{position:relative;display:flex;align-items:center;justify-content:center;width:16px;height:16px;flex-shrink:0;color:rgb(178,214,239)}
/* PLAYER SLOTS' icon is a raster PNG (a solid black silhouette on transparent) rather than an
   inline SVG, so it can't pick up currentColor the way the brush icon's <svg stroke="currentColor">
   does. A CSS mask (background tinted through the PNG's own alpha shape, via --icon-mask set
   inline in the HTML) recolors it to the exact same light-blue as the label text instead —
   plain brightness/invert filters can only push it to white or black, not an arbitrary color.
   The <img> itself is kept in the DOM (for alt text / graceful degradation) but hidden. */
.spinners-create-label-icon img{width:100%;height:100%;object-fit:contain;opacity:0}
.spinners-create-label-icon[style*="--icon-mask"]::before{content:"";position:absolute;inset:0;background:rgb(178,214,239);-webkit-mask-image:var(--icon-mask);mask-image:var(--icon-mask);-webkit-mask-size:contain;mask-size:contain;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-position:center;mask-position:center}
.spinners-brush-icon svg{width:100%;height:100%}
.spinners-slot-group{display:flex;gap:8px}
.spinners-slot-btn{width:38px;height:38px;flex-shrink:0;box-sizing:border-box;border-radius:9px;border:1px solid transparent;background:rgba(110,107,101,0.75);color:#fff;font-size:13px;font-weight:700;font-family:var(--font);cursor:pointer;transition:all .16s}
.spinners-slot-btn:hover{filter:brightness(1.15)}
/* "2v2" needs more than the square 38px the single digits use. */
.spinners-slot-btn-2v2{width:auto;padding:0 13px}
.spinners-slot-btn.active{background:rgb(25,61,86);color:rgb(178,214,239)}
.spinners-color-group{display:flex;gap:8px}
/* Dark neutral square (like the slot buttons), with just a small swatch block centered inside
   via ::after — not the whole button filled with color. Active state changes the button's own
   background to the same dark blue the active slot button uses, not an outline. */
.spinners-color-btn{position:relative;width:38px;height:38px;flex-shrink:0;box-sizing:border-box;border-radius:9px;border:1px solid transparent;background:rgba(110,107,101,0.75);cursor:pointer;transition:all .16s}
.spinners-color-btn::after{content:"";position:absolute;top:50%;left:50%;width:16px;height:16px;transform:translate(-50%,-50%);border-radius:4px;background:var(--swatch)}
.spinners-color-btn:hover{filter:brightness(1.15)}
.spinners-color-btn.active{background:rgb(25,61,86)}
.spinners-amount-row{display:flex;gap:8px}
.spinners-amount-input-wrap{flex:1;height:42px;box-sizing:border-box;display:flex;align-items:center;gap:6px;padding:0 12px;border-radius:10px;border:1px solid rgba(255,255,255,0.08);background:rgba(255,255,255,0.03)}
.spinners-amount-input-wrap img{width:20px;height:20px;object-fit:contain;flex-shrink:0}
.spinners-amount-input-wrap input{flex:1;width:0;min-width:0;background:none;border:none;outline:none;color:#fff;font-size:13.5px;font-weight:600;font-family:var(--font)}
.spinners-quick-btn{width:46px;height:42px;box-sizing:border-box;flex-shrink:0;display:flex;align-items:center;justify-content:center;border-radius:10px;border:1px solid rgb(38,92,129);background:rgb(38,92,129);color:rgb(178,214,239);font-size:12.5px;font-weight:700;font-family:var(--font);cursor:pointer;transition:all .16s}
.spinners-quick-btn:hover{filter:brightness(1.15)}
.spinners-create-btn{width:100%;margin-top:22px;padding:14px;border-radius:11px;border:1px solid transparent;background:rgba(255,255,255,0.12);color:rgba(255,255,255,0.3);font-size:13.5px;font-weight:800;letter-spacing:.02em;font-family:var(--font);cursor:pointer;transition:all .16s}
.spinners-create-btn:disabled{cursor:default}
/* Same ready-state colors as the Scrap Upgrader's UPGRADE button. */
.spinners-create-btn.ready{background:#66852F;border-color:#66852F;color:#DDF2B8}
.spinners-create-btn.ready:hover{background:#75993a}

/* "Your games" — the relocated .spinners-top-row (title + REMOVE FINISHED + CREATE A GAME)
   renders as the first child here once at least one game exists; the list sits right below it.
   940px (not 820) is what actually fits a 4th 220px card per row: 4x220 + 3x14px gaps = 922px,
   which needs more room than 820px has. .spinners-header/.spinners-games-title-row above match
   this same 940px so REMOVE FINISHED / CREATE A GAME / "Games" stay lined up with the grid. */
.spinners-your-games{margin-top:36px}
.spinners-your-games .spinners-games-list{max-width:940px;margin:22px auto 0}

.spinners-games-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:14px}

/* One created/joined game — mirrors .case-card's vertical-tile look (dark panel, rounded,
   padded) rather than the horizontal .battle-card row used on the Case Battles list. */
/* min-height keeps the card at its original size even though the wheel above got smaller —
   .spinner-game-card-players has flex:1, so the leftover room the smaller wheel leaves behind
   is absorbed there (pushing CANCEL back down to where it was) instead of the whole card
   shrinking to hug its now-shorter content. */
.spinner-game-card{position:relative;display:flex;flex-direction:column;min-height:340px;background:rgba(255,255,255,0.03);border:1px solid rgba(255,255,255,0.08);border-radius:12px;padding:12px}
.spinner-game-card-pool{position:absolute;top:12px;left:12px;z-index:2;display:flex;align-items:center;gap:6px;font-size:14px;font-weight:800;color:#fff}
.spinner-game-card-pool img{width:16px;height:16px;object-fit:contain}
/* Applied only to a card the instant it's actually new (see renderSpinnersYourGames in
   script.js, which now updates existing cards in place instead of recreating them) — so
   creating one game plays this once for that card alone, instead of every card in the list
   replaying an entrance animation together on every render. */
.spinner-game-card-enter{animation:spinnerCardIn .38s cubic-bezier(.16,1,.3,1) both}
@keyframes spinnerCardIn{from{opacity:0;transform:translate3d(0,10px,0) scale(.96)}to{opacity:1;transform:translate3d(0,0,0) scale(1)}}

/* Wheel: spinner.png (neutral cracked-earth texture, quartered by its own printed cross lines)
   with a conic-gradient pie overlay tinted per player slot sitting on top of it — semi-
   transparent so the texture still shows through the color instead of being fully hidden. The
   arrow pointer sits above both, anchored to the top like the case-opening reel's pointer. */
.spinner-game-card-wheel-wrap{position:relative;width:100%;aspect-ratio:1;margin:34px auto 14px;max-width:150px}
.spinner-game-card-wheel-arrow{position:absolute;top:-16px;left:50%;transform:translateX(-50%);z-index:3;width:55px;height:55px;filter:drop-shadow(0 2px 4px rgba(0,0,0,0.6))}
.spinner-game-card-wheel-arrow img{width:100%;height:100%;object-fit:contain}
/* The circular clip (border-radius+overflow:hidden) and the background color live here, on an
   element that never itself rotates — .spinner-game-card-wheel-spin (a plain child with nothing
   but a transform on it) is what actually spins during the roll. Putting the clip mask and the
   mix-blend-mode fill on the *same* element being rotated forced a full repaint every animation
   frame (clipping and blend compositing both have to be re-resolved against the new angle, which
   can't just be handed to the GPU as a cheap re-transform the way a bare rotate() can) — that
   per-frame repaint work was the actual cause of the spin feeling laggy, not frame-rate/GPU
   limits. Splitting them apart means the only thing changing every frame is a transform on an
   element with no clip and no blend mode of its own, which the browser can composite instead of
   repaint. will-change hints the browser to promote that layer up front (skip discovering it
   needs one on the first animated frame, which is its own small stutter). */
.spinner-game-card-wheel{position:relative;width:100%;height:100%;border-radius:50%;overflow:hidden;background:#000}
.spinner-game-card-wheel-spin{position:absolute;inset:0;will-change:transform}
.spinner-game-card-wheel-spin img{position:absolute;inset:0;width:100%;height:100%;object-fit:contain}
/* No flat opacity here — each segment carries its own alpha directly in the conic-gradient's
   rgba stops (spinnerGameConicGradient in script.js), so the correct pre-/post-landing value is
   baked in per segment instead of one uniform value applying to the whole layer. */
.spinner-game-card-wheel-fill{position:absolute;inset:0;mix-blend-mode:multiply}
/* mix-blend-mode is dropped ONLY below this width AND only while .spin-active is on the parent
   .spinner-game-card-wheel-spin (set by spinSpinnerWheel in script.js for exactly the duration
   the wheel is actually rotating, removed the instant it settles). This element is a CHILD of
   that rotating element, not a sibling sitting outside the rotation — so despite the earlier
   desktop pass separating the *clip* from the rotating layer, this blend mode was still riding
   along on every rotated frame. mix-blend-mode forces the compositor to re-read and re-blend
   against the backdrop on every frame a transform changes, which weaker mobile GPUs feel much
   more than desktop ones.
   Originally this dropped the blend mode unconditionally below 820px, all the time — but at
   opacity:1.0 (the landed winning segment) a flat alpha-composited color is fully opaque and
   hides the wheel's texture completely, reading as a cheap flat color block instead of the
   richly textured, multiply-darkened look PC has always had. Scoping the drop to only the
   actively-spinning window keeps every idle/landed card — the vast majority of the time any
   wheel is ever on screen — looking exactly like PC, and only trades that look away for the few
   seconds a wheel is genuinely mid-spin, which is a much smaller and worthwhile cost. */
@media (max-width:820px){
  .spinner-game-card-wheel-spin.spin-active .spinner-game-card-wheel-fill{mix-blend-mode:normal}
}

/* flex:1 lets this stretch to fill whatever room is left in the card once CSS Grid has
   stretched every card in the row to match the tallest one — so a 2-slot card's shorter player
   list still pushes CANCEL down to the same line as a 4-slot card's, instead of CANCEL sitting
   right under however many rows this particular game happens to have. justify-content keeps the
   rows themselves anchored to the top rather than spreading out to fill that extra space. */
.spinner-game-card-players{display:flex;flex-direction:column;justify-content:flex-start;gap:6px;margin-bottom:4px;flex:1}
/* Fixed height = the tallest content a row can hold (the 20px pfp) — an empty text-only row
   and a filled row with a pfp measure identical, so a slot filling never shifts or resizes
   anything around it. */
.spinner-game-card-player{display:flex;align-items:center;gap:8px;height:20px;font-size:12.5px;font-weight:600;color:#fff;min-width:0}
/* The callable/joinable hover-pill trick (padding:2px + margin:-2px) shrinks those rows'
   LAYOUT footprint by 4px vs a plain row — so they get 4px more height to compensate, keeping
   every row's flow footprint exactly 20px whether empty or filled. */
.spinner-game-card-player.empty.callable,.spinner-game-card-player.empty.joinable{height:24px}
.spinner-game-card-player-swatch{width:14px;height:14px;flex-shrink:0;border-radius:4px;background:var(--swatch)}
.spinner-game-card-player-pfp{width:20px;height:20px;flex-shrink:0;object-fit:contain}
.spinner-game-card-player-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.spinner-game-card-player.empty{color:rgba(255,255,255,0.4)}
/* Only rows on your own cards get the clickable "call a bandit" treatment (see .callable, added
   only when spinnerGamePlayerRowHTML is rendering for the card's owner) — public-list cards
   stay plain text since calling a bandit into someone else's game isn't allowed.
   Box-identical to a plain .spinner-game-card-player on purpose: padding is offset by an equal
   negative margin on every side (not just left/right), so this row occupies the exact same
   width AND height whether it's showing "Call a bot" or, once filled, the plain row markup a
   real username swaps in as. Letting them differ in size was what made the swatch/name visibly
   "jump" into place right when a bot filled the slot, and also meant a card with more open
   slots was measurably taller than the same card once those slots filled in — which is what
   caused *other* cards in the row to visibly reflow (their row's tallest card changed) whenever
   a card was added/removed nearby, e.g. cancelling one card shifting the remaining ones. */
.spinner-game-card-player.empty.callable{cursor:pointer;border-radius:6px;margin:-2px -6px;padding:2px 6px;transition:background-color .15s ease,color .15s ease}
.spinner-game-card-player.empty.callable:hover{background:rgba(255,255,255,0.06);color:rgba(255,255,255,0.75)}
.spinner-game-card-player.empty.callable:active{background:rgba(255,255,255,0.1)}
/* Join — the public "Games" list's real-money equivalent of .callable's free "Call a bot".
   Same hover/box treatment (box-identical to a filled row for the same reason .callable is —
   see its own note above) so it reads as the same kind of clickable row language, just with a
   scrap amount inline instead of "Call a bot" text. */
.spinner-game-card-player.empty.joinable{cursor:pointer;border-radius:6px;margin:-2px -6px;padding:2px 6px;transition:background-color .15s ease,color .15s ease}
.spinner-game-card-player.empty.joinable:hover{background:rgba(255,255,255,0.06);color:rgba(255,255,255,0.75)}
.spinner-game-card-player.empty.joinable:active{background:rgba(255,255,255,0.1)}
.spinner-game-card-player-join-icon{width:12px;height:12px;object-fit:contain;vertical-align:-1px;margin:0 2px}

.spinner-game-card-cancel-btn{margin-top:10px;padding:10px;border-radius:9px;border:1px solid #7A2E2E;background:#7A2E2E;color:#F5C6C6;font-size:12px;font-weight:800;letter-spacing:.02em;font-family:var(--font);cursor:pointer;transition:all .16s}
.spinner-game-card-cancel-btn:hover{background:#8c3636}
/* STARTING / ROLLING / ROLLED — once the board's full and a winner's been decided, cancelling is
   no longer possible (see the server's ALREADY_SPINNING guard), so the button becomes a plain
   status readout instead of the red cancel action for the rest of that game's lifetime. Same
   class/look for all three labels; only the text (spinnerCancelButtonState in script.js) changes
   as the game moves from full -> turning -> at rest. cursor:default since it's inert now. */
.spinner-game-card-cancel-btn.starting{background:rgba(255,255,255,0.12);border-color:transparent;color:rgba(255,255,255,0.3);cursor:default}
.spinner-game-card-cancel-btn.starting:hover{background:rgba(255,255,255,0.12)}

/* JOIN GAME — non-owner cards' bottom button, same position/sizing as CANCEL but green, matching
   CREATE GAME's own .ready state exactly (#66852F/#DDF2B8, hover #75993a). Once the game fills,
   spinnerJoinButtonState swaps this to the same STARTING/ROLLING/ROLLED progression CANCEL uses
   — reusing .starting's exact look here too, so both bottom-button roles read as the identical
   "now inert, just a status" state once a game is no longer joinable/cancellable. */
.spinner-game-card-join-btn{margin-top:10px;padding:10px;border-radius:9px;border:1px solid #66852F;background:#66852F;color:#DDF2B8;font-size:12px;font-weight:800;letter-spacing:.02em;font-family:var(--font);cursor:pointer;transition:all .16s}
.spinner-game-card-join-btn:hover{background:#75993a}
.spinner-game-card-join-btn.starting{background:rgba(255,255,255,0.12);border-color:transparent;color:rgba(255,255,255,0.3);cursor:default}
.spinner-game-card-join-btn.starting:hover{background:rgba(255,255,255,0.12)}

/* ── Wheel (PC only — this page is being built section by section, no mobile pass yet) ────── */
/* min-height fills the viewport minus .wrap's own 104px/70px top/bottom padding, so
   align-items:center lands the wheel+panel row in the vertical middle of the screen rather
   than hanging just below the nav. */
.wheel-layout{display:flex;align-items:center;justify-content:center;gap:250px;min-height:calc(100vh - 174px)}
/* position:relative so the pointer arrow (a direct child, positioned absolutely) anchors to
   this box — which tightly wraps .wheel-main-wrap, so the arrow's coordinates are identical to
   when it lived inside the wrap. It was moved out so the wrap can clip its rotating image's
   oversized bounding box on mobile without slicing the arrow. */
.wheel-main{position:relative;display:flex;justify-content:center;flex-shrink:0}
.wheel-main-wrap{position:relative;width:700px;aspect-ratio:1}
/* The shadow lives on a static circle BEHIND the wheel, not as a filter on the wheel image —
   a filter on the element that rotates during the spin forces the browser to re-render the
   filter every animated frame (same per-frame repaint trap the spinner-battles wheel hit),
   whereas a bare transform on a filter-free img composites cheaply. will-change pre-promotes
   the layer so the first spin frame doesn't stutter on layer creation. */
.wheel-main-wrap::before{content:"";position:absolute;inset:2%;border-radius:50%;box-shadow:0 12px 32px rgba(0,0,0,0.55)}
.wheel-main-img{position:relative;width:100%;height:100%;object-fit:contain;will-change:transform}
/* Top-center pointer, sized big relative to the wheel and pulled down so roughly its bottom
   half overlaps into the wheel's rim rather than just touching the edge. */
.wheel-main-arrow{position:absolute;top:-20px;left:50%;transform:translateX(-50%);width:110px;height:auto;z-index:2;filter:drop-shadow(0 4px 10px rgba(0,0,0,0.6))}

/* Right-side control panel — static for now (no click handlers do anything yet), built to match
   an exact reference screenshot's layout: title+help row, an info blurb, a time-left row, the
   five payout slots, then the scrap-stacks amount controls. */
.wheel-panel{position:relative;width:600px;flex-shrink:0;display:flex;flex-direction:column;gap:16px}
/* Round-history strip hanging off the panel's right edge: blue history icon up top (site-
   standard .icon-btn-wrap/.icon-tooltip hover tooltip), then one colored square per finished
   round — newest at the top, sliding down as new results land, clipped at the panel's bottom. */
/* top/height are set by positionWheelHistory in script.js (measured against the info section
   and the stacks card), not fixed here. */
.wheel-history{position:absolute;left:calc(100% + 14px);top:50px;display:flex;flex-direction:column;align-items:center;gap:10px}
.wheel-history-icon{display:flex;align-items:center;justify-content:center;width:30px;height:30px;border-radius:9px;border:none;background:none;color:rgb(178,214,239);cursor:pointer;transition:all .16s}
.wheel-history-icon:hover{color:#fff}
.wheel-history-icon svg{width:17px;height:17px}
.wheel-history-list{display:flex;flex-direction:column;align-items:center;gap:6px;flex:1;overflow:hidden}
.wheel-history-square{width:15px;height:15px;flex-shrink:0;border-radius:3px;border:1px solid rgba(0,0,0,0.5)}
.wheel-history-square.new{animation:wheelHistIn .3s cubic-bezier(.22,1,.36,1) both}
@keyframes wheelHistIn{from{opacity:0;transform:translateY(-8px) scale(.5)}to{opacity:1;transform:translateY(0) scale(1)}}
.wheel-panel-header{display:flex;align-items:center;gap:10px}
.wheel-panel-title{flex:1;font-size:19px;font-weight:800;color:rgb(239,239,239);letter-spacing:.02em}
.wheel-panel-sound-btn,.wheel-panel-help-btn{display:flex;align-items:center;gap:6px;flex-shrink:0;padding:8px 10px;border-radius:9px;border:1px solid rgba(255,255,255,0.08);background:rgba(255,255,255,0.03);color:rgba(255,255,255,0.7);font-size:12px;font-weight:800;letter-spacing:.03em;font-family:var(--font);cursor:pointer;transition:all .16s}
.wheel-panel-sound-btn:hover,.wheel-panel-help-btn:hover{color:#fff;border-color:rgba(255,255,255,0.16);background:rgba(255,255,255,0.06)}
/* Same red muted treatment the site's other sound toggles use. */
.wheel-panel-sound-btn.muted{color:rgb(230,70,50);border-color:rgba(230,70,50,0.35);background:rgba(230,70,50,0.1)}
.wheel-panel-sound-btn svg,.wheel-panel-help-btn svg{width:16px;height:16px;flex-shrink:0}

.wheel-panel-info{display:flex;align-items:center;gap:14px;padding:14px 16px;border-radius:11px;background:rgba(255,255,255,0.03);border:1px solid rgba(255,255,255,0.06)}
.wheel-panel-info-icon{flex-shrink:0;width:34px;height:34px;color:rgba(255,255,255,0.4)}
.wheel-panel-info-icon svg{width:100%;height:100%}
.wheel-panel-info p{font-size:17px;line-height:1.5;color:rgb(239,239,239)}

.wheel-panel-timer-row{display:flex;align-items:stretch;gap:10px}
.wheel-panel-timer-info{flex:1;padding:14px 16px;border-radius:11px;background:rgba(255,255,255,0.03);border:1px solid rgba(255,255,255,0.06)}
.wheel-panel-timer-label{font-size:16px;font-weight:800;letter-spacing:.04em;color:rgb(239,239,239)}
.wheel-panel-timer-info p{margin-top:4px;font-size:16px;color:rgb(239,239,239)}
/* Fixed width on the 20s box; the TIME LEFT card next to it is flex:1, so widening this one
   automatically shortens that one — the two always share the row's full width. */
.wheel-panel-timer-value{position:relative;overflow:hidden;flex-shrink:0;width:150px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;border-radius:11px;background:rgba(255,255,255,0.03);border:1px solid rgba(255,255,255,0.06);color:rgba(255,255,255,0.35)}
.wheel-panel-timer-value span{font-size:34px;font-weight:800;color:rgb(255,255,255)}
/* White countdown bar pinned along the box's bottom edge — the fill drains right-to-left via
   scaleX (transform-origin left), driven by a single CSS transition per round from script.js. */
.wheel-panel-timer-bar{position:absolute;left:0;right:0;bottom:0;height:5px;background:rgba(255,255,255,0.08);overflow:hidden}
/* Lock icon shown in place of the countdown once betting closes (entries final). Font
   Awesome's fa-lock — note the free FA set only ships the filled style. */
.wheel-panel-lock{font-size:30px;color:rgba(255,255,255,0.55)}
.wheel-panel-timer-bar-fill{position:absolute;inset:0;background:#fff;transform-origin:left center;transition:transform .25s linear}

.wheel-panel-slots{display:grid;grid-template-columns:repeat(5,1fr);gap:6px;padding:16px;border-radius:11px;background:rgba(255,255,255,0.03);border:1px solid rgba(255,255,255,0.06)}
/* The slot artwork (colored box, number, PAYS X label, worn texture) is all baked into the
   wheel1/3/5/10/20.png images themselves — the button is just a plain clickable frame around
   the image, no CSS-drawn background/texture of its own. data-mult carries which multiplier
   the button represents, for the game logic to come. */
.wheel-panel-slot{position:relative;display:block;padding:0;border:none;background:none;cursor:pointer;transition:transform .12s;font-family:var(--font);touch-action:none}
/* Bets locked: tiles are completely inert — no hover grow, no green wash, no clicks. */
.wheel-panel-slots.locked .wheel-panel-slot{pointer-events:none}
/* Hover: grow slightly in place (no float-up) with a green wash over the tile artwork. */
.wheel-panel-slot:hover{transform:scale(1.015)}
.wheel-panel-slot-img{position:relative;display:block;width:100%}
.wheel-panel-slot-img img{display:block;width:100%;height:auto}
/* z-index:3 keeps the hover wash above the placed-bet scrap overlay (z-index:2 below), so a
   tile with scrap on it tints green across everything — artwork and scrap pile alike. */
.wheel-panel-slot-img::after{content:"";position:absolute;inset:0.1px;z-index:3;border:2px solid #000;pointer-events:none;transition:background .12s,border-color .12s}
.wheel-panel-slot:hover .wheel-panel-slot-img::after{background:rgba(88,190,140,0.45);border-color:rgba(60,130,96,0.8);box-shadow:inset 0 0 10px rgba(88,190,140,0.6)}
/* Overlaid on the artwork itself, sitting just under the big number baked into the PNG. */
.wheel-panel-slot-pays{position:absolute;left:0;right:0;bottom:9%;z-index:1;text-align:center;font-size:11px;font-weight:800;letter-spacing:.04em;color:rgb(0,0,0);pointer-events:none}
/* A placed bet: scrap pile art centered over the tile with the running total pinned to the
   pile's bottom-right corner in white — repeat clicks just update the number. */
.wheel-panel-slot-bet{position:absolute;inset:0;z-index:2;display:flex;align-items:center;justify-content:center;pointer-events:none}
.wheel-panel-slot-bet img{width:90%;height:auto;filter:drop-shadow(0 2px 6px rgba(0,0,0,0.6))}
.wheel-panel-slot-bet b{position:absolute;right:5%;bottom:7%;font-size:15px;font-weight:800;color:#fff;text-shadow:0 1px 3px rgba(0,0,0,0.9),0 0 6px rgba(0,0,0,0.7)}

.wheel-panel-stacks{display:flex;flex-direction:column;gap:12px;padding:16px;border-radius:11px;background:rgba(255,255,255,0.03);border:1px solid rgba(255,255,255,0.06)}
.wheel-panel-stacks-row{display:flex;align-items:center;justify-content:space-between}
.wheel-panel-stacks-label{display:flex;align-items:center;gap:8px;font-size:13px;font-weight:800;letter-spacing:.04em;color:rgb(239,239,239)}
/* "?" next to SCRAP STACKS, mouse mode only — hover brings up the Rust-keybinds tooltip. */
.wheel-stacks-help{color:rgba(255,255,255,0.45);cursor:default;font-size:14px;transition:color .16s}
.wheel-stacks-help:hover{color:rgba(255,255,255,0.8)}
.wheel-keybinds-tooltip{position:absolute;bottom:calc(100% + 9px);left:-12px;width:290px;padding:11px 13px;border-radius:8px;background:rgba(9,9,9,0.98);border:1px solid rgba(255,255,255,0.1);box-shadow:0 10px 28px rgba(0,0,0,0.5);opacity:0;transform:translateY(4px);pointer-events:none;transition:opacity .16s ease,transform .16s ease;z-index:20;text-align:left;letter-spacing:normal}
.wheel-stacks-help:hover .wheel-keybinds-tooltip{opacity:1;transform:translateY(0);transition-delay:0.3s}
.wheel-keybinds-tooltip b{display:block;font-size:13px;font-weight:800;color:#fff;margin-bottom:6px}
.wheel-keybinds-tooltip ul{margin:0;padding-left:16px;display:flex;flex-direction:column;gap:3px}
.wheel-keybinds-tooltip li{font-size:12.5px;font-weight:500;line-height:1.45;color:rgba(255,255,255,0.85)}
.wheel-panel-stacks-total{display:flex;align-items:center;gap:7px;font-size:14px;font-weight:800;color:rgb(239,239,239)}
.wheel-panel-stacks-total img{width:16px;height:16px;object-fit:contain}
.wheel-panel-stacks-right{display:flex;align-items:center;gap:14px}
/* Mouse / keyboard input toggle: whichever side is active glows green, the other sits gray.
   Defaults to keyboard (switch on / knob right). */
.wheel-input-toggle{display:flex;align-items:center;gap:7px}
.wheel-input-icon{width:23px;height:23px;display:flex;align-items:center;justify-content:center;font-size:19px;color:rgba(255,255,255,0.35);transition:color .16s}
.wheel-input-toggle.keyboard .wheel-input-kb{color:rgb(170,222,78)}
.wheel-input-toggle.mouse .wheel-input-mouse{color:rgb(170,222,78)}
.wheel-input-switch{position:relative;width:26px;height:15px;flex-shrink:0;border-radius:8px;border:none;background:rgba(255,255,255,0.18);cursor:pointer;transition:background .16s;padding:0}
.wheel-input-switch-knob{position:absolute;top:2px;left:2px;width:11px;height:11px;border-radius:50%;background:#fff;transition:transform .18s cubic-bezier(.22,1,.36,1)}
.wheel-input-toggle.keyboard .wheel-input-switch-knob{transform:translateX(11px)}
.wheel-panel-amount-row{display:flex;align-items:center;gap:8px}
/* Same construction as .spinners-amount-input-wrap / .spinners-quick-btn on the Spinner Battles
   create panel — deliberately identical colors and behavior so the two amount controls read as
   the same component site-wide. */
.wheel-panel-amount-input-wrap{flex:1;height:42px;box-sizing:border-box;display:flex;align-items:center;gap:6px;padding:0 12px;border-radius:10px;border:1px solid rgba(255,255,255,0.08);background:rgba(255,255,255,0.03)}
.wheel-panel-amount-input-wrap img{width:20px;height:20px;object-fit:contain;flex-shrink:0}
.wheel-panel-amount-input-wrap input{flex:1;width:0;min-width:0;background:none;border:none;outline:none;color:#fff;font-size:13.5px;font-weight:600;font-family:var(--font)}
.wheel-panel-quick-btn{flex-shrink:0;height:42px;box-sizing:border-box;display:flex;align-items:center;justify-content:center;padding:0 12px;border-radius:10px;border:1px solid rgb(38,92,129);background:rgb(38,92,129);color:rgb(178,214,239);font-size:12.5px;font-weight:700;font-family:var(--font);cursor:pointer;transition:all .16s;white-space:nowrap}
.wheel-panel-quick-btn:hover{filter:brightness(1.15)}
.wheel-panel-hint{font-size:12.5px;line-height:1.5;color:rgb(140,194,231)}
/* Mouse-input mode: draggable scrap stacks replacing the amount textbox/quick buttons — a
   5-wide window over the denomination list, paged one step at a time by the edge arrows. */
.wheel-stacks-drag{position:relative}
.wheel-stacks-tiles{display:flex;gap:8px;min-width:0}
/* touch-action:none lets the pointer-drag engine own touch gestures on these — without it a
   finger-drag scrolls the page instead of moving scrap. No effect on mouse/PC. */
.wheel-stack-tile{position:relative;flex:1;aspect-ratio:1;border-radius:8px;background:rgba(255,255,255,0.05);cursor:grab;display:flex;align-items:center;justify-content:center;user-select:none;transition:background .15s;touch-action:none}
.wheel-stack-tile:hover{background:rgba(255,255,255,0.09)}
.wheel-stack-tile:active{cursor:grabbing}
.wheel-stack-tile img{width:86%;height:auto;pointer-events:none;filter:drop-shadow(0 2px 5px rgba(0,0,0,0.5))}
.wheel-stack-tile b{position:absolute;right:7%;bottom:6%;font-size:14px;font-weight:800;color:#fff;text-shadow:0 1px 3px rgba(0,0,0,0.9),0 0 6px rgba(0,0,0,0.7);pointer-events:none}
/* Bets locked: stacks read as simply disabled — faded out at their normal colors (no gloomy
   grayscale), untouchable until the next round's betting opens. */
.wheel-stacks-drag.locked .wheel-stack-tile{pointer-events:none;opacity:0.35}
/* Arrows float ON TOP of the outer tiles at the row's edges (not beside the row), so the tiles
   themselves stretch the full panel width. */
.wheel-stacks-arrow{position:absolute;top:50%;transform:translateY(-50%);z-index:2;display:flex;align-items:center;justify-content:center;width:30px;height:30px;border-radius:50%;border:none;background:rgba(20,20,20,0.85);color:rgba(255,255,255,0.8);cursor:pointer;transition:all .16s;box-shadow:0 2px 8px rgba(0,0,0,0.5)}
#wheelStacksLeft{left:-22px}
#wheelStacksRight{right:-22px}
.wheel-stacks-arrow:hover{background:rgba(45,45,45,0.95);color:#fff}
.wheel-stacks-arrow svg{width:17px;height:17px}
/* Floating drag ghost following the pointer during a custom (pointer-event-based) scrap drag —
   the native HTML5 drag API only works for left-click, and the Rust keybinds need right/middle
   drags too, so dragging is done manually with this element. */
/* Anchored at 0,0 and moved purely via transform (never left/top) — a transform on a
   will-change-promoted layer is composited on the GPU each frame, whereas left/top writes
   force style/layout work per pointermove, which is what made the drag feel laggy. Width is
   set at drag start from the real on-screen stack-tile image size so the ghost matches it. */
.wheel-drag-ghost{position:fixed;left:0;top:0;z-index:300;pointer-events:none;width:100px;opacity:0.9;will-change:transform}
.wheel-drag-ghost img{width:100%;height:auto;filter:drop-shadow(0 3px 8px rgba(0,0,0,0.6))}
.wheel-drag-ghost b{position:absolute;right:2%;bottom:2%;font-size:13px;font-weight:800;color:#fff;text-shadow:0 1px 3px rgba(0,0,0,0.9)}
/* While a scrap stack is being dragged: spotlight the number fields by dimming everything else
   DIRECTLY (a brightness filter on each major region) rather than sliding a full-screen shade
   over the page — .wrap keeps a filled CSS animation from page transitions, which makes it one
   sealed stacking context, so no overlay can ever sit between its layers: it either darkened
   the slots too (the bug this replaces) or nothing. The slots card itself is skipped by the
   selectors, gets a solid brighter fill, and its tiles a small brightness boost. */
body.wheel-dragging header,
body.wheel-dragging .wheel-main,
body.wheel-dragging .wheel-history,
body.wheel-dragging .wheel-panel>*:not(.wheel-panel-slots){filter:brightness(0.4)}
body.wheel-dragging .wheel-panel-slots{background:rgb(44,44,48);border-color:rgba(255,255,255,0.14)}
body.wheel-dragging .wheel-panel-slot{filter:brightness(1.1)}
/* Same green treatment as :hover, applied while a scrap stack is dragged over a slot. */
.wheel-panel-slot.dragover{transform:scale(1.015)}
.wheel-panel-slot.dragover .wheel-panel-slot-img::after{background:rgba(88,190,140,0.45);border-color:rgba(60,130,96,0.8);box-shadow:inset 0 0 10px rgba(88,190,140,0.6)}

.wheel-panel-players-row{display:flex;align-items:center;justify-content:space-between}
.wheel-panel-players{font-size:13px;font-weight:800;letter-spacing:.04em;color:rgb(232,120,105)}
.wheel-panel-players-total{display:flex;align-items:center;gap:4px;font-size:13px;font-weight:800;color:rgba(255,255,255,0.55)}
.wheel-panel-players-total img{width:15px;height:15px;object-fit:contain}
/* Bettor pfps under the players row — one circle per player in the round. min-height keeps the
   panel from shifting when the first bettor appears. */
.wheel-panel-bettors{display:flex;align-items:center;gap:5px;min-height:40px;margin-top:-8px}
/* No overflow:hidden here — the hover tooltip is a child and would get clipped; the item art
   (78%, contain-fit) never exceeds the circle anyway. */
.wheel-panel-bettor{position:relative;display:flex;align-items:center;justify-content:center;width:40px;height:40px;border-radius:50%;background:rgba(255,255,255,0.07);border:1px solid rgba(255,255,255,0.1);transition:transform .15s ease;cursor:pointer}
.wheel-panel-bettor:hover{transform:translateY(-4px)}
.wheel-panel-bettor>img{width:78%;height:78%;object-fit:contain}
/* Bettor hover tooltip: pfp + name + round total (players-strip red), then per-field colored
   squares with amounts. Same dark surface as the site's other tooltips/modals. */
.wheel-bettor-tooltip{position:absolute;bottom:calc(100% + 9px);left:50%;transform:translateX(-50%) translateY(4px);display:block;padding:9px 12px;border-radius:8px;background:rgba(9,9,9,0.98);border:1px solid rgba(255,255,255,0.1);box-shadow:0 10px 28px rgba(0,0,0,0.5);opacity:0;pointer-events:none;transition:opacity .16s ease,transform .16s ease;z-index:30;white-space:nowrap}
.wheel-panel-bettor:hover .wheel-bettor-tooltip{opacity:1;transform:translateX(-50%) translateY(0)}
.wheel-bettor-tooltip-head{display:flex;align-items:center;gap:7px}
.wheel-bettor-tooltip-pfp{width:20px;height:20px;object-fit:contain}
.wheel-bettor-tooltip-name{font-size:14.5px;font-weight:800;color:rgb(232,120,105)}
.wheel-bettor-tooltip-total{display:flex;align-items:center;gap:4px;margin-left:10px;font-size:14.5px;font-weight:800;color:rgb(232,120,105)}
.wheel-bettor-tooltip-total img{width:14px;height:14px;object-fit:contain}
/* margin-left centers the 10px squares under the 20px pfp above ((20-10)/2 = 5px). */
.wheel-bettor-tooltip-bets{display:flex;align-items:center;gap:11px;margin-top:7px;margin-left:5px}
.wheel-bettor-tooltip-bet{display:flex;align-items:center;gap:5px;font-size:12.5px;font-weight:700;color:#fff}
.wheel-bettor-tooltip-bet i{width:10px;height:10px;border-radius:2px;flex-shrink:0}
/* Entrance: starts collapsed into a negative margin (its own width + gap) and expands to full
   size — the expansion is what smoothly slides every circle after it to the right, instead of
   them all jumping a slot instantly. */
.wheel-panel-bettor.new{animation:wheelBettorIn .35s cubic-bezier(.22,1,.36,1) both}
/* margin-left is deliberately ABSENT from the "to" keyframe: with fill-mode both, an explicit
   end value would pin itself on the element forever — omitting it animates the margin from the
   collapsed start to the element's natural resting value. */
@keyframes wheelBettorIn{
  from{margin-left:-48px;opacity:0;transform:scale(.4)}
  to{opacity:1;transform:scale(1)}
}

/* ── Wheel of Fortune: mobile/tablet (≤1366px) — PC above this is untouched. 1366 covers every
   iPad including a 12.9" Pro in landscape; the side-by-side desktop layout needs ~1614px, so
   anything iPad-sized panned/zoomed around an oversized page before this. Must stay in sync
   with WHEEL_STACKED_MQ in script.js. ── */
@media (max-width:1366px){
  /* Tablet band: stays side by side like desktop, but wheel and panel share the viewport
     fluidly (wheel ~44vw, panel takes the rest) with a small gap instead of desktop's fixed
     700px + 250px + 600px that forced iPads to pan/zoom. Everything also runs compact:
     tighter paddings, smaller type. Phones (<=700px) stack instead — see below. */
  .wheel-layout{gap:24px;min-height:0;margin-top:14px}
  /* overflow:clip stops the ROTATED wheel image's bounding box (wider than the wrap — a turned
     square's box grows toward its diagonal) from widening the page. Only transparent corner
     pixels get clipped; the visible circle always fits the wrap. Mobile-gated so PC rendering
     is untouched. */
  .wheel-main-wrap{width:min(500px,44vw);overflow:clip}
  .wheel-main-arrow{width:clamp(56px,14%,90px);top:-14px}
  .wheel-panel{width:auto;flex:1 1 0;min-width:0;max-width:600px;gap:10px}
  .wheel-panel-title{font-size:17px}
  .wheel-panel-info{padding:10px 12px;gap:10px}
  .wheel-panel-info-icon{width:26px;height:26px}
  .wheel-panel-info p{font-size:14px}
  .wheel-panel-timer-info{padding:10px 12px}
  .wheel-panel-timer-label{font-size:14px}
  .wheel-panel-timer-info p{font-size:13.5px}
  .wheel-panel-timer-value{width:110px}
  .wheel-panel-timer-value span{font-size:26px}
  .wheel-panel-lock{font-size:24px}
  .wheel-panel-slots{padding:10px;gap:5px}
  .wheel-panel-stacks{padding:12px;gap:9px}
  /* The history strip can't hang off the panel's right edge when there's no side room — it
     becomes a horizontal row at the top of the panel (icon, then squares newest-first).
     positionWheelHistory in script.js skips its top/height measurements in this mode. */
  .wheel-history{position:static;width:100%;flex-direction:row;align-items:center;gap:8px;order:-1;top:auto!important;height:auto!important}
  .wheel-history-list{flex-direction:row;flex:1;height:16px;overflow:hidden;gap:5px}
  /* Amount input takes its own line so the four quick buttons never crush it on a phone. */
  .wheel-panel-amount-row{flex-wrap:wrap}
  .wheel-panel-amount-input-wrap{flex:1 1 100%}
}
@media (max-width:700px){
  /* Phones: side-by-side can't fit — wheel stacks above the panel. */
  .wheel-layout{flex-direction:column;align-items:center;gap:18px}
  .wheel-main-wrap{width:min(540px,90vw)}
  .wheel-panel{width:100%;flex:none}
}
@media (max-width:600px){
  .wheel-help-row{flex-direction:column}
  .wheel-help-row-flip .wheel-help-img{order:2}
  .wheel-help-img{width:100%;max-width:320px;align-self:center}
}

/* ── Wheel of Fortune: HOW TO PLAY modal ─────────────────────────────────── */
.wheel-help-backdrop{position:fixed;inset:0;z-index:210;display:flex;align-items:center;justify-content:center;background:rgba(4,4,6,0);backdrop-filter:blur(0px);-webkit-backdrop-filter:blur(0px);opacity:0;pointer-events:none;transition:opacity .3s ease,background .3s ease,backdrop-filter .3s ease}
.wheel-help-backdrop.open{opacity:1;pointer-events:auto;background:rgba(4,4,6,0.72);backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px)}
.wheel-help-modal{width:min(640px,92vw);max-height:88vh;overflow-y:auto;padding:30px 32px 26px;background:rgba(9,9,9,0.98);border:1px solid rgba(255,255,255,0.09);border-radius:18px;box-shadow:0 24px 64px rgba(0,0,0,0.55);transform:translateY(14px) scale(.96);opacity:0;transition:transform .32s cubic-bezier(.16,1,.3,1),opacity .28s ease}
.wheel-help-backdrop.open .wheel-help-modal{transform:translateY(0) scale(1);opacity:1}
.wheel-help-label{font-size:13px;font-weight:800;letter-spacing:.06em;color:rgb(63,153,215)}
.wheel-help-title{margin-top:4px;font-size:26px;font-weight:800;color:rgb(255,255,255);letter-spacing:.01em}
.wheel-help-intro{margin-top:12px;font-size:15.5px;line-height:1.55;color:rgba(255,255,255,0.7)}
.wheel-help-row{display:flex;align-items:flex-start;gap:22px;margin-top:26px}
.wheel-help-img{width:220px;height:auto;flex-shrink:0;border-radius:10px}
.wheel-help-text{flex:1;min-width:0}
.wheel-help-text h3{font-size:17px;font-weight:800;color:rgb(101,173,223)}
.wheel-help-text p{margin-top:8px;font-size:14.5px;line-height:1.55;color:rgba(255,255,255,0.7)}
.wheel-help-text b{color:rgba(255,255,255,0.9)}
.wheel-help-link{color:rgb(170,222,78) !important;font-weight:600;cursor:pointer;font-size:12.5px !important}
.wheel-help-ok-btn{width:100%;margin-top:28px;padding:15px;border-radius:8px;border:none;background:rgb(92,122,42);color:rgb(170,222,78);font-size:15px;font-weight:800;letter-spacing:.03em;font-family:var(--font);cursor:pointer;transition:filter .16s}
.wheel-help-ok-btn:hover{filter:brightness(1.12)}

/* ── Case Battles ─────────────────────────────────────────────────────────── */
.battles-header{display:flex;align-items:center;justify-content:space-between;gap:20px;flex-wrap:wrap;margin-top:36px;margin-bottom:22px}
.battles-title{font-size:24px;font-weight:800;color:#fff;letter-spacing:.01em}
.battles-sub{margin-top:5px;font-size:16px;color:rgba(255,255,255,0.62)}
.battles-controls{display:flex;align-items:center;gap:11px;flex-shrink:0}
/* Matches the upgrader's ready state so the primary action reads the same site-wide. */
/* The shared .dd-menu has a 200px min-width for the cases sort labels. Here the menu should
   line up with its own trigger instead, so that floor is dropped and the width is pinned to
   the dropdown wrapper (which is sized by the button). */
#battleShowMenu{min-width:0;width:auto;left:0;right:0}
.create-battle-btn{flex-shrink:0;padding:11px 20px;border-radius:11px;border:1px solid #66852F;background:#66852F;color:#DDF2B8;font-size:13.5px;font-weight:800;letter-spacing:.02em;font-family:var(--font);cursor:pointer;transition:all .16s;white-space:nowrap}
.create-battle-btn:hover{background:#75993a;border-color:#75993a}

/* ── Battles browse list ──────────────────────────────────────────────────── */
.battles-list{display:flex;flex-direction:column;gap:10px;margin-bottom:40px}
.battles-empty{display:none;padding:60px 20px;text-align:center;color:rgba(255,255,255,0.45);font-size:15px}
.battle-card{display:flex;align-items:center;gap:22px;padding:14px 18px;border-radius:14px;border:1px solid rgba(255,255,255,0.06);background:rgba(255,255,255,0.02);animation:fadeIn .35s ease both}
/* Fixed width (not a min-width) so this column is identical on every card — otherwise a long
   title like "Cursed 1v1v1v1 Jackpot" grows the column and pushes that card's case icons
   further right than a plain "1v1 Battle" card's, breaking the row-to-row alignment. */
.battle-card-left{display:flex;flex-direction:column;gap:10px;flex-shrink:0;width:min(230px,100%)}
.battle-card-total{display:flex;align-items:center;gap:7px;flex-wrap:wrap}
.battle-card-total .scrap-icon{width:15px;height:15px;flex-shrink:0}
.battle-card-total-amt{font-size:15px;font-weight:800;color:#fff;flex-shrink:0}
/* Title truncates instead of wrapping/overflowing so it can't push the fixed-width column
   (and therefore the case icons after it) out of alignment. */
.battle-card-title{display:inline-flex;align-items:center;gap:5px;font-size:14px;font-weight:800;color:rgba(255,255,255,0.85);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}
.battle-card-title span{color:inherit;overflow:hidden;text-overflow:ellipsis}
.battle-card-title-icon{width:14px;height:14px;flex-shrink:0}
.battle-card-slots{display:flex;align-items:center;flex-wrap:wrap;row-gap:6px}
.battle-card-slot{display:flex;align-items:center;justify-content:center;height:30px;padding:0 10px;border-radius:7px;font-size:11.5px;font-weight:700;border-bottom:2px solid rgba(255,255,255,0.12);background:rgba(255,255,255,0.03)}
.battle-card-slot.filled{background:rgba(255,255,255,0.05)}
.battle-card-slot-name{color:rgba(255,255,255,0.85);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:90px}
/* Team modes only ever use p-0/p-1 (team vs team, red vs green). Regular modes (no teams) use
   all four — one distinct color per player slot, red/green/blue/purple in join order. */
.battle-card-slot.p-0{border-bottom-color:rgb(224,90,80)}
.battle-card-slot.p-1{border-bottom-color:rgb(120,205,145)}
.battle-card-slot.p-2{border-bottom-color:rgb(90,160,224)}
.battle-card-slot.p-3{border-bottom-color:rgb(178,120,224)}
.battle-card-slot-vs{display:flex;align-items:center;justify-content:center;padding:0 8px;font-size:11px;font-weight:700;color:rgba(255,255,255,0.4);flex-shrink:0}
.battle-card-cases{display:flex;align-items:center;gap:8px;flex:1;overflow:hidden}
.battle-card-case{position:relative;display:flex;align-items:center;justify-content:center;width:68px;height:68px;flex-shrink:0}
.battle-card-case img{width:100%;height:100%;object-fit:contain;filter:drop-shadow(0 3px 8px rgba(0,0,0,0.5))}
.battle-card-case-qty{position:absolute;right:-2px;bottom:-2px;min-width:18px;height:18px;padding:0 4px;border-radius:9px;background:rgba(0,0,0,0.72);border:1px solid rgba(255,255,255,0.12);display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:800;color:#fff}
.battle-card-right{display:flex;align-items:center;gap:14px;flex-shrink:0}
.battle-card-rounds{font-size:13px;font-weight:700;color:rgba(255,255,255,0.55);white-space:nowrap}
.battle-card-eye-btn{width:38px;height:38px;flex-shrink:0;display:flex;align-items:center;justify-content:center;border-radius:9px;border:1px solid rgba(255,255,255,0.08);background:rgba(255,255,255,0.03);color:rgba(255,255,255,0.55);cursor:pointer;transition:all .16s}
.battle-card-eye-btn:hover{color:rgba(255,255,255,0.85);border-color:rgba(255,255,255,0.16);background:rgba(255,255,255,0.05)}
.battle-card-eye-btn svg{width:17px;height:17px}
.battle-card-join-btn{flex-shrink:0;padding:11px 18px;border-radius:9px;border:1px solid #66852F;background:#66852F;color:#DDF2B8;font-size:12.5px;font-weight:800;letter-spacing:.02em;font-family:var(--font);cursor:pointer;transition:all .16s;white-space:nowrap}
.battle-card-join-btn:hover{background:#75993a;border-color:#75993a}
@media (max-width:820px){
  .battle-card{flex-wrap:wrap}
  .battle-card-cases{order:3;width:100%;margin-top:4px}
  .battle-card-right{order:2;margin-left:auto}
}
@media (max-width:480px){
  .battle-card-left{width:100%}
  .battle-card-right{width:100%;margin-left:0;justify-content:space-between}
  .battle-card-join-btn{flex:1}
}

/* ── Crate Battle setup ────────────────────────────────────────────────────── */
/* Constrained to the same 880px block as the config below, so the back button lines up with
   the left edge of the cards instead of the page. */
.battle-create-bar{position:relative;display:flex;align-items:center;max-width:880px;margin:34px auto 38px}
.battle-create-bar .case-detail-back{position:absolute;left:0;margin-top:0;margin-right:0}
.battle-create-title{flex:1;text-align:center;font-size:24px;font-weight:800;color:#fff;letter-spacing:.01em}
/* Battle lobby bar — same back-button-pinned-left layout as the create bar, but the center
   slot holds a title+modifier-list stack instead of just a title, and the right side gets its
   own icon-button cluster instead of nothing. */
.battle-lobby-bar{justify-content:center}
.battle-lobby-heading .battle-create-title{font-size:20px}
.battle-lobby-heading{flex:1;display:flex;flex-direction:column;align-items:center;gap:10px}
.battle-lobby-modifiers{display:flex;align-items:center;gap:10px;flex-wrap:wrap;justify-content:center}
.battle-lobby-modifier{display:flex;align-items:center;gap:4px;font-size:13px;font-weight:700}
.battle-lobby-modifier svg{width:15px;height:15px;flex-shrink:0}
.battle-lobby-actions{position:absolute;right:0;display:flex;align-items:center;gap:6px}

/* Info bar — TOTAL cost on the left, the rounds pill (case art background) centered, spectator
   count on the right. Same 880px column as the rest of the create/lobby content. A plain flex
   row with justify-content:space-between only centers the pill when the TOTAL and spectator
   blocks happen to be the same width — a 3-column grid with the pill in the middle column
   keeps it centered on the page regardless of how wide either side block is. */
.battle-lobby-info{display:grid;grid-template-columns:1fr auto 1fr;align-items:center;max-width:880px;margin:0 auto;padding:0 4px}
.battle-lobby-info>.battle-lobby-rounds-pill{justify-self:center}
.battle-lobby-info>.battle-lobby-spectators{justify-self:end}
.battle-lobby-total{display:flex;align-items:center;gap:7px;font-size:14px;font-weight:700;color:rgba(255,255,255,0.85)}
.battle-lobby-info-label{font-size:12px;font-weight:800;letter-spacing:.08em;color:rgba(255,255,255,0.5)}
.battle-lobby-total img{width:16px;height:16px;object-fit:contain}
.battle-lobby-spectators{display:flex;align-items:center;gap:6px;font-size:14px;font-weight:700;color:rgba(255,255,255,0.75)}
.battle-lobby-spectators svg{width:17px;height:17px;flex-shrink:0}

.battle-lobby-rounds-pill{position:relative;width:min(330px,100%);height:60px;border-radius:14px;overflow:hidden;background:rgba(255,255,255,0.04);border:1px solid rgba(255,255,255,0.08);display:flex;align-items:center;justify-content:flex-end;padding:0 14px}
/* One small icon per distinct case, left-aligned and vertically centered in the pill, then
   faded out toward the pill's bottom edge — a much smaller/cropped version of what it looked
   like when a single oversized image bled off the top of the pill. */
.battle-lobby-rounds-art{position:absolute;left:14px;top:0;bottom:0;display:flex;align-items:center;gap:6px;-webkit-mask-image:linear-gradient(to bottom, #000 70%, transparent 96%);mask-image:linear-gradient(to bottom, #000 70%, transparent 96%)}
.battle-lobby-rounds-art img{width:44px;height:44px;object-fit:contain;filter:drop-shadow(0 3px 8px rgba(0,0,0,0.5))}
.battle-lobby-rounds-count{position:relative;z-index:2;font-size:13px;font-weight:800;color:#fff;text-shadow:0 1px 4px rgba(0,0,0,0.6)}
.battle-section-title{max-width:880px;margin-left:auto;margin-right:auto;margin-top:76px;font-size:14px;font-weight:800;letter-spacing:.09em;color:rgba(255,255,255,0.92)}
.battle-section-sub{max-width:880px;margin-left:auto;margin-right:auto;margin-top:6px;font-size:15px;color:rgba(255,255,255,0.6)}
/* Three equal columns, but the row is capped below the full page width so the cards aren't
   stretched far wider than the icon + toggles they hold. */
.battle-modes{display:grid;grid-template-columns:repeat(3,1fr);gap:14px;margin-top:20px;max-width:880px;margin-left:auto;margin-right:auto}
.battle-mode-group{display:flex;align-items:center;gap:14px;padding:16px;border:1px solid rgba(255,255,255,0.07);border-radius:13px;background:rgba(255,255,255,0.02)}
.battle-mode-body{flex:1;min-width:0}
.battle-mode-name{font-size:15px;font-weight:700;color:#fff}
/* The source icons are light, so a red drop-shadow under a fully-offset image recolours them
   without needing a second asset per state. */
.battle-mode-icon{width:40px;height:40px;object-fit:contain;flex-shrink:0;filter:brightness(0) invert(1);transition:filter .16s}
.battle-mode-group.has-selection .battle-mode-icon{filter:brightness(0) saturate(100%) invert(28%) sepia(46%) saturate(1512%) hue-rotate(331deg) brightness(93%) contrast(92%)}
.battle-mode-opts{display:flex;gap:7px;margin-top:9px}
.battle-mode-opt{padding:7px 12px;border-radius:10px;border:1px solid rgba(255,255,255,0.08);background:rgba(255,255,255,0.03);color:rgba(255,255,255,0.65);font-size:13px;font-weight:700;font-family:var(--font);cursor:pointer;transition:all .16s;white-space:nowrap}
.battle-mode-opt:hover{color:#fff;border-color:rgba(255,255,255,0.18);background:rgba(255,255,255,0.06)}
.battle-mode-opt.selected{background:#8C3A32;border-color:#8C3A32;color:#F3D3D0}

/* ── Add battle rounds ─────────────────────────────────────────────────────── */
.battle-rounds-bar{display:flex;align-items:center;justify-content:space-between;gap:20px;max-width:880px;margin:44px auto 0}
/* The shared .battle-section-title centres itself inside the 880px block; here it sits at the
   start of a flex row instead, so those auto margins have to be cleared. */
.battle-rounds-title{margin:0;max-width:none}
.battle-rounds-title-cost{font-weight:600;letter-spacing:normal;color:rgba(255,255,255,0.55);display:inline-flex;align-items:center;gap:4px}
.battle-rounds-title-cost img{width:13px;height:13px;object-fit:contain}
.battle-toggle{display:flex;align-items:center;gap:11px;padding:0;border:none;background:none;cursor:pointer;font-family:var(--font)}
.battle-toggle-label{font-size:12.5px;font-weight:800;letter-spacing:.09em;color:rgba(255,255,255,0.6)}
.battle-toggle-track{position:relative;width:46px;height:25px;flex-shrink:0;border-radius:999px;background:rgba(255,255,255,0.13);transition:background .22s ease}
.battle-toggle-dot{position:absolute;top:3px;left:3px;width:19px;height:19px;border-radius:50%;background:rgba(255,255,255,0.75);transition:transform .22s cubic-bezier(.22,1,.36,1),background .22s ease}
.battle-toggle.on .battle-toggle-track{background:#3F6B2B}
.battle-toggle.on .battle-toggle-dot{transform:translateX(21px);background:#A6E05F}
.modifier-card .modifier-toggle.on .battle-toggle-track{background:color-mix(in srgb, var(--mc) 35%, transparent)}
.modifier-card .modifier-toggle.on .battle-toggle-dot{background:var(--mc)}
#customSortingToggle .battle-toggle-track{width:41.7px;height:22.7px}
#customSortingToggle .battle-toggle-dot{width:17.2px;height:17.2px}
#customSortingToggle.on .battle-toggle-dot{transform:translateX(19px)}
.battle-rounds-grid{display:grid;grid-template-columns:repeat(5,1fr);gap:12px;max-width:880px;margin:16px auto 0}
/* Same lift-on-hover as the case cards on /cases, so the two grids feel like one system. */
.battle-add-crate{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:14px;min-height:240.75px;padding:16px;border-radius:12px;border:1px solid rgba(255,255,255,0.08);background:rgba(255,255,255,0.03);cursor:pointer;font-family:var(--font);transition:transform .6s cubic-bezier(.16,1,.3,1),border-color .3s ease,background .3s ease}
.battle-add-crate:hover{transform:translateY(-3px);border-color:rgba(255,255,255,0.18);background:rgba(255,255,255,0.05)}
.battle-add-crate-box{display:flex;align-items:center;justify-content:center;width:68px;height:68px;border:2px dashed rgba(255,255,255,0.28);border-radius:8px;transition:border-color .3s ease}
.battle-add-crate:hover .battle-add-crate-box{border-color:rgba(255,255,255,0.45)}
/* The source PNG is a blue plus on transparency. A light-blue disc is painted behind it via the
   parent, and the glyph itself is knocked down to near-black — filtering the img alone would
   invert its own background too. */
.battle-add-crate-icon{display:flex;align-items:center;justify-content:center;width:39px;height:39px;border-radius:50%;background:#A9D4F5}
.battle-add-crate-icon img{width:23px;height:23px;object-fit:contain;filter:brightness(0)}
.battle-add-crate-label{margin-top:3px;font-size:12.5px;font-weight:800;letter-spacing:.05em;color:#4A9FE0}

.battle-round-card{--glow:120,205,145;position:relative;display:flex;flex-direction:column;align-items:center;padding:10px 8px 12px;border-radius:12px;border:1px solid rgba(255,255,255,0.045);background:rgba(255,255,255,0.008);cursor:pointer;box-sizing:border-box;transition:transform .3s cubic-bezier(.16,1,.3,1),border-color .3s ease,background .3s ease}
.battle-round-card:hover{transform:translateY(-3px);border-color:rgba(255,255,255,0.14);background:rgba(255,255,255,0.02);z-index:2}
.battle-round-card-preview{position:absolute;top:2px;left:2px;width:26px;height:26px;display:flex;align-items:center;justify-content:center;color:rgba(255,255,255,0.75);opacity:0;transition:opacity .15s;z-index:5;pointer-events:none}
.battle-round-card:hover .battle-round-card-preview{opacity:1}
.battle-round-card-preview svg{width:16px;height:16px}
.battle-round-card-name{font-size:14.5px;font-weight:600;color:rgba(255,255,255,0.85);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;text-align:center;width:100%}
.battle-round-card-price{display:flex;align-items:center;justify-content:center;gap:5px;font-size:13px;font-weight:600;color:rgba(255,255,255,0.6);margin-top:6px}
.battle-round-card-price img{width:14px;height:14px;object-fit:contain}
.battle-round-card-art{width:100%;aspect-ratio:4/3;display:flex;align-items:center;justify-content:center;position:relative;margin-top:8px}
.battle-round-card-art img{width:78%;height:78%;object-fit:contain;filter:drop-shadow(0 0 0 rgba(var(--glow),0));transition:filter .5s ease}
.battle-round-card:hover .battle-round-card-art img{filter:drop-shadow(0 0 14px rgba(var(--glow),0.55))}
.battle-round-card-slider{position:relative;width:75%;height:4px;display:flex;gap:3px;margin-top:8px}
.battle-round-card-slider .seg{flex:1;height:100%;border-radius:3px;background:rgba(255,255,255,0.12)}
.battle-round-card-slider .seg.lit:nth-child(1){background:rgb(120,205,145)}
.battle-round-card-slider .seg.lit:nth-child(2){background:rgb(240,160,55)}
.battle-round-card-slider .seg.lit:nth-child(3){background:rgb(235,80,70)}
.battle-round-card-slider .pin{position:absolute;top:-2.5px;width:3px;height:9px;border-radius:2px;background:#fff;transform:translateX(-50%)}
.battle-round-card-qty{display:flex;align-items:center;justify-content:center;gap:10px;width:75%;margin-top:10px}
.battle-round-card-remove{display:flex;align-items:center;justify-content:center;gap:8px;width:75%;margin-top:10px;padding:9px 8px;border-radius:9px;border:1px solid rgba(255,255,255,0.06);background:rgba(255,255,255,0.04);color:rgb(235,140,130);font-size:12.5px;font-weight:800;font-family:var(--font);letter-spacing:.02em;cursor:pointer;transition:background .15s ease}
.battle-round-card-remove:hover{background:rgba(255,255,255,0.07)}
.battle-round-card-remove svg{width:15px;height:15px;flex-shrink:0}
.battle-round-card-menu{position:absolute;top:2px;right:2px;width:26px;height:26px;display:flex;align-items:center;justify-content:center;color:rgba(255,255,255,0.55);z-index:5}
.battle-round-card-menu svg{width:16px;height:16px}
.battle-round-card[data-unit]{cursor:grab}
/* Custom sorting cards skip the hover lift/border/background highlight the grouped cards
   use — with drag-to-reorder in play, that highlight fighting for the same visual space as
   the drag interaction read as noisy rather than useful. */
.battle-round-card[data-unit]:hover{transform:none;border-color:rgba(255,255,255,0.045);background:rgba(255,255,255,0.008)}
/* SortableJS's own class names — it toggles these itself, styling is on us. .ghost is the
   placeholder left in the list at the drop position; .sortable-chosen is the original card
   being dragged. */
.battle-round-card.ghost{opacity:0.35;background:rgba(255,255,255,0.03)}
.battle-round-card.sortable-chosen{cursor:grabbing}

/* ── Battle modifiers ──────────────────────────────────────────────────────── */
.modifiers-title{max-width:880px;margin:44px auto 0}
.modifiers-grid{display:grid;grid-template-columns:repeat(2,1fr);grid-auto-rows:min-content;align-items:start;gap:14px;max-width:880px;margin:16px auto 0}
.modifier-card{display:flex;align-items:center;gap:14px;padding:16px 18px;border-radius:13px;border:1px solid rgba(255,255,255,0.08);background:rgba(255,255,255,0.03);cursor:pointer;transition:transform .6s cubic-bezier(.16,1,.3,1),border-color .3s ease,background .3s ease,opacity .22s ease,scale .22s ease}
.modifier-card-hiding{opacity:0;scale:.94;pointer-events:none}
.modifier-card-hidden{display:none}
.battle-create-submit-bar{max-width:880px;margin:24px auto 0;display:flex;justify-content:flex-end;gap:12px}
.battle-share-setup-btn{display:none;margin-right:auto;padding:16px 32px;border-radius:12px;border:1px solid rgba(74,143,217,0.3);background:#265c81;color:#b2d6ef;font-size:15px;font-weight:800;letter-spacing:.02em;font-family:var(--font);cursor:pointer;transition:background .16s}
.battle-share-setup-btn.visible{display:inline-flex}
.battle-share-setup-btn:hover{background:#2d6c98}
.battle-create-total{display:none;align-items:center;justify-content:center;gap:8px;padding:16px 20px;border-radius:12px;border:1px solid rgba(255,255,255,0.08);background:rgba(255,255,255,0.05);font-size:15px;font-weight:700;color:rgba(255,255,255,0.75)}
.battle-create-total.visible{display:flex}
.battle-create-total img{width:18px;height:18px;object-fit:contain}
.battle-create-submit-btn{padding:16px 32px;border-radius:12px;border:1px solid rgba(255,255,255,0.08);background:rgba(255,255,255,0.05);color:rgba(255,255,255,0.4);font-size:15px;font-weight:800;letter-spacing:.02em;font-family:var(--font);cursor:default;transition:all .16s}
.battle-create-submit-btn.ready{cursor:pointer;background:#66852F;border-color:#66852F;color:#DDF2B8}
.battle-create-submit-btn.ready:hover{background:#75993a}
.modifiers-grid.group-unbox-order [data-modifier-order="private"]{order:1}
.modifiers-grid.group-unbox-order [data-modifier-order="fast"]{order:2}
.modifiers-grid.group-unbox-order [data-modifier-order="partialfunding"]{order:3}
.modifiers-grid.group-unbox-order [data-modifier-order="banditspins"]{order:4}
.modifier-card-expandable{display:block;cursor:default}
.modifier-card-row{display:flex;align-items:center;gap:14px;cursor:pointer}
.modifier-pct{font-size:19px;font-weight:800;color:var(--mc);width:44px;text-align:right;opacity:0;white-space:nowrap;transition:opacity .3s ease}
.modifier-card-expandable.expanded .modifier-pct{opacity:1}
.modifier-card-expand{max-height:0;overflow:hidden;will-change:max-height;contain:layout;transition:max-height .38s cubic-bezier(.16,1,.3,1)}
.modifier-card-expand-inner{padding-top:20px}
.modifier-slider{--fill:50%;width:100%;appearance:none;height:6px;border-radius:999px;background:linear-gradient(to right, rgba(255,255,255,0.85) 0%, rgba(255,255,255,0.85) var(--fill), rgba(255,255,255,0.13) var(--fill), rgba(255,255,255,0.13) 100%);cursor:pointer;outline:none}
.modifier-slider::-webkit-slider-thumb{appearance:none;width:7px;height:20px;border-radius:3.5px;background:var(--mc);cursor:pointer}
.modifier-slider::-moz-range-thumb{width:7px;height:20px;border:none;border-radius:3.5px;background:var(--mc);cursor:pointer}
.modifier-slider::-moz-range-progress{height:6px;border-radius:999px;background:rgba(255,255,255,0.85)}
.modifier-slider::-moz-range-track{height:6px;border-radius:999px;background:rgba(255,255,255,0.13)}
.modifier-sub-row{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-top:18px}
.modifier-sub-title{font-size:14.5px;font-weight:700;color:rgba(255,255,255,0.92)}
.modifier-sub-desc{margin-top:3px;font-size:13px;line-height:1.4;color:rgba(255,255,255,0.5)}
.level-stepper{display:flex;align-items:center;gap:8px;flex-shrink:0}
.level-stepper-btn{width:26px;height:26px;border-radius:50%;border:none;background:rgba(255,255,255,0.1);color:rgba(255,255,255,0.8);font-size:16px;font-weight:700;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:background .15s ease}
.level-stepper-btn:hover{background:rgba(255,255,255,0.18)}
.level-stepper-input{width:64px;height:32px;border-radius:8px;border:none;background:#1b2420;color:#fff;font-size:13px;font-weight:700;text-align:center;font-family:var(--font)}
.level-stepper-input:focus{outline:2px solid var(--mc)}
.modifier-card:hover{transform:translateY(-3px);border-color:rgba(255,255,255,0.18);background:rgba(255,255,255,0.05)}
.modifier-icon{display:flex;align-items:center;justify-content:center;width:50px;height:50px;flex-shrink:0;color:var(--mc)}
.modifier-icon svg{width:32px;height:32px}
.modifier-icon svg .fa-secondary{opacity:.4}
.modifier-body{flex:1;min-width:0}
.modifier-title{font-size:14.5px;font-weight:700}
.modifier-desc{margin-top:3px;font-size:13px;line-height:1.4;color:rgba(255,255,255,0.5)}
.modifier-toggle{flex-shrink:0}
.modifier-min-rounds{display:none;flex-shrink:0;font-size:12.5px;font-weight:600;color:rgba(255,255,255,0.4);white-space:nowrap}
.modifier-card.locked .modifier-toggle{display:none}
.modifier-card.locked .modifier-min-rounds{display:block}

/* ── Add-crate modal ───────────────────────────────────────────────────────── */
.crate-modal-backdrop{position:fixed;inset:0;z-index:200;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,0);backdrop-filter:blur(0px);-webkit-backdrop-filter:blur(0px);opacity:0;pointer-events:none;transition:opacity .28s ease,background .28s ease,backdrop-filter .28s ease}
.crate-modal-backdrop.open{opacity:1;pointer-events:auto;background:rgba(0,0,0,0.6);backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px)}
.crate-modal{width:min(1100px,92vw);max-height:92vh;display:flex;flex-direction:column;background:rgba(9,9,9,0.98);border:1px solid rgba(255,255,255,0.08);border-radius:18px;box-shadow:0 24px 64px rgba(0,0,0,0.6);padding:22px 22px 18px;transform:translateY(18px) scale(.97);opacity:0;transition:transform .28s cubic-bezier(.16,1,.3,1),opacity .28s ease}
.crate-modal-backdrop.open .crate-modal{transform:translateY(0) scale(1);opacity:1}
.crate-modal-topbar{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.crate-modal-topbar .filter-chips{display:flex;align-items:center;gap:8px;flex-wrap:wrap;flex:1}
.crate-modal-search{max-width:220px;margin:0}
.crate-modal-search input{padding:9px 15px 9px 40px;border-radius:11px;font-size:13px}
.crate-modal-search .search-ico{width:15px;height:15px;left:15px}
.crate-modal-grid{height:calc(3 * var(--crate-row-h, 246px));max-height:100%;min-height:0;overflow-y:auto;overscroll-behavior:contain;scrollbar-width:none;-ms-overflow-style:none;margin-top:12px;padding:6px 0 0;will-change:scroll-position;transform:translateZ(0);contain:layout style paint}
.crate-modal-grid::-webkit-scrollbar{display:none}
.crate-modal-spacer{display:grid;grid-template-columns:repeat(6,1fr);gap:10px}
.crate-modal-card{--glow:120,205,145;display:flex;flex-direction:column;align-items:center;background:rgba(255,255,255,0.008);border:1px solid rgba(255,255,255,0.045);border-radius:12px;padding:10px 8px 12px;position:relative;transition:transform .3s cubic-bezier(.16,1,.3,1),border-color .3s ease,background .3s ease;box-sizing:border-box;animation:fadeIn .4s ease both;contain:content}
.crate-modal-card:hover{transform:translateY(-3px);border-color:rgba(255,255,255,0.1);background:rgba(255,255,255,0.02);z-index:2}
.crate-modal-card.selected{border-color:rgba(255,255,255,0.35)}
.crate-modal-card-fav{position:absolute;top:6px;right:6px;width:24px;height:24px;background:none;border:none;display:flex;align-items:center;justify-content:center;cursor:pointer;opacity:0;transition:opacity .15s;z-index:5}
.crate-modal-card:hover .crate-modal-card-fav{opacity:1}
.crate-modal-card-fav.active{opacity:1}
.crate-modal-card-fav svg{width:18px;height:18px;color:rgba(255,255,255,0.55);transition:color .15s;filter:drop-shadow(0 1px 2px rgba(0,0,0,0.8))}
.crate-modal-card-fav:hover svg{color:rgba(255,255,255,0.9)}
.crate-modal-card-fav.active svg{color:rgb(255,165,80);fill:rgb(255,165,80)}
.crate-modal-card-name{order:1;font-size:14.5px;font-weight:600;color:rgba(255,255,255,0.85);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;text-align:center;width:100%}
.crate-modal-card-price{order:2;display:flex;align-items:center;justify-content:center;gap:5px;font-size:13px;font-weight:600;color:rgba(255,255,255,0.6);margin-top:6px}
.crate-modal-card-price img{width:14px;height:14px;object-fit:contain}
.crate-modal-card .case-art{order:3;width:100%;aspect-ratio:4/3;display:flex;align-items:center;justify-content:center;position:relative;border-radius:8px;margin-top:8px}
.crate-modal-card .case-glow{display:none}
.crate-modal-card .case-art img{position:relative;z-index:1;width:78%;height:78%;object-fit:contain;filter:drop-shadow(0 0 0 rgba(var(--glow),0));transition:filter .5s ease}
.crate-modal-card:hover .case-art img{filter:drop-shadow(0 0 14px rgba(var(--glow),0.55))}
.crate-modal-card-slider{order:4;position:relative;width:75%;height:4px;display:flex;gap:3px;margin-top:8px}
.crate-modal-card-slider .seg{flex:1;height:100%;border-radius:3px;background:rgba(255,255,255,0.12)}
.crate-modal-card-slider .seg.lit:nth-child(1){background:rgb(120,205,145)}
.crate-modal-card-slider .seg.lit:nth-child(2){background:rgb(240,160,55)}
.crate-modal-card-slider .seg.lit:nth-child(3){background:rgb(235,80,70)}
.crate-modal-card-slider .pin{position:absolute;top:-2.5px;width:3px;height:9px;border-radius:2px;background:#fff;transform:translateX(-50%)}
.crate-modal-card-actions{order:5;display:flex;align-items:center;justify-content:center;gap:6px;width:75%;margin-top:10px}
.crate-modal-card-add{flex:1;display:flex;align-items:center;justify-content:center;gap:6px;height:32px;border-radius:8px;border:none;background:#3F6B2B;color:#DDF2B8;font-size:12.5px;font-weight:800;font-family:var(--font);cursor:pointer;transition:background .15s ease}
.crate-modal-card-add:hover{background:#4c8034}
.crate-modal-card-add svg{width:16px;height:16px}
.crate-modal-card-preview{width:32px;height:32px;flex-shrink:0;display:flex;align-items:center;justify-content:center;border-radius:8px;border:1px solid rgba(255,255,255,0.1);background:rgba(255,255,255,0.05);color:rgba(255,255,255,0.7);cursor:pointer;transition:background .15s ease}
.crate-modal-card-preview:hover{background:rgba(255,255,255,0.1)}
.crate-modal-card-preview svg{width:16px;height:16px}
.crate-modal-card-qty{display:none;align-items:center;justify-content:center;gap:10px;width:100%}
.crate-modal-card.selected .crate-modal-card-qty{display:flex}
.crate-modal-card.selected .crate-modal-card-add,.crate-modal-card.selected .crate-modal-card-preview{display:none}
.crate-modal-qty-btn{display:flex;align-items:center;justify-content:center;width:32px;height:32px;flex-shrink:0;border-radius:8px;border:none;background:none;cursor:pointer;transition:opacity .15s ease}
.crate-modal-qty-minus{color:rgb(220,90,80)}
.crate-modal-qty-minus:hover{opacity:.75}
.crate-modal-qty-plus{color:rgb(80,150,220)}
.crate-modal-qty-plus:hover{opacity:.75}
.crate-modal-qty-btn svg{width:16px;height:16px}
.crate-modal-qty-value{font-size:14px;font-weight:800;color:#fff;min-width:26px;text-align:center}
.crate-modal-footer{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-top:6px;padding-top:14px}
.crate-modal-count{display:flex;align-items:center;gap:6px;font-size:14px;font-weight:600;color:rgba(255,255,255,0.75)}
.crate-modal-count img{width:16px;height:16px;object-fit:contain}
.crate-modal-footer-btns{display:flex;align-items:center;gap:10px}
.crate-modal-cancel-btn{padding:11px 24px;border-radius:11px;border:1px solid rgba(220,90,80,0.4);background:rgba(220,90,80,0.14);color:rgb(235,140,130);font-size:13px;font-weight:800;font-family:var(--font);cursor:pointer;transition:background .15s ease}
.crate-modal-cancel-btn:hover{background:rgba(220,90,80,0.22)}
.crate-modal-add-btn{padding:13px 28px;border-radius:11px;border:1px solid rgba(255,255,255,0.08);background:rgba(255,255,255,0.05);color:rgba(255,255,255,0.4);font-size:14px;font-weight:800;font-family:var(--font);cursor:default;transition:all .15s ease;white-space:nowrap}
.crate-modal-add-btn.ready{cursor:pointer;background:#66852F;border-color:#66852F;color:#DDF2B8}
.crate-modal-add-btn.ready:hover{background:#75993a}
@media (max-width:1300px){.crate-modal-spacer{grid-template-columns:repeat(4,1fr)}}
@media (max-width:700px){.crate-modal-spacer{grid-template-columns:repeat(2,1fr)}}

/* ── Case preview modal (opened from the magnifier icon on a round card) ─────────────────── */
.case-preview-modal{position:relative;width:min(720px,92vw);max-height:85vh;overflow-y:auto;padding:32px;gap:0}
.case-preview-modal .case-detail-heading{flex-direction:row;align-items:center;justify-content:flex-start;gap:14px;margin-bottom:8px}
.case-preview-modal .case-detail-art{width:76px;height:76px;flex-shrink:0}
.case-preview-modal .case-detail-name-wrap{display:flex;flex-direction:column;align-items:flex-start;gap:6px}
.case-preview-modal .case-detail-name{text-align:left}
.case-preview-modal .case-price{margin:0;width:auto;justify-content:flex-start;background:none;border:none;padding:0}
.case-preview-modal .case-items-section{max-width:none;margin:28px 0 0}
/* Item cards ~10% smaller than the case-detail page's version (padding, image, and text all
   scaled down together), gap tightened from 12px to 10px to match. */
.case-preview-modal .case-items-grid{grid-template-columns:repeat(4,1fr);gap:10px}
.case-preview-modal .case-item-card{padding:13px 9px 14px}
.case-preview-modal .case-item-card>img{width:76px;height:76px;margin:13px 0 11px}
.case-preview-modal .case-item-name{font-size:12px}
.case-preview-modal .case-item-price{font-size:12px}
.case-preview-modal .case-item-price img{width:13px;height:13px}
.case-preview-modal .case-item-chance,.case-preview-modal .case-item-range{font-size:10px}
@media (max-width:600px){.case-preview-modal .case-items-grid{grid-template-columns:repeat(2,1fr)}}
