/* NULL SIGNAL — style.css */
@import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&family=Share+Tech+Mono&display=swap');
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
:root{
  --bg:#030210;--panel:#06041a;--line:#12103a;--dim:#28206a;
  --pur:#6633ff;--purL:#9966ff;--cyan:#00eeff;
  --gold:#ffcc00;--red:#ff3355;--grn:#00ff88;
  --txt:#ccd6ff;--mut:#3a3560;
  --FH:'Orbitron',sans-serif;--FM:'Share Tech Mono',monospace;
}
html,body{width:100%;height:100%;overflow:hidden;background:var(--bg);font-family:var(--FM);color:var(--txt);-webkit-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;touch-action:manipulation}
img,canvas{image-rendering:pixelated;image-rendering:-moz-crisp-edges;image-rendering:crisp-edges}
@keyframes fadeIn{from{opacity:0}to{opacity:1}}
@keyframes pulse{0%,100%{opacity:.4}50%{opacity:1}}
@keyframes shake{0%,100%{transform:translateX(0)}20%{transform:translateX(-6px)}40%{transform:translateX(6px)}60%{transform:translateX(-4px)}80%{transform:translateX(4px)}}
@keyframes popIn{from{transform:scale(.8);opacity:0}to{transform:scale(1);opacity:1}}
@keyframes xpop{0%{opacity:1;transform:translateY(0)}100%{opacity:0;transform:translateY(-40px)}}

/* LAYOUT */
#game{position:fixed;inset:0;display:flex;flex-direction:column;background:var(--bg)}

/* ── FIRST-RUN INTRO ────────────────────────────────────────── */
#intro{display:none;position:fixed;inset:0;z-index:400;background:rgba(3,2,16,.94);
  align-items:center;justify-content:center;padding:20px;animation:fadeIn .2s}
#intro.on{display:flex}
#intro-box{width:100%;max-width:430px;background:var(--panel);border:1px solid var(--pur);
  box-shadow:0 0 60px rgba(102,51,255,.3);padding:22px 20px;text-align:center}
.in-title{font-family:var(--FH);font-size:22px;letter-spacing:5px;color:var(--purL)}
.in-tag{font-size:9px;color:var(--mut);letter-spacing:1px;margin-top:6px;margin-bottom:18px}
.in-rows{display:flex;flex-direction:column;gap:11px;text-align:left;margin-bottom:16px}
.in-row{display:flex;gap:10px;align-items:flex-start;font-size:10px;line-height:1.6;color:var(--txt)}
.in-row b{color:var(--cyan);font-weight:400}
.in-ico{color:var(--purL);font-size:13px;line-height:1.3;width:16px;flex-shrink:0;text-align:center}
.in-keys{display:flex;flex-wrap:wrap;gap:12px;justify-content:center;font-size:8px;
  color:var(--mut);letter-spacing:1px;padding:10px 0;border-top:1px solid var(--line)}
.in-keys kbd{font-family:var(--FM);background:var(--line);border:1px solid var(--dim);
  padding:1px 5px;margin-right:2px;color:var(--txt);font-size:8px}
.in-note{font-size:8px;color:var(--gold);letter-spacing:.5px;line-height:1.7;
  padding:9px;background:rgba(255,204,0,.06);border:1px solid rgba(255,204,0,.25);margin-bottom:16px}
.in-btn{width:100%;padding:13px;font-family:var(--FH);font-size:12px;letter-spacing:4px;
  background:linear-gradient(135deg,var(--pur),var(--purL));color:#fff;border:none;cursor:pointer}
.in-btn:active{opacity:.85}
/* Keyboard hints are meaningless on a touch device. */
@media (max-width:1023px){.in-keys{display:none}}

/* ── COLLAPSIBLE SECTIONS (side panel) ─────────────────────── */
.sect-head{
  display:flex;align-items:center;gap:8px;
  padding:9px 12px;cursor:pointer;user-select:none;
  background:rgba(102,51,255,.06);
  border-bottom:1px solid var(--line);
  transition:background .15s;
}
.sect-head:hover{background:rgba(102,51,255,.14)}
.sect-head:active{background:rgba(102,51,255,.2)}
.sect-caret{
  font-size:10px;color:var(--mut);line-height:1;flex-shrink:0;
  display:inline-block;transition:transform .18s ease;
}
.sect-head.open .sect-caret{transform:rotate(90deg);color:var(--purL)}
.sect-titles{display:flex;flex-direction:column;gap:1px;flex:1;min-width:0}
.sect-title{font-family:var(--FH);font-size:9px;letter-spacing:2px}
.sect-sub{font-size:7px;color:var(--mut);letter-spacing:.5px}
.sect-cur{font-family:var(--FH);font-size:15px;flex-shrink:0}
/* Collapsed bodies are removed from layout entirely, so the panel shrinks to
   just its headers rather than leaving a gap. */
.sect-body.collapsed{display:none}

/* Scrollbars: the browser default is a pale strip that reads as a rendering bug
   against this palette. Styled for both engines. */
*{scrollbar-width:thin;scrollbar-color:var(--dim) transparent}
::-webkit-scrollbar{width:8px;height:8px}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{background:var(--dim);border-radius:0}
::-webkit-scrollbar-thumb:hover{background:var(--pur)}

/* STAGE — single column by default (narrow screens), three columns on desktop. */
#stage{flex:1;min-height:0;display:flex;flex-direction:column}
/* Panel geometry lives here, not inline, so the desktop media query can override it. */
#panel-upg{flex:1;min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch;background:var(--bg)}
#panel-board{flex:1;min-height:0;flex-direction:column;background:var(--bg)}

#topbar{flex-shrink:0;display:flex;align-items:center;justify-content:space-between;padding:max(env(safe-area-inset-top),6px) 12px 6px;background:rgba(6,4,26,.96);border-bottom:1px solid var(--line);gap:6px}
#tb-left{display:flex;flex-direction:column;align-items:flex-start;gap:2px}
#tb-mid{display:flex;gap:10px;align-items:center}
/* Base state must be declared BEFORE the desktop media query that turns it on —
   media queries add no specificity, so a later rule of equal weight wins. */
#tb-stats{display:none}
/* Control labels are desktop-only; on a phone they wrap and crowd the row, so
   narrow screens fall back to icon + state as before. */
.ctrl-lbl{display:none}
#tb-shields{display:flex;gap:2px;align-items:center}
.shield{font-size:16px;transition:all .2s}
.shield.lost{opacity:.15;filter:grayscale(1)}
.tb-cur{display:flex;align-items:center;gap:3px;font-family:var(--FH);font-size:11px}
#score-val{font-family:var(--FH);font-size:14px;color:var(--gold);letter-spacing:1px}

/* DIFF BAR */
#diff-bar{flex-shrink:0;display:flex;align-items:center;gap:8px;padding:4px 12px;background:rgba(6,4,26,.85);border-bottom:1px solid var(--line)}
#diff-lbl{font-family:var(--FH);font-size:8px;color:var(--purL);letter-spacing:2px;white-space:nowrap}
#diff-prog{flex:1;height:3px;background:var(--line);border-radius:0;overflow:hidden}
#diff-fill{height:100%;background:linear-gradient(90deg,var(--pur),var(--cyan));width:0%;transition:width .3s}
#streak-lbl{font-family:var(--FH);font-size:11px;color:var(--cyan);min-width:32px;text-align:right}

/* RADAR */
#radar-wrap{flex:1;min-height:0;position:relative;overflow:hidden;background:var(--bg)}
#main-canvas{position:absolute;inset:0;width:100%;height:100%}
#phase-lbl{position:absolute;top:6px;left:50%;transform:translateX(-50%);font-family:var(--FH);font-size:8px;color:var(--purL);letter-spacing:2px;animation:pulse 2s infinite;pointer-events:none;z-index:5;white-space:nowrap}
#alert-lbl{display:none;position:absolute;top:calc(50% - 40px);left:50%;transform:translateX(-50%);font-family:var(--FH);font-size:14px;font-weight:900;color:var(--red);letter-spacing:4px;pointer-events:none;z-index:10;text-shadow:0 0 30px var(--red);animation:pulse .5s infinite}
#hit-flash{display:none;position:absolute;inset:0;background:rgba(255,51,85,.12);pointer-events:none;z-index:8}
#kill-feed{position:absolute;top:28px;left:6px;display:flex;flex-direction:column;gap:2px;pointer-events:none;z-index:6}
.kf-row{font-size:8px;letter-spacing:.5px;padding:2px 6px;background:rgba(3,2,16,.8);border-left:2px solid;animation:fadeIn .15s;white-space:nowrap}
.xtal-pop{position:absolute;pointer-events:none;z-index:50;font-family:var(--FH);font-size:9px;color:var(--cyan);animation:xpop .8s ease-out forwards}

/* UPGRADE STATUS STRIP */
#upg-strip{position:absolute;right:8px;top:50%;transform:translateY(-50%);display:flex;flex-direction:column;gap:6px;pointer-events:none;z-index:5;background:rgba(3,2,16,.75);padding:10px 8px;border-radius:0;border:1px solid rgba(102,51,255,.2)}
.us-row{display:flex;align-items:center;gap:5px;line-height:1}
.us-row.active{color:var(--purL)}
.us-sym{font-size:16px;width:20px;text-align:center}
.us-lv{font-family:var(--FH);font-size:13px;min-width:14px;color:var(--cyan)}

/* STATUS BAR (bottom of radar) */
#status-bar{position:absolute;bottom:0;left:0;right:0;display:flex;justify-content:space-around;align-items:center;padding:4px 0 calc(4px + env(safe-area-inset-bottom));background:rgba(3,2,16,.75);border-top:1px solid rgba(102,51,255,.2);pointer-events:none;z-index:5}
.sb-item{display:flex;flex-direction:column;align-items:center;gap:1px}
.sb-val{font-family:var(--FH);font-size:11px;color:var(--purL)}
.sb-lbl{font-size:7px;color:var(--mut);letter-spacing:1px}

/* WEAPON BAR */
#weapon-bar{flex-shrink:0;display:flex;height:38px;border-top:1px solid var(--line);background:rgba(3,2,16,.95)}
.wb-btn{flex:1;display:flex;align-items:center;justify-content:center;gap:4px;border:none;background:transparent;border-right:1px solid var(--line);border-bottom:2px solid transparent;font-family:var(--FM);font-size:9px;color:var(--mut);cursor:pointer;transition:all .15s;letter-spacing:.5px}
.wb-btn:last-child{border-right:none}
.wb-btn.active{background:rgba(255,255,255,.04);border-bottom-color:currentColor}
.wb-btn.locked{opacity:.4}
.wb-lv{font-size:7px;padding:1px 3px;border:1px solid currentColor;border-radius:0;opacity:.7}

/* CONTROLS */
#controls{flex-shrink:0;height:40px;display:flex;border-top:1px solid var(--line);background:rgba(6,4,26,.96)}
.ctrl-btn{flex:1;display:flex;align-items:center;justify-content:center;gap:5px;border:none;background:transparent;border-right:1px solid var(--line);font-family:var(--FM);font-size:9px;color:var(--purL);cursor:pointer;letter-spacing:.5px}
.ctrl-btn:last-child{border-right:none}
.ctrl-btn.on{color:var(--cyan);background:rgba(0,238,255,.04)}
/* RANK MODE: the ranked lock. Active state reads red = committed/hardcore. */
.ctrl-btn.rank.on{color:var(--red);background:rgba(255,51,85,.08)}
/* Assist buttons while rank mode is engaged: visibly locked out. */
.ctrl-btn.locked{opacity:.3;cursor:not-allowed}

/* BOTTOM NAV BAR */
#nav-bar{flex-shrink:0;display:flex;height:48px;background:var(--panel);border-top:2px solid var(--line)}
.nav-btn{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;border:none;background:transparent;cursor:pointer;color:var(--mut);transition:all .15s;border-top:2px solid transparent}
.nav-btn.active{color:var(--purL);border-top-color:var(--purL);background:rgba(102,51,255,.06)}
.nav-btn:active{background:rgba(102,51,255,.1)}
.nav-icon{font-size:18px;line-height:1}
.nav-lbl{font-family:var(--FH);font-size:7px;letter-spacing:1px}

/* BANNER AD */
/* Bottom banner. Holds a fixed 728x90 ad; fitBanner() scales #ad-slot to the
   strip width on narrow screens and sets the strip height to match, so the ad is
   always fully visible (native on desktop, shrunk on phones) and never overflows. */
#banner-ad{flex-shrink:0;height:56px;display:flex;align-items:center;justify-content:center;background:#050214;border-top:1px solid var(--line);overflow:hidden}
#ad-slot{position:relative;width:728px;height:90px;flex-shrink:0;transform-origin:center center;display:flex;align-items:center;justify-content:center}
/* "ADVERTISEMENT" label sitting BEHIND the ad (z-index:-1) so the loading/empty
   slot is identifiable instead of an invisible black strip; the ad iframe paints
   on top once it fills. #ad-slot's transform makes this a self-contained layer. */
.ad-ph{position:absolute;inset:0;z-index:-1;display:flex;align-items:center;justify-content:center;color:var(--mut);font-family:var(--FH);font-size:11px;letter-spacing:3px;opacity:.4;border:1px dashed var(--line)}



/* WEAPON UPGRADE CARDS */
.wsection{border-bottom:1px solid var(--line)}
.wheader{display:flex;align-items:center;gap:9px;padding:9px 12px 7px;cursor:pointer;transition:background .12s}
.wheader:hover{background:rgba(102,51,255,.07)}
.wsection.active .wheader{background:rgba(102,51,255,.09)}
.wheader-sym{display:flex;align-items:center;justify-content:center;width:24px;flex-shrink:0}
.wheader-info{flex:1;min-width:0}
.wheader-name{font-family:var(--FH);font-size:11px;letter-spacing:2px;margin-bottom:2px}
.wheader-desc{font-size:8px;color:var(--mut);line-height:1.4}
/* Unlock buttons sit side by side; stacked they crowded the row and made the
   cheaper option look subordinate rather than alternative. */
.wunlock-wrap{display:flex;gap:5px;flex-shrink:0}
.wunlock{display:flex;align-items:center;gap:3px;font-family:var(--FH);font-size:9px;
  padding:6px 8px;cursor:pointer;border:1px solid var(--gold);background:rgba(255,204,0,.08);
  color:var(--gold);letter-spacing:1px;border-radius:2px;white-space:nowrap;transition:all .12s}
.wunlock:hover{background:rgba(255,204,0,.18)}
.wunlock.crystal{border-color:var(--cyan);color:var(--cyan);background:rgba(0,238,255,.08)}
.wunlock.crystal:hover{background:rgba(0,238,255,.18)}
.wunlock[disabled]{opacity:.4;cursor:default}

.wupg-list{padding:2px 12px 8px}
.wupg-row{display:grid;grid-template-columns:1fr auto;grid-template-areas:'name cost' 'meter cost';
  column-gap:8px;row-gap:3px;align-items:center;padding:6px 0;
  border-bottom:1px solid var(--line);cursor:default;transition:opacity .12s}
.wupg-row:last-child{border-bottom:none}
.wupg-row.can{cursor:pointer}
.wupg-row.can:hover .wupg-cost{background:rgba(255,204,0,.18)}
.wupg-name{grid-area:name;font-size:9px;color:var(--txt);letter-spacing:.5px}
.wupg-sub{color:var(--mut);font-size:8px}
.wupg-meter{grid-area:meter;display:flex;align-items:center;gap:5px}
.wupg-bars{display:flex;gap:2px;flex:1}
.wupg-bar{height:3px;flex:1;max-width:16px;background:rgba(255,255,255,.09)}
.wupg-bar.filled{background:currentColor}
.wupg-cost{grid-area:cost;display:flex;align-items:center;gap:3px;font-family:var(--FH);font-size:9px;
  white-space:nowrap;padding:4px 6px;border:1px solid var(--line);border-radius:2px;color:var(--mut)}
.wupg-row.can .wupg-cost{color:var(--gold);border-color:rgba(255,204,0,.5);background:rgba(255,204,0,.08)}
.wupg-row.max .wupg-cost{color:var(--grn);border-color:rgba(0,255,136,.3)}
.wupg-row.max{opacity:.55}

/* PERMA CARDS */
/* ── UPGRADE CARDS ──────────────────────────────────────────
   Three states have to be readable at a glance while the radar is moving:
   affordable, not yet affordable, and maxed. The old card showed all three
   almost identically — a 3px border tint was the only difference — so you had
   to read the numbers to know whether a tap would do anything. */
.pcard{
  display:grid;
  grid-template-columns:26px 1fr auto;
  grid-template-areas:'sym name cost' 'sym desc cost' 'sym meter cost';
  align-items:center;
  column-gap:9px;row-gap:2px;
  padding:9px 12px;
  border-bottom:1px solid var(--line);
  border-left:3px solid transparent;
  cursor:default;
  transition:background .12s,border-color .12s;
}
.pcard-sym{grid-area:sym;display:flex;align-items:center;justify-content:center}
.pcard-name{grid-area:name;font-family:var(--FH);font-size:10px;color:var(--txt);letter-spacing:1px}
.pcard-desc{grid-area:desc;font-size:8px;color:var(--mut);line-height:1.45}
.pcard-meter{grid-area:meter;display:flex;align-items:center;gap:6px;margin-top:3px}
.pcard-cost{grid-area:cost;display:flex;align-items:center;gap:3px;
  font-family:var(--FH);font-size:11px;color:var(--mut);white-space:nowrap;
  padding:4px 7px;border:1px solid var(--line);border-radius:2px;transition:all .12s}
.pcard-cost img{opacity:.5;transition:opacity .12s}

/* Affordable: the only state that is actually clickable, so it is the only one
   that lights up and responds to hover. */
.pcard.can{cursor:pointer;border-left-color:var(--cyan)}
.pcard.can .pcard-name{color:#fff}
.pcard.can .pcard-cost{color:var(--cyan);border-color:var(--cyan);background:rgba(0,238,255,.09)}
.pcard.can .pcard-cost img{opacity:1}
.pcard.can:hover{background:rgba(0,238,255,.06)}
.pcard.can:active{background:rgba(0,238,255,.14)}

/* Too expensive: legible, clearly inert. Dimming the whole row made the text
   unreadable, so only the cost chip signals it. */
.pcard.cant .pcard-cost{color:var(--red);border-color:rgba(255,51,85,.35)}

/* Maxed: finished, not broken — keep it readable rather than faded out. */
.pcard.max{opacity:.55}
.pcard.max .pcard-cost{color:var(--grn);border-color:rgba(0,255,136,.3);background:rgba(0,255,136,.06)}

/* Level meter — segment count IS the max, so "how far along" needs no reading. */
.pmeter{display:flex;gap:2px;flex:1}
.pseg{height:3px;flex:1;max-width:14px;background:rgba(255,255,255,.09);transition:background .15s}
.pseg.on{background:var(--cyan)}
.pcard.max .pseg.on{background:var(--grn)}
.plv{font-family:var(--FH);font-size:8px;color:var(--mut);letter-spacing:.5px;flex-shrink:0}



/* GAME OVER */
#overlay{display:none;position:fixed;inset:0;z-index:800;background:rgba(3,2,16,.94);align-items:center;justify-content:center}
#overlay.on{display:flex;animation:fadeIn .3s}
#ov-box{text-align:center;padding:30px 24px;max-width:320px;width:90vw;border:2px solid var(--pur);background:var(--panel);border-radius:0;animation:popIn .3s;box-shadow:0 0 40px rgba(102,51,255,.3),inset 0 0 20px rgba(102,51,255,.05);image-rendering:pixelated;overflow:hidden}
/* Game-over 300x250 ad. Negative side margins reclaim the box padding so the fixed
   300px unit fits inside the 320px modal; empty until the ad injects on first death. */
#ov-ad{margin:16px -15px 0;display:flex;justify-content:center}
#ov-ad:empty{display:none}
.ov-icon{font-size:44px;margin-bottom:12px}
.ov-title{font-family:var(--FH);font-size:18px;font-weight:900;letter-spacing:3px;margin-bottom:6px}
.ov-sub{font-size:10px;color:var(--mut);letter-spacing:1px;line-height:1.8;margin-bottom:18px}
.ov-btn{font-family:var(--FH);font-size:10px;letter-spacing:2px;padding:11px 24px;border:none;cursor:pointer;border-radius:0;display:block;width:100%;margin-bottom:8px}
.ov-btn.pri{background:var(--pur);color:#fff}
.ov-btn.sec{background:transparent;border:1px solid var(--dim);color:var(--mut)}

/* INTERSTITIAL */
#inter{display:none;position:fixed;inset:0;z-index:9999;background:rgba(3,2,16,.97);align-items:center;justify-content:center}
#inter.on{display:flex;animation:fadeIn .2s}
.i-wrap{width:min(380px,92vw);background:var(--panel);border:1px solid var(--pur);box-shadow:0 0 60px rgba(102,51,255,.2);overflow:hidden}
.i-head{display:flex;align-items:center;justify-content:space-between;padding:8px 14px;background:rgba(102,51,255,.08);border-bottom:1px solid var(--line)}
.i-lbl{font-size:9px;color:var(--mut);letter-spacing:2px;font-family:var(--FH)}
.i-skip{font-size:10px;padding:4px 10px;cursor:pointer;font-family:var(--FM);border:1px solid var(--dim);background:transparent;color:var(--mut)}
.i-skip.ready{color:var(--purL);border-color:var(--purL)}
.i-prog{height:2px;background:var(--dim)}
.i-prog-fill{height:100%;background:var(--pur);width:100%;transition:width 5s linear}
.i-body{height:260px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;background:radial-gradient(ellipse at 50% 40%,#0d0525,#030210 70%);position:relative}
.i-foot{font-size:8px;color:var(--mut);text-align:center;padding:5px 0;border-top:1px solid var(--line);letter-spacing:1px}

/* ── LEADERBOARD ────────────────────────────────────────── */
#board-head{flex-shrink:0;padding:10px 12px;background:var(--panel);border-bottom:2px solid var(--line)}
.bh-row{display:flex;justify-content:space-between;align-items:flex-start;gap:8px}
.bh-title{font-family:var(--FH);font-size:11px;letter-spacing:2px;color:var(--cyan)}
.bh-season{font-family:var(--FM);font-size:8px;color:var(--mut);margin-top:2px}
.bh-timer{font-family:var(--FH);font-size:13px;color:var(--gold);letter-spacing:1px;text-align:right}
.bh-timer-lbl{font-size:7px;color:var(--mut);letter-spacing:1px;text-align:right;margin-top:1px}
.wallet-btn{width:100%;margin-top:8px;padding:7px;background:transparent;border:1px solid var(--purL);color:var(--purL);
  font-family:var(--FH);font-size:9px;letter-spacing:2px;cursor:pointer;transition:all .15s}
.wallet-btn:active{background:rgba(153,102,255,.15)}
.wallet-btn.linked{border-color:var(--grn);color:var(--grn)}
.wallet-btn[disabled]{opacity:.55;cursor:default}
/* Ranked / Auto board switch. */
.bd-tabs{display:flex;gap:4px;margin-top:8px}
.bd-tab{flex:1;padding:6px;background:transparent;border:1px solid var(--line);color:var(--mut);font-family:var(--FH);font-size:8px;letter-spacing:1.5px;cursor:pointer;border-radius:2px}
.bd-tab.on{border-color:var(--cyan);color:var(--cyan);background:rgba(0,238,255,.06)}
.bd-note{margin-top:8px;font-size:8px;color:var(--mut);letter-spacing:.5px;line-height:1.6;text-align:center}
.claim-btn{width:100%;margin-top:8px;padding:10px;border:1px solid var(--gold);border-radius:2px;
  background:linear-gradient(135deg,rgba(255,204,0,.18),rgba(255,153,0,.1));color:var(--gold);
  font-family:var(--FH);font-size:11px;letter-spacing:2px;cursor:pointer;transition:all .15s;
  animation:pulse 2.5s infinite}
.claim-btn:hover{background:rgba(255,204,0,.25)}
.claim-btn:active{transform:scale(.99)}
#board-list{flex:1;min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch}
.bd-row{display:flex;align-items:center;gap:8px;padding:7px 12px;border-bottom:1px solid var(--line)}
.bd-row.me{background:rgba(0,238,255,.07);box-shadow:inset 2px 0 0 var(--cyan)}
.bd-rank{font-family:var(--FH);font-size:11px;color:var(--mut);width:30px;flex-shrink:0}
.bd-row.me .bd-rank{color:var(--cyan)}
.bd-rank.top1{color:var(--gold)}
.bd-rank.top2{color:#c0c8e0}
.bd-rank.top3{color:#cd7f32}
.bd-handle{flex:1;font-family:var(--FM);font-size:10px;color:var(--txt);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bd-score{font-family:var(--FH);font-size:11px;color:var(--gold);flex-shrink:0}
.bd-wave{font-family:var(--FM);font-size:8px;color:var(--mut);width:34px;text-align:right;flex-shrink:0}
.bd-msg{padding:24px 16px;text-align:center;font-size:9px;color:var(--mut);letter-spacing:1px;line-height:1.9}

/* ── DESKTOP LAYOUT ─────────────────────────────────────────
   Browser-first: the radar goes large and central, with upgrades and the
   leaderboard as permanent side columns. Tabbing between them wasted the screen
   and hid the leaderboard — the one thing a competitive player wants in view
   while playing.

   Must sit near the end of the file: these override base rules of equal
   specificity, and media queries add none of their own. */
@media (min-width:1024px){
  body{background:radial-gradient(ellipse at 50% 20%,#0a0620,#020109 70%)}

  #stage{flex-direction:row;align-items:stretch;gap:0}

  /* DOM order is radar-first (narrow screens want it first); desktop reorders. */
  #panel-upg  {order:1}
  #radar-wrap {order:2}
  #panel-board{order:3}

  /* Side columns are fixed-width so the radar keeps a stable square-ish box —
     a radar that resizes as panels reflow would change tap geometry mid-run. */
  #panel-upg,#panel-board{
    flex:0 0 300px;width:300px;min-height:0;
    display:flex;flex-direction:column;
    background:var(--panel);
  }
  #panel-upg{border-right:1px solid var(--line);overflow-y:auto}
  #panel-board{border-left:1px solid var(--line)}

  #radar-wrap{flex:1 1 auto;min-width:0}

  /* The bottom tab bar only switches between views; on desktop every view is on
     screen at once, so the whole bar is redundant. */
  #nav-bar{display:none}

  /* Bigger hit targets and type now that there is room for them. */
  #score-val{font-size:20px}
  .tb-cur{font-size:13px}
  .shield{font-size:18px}
  #weapon-bar{height:52px}
  .wb-btn{font-size:11px}
  #controls{height:46px}
  .bd-row{padding:9px 12px}
  .bd-handle{font-size:11px}
  .bd-score{font-size:12px}

  /* ── things that duplicate something else on desktop ──
     Every panel is already on screen, and the shard counter in the top bar is
     itself the "watch ad" button — so the whole nav row was one redundant
     control taking a full 48px strip away from the radar. */
  #nav-bar{display:none}

  /* The status strip floated over the radar repeating KILLS / BEST LV / WEAPON.
     Weapon is already shown by the highlighted weapon button, and the other two
     now live in the top bar — off the play area, where they belong. */
  #status-bar{display:none}

  /* The floating upgrade strip duplicates the left column. */
  #upg-strip{display:none !important}

  .ctrl-lbl{display:inline}

  /* Stats in the top bar (desktop only). */
  #tb-stats{display:flex;gap:22px;align-items:center}
  .tb-stat{display:flex;flex-direction:column;align-items:center;gap:1px}
  .tb-stat-val{font-family:var(--FH);font-size:15px;color:var(--purL);line-height:1}
  .tb-stat-lbl{font-size:7px;color:var(--mut);letter-spacing:1.5px}
}

/* ── LANDSCAPE PHONES ───────────────────────────────────────
   MUST stay at the end of the file. Media queries carry no extra specificity, so
   these overrides lose to the same-specificity rules above if placed earlier —
   which is exactly what happened: the query matched and nothing applied.

   A phone in landscape leaves the radar ~130px tall (a 52px play radius). No
   amount of reclaimed chrome makes that playable, and the radar is the entire
   game. Asking for a rotate is honest; shipping an unplayable board is not. */
#rotate-prompt{display:none}
@media (max-height:500px) and (orientation:landscape) and (max-width:900px){
  #game{display:none}
  #rotate-prompt{
    display:flex;position:fixed;inset:0;z-index:9999;
    flex-direction:column;align-items:center;justify-content:center;gap:14px;
    background:var(--bg);text-align:center;padding:20px;
  }
  .rp-icon{font-family:var(--FH);font-size:38px;color:var(--purL);animation:pulse 2s infinite;line-height:1}
  .rp-title{font-family:var(--FH);font-size:13px;letter-spacing:3px;color:var(--cyan)}
  .rp-sub{font-size:9px;color:var(--mut);letter-spacing:1px;line-height:1.8;max-width:280px}
}