/* Touch controls and the phone layout (landscape). See src/touch.js.
   Zones: top-left minimap + vitals · top-centre timer, objective, boss bar, messages · top-right icon row (full screen, chat,
   bag, trade, pause) and the online count · bottom-centre Data Stick chips · bottom-right the thumb cluster with the gun
   readout above it · the left 45% is free for the movement stick. Held upright, #rotateOverlay covers play. */
#touch { position: fixed; inset: 0; z-index: 6; touch-action: none; user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; }
#touch.hidden { display: none; }
#touch .stick { position: absolute; width: 112px; height: 112px; margin: -56px 0 0 -56px; border-radius: 50%; border: 2px solid rgba(57,255,136,.45); background: rgba(2,10,6,.25); pointer-events: none; }
#touch .stick.hidden { display: none; }
#touch .stick.sprint { border-color: var(--gold); }
#touch .stick i { position: absolute; left: 50%; top: 50%; width: 48px; height: 48px; margin: -24px 0 0 -24px; border-radius: 50%; background: rgba(57,255,136,.55); }
/* the thumb cluster: 3 rows instead of 4 now that the utility buttons live in the top-right row */
#touch .tbtns { --b: 54px; position: absolute; right: max(12px, env(safe-area-inset-right)); bottom: max(10px, env(safe-area-inset-bottom)); display: grid; gap: 8px;
  grid-template-columns: repeat(4, var(--b)); grid-template-rows: repeat(4, var(--b));
  grid-template-areas: ". summon slide grapple" "heal crouch swap reload" "aim jump fire fire" "use use fire fire"; }
#touch .tb { width: 100%; height: 100%; padding: 0; border-radius: 50%; border: 1px solid rgba(57,255,136,.45); background: rgba(2,10,6,.55); color: var(--fg); font: 600 22px/1 var(--font); box-shadow: 0 0 10px rgba(0,0,0,.4); touch-action: none; }
#touch .tb[hidden] { display: none; }
#touch .tb.down { background: rgba(57,255,136,.35); transform: scale(.94); }
#touch .tb.on { border-color: var(--gold); box-shadow: 0 0 12px rgba(255,194,61,.5); }
#touch .tb-fire { grid-area: fire; font-size: 36px; border-width: 2px; } #touch .tb-aim { grid-area: aim; } #touch .tb-jump { grid-area: jump; }
#touch .tb-use { grid-area: use; border-radius: 27px; } #touch .tb-reload { grid-area: reload; } #touch .tb-swap { grid-area: swap; }
#touch .tb-crouch { grid-area: crouch; } #touch .tb-heal { grid-area: heal; } #touch .tb-slide { grid-area: slide; } #touch .tb-grapple { grid-area: grapple; }
#touch .tb-grapple.cd { opacity: .45; }
/* vehicles: 🏍 summon (in a raid, while you carry a capsule or yours is out); riding (body.nxRide, vehicles/hud.js), the
   pad swaps to what a rider needs, big: ⚡ boost (its ring is the boost meter), ↯ drift, ⤒ jump, ⏏ get off; a gunner
   (or a mech pilot) keeps fire, aim, reload and swap. 2-3 rows instead of 4, so the vehicle HUD has room beside it. */
#touch .tb-summon { grid-area: summon; } body:not(.nxCanRide) #touch .tb-summon, body.nxRide #touch .tb-summon { display: none !important; }
#touch .tb-boost { grid-area: boost; } #touch .tb-drift { grid-area: drift; } #touch .tb-exit { grid-area: exit; }
#touch .tb small { display: block; font-size: 10px; letter-spacing: .08em; margin-top: 2px; color: var(--muted); }
body.nxRide #touch .tbtns .tb { display: none !important; }
body.nxRide #touch .tbtns { grid-template-rows: repeat(2, var(--b)); grid-template-areas: "drift jump boost boost" "exit exit boost boost"; }
body.nxRide[data-ride-seat=rider] #touch .tbtns :is(.tb-boost, .tb-exit), body.nxRide.nxRideJump #touch .tbtns .tb-jump, body.nxRide #touch .tbtns .tb-exit { display: flex !important; flex-direction: column; align-items: center; justify-content: center; }
body.nxRide[data-ride-seat=rider][data-ride-kind=hoverbike] #touch .tbtns .tb-drift { display: flex !important; flex-direction: column; align-items: center; justify-content: center; }
body.nxRide.nxRideGun #touch .tbtns { grid-template-rows: repeat(3, var(--b)); grid-template-areas: "aim reload swap boost" "exit exit fire fire" "jump jump fire fire"; }
body.nxRide.nxRideGun #touch .tbtns :is(.tb-fire, .tb-aim, .tb-reload, .tb-swap) { display: block !important; }
#touch .tb-boost { font-size: 34px; border-width: 2px; border-color: rgba(55,232,255,.7); background: conic-gradient(rgba(55,232,255,.42) calc(var(--boost, 1) * 1turn), rgba(2,10,6,.6) 0); }
body.nxRideGun #touch .tb-boost { font-size: 22px; } body.nxRideGun #touch .tb-boost small { display: none; }
#touch .tb-exit { border-radius: 27px; font-size: 20px; flex-direction: row !important; gap: 6px; } #touch .tb-exit small { margin: 0; font-size: 12px; color: var(--fg); }
#touch .tb-drift { border-color: rgba(255,194,61,.6); }
/* the mech: jump is its ground stomp (labelled, its ring the cooldown); the horse's boost says GALLOP (vehicles/hud.js) */
body.nxRide[data-ride-kind=mech] #touch .tb-jump { border-radius: 27px; flex-direction: row !important; gap: 6px; border-color: rgba(255,194,61,.7); background: conic-gradient(rgba(255,194,61,.38) calc(var(--stomp, 1) * 1turn), rgba(2,10,6,.6) 0); }
body.nxRide[data-ride-kind=mech] #touch .tb-jump::after { content: "STOMP"; font-size: 12px; letter-spacing: .08em; }
/* a driver's vehicle ability (Q: the swap button becomes ✦, its ring the cooldown) and repair with cells (R: the reload
   button becomes 🔧), vehicles/ability.js; a third row, so boost stays big */
body.nxRide.nxRideAb[data-ride-seat=rider]:not(.nxRideGun) #touch .tbtns { grid-template-rows: repeat(3, var(--b)); grid-template-areas: "drift jump boost boost" "swap reload boost boost" "exit exit exit exit"; }
body.nxRide.nxRideAb[data-ride-seat=rider]:not(.nxRideGun) #touch .tbtns :is(.tb-swap, .tb-reload) { display: flex !important; align-items: center; justify-content: center; font-size: 0; }
body.nxRide.nxRideAb[data-ride-seat=rider]:not(.nxRideGun) #touch .tb-swap::before { content: "✦"; font-size: 24px; }
body.nxRide.nxRideAb[data-ride-seat=rider]:not(.nxRideGun) #touch .tb-swap { border-width: 2px; border-color: rgba(181,108,255,.75); background: conic-gradient(rgba(181,108,255,.4) calc(var(--ab, 1) * 1turn), rgba(2,10,6,.6) 0); }
body.nxRide.nxRideAb[data-ride-seat=rider]:not(.nxRideGun) #touch .tb-reload::before { content: "🔧"; font-size: 20px; }
/* the small icon row, top right */
#touch .tutil { position: absolute; top: max(8px, env(safe-area-inset-top)); right: max(10px, env(safe-area-inset-right)); display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }
#touch .tutil .tb { flex: none; width: 42px; height: 42px; font-size: 17px; background: rgba(2,10,6,.45); border-color: rgba(57,255,136,.3); }
@media (max-height: 400px) { #touch .tbtns { --b: 48px; gap: 7px; } #touch .tutil .tb { width: 38px; height: 38px; font-size: 15px; } }   /* (an iPhone held sideways is 390 tall: the full pad reached up into the icon rows) */
@media (max-height: 340px) { #touch .tbtns { --b: 44px; gap: 6px; } #touch .tutil .tb { width: 36px; height: 36px; } }

/* held upright: turn the phone (gameplay is landscape; menus and sign-in still work upright) */
#rotateOverlay { display: none; position: fixed; inset: 0; z-index: 14; flex-direction: column; align-items: center; justify-content: center; gap: 10px; padding: 24px;
  text-align: center; background: radial-gradient(ellipse at center, rgba(4,20,12,.97), rgba(1,4,3,.99)); color: var(--fg); font: 600 18px var(--font); }
#rotateOverlay .rotIcon { font-size: 54px; animation: nexTurn 2.4s ease-in-out infinite; }
@keyframes nexTurn { 0%, 30% { transform: rotate(0); } 60%, 100% { transform: rotate(-90deg); } }
@media (prefers-reduced-motion: reduce) { #rotateOverlay .rotIcon { animation: none; } }
@media (orientation: portrait) {
  body.touch:is([data-mode=hub], [data-mode=raid], [data-mode=dying], [data-mode=lounge], [data-mode=apt]) #rotateOverlay { display: flex; }
  body.touch:is([data-mode=hub], [data-mode=raid], [data-mode=dying]) :is(#touch, #hud, #acctBadge) { visibility: hidden; }
}

/* the phone HUD (landscape) */
body.touch #VRButton { display: none !important; }
body.touch #minimap { width: 96px; height: 96px; top: max(10px, env(safe-area-inset-top)); left: max(10px, env(safe-area-inset-left)); }
body.touch #vitals { top: max(10px, env(safe-area-inset-top)); bottom: auto; left: calc(max(10px, env(safe-area-inset-left)) + 106px); width: min(170px, 20vw); gap: 4px; font-size: .72rem; }
body.touch[data-mode=hub] #vitals { display: none; }   /* nothing can hurt you in the hub */
body.touch #topbar { top: max(8px, env(safe-area-inset-top)); max-width: 30vw; }
body.touch #timer { font-size: 1.4rem; }
body.touch #objective { font-size: .78rem; }
body.touch[data-mode=hub] #topbar { top: auto; bottom: max(10px, env(safe-area-inset-bottom)); left: 40%; max-width: 34vw; }
body.touch #bossbar { top: calc(max(8px, env(safe-area-inset-top)) + 72px); width: min(360px, 40vw); }
body.touch #online { top: calc(max(8px, env(safe-area-inset-top)) + 48px); right: max(10px, env(safe-area-inset-right)); font-size: .72rem; padding: 2px 8px; }
/* left of the pad, above the Data Stick bar (it sat in the pad's empty top-left corner, inside the pad's own box) */
body.touch #weapon { top: auto; right: calc(max(12px, env(safe-area-inset-right)) + 4 * var(--tb, 54px) + 3 * var(--tg, 8px) + 14px); bottom: calc(max(10px, env(safe-area-inset-bottom)) + 84px); }
body.touch :is(#nexPurgeBtn, #nexReplayOffer) { bottom: calc(max(10px, env(safe-area-inset-bottom)) + 4 * var(--tb, 54px) + 110px) !important; }
body.touch #weapon #ammo b { font-size: 1.5rem; }
body.touch #weapon #wname { font-size: .78rem; }
@media (max-height: 400px) { body.touch #weapon { --tb: 48px; --tg: 7px; } }
@media (max-height: 340px) { body.touch #weapon { --tb: 44px; --tg: 6px; } }
body.touch #abilities { left: 42%; bottom: max(10px, env(safe-area-inset-bottom)); transform: translateX(-50%); }
body.touch .ab { width: 54px; } body.touch .ab small { display: none; }
body.touch #toasts { left: 46%; right: auto; top: calc(max(8px, env(safe-area-inset-top)) + 74px); transform: translateX(-50%); width: min(400px, 40vw); max-width: none; font-size: .82rem; align-items: center; }
body.touch #toasts > :nth-child(n+3) { display: none; }   /* only the latest two */
body.touch #hud:has(#bossbar:not(.hidden)) #toasts { top: calc(max(8px, env(safe-area-inset-top)) + 112px); }   /* below the boss bar */
body.touch #chatlog { top: calc(max(10px, env(safe-area-inset-top)) + 106px); bottom: auto; left: max(10px, env(safe-area-inset-left)); width: min(260px, 26vw); max-height: 34vh; overflow: hidden; font-size: .76rem; }
body.touch[data-mode=hub] #chatlog { top: 56px; }
body.touch #prompt { top: 60%; border-color: var(--nex); font-size: .9rem; }
body.touch #prompt::after { content: " · tap"; color: var(--muted); font-weight: 500; }
body.touch .controls { display: none; }
#online { pointer-events: auto; }
/* the account bar (hub): compact, and the keyboard hints go */
body.touch #acctBadge { top: max(8px, env(safe-area-inset-top)); left: max(8px, env(safe-area-inset-left)); font-size: 12px; padding: 2px 4px 2px 8px; max-width: calc(100vw - 300px); gap: 4px; }
body.touch #acctBadge .btn.mini, body.touch #acctBadge .mini { padding: 7px 9px; min-height: 44px; }

/* panels, menus and banners: thumb-sized targets, no keyboard hints, fit the short screen */
body.touch kbd { display: none; }
body.touch .mini { min-height: 44px; min-width: 44px; padding: 8px 11px; font-size: .85rem; }
body.touch #panel { padding: max(6px, env(safe-area-inset-top)) max(8px, env(safe-area-inset-right)) max(6px, env(safe-area-inset-bottom)) max(8px, env(safe-area-inset-left)); }
body.touch #panel > .card, body.touch .overlay > .card { max-height: calc(100dvh - 16px); overflow: auto; -webkit-overflow-scrolling: touch; overscroll-behavior: contain; }
body.touch #panel header { position: sticky; top: 0; z-index: 1; background: inherit; }
body.touch #panelClose { min-height: 44px; }
body.touch .duelBar, body.touch .friendInvite, body.touch #invite { top: calc(max(8px, env(safe-area-inset-top)) + 52px); }
.fsNote { position: fixed; left: 50%; bottom: max(16px, env(safe-area-inset-bottom)); transform: translateX(-50%); z-index: 99; max-width: min(520px, 92vw); padding: 10px 14px; border-radius: 10px;
  background: #0b1410; color: #e7fff1; border: 1px solid #39ff88; font: 600 14px var(--font); text-align: center; box-shadow: 0 8px 30px #0008; }
/* amount boxes in the bank (all devices) */
.amt { width: 4.6em; padding: 6px 6px; border-radius: 7px; border: 1px solid var(--line); background: rgba(2,10,6,.6); color: var(--fg); font: 600 .85rem var(--font); }
body.touch .amt { min-height: 40px; font-size: 16px; }   /* 16px stops iPhone zooming in on focus */
/* Desktop panel sizing (every device; phones keep the touch rules above). Big windows get wider panels, so grids add
   columns instead of growing tall; long names stop at their slot's edge instead of pushing it wider. */
.slot { min-width: 0; } .slot .item { max-width: 100%; min-width: 0; } .slot .item > span:last-child { min-width: 0; overflow: hidden; overflow-wrap: anywhere; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; }
.acts { max-width: 100%; } .acts .mini { white-space: nowrap; }
@media (min-width: 1200px) and (pointer: fine) {
  #panel > .card { width: min(1040px, 86vw); }
  #panel .grid { grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); }
}
@media (min-width: 1800px) and (pointer: fine) {
  #panel > .card { width: min(1320px, 74vw); padding: 26px 30px; font-size: 1.05rem; }
  #panel > .card > header:first-child { margin: -26px -30px 10px; padding: 18px 30px 12px; top: -26px; }   /* app.css sticky header, at this padding */
  #panel .grid { grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); }
}
@media (max-height: 700px) and (pointer: fine) { #menu .card { padding: 14px 20px; } }

/* the GLITCH invasion bar (invasion.js): over the buttons on phones; up under the top bar instead */
body.touch #nexInvasion { bottom: auto !important; top: calc(max(8px, env(safe-area-inset-top)) + 64px) !important; width: min(420px, 60vw) !important; }

/* panels never taller than the visible screen (inline 90vh heights were cut off behind Safari's toolbar), and fast taps
   on Buy/Sell don't zoom the page */
body.touch :is([role=dialog], .overlay, #panel) .card { max-height: calc(100dvh - 16px) !important; overflow: auto; }
html { touch-action: manipulation; }

/* sticky action rows: Take all, Back to the Hub and Deploy stay in reach on short phone screens */
body.touch #panelBody > .row:last-child, body.touch #summary .card > .row { position: sticky; bottom: -16px; z-index: 2; padding: 8px 0; background: rgba(4,16,10,.96); }
