/* safe areas as variables: in a match turned 90° on an upright phone, #app's edges are other physical edges */
:root { --sa-t: env(safe-area-inset-top, 0px); --sa-r: env(safe-area-inset-right, 0px); --sa-b: env(safe-area-inset-bottom, 0px); --sa-l: env(safe-area-inset-left, 0px); }
#app.rot { --sa-t: env(safe-area-inset-right, 0px); --sa-r: env(safe-area-inset-bottom, 0px); --sa-b: env(safe-area-inset-left, 0px); --sa-l: env(safe-area-inset-top, 0px); }
#app.rot-ccw { --sa-t: env(safe-area-inset-left, 0px); --sa-r: env(safe-area-inset-top, 0px); --sa-b: env(safe-area-inset-right, 0px); --sa-l: env(safe-area-inset-bottom, 0px); }
:root {
  --yellow: #f9de0b; --amber: #f6ad13; --orange: #f27d1c; --red: #ef4c24; --ink: #231f20;
  --bg: #111; --surface: #1d1a1b; --line: rgba(255,255,255,.1); --text: #f4f2f2; --muted: #a9a3a4;
  --grad: linear-gradient(135deg, var(--yellow), var(--amber) 28%, var(--orange) 55%, var(--red));
  --pixel: "Press Start 2P", monospace;
}
* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; overflow: hidden; background: var(--bg); color: var(--text); font-family: "Inter", system-ui, sans-serif;
  overscroll-behavior: none; -webkit-tap-highlight-color: transparent; -webkit-text-size-adjust: 100%; }
/* everything lives in #app; on phones held upright it is rotated 90° so the game is always landscape */
/* JS sizes #app to the visible viewport (browser bars excluded) and rotates it during a match on an upright phone */
#app { position: fixed; left: 0; top: 0; width: 100vw; height: 100dvh; overflow: hidden; transform-origin: 0 0; }
canvas#game { position: absolute; inset: 0; width: 100%; height: 100%; display: block; image-rendering: pixelated; cursor: crosshair; touch-action: none; }
.hidden { display: none !important; }

.screen {
  position: absolute; inset: 0; z-index: 10; display: grid; place-items: center; padding: 16px; overflow-y: auto;
  background: radial-gradient(60% 60% at 50% 40%, rgba(242,125,28,.18), transparent 70%), rgba(17,17,17,.72);
  backdrop-filter: blur(3px);
}
.panel {
  width: min(560px, 100%); padding: 32px; border-radius: 24px;
  background: rgba(29,26,27,.94); border: 1px solid rgba(242,125,28,.35);
  box-shadow: 0 30px 80px -30px rgba(0,0,0,.8);
}
.logo { width: 200px; display: block; margin: 0 auto; }
h1 { font-family: var(--pixel); font-size: 1.6rem; text-align: center; margin: 14px 0 10px; letter-spacing: .3em;
  background: var(--grad); -webkit-background-clip: text; background-clip: text; color: transparent; }
h2 { font-size: 1.8rem; font-weight: 900; margin: 4px 0 20px; }
.sub { text-align: center; color: var(--muted); margin: 0 0 24px; }
.eyebrow { margin: 0; font-size: .75rem; font-weight: 700; letter-spacing: .16em; text-transform: uppercase; color: var(--amber); }
.field { display: block; margin-bottom: 18px; }
.field > span { display: block; font-size: .8rem; font-weight: 600; color: var(--muted); margin-bottom: 8px; }
input {
  width: 100%; font: inherit; font-size: 1rem; color: var(--text);
  padding: 12px 14px; border-radius: 12px; border: 1px solid var(--line); background: #141213; outline: none;
}
input:focus { border-color: var(--orange); }

.chars { display: grid; grid-template-columns: repeat(5, 1fr); gap: 8px; }
.char {
  position: relative; height: 92px; border-radius: 12px; cursor: pointer; overflow: hidden;
  border: 2px solid var(--line); background: linear-gradient(180deg, #2a2526, #141213); padding: 0;
  display: flex; align-items: flex-end; justify-content: center;
}
.char img { height: 78px; width: auto; max-width: 110%; object-fit: contain; filter: grayscale(.6) brightness(.8); transition: .2s; }
.char:hover img { filter: none; }
.char[aria-checked="true"] { border-color: var(--yellow); box-shadow: 0 0 0 3px rgba(249,222,11,.2); }
.char[aria-checked="true"] img { filter: none; transform: scale(1.06); }
.char-name { text-align: center; font-size: .85rem; color: var(--amber); margin-top: 8px; min-height: 1.2em; font-weight: 600; }

.btn {
  font: inherit; font-weight: 700; font-size: .95rem; cursor: pointer;
  padding: 13px 20px; border-radius: 999px; border: 1px solid rgba(255,255,255,.18);
  background: rgba(255,255,255,.04); color: var(--text); transition: transform .15s, border-color .15s;
}
.btn:hover { transform: translateY(-2px); border-color: var(--orange); }
.btn.primary { background: var(--grad); color: var(--ink); border-color: transparent; }
.btn.small { padding: 8px 14px; font-size: .82rem; }
.btn:disabled { opacity: .45; cursor: not-allowed; transform: none; }
.actions { display: flex; gap: 10px; margin-top: 8px; }
.actions .btn { flex: 1; }
.join { display: flex; gap: 10px; margin-top: 10px; }
.join input { text-transform: uppercase; letter-spacing: .3em; font-family: var(--pixel); font-size: .85rem; text-align: center; }
.join .btn { flex: none; }
.status { min-height: 1.4em; color: var(--red); font-size: .9rem; margin: 12px 0 0; text-align: center; }
.back { display: block; text-align: center; color: var(--muted); font-size: .85rem; margin-top: 10px; text-decoration: none; }
.back:hover { color: var(--amber); }

.code-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin: 8px 0 20px; }
.code { font-family: var(--pixel); font-size: 2rem; letter-spacing: .2em; background: var(--grad); -webkit-background-clip: text; background-clip: text; color: transparent; }
.roster { list-style: none; padding: 0; margin: 0 0 16px; display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; }
.roster li { display: flex; align-items: center; gap: 10px; padding: 8px 12px; border-radius: 12px; background: #141213; border: 1px solid var(--line); }
.roster img { width: 36px; height: 36px; object-fit: contain; }
.roster .host { margin-left: auto; font-size: .7rem; color: var(--ink); background: var(--grad); padding: 2px 8px; border-radius: 999px; font-weight: 800; }
.roster .me { color: var(--amber); }
.howto { display: flex; flex-wrap: wrap; gap: 8px 14px; margin-top: 18px; font-size: .8rem; color: var(--muted); }
kbd { font-family: inherit; font-size: .72rem; padding: 2px 6px; border-radius: 5px; border: 1px solid var(--line); background: #141213; color: var(--text); margin-right: 2px; }

/* HUD */
.hud { position: absolute; inset: 0; z-index: 5; pointer-events: none; font-family: var(--pixel); font-size: 10px; }
.hud-top { position: absolute; top: 12px; left: 50%; transform: translateX(-50%); display: flex; align-items: center; gap: 12px; }
.round { font-family: "Inter", system-ui, sans-serif; font-weight: 900; font-size: 13px; letter-spacing: .06em; padding: 7px 12px; border-radius: 10px; background: rgba(17,17,17,.8); border: 1px solid var(--line); color: var(--amber); white-space: nowrap; }
.pips { list-style: none; margin: 0; padding: 6px 10px; display: flex; gap: 14px; border-radius: 10px; background: rgba(17,17,17,.8); border: 1px solid var(--line); }
.pips li { display: flex; align-items: center; gap: 6px; }
.pips img { width: 26px; height: 26px; object-fit: contain; }
.pips i { width: 9px; height: 9px; border-radius: 2px; border: 1px solid var(--c); display: inline-block; }
.pips i.on { background: var(--c); }
.pips li.dead img { filter: grayscale(1) brightness(.5); }
.banner { position: absolute; left: 50%; top: 32%; transform: translate(-50%, -50%); font-family: "Inter", system-ui, sans-serif; font-weight: 900; font-size: 46px; letter-spacing: .02em; text-align: center; line-height: 1.4;
  text-shadow: 0 4px 0 #000, 0 0 30px rgba(239,76,36,.6); animation: pop .35s cubic-bezier(.2,1.6,.4,1); }
.banner small { display: block; font-size: 12px; color: var(--muted); margin-top: 10px; text-shadow: none; }
@keyframes pop { from { transform: translate(-50%, -50%) scale(.4); opacity: 0; } }
.feed { position: absolute; top: 60px; left: 12px; display: flex; flex-direction: column; gap: 6px; }
.feed div { font-family: "Inter", system-ui, sans-serif; font-weight: 700; font-size: 12px; padding: 6px 10px; border-radius: 8px; background: rgba(17,17,17,.75); animation: fade 4s forwards; }
@keyframes fade { 80% { opacity: 1; } 100% { opacity: 0; } }
.hud-bottom { position: absolute; left: 12px; bottom: 12px; display: flex; gap: 14px; align-items: center; padding: 10px 14px; border-radius: 12px; background: rgba(17,17,17,.8); border: 1px solid var(--line); }
.meter { display: flex; align-items: center; gap: 8px; }
.bar { width: 120px; height: 10px; border-radius: 3px; background: rgba(255,255,255,.1); overflow: hidden; }
.bar i { display: block; height: 100%; width: 100%; }
.bar.hp i { background: linear-gradient(90deg, var(--red), var(--amber)); }
.bar.fuel i { background: linear-gradient(90deg, #4cc3ff, #8be0ff); }
.weapon { color: var(--amber); font-family: "Inter", system-ui, sans-serif; font-weight: 800; font-size: 13px; }
.exit { position: absolute; top: 12px; left: 12px; pointer-events: auto; font-family: inherit; }

.podium { list-style: none; padding: 0; margin: 0 0 20px; display: grid; gap: 8px; counter-reset: r; }
.podium li { counter-increment: r; display: grid; grid-template-columns: 34px 44px 1fr auto; align-items: center; gap: 12px; padding: 10px 14px; border-radius: 14px; background: #141213; border: 1px solid var(--line); }
.podium li::before { content: counter(r); font-family: var(--pixel); font-size: 14px; color: var(--muted); text-align: center; }
.podium li:first-child { border-color: var(--yellow); background: linear-gradient(90deg, rgba(249,222,11,.12), #141213); }
.podium li:first-child::before { content: "👑"; font-size: 20px; }
.podium img { width: 44px; height: 44px; object-fit: contain; }
.podium small { color: var(--muted); display: block; }
.podium b { font-family: var(--pixel); font-size: 12px; color: var(--amber); }



@media (max-width: 560px) {
  .panel { padding: 22px 18px; }
  .chars { grid-template-columns: repeat(5, 1fr); }
  .roster { grid-template-columns: 1fr; }
}

/* lobby: rename + change character while waiting */
.lobby-me { display: grid; grid-template-columns: 1fr 1.4fr; gap: 14px; margin-bottom: 4px; }
.chars.small { grid-template-columns: repeat(5, 1fr); gap: 6px; }
.chars.small .char { height: 54px; }
.chars.small .char img { height: 46px; }
.lobby-me .char-name { text-align: left; font-size: .78rem; }

/* hotbar: weapon · grenade · 2 skills */
.hotbar { position: absolute; left: 50%; bottom: 12px; transform: translateX(-50%); display: flex; gap: 8px; pointer-events: auto; }
.slot-cell {
  position: relative; width: 74px; height: 70px; border-radius: 14px; overflow: hidden; cursor: pointer;
  background: rgba(17,17,17,.85); border: 2px solid var(--line);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
  font-family: "Inter", system-ui, sans-serif; transition: transform .12s, border-color .12s;
}
.slot-cell::before { content: attr(data-key); position: absolute; top: 4px; left: 7px; font-size: 10px; font-weight: 800; color: var(--muted); }
.slot-cell .ic { font-size: 24px; line-height: 1; }
.slot-cell .nm { font-size: 9.5px; font-weight: 700; color: var(--muted); max-width: 68px; text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.slot-cell .cd { position: absolute; left: 0; right: 0; bottom: 0; height: 0; background: rgba(0,0,0,.62); }
.slot-cell .cdt { position: absolute; inset: 0; display: grid; place-items: center; font-size: 20px; font-weight: 900; color: #fff; text-shadow: 0 2px 0 #000; }
.slot-cell.on { border-color: var(--yellow); transform: translateY(-6px); box-shadow: 0 0 0 3px rgba(249,222,11,.2), 0 10px 24px -8px rgba(249,222,11,.5); }
.slot-cell.on .nm { color: var(--yellow); }
.slot-cell.ready:not(.on) { border-color: rgba(255,255,255,.18); }
.netstat { position: absolute; top: 14px; right: 14px; display: flex; gap: 6px; }
.link { font-family: "Inter", system-ui, sans-serif; font-weight: 900; font-size: 11px; padding: 6px 8px; border-radius: 8px; letter-spacing: .06em; border: 1px solid var(--line); background: rgba(17,17,17,.8); }
.link.udp { color: #78dcb4; } .link.tcp { color: var(--amber); }
.ping { font-family: "Inter", system-ui, sans-serif; font-weight: 800; font-size: 12px; padding: 6px 10px; border-radius: 8px; background: rgba(17,17,17,.8); border: 1px solid var(--line); }
.ping::before { content: "●"; margin-right: 6px; }
.ping.good::before { color: #78dcb4; } .ping.ok::before { color: #f6ad13; } .ping.bad::before { color: #ef4c24; }
@media (max-width: 900px) { .lobby-me { grid-template-columns: 1fr; } .slot-cell { width: 60px; height: 60px; } }

/* skill set cards */
.skill-list { display: grid; gap: 6px; margin-top: 4px; text-align: left; }
.skill-list .sk { display: grid; grid-template-columns: auto auto 1fr; align-items: start; gap: 8px; padding: 8px 10px; border-radius: 12px; background: #141213; border: 1px solid var(--line); }
.skill-list .sk:last-child { opacity: .8; }
.skill-list kbd { margin-top: 3px; }
.skill-list .ic { font-size: 22px; line-height: 1; }
.skill-list b { font-size: .88rem; }
.skill-list small { margin-left: 6px; font-size: .72rem; color: var(--amber); font-weight: 700; }
.skill-list p { margin: 2px 0 0; font-size: .78rem; color: var(--muted); line-height: 1.35; }
.skill-list.compact .sk { padding: 6px 8px; }
.skill-list.compact p { font-size: .72rem; }
.mini-skills { display: inline-flex; gap: 2px; margin-left: 4px; }
.mini-skills i { font-style: normal; font-size: 15px; cursor: help; }
.menu-panel, .lobby-panel { max-height: none; }
.lobby-panel { width: min(680px, 100%); }

/* F3 diagnostics */
.diag { position: absolute; left: 12px; bottom: 96px; z-index: 30; margin: 0; padding: 10px 12px; border-radius: 10px; pointer-events: none;
  background: rgba(0,0,0,.78); border: 1px solid var(--line); color: #b9f5dc; font: 600 11px/1.6 ui-monospace, Consolas, monospace; white-space: pre; }

/* room size limit */
.limit-row { display: flex; align-items: center; justify-content: space-between; margin: -8px 0 10px; font-size: .85rem; color: var(--muted); font-weight: 600; }
.limit-row label { display: flex; align-items: center; gap: 8px; }
.limit-row select { font: inherit; color: var(--text); background: #141213; border: 1px solid var(--line); border-radius: 10px; padding: 6px 10px; }
.limit-row select:disabled { opacity: .6; }
/* many players: compact, wrapping round HUD */
.hud-top { flex-wrap: wrap; justify-content: center; max-width: min(92vw, 1100px); }
.pips { flex-wrap: wrap; justify-content: center; gap: 6px 12px; max-width: min(80vw, 900px); }
.pips img { width: 22px; height: 22px; }
.roster { max-height: 300px; overflow-y: auto; }

/* ---------- PC action bar: direct keys ---------- */
.slot-cell::before { font-size: 9px; letter-spacing: .02em; }
.slot-cell.small { width: 60px; }
.slot-cell.off { opacity: .35; }
.touch-only { display: none; }
body.touch-ui .touch-only { display: inline; }
body.touch-ui .pc-only { display: none; }

/* ---------- touch controls ---------- */
.touch { position: absolute; inset: 0; z-index: 6; pointer-events: none; user-select: none; -webkit-user-select: none; touch-action: none; }
.stick-zone { position: absolute; left: 0; top: 18%; bottom: 0; width: 42%; pointer-events: auto; touch-action: none; }
.stick-hint { position: absolute; left: 28px; bottom: 26px; font: 700 11px Inter, sans-serif; color: rgba(255,255,255,.35); }
.stick-base { position: absolute; left: 0; top: 0; width: 112px; height: 112px; border-radius: 50%; opacity: 0; transition: opacity .12s;
  background: radial-gradient(circle, rgba(255,255,255,.08), rgba(255,255,255,.02)); border: 2px solid rgba(255,255,255,.22); }
.stick-base.on { opacity: 1; }
.stick-base.on + .stick-hint { opacity: 0; }
.stick-knob { position: absolute; left: 31px; top: 31px; width: 50px; height: 50px; border-radius: 50%;
  background: radial-gradient(circle at 35% 35%, #fff6c9, var(--amber)); box-shadow: 0 4px 14px rgba(0,0,0,.5); }
.tbtn { position: absolute; pointer-events: auto; touch-action: none; border-radius: 50%; border: 2px solid rgba(255,255,255,.28);
  background: rgba(29,26,27,.72); color: #fff; display: grid; place-items: center; padding: 0; overflow: hidden;
  font: inherit; } /* no backdrop blur: on a live game behind it, that re-blurred every button on every frame (weak GPUs) */
.tbtn .ic { font-size: 26px; line-height: 1; position: relative; z-index: 1; }
.tbtn.down { transform: scale(.92); border-color: var(--yellow); background: rgba(249,222,11,.22); }
.tbtn .cdt { position: absolute; inset: 0; display: grid; place-items: center; z-index: 2; font: 900 18px Inter, sans-serif; text-shadow: 0 2px 0 #000; }
/* radial cooldown sweep */
.tbtn::after { content: ""; position: absolute; inset: 0; border-radius: 50%; background: conic-gradient(rgba(0,0,0,.66) var(--cd, 0%), transparent 0); }
.tbtn.cooling .ic { opacity: .55; }
.t-attack { right: max(22px, var(--sa-r)); bottom: 22px; width: 92px; height: 92px; background: linear-gradient(135deg, rgba(249,222,11,.5), rgba(239,76,36,.55)); border-color: rgba(249,222,11,.7); }
.t-attack .ic { font-size: 36px; }
.t-jump { right: calc(max(22px, var(--sa-r)) + 104px); bottom: 14px; width: 70px; height: 70px; }
.t-jump .ic { font-size: 30px; font-weight: 900; }
.t-s1 { right: calc(max(22px, var(--sa-r)) + 8px); bottom: 126px; width: 62px; height: 62px; }
.t-s0 { right: calc(max(22px, var(--sa-r)) + 88px); bottom: 100px; width: 62px; height: 62px; }
.t-nade { right: calc(max(22px, var(--sa-r)) + 166px); bottom: 82px; width: 58px; height: 58px; }
.t-throw { right: calc(max(22px, var(--sa-r)) + 184px); bottom: 16px; width: 50px; height: 50px; }
.t-throw .ic { font-size: 20px; }
.t-throw.hidden { display: none; }
/* phone HUD: keep the bottom free for thumbs */
body.touch-ui .hotbar { display: none; }
body.touch-ui .hud-bottom { left: auto; right: 12px; bottom: auto; top: 54px; padding: 6px 10px; gap: 8px; }
body.touch-ui .hud-bottom .bar { width: 80px; }
body.touch-ui .hud-top { top: 8px; transform: translateX(-50%) scale(.85); transform-origin: top center; }
body.touch-ui .feed { top: 54px; }
body.touch-ui .banner { font-size: 32px; }
body.touch-ui .netstat { top: 10px; transform: scale(.9); transform-origin: top right; }
body.touch-ui .exit { top: 10px; }
@media (max-height: 420px) and (min-width: 560px) {
  .panel { padding: 16px 18px; }
  .menu-panel h1 { font-size: 1.2rem; margin: 6px 0; }
  .sub { margin-bottom: 10px; }
}



/* Liên Quân-style cancel target while dragging a skill button */
.t-cancel { position: absolute; top: max(14px, var(--sa-t)); right: 26%; padding: 10px 18px; border-radius: 999px; pointer-events: none;
  font: 900 15px Inter, sans-serif; color: #fff; background: rgba(35,31,32,.75); border: 2px solid rgba(239,76,36,.6); opacity: 0; transform: translateY(-8px); transition: opacity .15s, transform .15s; }
.touch.aiming .t-cancel { opacity: 1; transform: none; }
.t-cancel.hot { background: rgba(239,76,36,.9); border-color: #fff; transform: scale(1.08); }

/* Né lướt button: above the jump button */
.t-dodge { right: calc(max(22px, var(--sa-r)) + 112px); bottom: 172px; width: 54px; height: 54px; }
.t-dodge .ic { font-size: 22px; }
.mod-chip { position: absolute; left: 50%; top: 58px; transform: translateX(-50%); padding: 6px 14px; border-radius: 999px; font: 800 13px Inter, sans-serif;
  color: #231f20; background: linear-gradient(135deg, #f9de0b, #f27d1c); box-shadow: 0 6px 18px rgba(0,0,0,.35); pointer-events: none; white-space: nowrap; }
.mod-chip.hidden { display: none; }

/* ---------- fullscreen button (phones) ---------- */
.fs-btn { position: absolute; z-index: 40; top: calc(var(--sa-t) + 10px); right: calc(var(--sa-r) + 10px);
  display: inline-flex; align-items: center; gap: 6px; padding: 8px 12px; border-radius: 999px; cursor: pointer;
  font: 800 12px Inter, sans-serif; color: var(--text); background: rgba(17,17,17,.82); border: 1px solid rgba(249,222,11,.45); }
.fs-btn svg { width: 16px; height: 16px; fill: none; stroke: var(--yellow); stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; }
.fs-btn.on svg { stroke: var(--muted); }
#app.in-game .fs-btn { top: calc(var(--sa-t) + 8px); right: auto; left: calc(var(--sa-l) + 58px); padding: 7px 9px; }
#app.in-game .fs-btn .fs-label { display: none; }

/* how-to-play: collapsible */
.howto-box { margin-top: 14px; }
.howto-box summary { cursor: pointer; font-size: .82rem; font-weight: 700; color: var(--muted); list-style: none; }
.howto-box summary::before { content: "▸ "; color: var(--amber); }
.howto-box[open] summary::before { content: "▾ "; }
.howto-box .howto { margin-top: 10px; }

/* short screens (phones in landscape): let the menus scroll from the top */
@media (max-height: 560px) {
  .screen { place-items: start center; }
}

/* ---------- phones (portrait menus) ---------- */
@media (max-width: 600px) {
  .screen { padding: 0; place-items: stretch; background: var(--bg); backdrop-filter: none; -webkit-overflow-scrolling: touch; }
  .panel, .lobby-panel { width: 100%; min-height: 100%; border-radius: 0; border: 0; box-shadow: none; background: transparent;
    padding: calc(var(--sa-t) + 54px) 16px 0; display: flex; flex-direction: column; }
  .panel > * { flex-shrink: 0; } /* the panel is as tall as the screen; let it scroll instead of squashing lists */
  .lobby-panel .btn.primary { white-space: nowrap; font-size: .9rem; }
  .logo { width: 132px; }
  h1 { font-size: 1.05rem; margin: 8px 0 6px; }
  .sub { font-size: .82rem; margin: 0 0 14px; line-height: 1.4; }
  .field { margin-bottom: 12px; }
  input { padding: 11px 12px; font-size: 16px; } /* 16px stops iOS from zooming into the field */

  /* character picker: 4 big touch tiles per row */
  .chars, .chars.small { grid-template-columns: repeat(4, 1fr); gap: 8px; }
  .char, .chars.small .char { height: 74px; }
  .char img, .chars.small .char img { height: 62px; }
  .char-name { margin-top: 6px; }
  .skill-list .sk { padding: 7px 9px; gap: 6px; }
  .skill-list .ic { font-size: 19px; }
  .skill-list b { font-size: .82rem; }
  .skill-list p { font-size: .74rem; }
  .skill-list kbd { display: none; }

  /* main buttons stay reachable at the bottom */
  .cta { position: sticky; bottom: 0; z-index: 2; margin: auto -16px 0; padding: 12px 16px calc(var(--sa-b) + 12px);
    background: linear-gradient(180deg, rgba(17,17,17,0), rgba(17,17,17,.96) 22%); }
  .cta .status:empty { display: none; }
  .actions .btn { padding: 14px 12px; }
  .join input { font-size: 13px; }
  .back { margin: 4px 0 6px; }

  /* lobby */
  .lobby-panel .eyebrow { font-size: .68rem; }
  .code-row { margin: 6px 0 12px; }
  .code { font-size: 1.45rem; }
  .limit-row { margin: 0 0 10px; }
  .roster { grid-template-columns: 1fr 1fr; gap: 6px; max-height: 168px; }
  .roster li { padding: 6px 8px; gap: 6px; font-size: .8rem; min-width: 0; }
  .roster li span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .roster img { width: 26px; height: 26px; }
  .roster .host { font-size: .6rem; padding: 2px 6px; }
  .lobby-me { grid-template-columns: 1fr; gap: 0; }
  .howto-box { margin: 4px 0 8px; }
  .howto { font-size: .76rem; }

  /* results */
  .over-panel { justify-content: center; }
}

/* hotbar in keyboard order: J · U · I · O · P · L */
.hotbar .slot-cell:nth-child(1) { order: 0; } .hotbar .slot-cell:nth-child(3) { order: 1; } .hotbar .slot-cell:nth-child(4) { order: 2; }
.hotbar .slot-cell:nth-child(2) { order: 3; } .hotbar .slot-cell:nth-child(5) { order: 4; } .hotbar .slot-cell:nth-child(6) { order: 5; }

/* character picker: one row that scrolls sideways (saves vertical space everywhere) */
.chars, .chars.small { display: flex; gap: 8px; overflow-x: auto; overflow-y: hidden; padding: 2px 2px 8px; scroll-snap-type: x proximity;
  scrollbar-width: thin; scrollbar-color: rgba(249,222,11,.5) transparent; -webkit-overflow-scrolling: touch; overscroll-behavior-x: contain; }
.chars::-webkit-scrollbar { height: 5px; } .chars::-webkit-scrollbar-thumb { background: rgba(249,222,11,.45); border-radius: 9px; }
.chars .char { flex: 0 0 78px; height: 86px; scroll-snap-align: center; }
.chars .char img { height: 72px; }
.chars.small .char { flex: 0 0 64px; height: 66px; }
.chars.small .char img { height: 56px; }
@media (max-width: 600px) {
  .chars, .chars.small { margin: 0 -16px; padding: 2px 16px 8px; scroll-padding: 0 16px; }
  .chars .char, .chars.small .char { flex: 0 0 68px; height: 72px; }
  .chars .char img, .chars.small .char img { height: 60px; }
}
/* a scrolling strip must never widen its panel */
.screen { grid-template-columns: minmax(0, 1fr); }
.panel, .field { min-width: 0; }
.chars { max-width: 100%; }
@media (max-width: 600px) { .chars, .chars.small { max-width: none; width: calc(100% + 32px); } }

/* svg action icons (throw weapon, dodge) */
.ic svg { width: 1em; height: 1em; display: block; color: #f4f2f2; }
.slot-cell .ic svg { width: 26px; height: 26px; }
.tbtn .ic svg { width: 26px; height: 26px; }

/* joystick: always visible at its resting spot, follows the thumb when touched */
.stick-base { opacity: .55; transition: opacity .12s; }
.stick-base.on { opacity: 1; }
.stick-hint { display: none; }

/* Liên Quân-style cancel: a round target just above the skill buttons, grows as the thumb approaches */
.t-cancel { top: auto; right: calc(max(22px, var(--sa-r)) + 70px); bottom: 232px; width: 64px; height: 64px; padding: 0;
  display: grid; place-items: center; border-radius: 50%; font-size: 13px; transform: scale(.85); transition: opacity .12s, transform .12s, background .12s; }
.touch.aiming .t-cancel { transform: scale(1); }
.t-cancel.near { transform: scale(1.25); }
.t-cancel.hot { transform: scale(1.4); background: rgba(239,76,36,.92); border-color: #fff; }

/* ---------- phones held sideways: two-column menus so nothing is squeezed ---------- */
@media (orientation: landscape) and (max-height: 520px) and (min-width: 560px) {
  .screen { padding: 0; place-items: stretch; background: var(--bg); backdrop-filter: none; }
  .panel, .lobby-panel { width: 100%; max-width: none; min-height: 100%; border-radius: 0; border: 0; box-shadow: none; background: transparent;
    padding: 12px calc(var(--sa-r) + 18px) 0 calc(var(--sa-l) + 18px);
    display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.25fr); column-gap: 22px; align-content: start; }
  .panel > * { min-width: 0; }
  /* menu: left = brand, name, buttons · right = characters + skills */
  .menu-panel .logo { width: 120px; margin: 0; }
  .menu-panel h1 { font-size: .95rem; margin: 6px 0; text-align: left; }
  .menu-panel .sub { text-align: left; font-size: .78rem; margin: 0 0 10px; }
  .menu-panel > .logo, .menu-panel > h1, .menu-panel > .sub, .menu-panel > label.field, .menu-panel > .cta, .menu-panel > .back { grid-column: 1; }
  .menu-panel > div.field { grid-column: 2; grid-row: 1 / span 6; }
  /* lobby: left = room, players, buttons · right = me (name, character, skills) */
  .lobby-panel > .eyebrow, .lobby-panel > .code-row, .lobby-panel > .limit-row, .lobby-panel > .roster, .lobby-panel > .cta { grid-column: 1; }
  .lobby-panel > .lobby-me, .lobby-panel > .howto-box { grid-column: 2; }
  .lobby-panel > .lobby-me { grid-row: 1 / span 5; }
  .code { font-size: 1.3rem; }
  .code-row { margin: 4px 0 8px; }
  .limit-row { margin: 0 0 8px; }
  .roster { grid-template-columns: 1fr; max-height: 34vh; gap: 5px; }
  .roster li { padding: 5px 8px; font-size: .8rem; }
  .roster img { width: 24px; height: 24px; }
  .field { margin-bottom: 8px; }
  input { padding: 9px 12px; font-size: 16px; }
  .chars .char, .chars.small .char { flex: 0 0 62px; height: 64px; }
  .chars .char img, .chars.small .char img { height: 54px; }
  .skill-list .sk { padding: 6px 8px; }
  .skill-list p { font-size: .72rem; }
  .cta { position: sticky; bottom: 0; padding: 8px 0 calc(var(--sa-b) + 8px); background: linear-gradient(180deg, rgba(17,17,17,0), var(--bg) 25%); }
  .cta .status:empty { display: none; }
  .actions { margin-top: 0; }
  .actions .btn, .join .btn { padding: 11px 12px; }
  .join { margin-top: 8px; }
  .howto-box { margin-top: 6px; }
}
.t-jump .ic svg { width: 32px; height: 32px; }
.lobby-panel .btn.primary { white-space: nowrap; }
.t-cancel { right: calc(max(22px, var(--sa-r)) + 175px); bottom: 172px; }

/* ===== review fixes ===== */
/* HUD top: centred band that wraps inside its own lane instead of spilling over the bars */
.hud-top, body.touch-ui .hud-top { left: 0; right: 0; margin: 0 auto; width: max-content; max-width: calc(100% - 300px); transform: none; }
body.touch-ui .hud-top { max-width: calc(100% - 250px); top: 8px; }
body.touch-ui .hud-top .round { font-size: 11px; padding: 5px 9px; }
body.touch-ui .pips { padding: 4px 8px; gap: 8px; }
body.touch-ui .pips img { width: 20px; height: 20px; }
/* HP / JET on phones: bottom centre, between the joystick and the action buttons */
body.touch-ui .hud-bottom { top: auto; bottom: 8px; right: auto; left: 50%; transform: translateX(-50%); padding: 5px 10px; }
body.touch-ui .hud-bottom .bar { width: 70px; }
/* modifier chip + kill feed: left column under the ✕ / fullscreen buttons */
.mod-chip { left: 12px; top: 58px; transform: none; font-size: 12px; padding: 5px 12px; }
.feed { top: 96px; }
body.touch-ui .feed { top: 92px; }
/* narrower PC windows: lift HP/JET above the hotbar */
/* (PC: HP / JET bottom-left, the skill buttons bottom-right — see the end of this file) */
/* hotbar cells are labels, not buttons */
.hotbar { pointer-events: none; }
.slot-cell { cursor: default; }
/* the ✕ and fullscreen buttons further apart */
#app.in-game .fs-btn { left: calc(var(--sa-l) + 74px); }
/* resting joystick: faint and smaller so it doesn't hide the fighter behind it */
.stick-base { opacity: .28; transition: opacity .12s; } /* no scale here: it would also shrink the positioning translate */
.stick-base.on { opacity: 1; }
/* action buttons stay readable over bright lava */
.tbtn { background-color: rgba(17,17,17,.5); }
/* cancel target: top-right corner, out of the way of upward aiming (Liên Quân default spot) */
.t-cancel { top: calc(var(--sa-t) + 52px); bottom: auto; right: calc(var(--sa-r) + 16px); }
/* touch: no keyboard hints */
body.touch-ui .skill-list kbd { display: none; }
/* match-over screen is never a 2-column grid */
@media (orientation: landscape) and (max-height: 520px) and (min-width: 560px) {
  .over-panel { display: flex; flex-direction: column; justify-content: center; }
  .over-panel .actions .btn { flex: 1; padding: 12px; }
}
.podium li.me { outline: 2px solid var(--yellow); outline-offset: -2px; }
/* lobby on narrow phones: one player per row, badge shrinks to a crown */
@media (max-width: 600px) {
  .roster { grid-template-columns: 1fr; max-height: 150px; }
  .roster .host { font-size: 0; padding: 0; background: none; }
  .howto-box summary { padding: 12px 0; }
  .btn.small { min-height: 40px; }
  .limit-row select { min-height: 40px; }
}
@media (orientation: landscape) and (max-height: 520px) and (min-width: 560px) { .menu-panel h1 { margin-top: 10px; } }

/* HUD numbers */
.meter .val { font-family: "Inter", system-ui, sans-serif; font-weight: 900; font-size: 13px; min-width: 26px; text-align: right; color: var(--text); font-variant-numeric: tabular-nums; }
.meter .rate { font-family: "Inter", system-ui, sans-serif; font-weight: 800; font-size: 11px; min-width: 52px; color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
.meter .rate.up { color: #8be0ff; } .meter .rate.down { color: #f6ad13; }
body.touch-ui .meter .val { font-size: 12px; min-width: 22px; }
body.touch-ui .meter .rate { font-size: 10px; min-width: 44px; }
body.touch-ui .hud-bottom { gap: 10px; }
body.touch-ui .hud-bottom .bar { width: 56px; }


/* HP bar, League of Legends style: instant fill + lingering light "lost" chunk + segment ticks */
.bar.hp { position: relative; }
.bar.hp i { position: absolute; left: 0; top: 0; height: 100%; }
.bar.hp .trail { background: #fff3c4; transition: width .45s cubic-bezier(.3,.7,.4,1) .4s; }
.bar.hp .fill { background: linear-gradient(90deg, var(--red), var(--amber)); }
.bar.hp::after { content: ""; position: absolute; inset: 0; pointer-events: none;
  background: repeating-linear-gradient(90deg, transparent 0 calc(25% - 1px), rgba(0,0,0,.55) calc(25% - 1px) 25%); }

/* PC cancel target while aiming with the mouse */
.pc-cancel { position: absolute; left: 50%; bottom: 100px; transform: translateX(-50%); padding: 10px 22px; border-radius: 999px; pointer-events: none;
  font: 900 14px Inter, sans-serif; color: #fff; background: rgba(35,31,32,.82); border: 2px solid rgba(239,76,36,.6); }
.pc-cancel.hot { background: rgba(239,76,36,.92); border-color: #fff; transform: translateX(-50%) scale(1.08); }
body.touch-ui .pc-cancel { display: none; }
.slot-cell .ic svg { width: 30px; }
.tbtn.t-attack .ic svg { width: 40px; height: 28px; }

/* minimap: top-right, under the ping */
.minimap { position: absolute; top: 56px; right: 14px; width: 200px; height: 113px; border-radius: 10px; border: 1px solid rgba(255,255,255,.18);
  background: rgba(17,17,17,.7); pointer-events: auto; cursor: crosshair; box-shadow: 0 6px 18px rgba(0,0,0,.35); }
body.touch-ui .minimap { top: 46px; right: 10px; width: 148px; height: 84px; pointer-events: none; }
/* phones: camera swipe zone (invisible) on the right half, under the buttons */
.cam-zone { position: absolute; left: 52%; right: 0; top: 0; bottom: 0; pointer-events: auto; touch-action: none; }
/* touch cancel target moves left of the minimap */
.t-cancel { right: calc(var(--sa-r) + 170px); top: calc(var(--sa-t) + 48px); }

/* rates printed inside the HP / JET bars */
.bar { position: relative; height: 14px; }
.bar-rate { position: absolute; right: 4px; top: 50%; transform: translateY(-50%); font: 900 9.5px Inter, system-ui, sans-serif; color: #fff;
  text-shadow: 0 1px 0 #000, 0 0 3px #000; letter-spacing: .02em; pointer-events: none; font-variant-numeric: tabular-nums; }
.bar-rate.down { color: #ffd38a; }
.meter .rate { display: none; }
body.touch-ui .bar { height: 12px; }
body.touch-ui .bar-rate { font-size: 8.5px; right: 3px; }
/* FPS next to the ping */
.fps-chip { font-family: "Inter", system-ui, sans-serif; font-weight: 800; font-size: 12px; padding: 6px 10px; border-radius: 8px;
  background: rgba(17,17,17,.8); border: 1px solid var(--line); color: var(--text); font-variant-numeric: tabular-nums; }
body.touch-ui .fps-chip { font-size: 11px; padding: 5px 8px; }

/* phones: the minimap can be dragged too */
body.touch-ui .minimap { pointer-events: auto; touch-action: none; }
.cam-zone { top: 138px; } /* leave the minimap (top-right) to its own drag */

body.touch-ui .hud-top { max-width: calc(100% - 330px); }
.hud-top { max-width: calc(100% - 420px); }

/* phones: minimap top-left (under ✕ / fullscreen), so the action buttons never cover it on short screens */
body.touch-ui .minimap { left: calc(var(--sa-l) + 10px); right: auto; top: 50px; width: 140px; height: 79px; }
body.touch-ui .mod-chip { top: 136px; }
body.touch-ui .feed { top: 168px; }
body.touch-ui .cam-zone { top: 46px; }
body.touch-ui .t-cancel { right: calc(var(--sa-r) + 16px); top: calc(var(--sa-t) + 50px); }
/* short phone screens: slightly smaller action cluster so it stays clear of the top bar */
body.touch-ui #app.in-game.vh400 .tbtn { scale: .88; transform-origin: bottom right; } /* (a match 400 px tall or less) */

/* phones held sideways: your name sits above the character picker (right column), clear of the fullscreen button */
@media (orientation: landscape) and (max-height: 520px) and (min-width: 560px) {
  .menu-panel > .logo, .menu-panel > h1, .menu-panel > .sub, .menu-panel > .cta, .menu-panel > .back { grid-column: 1; }
  .menu-panel > label.field { grid-column: 2; grid-row: 1; margin-top: 44px; }
  .menu-panel > div.field { grid-column: 2; grid-row: 2 / span 5; }
  .lobby-panel > .lobby-me { margin-top: 44px; }
}

@media (orientation: landscape) and (max-height: 520px) and (min-width: 560px) {
  .menu-panel > .menu-brand { grid-column: 1; grid-row: 1; align-self: end; }
  .menu-panel > label.field { grid-column: 2; grid-row: 1; align-self: end; }
  .menu-panel > div.field { grid-column: 2; grid-row: 2 / span 3; }
  .menu-panel > .cta { grid-column: 1; grid-row: 2; }
  .menu-panel > .back { grid-column: 1; grid-row: 3; }
}
.skill-list .sk { grid-template-columns: auto 1fr; } /* icon + text, no key badge */

/* top tools: sound toggle + fullscreen, side by side */
.top-tools { position: absolute; z-index: 40; top: calc(var(--sa-t) + 10px); right: calc(var(--sa-r) + 10px); display: flex; gap: 8px; align-items: center; }
#app.in-game .top-tools { right: auto; left: calc(var(--sa-l) + 62px); top: calc(var(--sa-t) + 8px); }
.top-tools .fs-btn { position: static; }
.snd-btn { display: inline-grid; place-items: center; width: 36px; height: 36px; padding: 0; border-radius: 999px; cursor: pointer;
  color: var(--yellow); background: rgba(17,17,17,.82); border: 1px solid rgba(249,222,11,.45); }
.snd-btn svg { width: 18px; height: 18px; }
.snd-btn.off { color: var(--muted); border-color: var(--line); }

/* voice chat button */
.mic-btn { display: inline-grid; place-items: center; width: 36px; height: 36px; padding: 0; border-radius: 999px; cursor: pointer;
  color: var(--muted); background: rgba(17,17,17,.82); border: 1px solid var(--line); }
.mic-btn svg { width: 18px; height: 18px; }
.mic-btn.on { color: #231f20; background: #78dcb4; border-color: transparent; }

/* icon-only round buttons in the top tools: music, effects, fullscreen (same size as mic) */
.top-tools .fs-btn, #app.in-game .top-tools .fs-btn { width: 36px; height: 36px; padding: 0; justify-content: center; gap: 0; }
.top-tools .fs-btn svg { width: 18px; height: 18px; }

/* phones: minimap back to the top-right (under the ping/FPS chips). On the left it sat inside the joystick's
   touch zone, so tapping it moved the fighter instead of the camera. The swipe-to-pan zone starts below it. */
body.touch-ui .minimap { left: auto; right: calc(var(--sa-r) + 10px); top: 46px; width: 140px; height: 79px; z-index: 6; }
body.touch-ui .cam-zone { top: 134px; }
body.touch-ui .t-cancel { right: calc(var(--sa-r) + 162px); top: calc(var(--sa-t) + 48px); }
body.touch-ui .mod-chip { top: 56px; }
body.touch-ui .feed { top: 96px; }

/* phones in a match: six round tools on the top-left (mic, listen, music, effects, fullscreen) — a bit smaller,
   and the round title sits in the free space between them and the ping/FPS chips instead of under them */
body.touch-ui #app.in-game .top-tools { gap: 5px; }
body.touch-ui #app.in-game .top-tools .mic-btn, body.touch-ui #app.in-game .top-tools .snd-btn, body.touch-ui #app.in-game .top-tools .fs-btn { width: 32px; height: 32px; }
body.touch-ui #app.in-game .top-tools svg { width: 16px; height: 16px; }
body.touch-ui #app.in-game .hud-top { left: calc(var(--sa-l) + 290px); right: calc(var(--sa-r) + 192px); max-width: none; width: auto; margin: 0; justify-content: center; gap: 6px; }
body.touch-ui #app.in-game .hud-top .round { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }

/* ===== in-match top HUD, reorganised =====
   left:   minimap in the corner → a small FPS · link · ping line → kill feed
   centre: round title + pips, the round's modifier chip under it
   right:  mic · listen · music · effects · fullscreen, then ✕ (leave) in the corner */
#app.in-game .minimap { left: calc(var(--sa-l) + 8px); right: auto; top: calc(var(--sa-t) + 8px); width: 200px; height: 113px; }
#app.in-game .netstat { left: calc(var(--sa-l) + 10px); right: auto; top: calc(var(--sa-t) + 125px); transform: none;
  gap: 8px; align-items: center; opacity: .8; pointer-events: none; }
#app.in-game .netstat > span { background: none; border: 0; padding: 0; border-radius: 0; font: 800 10px/1 Inter, system-ui, sans-serif; letter-spacing: .02em;
  color: rgba(255,255,255,.85); text-shadow: 0 1px 2px #000, 0 0 4px #000; }
#app.in-game .netstat .link.udp { color: #78dcb4; } #app.in-game .netstat .link.tcp { color: var(--amber); }
#app.in-game .netstat .ping::before { margin-right: 3px; }
#app.in-game .feed { left: calc(var(--sa-l) + 8px); top: calc(var(--sa-t) + 146px); }
#app.in-game .hud-top { left: calc(var(--sa-l) + 222px); right: calc(var(--sa-r) + 276px); top: calc(var(--sa-t) + 10px);
  width: auto; max-width: none; margin: 0; transform: none; justify-content: center; flex-wrap: nowrap; gap: 8px; }
#app.in-game .hud-top .round { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
#app.in-game .mod-chip { left: 50%; right: auto; top: calc(var(--sa-t) + 52px); transform: translateX(-50%); }
#app.in-game .exit { left: auto; right: calc(var(--sa-r) + 8px); top: calc(var(--sa-t) + 8px);
  width: 36px; height: 36px; padding: 0; display: grid; place-items: center; border-radius: 999px; }
#app.in-game .top-tools { left: auto; right: calc(var(--sa-r) + 52px); top: calc(var(--sa-t) + 8px); gap: 8px; }

/* phones: same arrangement, compact */
body.touch-ui #app.in-game .minimap { left: calc(var(--sa-l) + 8px); right: auto; top: calc(var(--sa-t) + 8px); width: 140px; height: 79px; }
body.touch-ui #app.in-game .netstat { top: calc(var(--sa-t) + 91px); }
body.touch-ui #app.in-game .netstat > span { font-size: 9px; }
body.touch-ui #app.in-game .feed { top: calc(var(--sa-t) + 108px); }
body.touch-ui #app.in-game .exit { width: 32px; height: 32px; top: calc(var(--sa-t) + 6px); }
body.touch-ui #app.in-game .top-tools { right: calc(var(--sa-r) + 45px); top: calc(var(--sa-t) + 6px); gap: 5px; }
body.touch-ui #app.in-game .hud-top { left: calc(var(--sa-l) + 158px); right: calc(var(--sa-r) + 232px); top: calc(var(--sa-t) + 7px); gap: 6px; }
body.touch-ui #app.in-game .mod-chip { top: calc(var(--sa-t) + 42px); }
/* the joystick's touch area starts under the minimap (it sits on a layer above the HUD, so it must not overlap) */
body.touch-ui .stick-zone { top: calc(var(--sa-t) + 112px); }
/* swipe-to-pan on the right starts under the button row; the skill cancel target sits right under the buttons */
body.touch-ui .cam-zone { top: calc(var(--sa-t) + 46px); }
body.touch-ui .t-cancel { right: calc(var(--sa-r) + 16px); top: calc(var(--sa-t) + 50px); }

/* on-screen keyboard open (menus): the main buttons stop being pinned to the bottom and follow the content,
   so they never cover the name / room-code field being typed in */
body.kbd-open .cta { position: static; background: none; }


/* ===== review round 1: controls & HUD fixes ===== */
/* skill cancel target: top-centre, far from every drag path (dragging a skill upward used to land on it) */
body.touch-ui .t-cancel { left: 50%; right: auto; top: calc(var(--sa-t) + 46px); bottom: auto; translate: -50% 0; z-index: 3; }
/* throw-weapon button above the grenade, clear of the HP/JET bars */
body.touch-ui .t-throw { right: calc(max(22px, var(--sa-r)) + 178px); bottom: 150px; }
/* PC: the cancel hint sits above the HP bar and hotbar */
.pc-cancel { bottom: 156px; }
/* results on a short landscape phone: the champion title stays reachable, clear of the top buttons */
.over-panel { justify-content: safe center; }
body.touch-ui .over-panel { padding-top: 52px; }
/* lobby on a landscape phone: the start button follows the list instead of covering it */
@media (orientation: landscape) and (max-height: 520px) and (min-width: 560px) { .lobby-panel .cta { position: static; background: none; } }
.host { font-size: 14px; letter-spacing: 0; padding: 0 2px; background: none; border: 0; }
/* cooldowns readable: greyed icon, big seconds on a dark disc, a flash when ready */
.tbtn.cooling .ic { filter: grayscale(1) brightness(.55); }
.tbtn .cdt { position: absolute; inset: 0; display: grid; place-items: center; z-index: 2; font: 900 20px Inter, system-ui, sans-serif; color: #fff;
  text-shadow: 0 1px 3px #000, 0 0 6px #000; pointer-events: none; }
.tbtn.cooling .cdt:not(:empty)::before { content: ""; position: absolute; width: 30px; height: 30px; border-radius: 50%; background: rgba(0,0,0,.55); z-index: -1; }
.tbtn.ready { animation: btnReady .45s ease-out; }
@keyframes btnReady { 0% { box-shadow: 0 0 0 0 rgba(249,222,11,.9); } 100% { box-shadow: 0 0 0 16px rgba(249,222,11,0); } }
.tbtn.deny, .slot-cell.deny { animation: btnDeny .3s ease; }
@keyframes btnDeny { 20%, 60% { translate: -5px 0; } 40%, 80% { translate: 5px 0; } }
/* attack button with a gun: ammo count in the corner, darker so the gun icon reads */
.tbtn.t-attack.armed { background: linear-gradient(135deg, rgba(40,36,38,.9), rgba(70,40,30,.9)); }
.tbtn.t-attack[data-ammo]:not([data-ammo=""])::after { content: attr(data-ammo); position: absolute; right: 8px; bottom: 8px; z-index: 3; min-width: 22px; padding: 1px 5px;
  border-radius: 999px; background: #f9de0b; color: #231f20; font: 900 12px/1.4 Inter, system-ui, sans-serif; text-align: center; }
/* knocked out: controls dim until the next round */
.touch.dead .tbtn, .touch.dead .stick-base { opacity: .35; }
/* kill feed: lines about you stand out */
.feed .mine { border-color: #f9de0b; color: #f9de0b; }
/* banner sub-line readable over the game */
.banner small { font-size: 16px; color: #fff; text-shadow: 0 2px 4px #000, 0 0 8px #000; font-weight: 700; }
/* score strip with many players: top 3 + you, head + "wins/needed" */
.pips.compact { gap: 8px; flex-wrap: nowrap; }
.pips.compact li b { font: 900 11px Inter, system-ui, sans-serif; color: var(--c); }
.pips li.me img { outline: 2px solid #f9de0b; border-radius: 50%; }
/* Vietnamese text never in the pixel font (its accents render as odd glyphs) */
#codeInput::placeholder, .podium, .over-panel .eyebrow { font-family: Inter, system-ui, sans-serif; }

/* first-match control labels (phones) */
.coach { position: absolute; inset: 0; z-index: 60; pointer-events: none; background: rgba(0,0,0,.35); animation: coachIn .3s ease; }
.coach-tip { position: absolute; transform: translateY(-50%); max-width: 210px; padding: 6px 10px; border-radius: 10px; background: #f9de0b; color: #231f20;
  font: 800 12px/1.3 Inter, system-ui, sans-serif; box-shadow: 0 4px 14px rgba(0,0,0,.5); }
.coach-tip.l::after, .coach-tip.r::before { content: ""; position: absolute; top: 50%; translate: 0 -50%; border: 6px solid transparent; }
.coach-tip.l::after { left: 100%; border-left-color: #f9de0b; }
.coach-tip.r::before { right: 100%; border-right-color: #f9de0b; }
.coach-hint { position: absolute; left: 50%; top: 40%; transform: translate(-50%, -50%); font: 900 16px Inter, system-ui, sans-serif; color: #fff; text-shadow: 0 2px 6px #000; }
@keyframes coachIn { from { opacity: 0; } }
.coach-tip { white-space: nowrap; max-width: none; }
.coach-tip.t { transform: translateX(-50%); }
.coach-tip.t::after { content: ""; position: absolute; left: 50%; top: 100%; translate: -50% 0; border: 6px solid transparent; border-top-color: #f9de0b; }
.coach-hint { text-align: center; white-space: nowrap; }
.coach-hint small { display: block; margin-top: 6px; font: 700 12px Inter, system-ui, sans-serif; color: #f9de0b; }

/* ===== top HUD, mirrored: minimap top-RIGHT (+ FPS·link·ping line and kill feed under it), tools top-LEFT (✕ in the corner) ===== */
#app.in-game .minimap { left: auto; right: calc(var(--sa-r) + 8px); }
#app.in-game .netstat { left: auto; right: calc(var(--sa-r) + 10px); justify-content: flex-end; }
#app.in-game .feed { left: auto; right: calc(var(--sa-r) + 8px); align-items: flex-end; }
#app.in-game .exit { right: auto; left: calc(var(--sa-l) + 8px); }
#app.in-game .top-tools { right: auto; left: calc(var(--sa-l) + 52px); }
#app.in-game .hud-top { left: calc(var(--sa-l) + 276px); right: calc(var(--sa-r) + 222px); }
body.touch-ui #app.in-game .minimap { left: auto; right: calc(var(--sa-r) + 8px); }
body.touch-ui #app.in-game .exit { right: auto; left: calc(var(--sa-l) + 8px); }
body.touch-ui #app.in-game .top-tools { right: auto; left: calc(var(--sa-l) + 45px); }
body.touch-ui #app.in-game .hud-top { left: calc(var(--sa-l) + 232px); right: calc(var(--sa-r) + 158px); }
/* phones: joystick zone starts under the button row; the swipe-to-pan zone on the right starts under the minimap */
body.touch-ui .stick-zone { top: calc(var(--sa-t) + 46px); }
body.touch-ui .cam-zone { top: calc(var(--sa-t) + 112px); }

/* coach: rules card top-left (solid, so nothing shows through), joystick label above the stick */
.coach-hint { left: calc(var(--sa-l) + 8px); top: calc(var(--sa-t) + 48px); transform: none; text-align: left; white-space: normal; max-width: 300px;
  padding: 10px 12px; border-radius: 12px; background: rgba(17,17,17,.95); border: 1px solid #f9de0b; font: 600 12px/1.5 Inter, system-ui, sans-serif; text-shadow: none; }
.coach-hint b { display: block; font-size: 14px; color: #f9de0b; margin-bottom: 4px; }
/* skill info card */
.skill-card { position: absolute; left: 50%; bottom: 168px; transform: translateX(-50%); z-index: 30; width: min(340px, 86vw); padding: 10px 14px; border-radius: 12px;
  background: rgba(17,17,17,.95); border: 1px solid rgba(249,222,11,.6); box-shadow: 0 8px 24px rgba(0,0,0,.5); pointer-events: none;
  font-family: Inter, system-ui, sans-serif; color: var(--text); }
.skill-card .sc-head { display: flex; align-items: center; gap: 8px; }
.skill-card .sc-ic { font-size: 22px; line-height: 1; display: inline-grid; place-items: center; width: 28px; height: 28px; }
.skill-card .sc-ic svg { width: 24px; height: 24px; }
.skill-card b { font-size: 15px; font-weight: 900; }
.skill-card em { margin-left: auto; font-style: normal; font-weight: 800; font-size: 12px; color: #f9de0b; }
.skill-card p { margin: 6px 0 0; font-size: 13px; line-height: 1.45; color: #e6e1e2; }
body.touch-ui .skill-card { bottom: auto; top: calc(var(--sa-t) + 46px); }
.hotbar .slot-cell { pointer-events: auto; cursor: pointer; }

/* ===== chat ===== */
.chat-log { position: absolute; z-index: 35; left: calc(var(--sa-l) + 12px); bottom: 150px; width: min(380px, 42vw); max-height: 190px; overflow: hidden;
  display: flex; flex-direction: column; gap: 3px; pointer-events: none; font: 600 13px/1.35 Inter, system-ui, sans-serif; }
/* new lines rise in from below and push the older ones up */
.chat-log > .chat-line { flex: none; animation: chatIn .22s ease-out; }
.chat-log > .chat-line:first-child { margin-top: auto; }
@keyframes chatIn { from { transform: translateY(10px); opacity: 0; } }
.chat-line .ts { font-style: normal; font-weight: 600; color: #a9a3a4; margin-right: 6px; font-variant-numeric: tabular-nums; font-size: .85em; }
.chat-line.kill .ts { margin-right: 2px; }
.chat-line.kill.mine { box-shadow: inset 0 0 0 1px #f9de0b; }
.chat-line.sys.mine { color: #f9de0b; }
.chat-line.event { font-weight: 700; }
.chat-line.event b { font-weight: 900; letter-spacing: .02em; }
.chat-line.round { color: #f6ad13; font-weight: 800; font-size: .92em; opacity: .9; }
.chat-log.open { overflow-y: auto; pointer-events: auto; background: rgba(17,17,17,.75); border-radius: 10px; padding: 6px 8px; }
.chat-line { color: #fff; text-shadow: 0 1px 2px #000, 0 0 4px #000; transition: opacity .6s; word-break: break-word; }
.chat-line.old { opacity: 0; }
.chat-log.open .chat-line.old { opacity: .75; }
.chat-line.sys { color: #a9a3a4; font-style: italic; }
.chat-line.mine b { text-decoration: underline; }
.chat-box { position: absolute; z-index: 45; left: 50%; bottom: 150px; transform: translateX(-50%); width: min(460px, 92vw); padding: 8px; border-radius: 12px;
  background: rgba(17,17,17,.96); border: 1px solid rgba(249,222,11,.5); display: flex; flex-direction: column; gap: 6px; }
.chat-row { display: flex; gap: 6px; }
.chat-row input { flex: 1; min-width: 0; padding: 9px 12px; font-size: 16px; border-radius: 8px; border: 1px solid var(--line); background: #1b1819; color: #fff; }
.chat-row .btn { padding: 8px 14px; }
.chat-quick { display: flex; flex-wrap: wrap; gap: 5px; }
.chat-quick button { padding: 5px 9px; border-radius: 999px; border: 1px solid var(--line); background: #231f20; color: #fff; font: 700 12px Inter, system-ui, sans-serif; cursor: pointer; }
body.touch-ui .chat-log { bottom: auto; top: calc(var(--sa-t) + 46px); width: min(300px, 40vw); max-height: 112px; font-size: 11.5px; }
body.touch-ui .chat-box { bottom: auto; top: calc(var(--sa-t) + 44px); }
#app:not(.in-game) .chat-log { bottom: 16px; }
/* ===== kill feed with heads ===== */
.feed .kill { display: flex; align-items: center; gap: 5px; padding: 3px 8px; border-radius: 8px; background: rgba(17,17,17,.8); border: 1px solid var(--line);
  font: 700 11px Inter, system-ui, sans-serif; }
.feed .kill.mine { border-color: #f9de0b; }
.feed .kf { display: inline-flex; align-items: center; gap: 3px; }
.feed .kf img { width: 18px; height: 18px; object-fit: contain; }
.feed .kill i { font-style: normal; }
/* ===== announcements ===== */
.announce { position: absolute; z-index: 32; left: 50%; top: 22%; transform: translateX(-50%); text-align: center; pointer-events: none; font-family: Inter, system-ui, sans-serif; }
.announce.show { animation: annIn .35s cubic-bezier(.2,1.5,.4,1); }
.ann-row { display: flex; align-items: center; justify-content: center; gap: 8px; margin-bottom: 4px; }
.ann-row img { width: 44px; height: 44px; object-fit: contain; border-radius: 50%; border: 3px solid #fff; background: rgba(17,17,17,.85); }
.ann-vs { font-size: 20px; text-shadow: 0 2px 4px #000; }
.ann-title { font-weight: 900; font-size: 30px; letter-spacing: .03em; text-shadow: 0 3px 0 #000, 0 0 20px rgba(239,76,36,.6); white-space: nowrap; }
.ann-sub { font-weight: 700; font-size: 14px; color: #fff; text-shadow: 0 2px 4px #000; }
body.touch-ui .announce { top: 18%; }
body.touch-ui .ann-title { font-size: 22px; }
body.touch-ui .ann-row img { width: 34px; height: 34px; }
@keyframes annIn { from { transform: translateX(-50%) scale(.5); opacity: 0; } }
/* seven round tools now (chat added): the round title starts after them */
#app.in-game .hud-top { left: calc(var(--sa-l) + 368px); }
body.touch-ui #app.in-game .hud-top { left: calc(var(--sa-l) + 312px); }
.coach-hint { max-width: 270px; font-size: 11.5px; line-height: 1.45; padding: 8px 10px; }
.announce { top: 13%; }
body.touch-ui .announce { top: 12%; }

/* ghost mode hint */
.ghost-hint { position: absolute; left: 50%; bottom: 168px; transform: translateX(-50%); z-index: 20; padding: 8px 14px; border-radius: 999px; pointer-events: none;
  background: rgba(17,17,17,.88); border: 1px solid rgba(230,225,226,.5); color: #f4f2f2; font: 800 13px Inter, system-ui, sans-serif; white-space: nowrap; }
body.touch-ui .ghost-hint { bottom: auto; top: 46px; }
/* knocked out on a phone: the controls let taps through to the arena (ghost mode) */
.touch.dead .tbtn, .touch.dead .stick-zone, .touch.dead .cam-zone { pointer-events: none; }

/* end-of-match awards */
.awards { list-style: none; margin: 10px 0 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 8px; }
.awards li { display: flex; align-items: center; gap: 8px; padding: 8px 10px; border-radius: 10px; background: rgba(255,255,255,.04); border: 1px solid var(--line); font-family: Inter, system-ui, sans-serif; }
.awards li.me { border-color: #f9de0b; }
.awards .aw-ic { font-size: 20px; }
.awards img { width: 28px; height: 28px; object-fit: contain; }
.awards .aw-t { display: flex; flex-direction: column; line-height: 1.25; min-width: 0; }
.awards b { font-size: 13px; color: #f9de0b; }
.awards small { font-size: 11.5px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.awards { grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); }

/* perk card picker */
.card-pick { position: absolute; z-index: 46; left: 50%; bottom: 18%; transform: translateX(-50%); width: min(620px, 94vw); padding: 10px; border-radius: 14px;
  background: rgba(17,17,17,.94); border: 1px solid rgba(249,222,11,.55); font-family: Inter, system-ui, sans-serif; animation: annIn .3s ease; }
.cp-title { text-align: center; font-weight: 900; font-size: 14px; color: #f9de0b; margin-bottom: 8px; }
.cp-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.cp-card { display: flex; flex-direction: column; align-items: center; gap: 4px; padding: 10px 8px; border-radius: 12px; border: 1px solid var(--line); background: #1d1a1b;
  color: #fff; cursor: pointer; font: inherit; text-align: center; transition: transform .12s, border-color .12s; }
.cp-card:hover, .cp-card:focus-visible { transform: translateY(-3px); border-color: #f9de0b; }
.cp-ic { font-size: 26px; line-height: 1; }
.cp-card b { font-size: 13px; }
.cp-card small { font-size: 11px; color: var(--muted); line-height: 1.3; }
body.touch-ui .card-pick { bottom: auto; top: 46px; }

/* ===== review round 2: game UI ===== */
/* ammo badge: a small pill in the corner (it inherited inset:0 from .tbtn::after and covered the whole button) */
.tbtn.t-attack[data-ammo]:not([data-ammo=""])::after { inset: auto; left: auto; top: auto; right: 6px; bottom: 6px; width: auto; height: auto; border-radius: 999px; background: #f9de0b; }
/* phones: card picker, chat box and skill card stay left of the action cluster and under the tool row */
body.touch-ui .card-pick { left: calc(var(--sa-l) + 8px); transform: none; width: min(520px, calc(100% - 180px)); top: 46px; padding: 8px; }
body.touch-ui .cp-card { padding: 6px; }
body.touch-ui .cp-ic { font-size: 20px; }
body.touch-ui .cp-card small { font-size: 10px; }
body.touch-ui .chat-box { left: calc(var(--sa-l) + 8px); transform: none; width: min(420px, calc(100% - 180px)); }
body.touch-ui .skill-card { left: calc(var(--sa-l) + 8px); transform: none; width: min(340px, calc(100% - 180px)); }
/* phones: kill lines live in the chat log (left), never over the buttons */
body.touch-ui #app.in-game .feed { display: none; }
.chat-line.kill { display: flex; align-items: center; gap: 4px; padding: 2px 6px; border: 0; background: rgba(17,17,17,.55); border-radius: 6px; width: max-content; max-width: 100%; }
.chat-line.kill img { width: 16px; height: 16px; object-fit: contain; }
.chat-line.kill .kf { display: inline-flex; align-items: center; gap: 3px; }
.chat-line.kill i { font-style: normal; }
/* ✕ a little apart from the other round buttons */
body.touch-ui #app.in-game .top-tools { left: calc(var(--sa-l) + 50px); }
#app.in-game .top-tools { left: calc(var(--sa-l) + 56px); }
/* mic outside a room does nothing: hide it */
.mic-btn.noroom { display: none; }
/* menus: the tool row has its own backdrop, so scrolled content never shows through it */
#app:not(.in-game) .top-tools { background: rgba(17,17,17,.9); padding: 4px; border-radius: 999px; }
/* results: "round" in Inter (the pixel font mangles Vietnamese) */
.podium b, .lobby-panel h2, .lobby-panel .eyebrow { font-family: Inter, system-ui, sans-serif; }

/* HUD bars scale instead of resizing (no layout work every update) */
.bar i, .bar.hp i, .bar.hp .fill, .bar.hp .trail, #hudFuel { width: 100%; transform-origin: left center; } /* (no will-change: each one was its own compositor layer, and pushed the layers over them to be separate too) */
.bar.hp .trail { transition: transform .45s cubic-bezier(.3,.7,.4,1) .4s; }


/* ===== hall (room browser) & lobby room controls ===== */
.me-row { display: flex; align-items: flex-end; gap: 12px; margin-bottom: 14px; }
.me-row .me-name { flex: 1; margin: 0; }
.me-char { flex: none; display: grid; grid-template-columns: 52px; justify-items: center; gap: 2px; padding: 6px 8px 5px; border-radius: 14px;
  border: 2px solid var(--line); background: linear-gradient(180deg, #2a2526, #141213); color: var(--text); cursor: pointer; font: inherit; }
.me-char img { width: 52px; height: 46px; object-fit: contain; }
.me-char .me-char-name { font-size: .68rem; font-weight: 700; color: var(--amber); max-width: 76px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.me-char[aria-expanded="true"] { border-color: var(--amber); }
.me-char:hover { border-color: rgba(246,173,19,.6); }
.char-drawer { margin: 0 0 14px; padding: 10px; border-radius: 14px; border: 1px solid var(--line); background: rgba(20,18,19,.7); }
.char-drawer .skill-list { margin-top: 10px; }
.rooms-head { display: flex; align-items: center; justify-content: space-between; margin: 4px 0 8px; font-size: .8rem; font-weight: 700; color: var(--muted); letter-spacing: .04em; }
.icon-btn { width: 34px; height: 34px; display: grid; place-items: center; border-radius: 10px; border: 1px solid var(--line); background: #141213; color: var(--muted); cursor: pointer; padding: 0; }
.icon-btn svg { width: 18px; height: 18px; }
.icon-btn:hover { color: var(--amber); }
.icon-btn.spin svg { animation: spin360 .6s ease; }
@keyframes spin360 { to { transform: rotate(360deg); } }
.room-list { list-style: none; margin: 0 0 12px; padding: 0; display: grid; gap: 8px; max-height: min(42vh, 330px); overflow-y: auto; overscroll-behavior: contain; }
.room-list .empty { padding: 18px 14px; border-radius: 12px; border: 1px dashed var(--line); color: var(--muted); font-size: .85rem; text-align: center; }
.room-item { display: grid; grid-template-columns: 40px 1fr auto; align-items: center; gap: 10px; padding: 8px 10px; border-radius: 12px; background: #141213; border: 1px solid var(--line); cursor: pointer; }
.room-item:hover { border-color: rgba(246,173,19,.5); }
.room-item.full { opacity: .55; cursor: default; }
.room-item img { width: 40px; height: 40px; object-fit: contain; }
.ri-text { min-width: 0; }
.ri-text b { display: block; font-size: .92rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ri-text small { display: block; font-size: .74rem; color: var(--muted); white-space: normal; overflow-wrap: anywhere; }
.ri-state { font-weight: 700; }
.ri-state.wait { color: #78dcb4; } .ri-state.live { color: var(--orange); }
.room-item .btn { min-width: 64px; }
.create-box { margin: 0 0 12px; padding: 12px; border-radius: 14px; border: 1px solid rgba(246,173,19,.35); background: rgba(20,18,19,.7); }
.create-box .field { margin-bottom: 10px; }
.create-row { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 16px; font-size: .85rem; color: var(--muted); font-weight: 600; }
.create-row .sel { display: flex; align-items: center; gap: 8px; }
.create-row select { font: inherit; color: var(--text); background: #141213; border: 1px solid var(--line); border-radius: 10px; padding: 6px 10px; }
.create-row .chk { display: flex; align-items: center; gap: 6px; cursor: pointer; }
.create-row .chk input { width: 18px; height: 18px; accent-color: var(--amber); margin: 0; }
.create-row .chk small { font-weight: 500; font-size: .72rem; }
.room-title { display: block; width: 100%; margin: 6px 0 0; padding: 4px 0; border: 0; border-bottom: 1px dashed transparent; background: transparent; outline: none;
  color: var(--text); font: 800 1.15rem/1.3 "Inter", system-ui, sans-serif; }
.room-title:not([readonly]) { border-bottom-color: var(--line); cursor: text; }
.room-title:not([readonly]):focus { border-bottom-color: var(--amber); }
.room-title[readonly]::placeholder { color: var(--text); opacity: 1; }
.code-row { flex-wrap: wrap; }
.code-row #btnPriv { margin-left: auto; }
.btn.ghost { background: transparent; }
.btn:disabled.ghost { opacity: .75; cursor: default; }
.roster .kick { margin-left: auto; flex: none; min-width: 30px; height: 28px; padding: 0 8px; border-radius: 8px; border: 1px solid var(--line); background: transparent;
  color: var(--muted); font: 700 .78rem/1 "Inter", system-ui, sans-serif; cursor: pointer; }
.roster .kick:hover { color: var(--red); border-color: rgba(239,76,36,.5); }
.roster .kick.armed { color: #fff; background: var(--red); border-color: var(--red); }
@media (max-width: 599px), (max-height: 500px) {
  .room-list { max-height: none; }
  .me-char img { width: 44px; height: 40px; }
  .me-char { grid-template-columns: 44px; }
}

#menu.creating .menu-panel > .cta { display: none; } /* the create form has its own buttons */
/* phones held sideways: left = brand, me, buttons · right = the room list */
@media (orientation: landscape) and (max-height: 520px) and (min-width: 560px) {
  .menu-panel > .menu-brand { grid-column: 1; grid-row: 1; align-self: start; }
  .menu-panel > .me-row { grid-column: 1; grid-row: 2; margin-bottom: 8px; }
  .menu-panel > .char-drawer { grid-column: 1; grid-row: 3; margin-bottom: 8px; }
  .menu-panel > .create-box { grid-column: 1; grid-row: 4; }
  .menu-panel > .cta { grid-column: 1; grid-row: 5; }
  .menu-panel > .back { grid-column: 1; grid-row: 6; }
  .menu-panel > .rooms-head { grid-column: 2; grid-row: 1; align-self: start; margin-top: 50px; }
  .menu-panel > .room-list { grid-column: 2; grid-row: 2 / span 5; align-self: start; }
  .menu-panel .sub { display: none; }
  .me-row .field > span { margin-bottom: 4px; }
  .create-box { padding: 10px; }
}
.create-box .actions { margin-top: 12px; }
@media (orientation: landscape) and (max-height: 520px) and (min-width: 560px) {
  .lobby-panel > .room-title { grid-column: 1; margin-top: 2px; font-size: 1rem; }
  .lobby-panel > .lobby-me { grid-row: 1 / span 6; }
  .lobby-panel .eyebrow { font-size: .62rem; }
  .code-row { flex-wrap: nowrap; gap: 8px; }
  .code-row #btnPriv { padding-inline: 10px; }
  .code-row #btnPriv span { display: none; }
  .code-row .btn { white-space: nowrap; }
}

/* "host it yourself?" dialog */
.modal { position: fixed; inset: 0; z-index: 80; display: grid; place-items: center; padding: 16px; background: rgba(0,0,0,.6); backdrop-filter: blur(3px); }
.modal-panel { width: min(440px, 100%); max-height: none; padding: 22px; }
.modal-panel h3 { margin: 0 0 10px; font: 900 1.25rem/1.25 "Inter", system-ui, sans-serif; }
.modal-panel p { margin: 0 0 10px; font-size: .92rem; line-height: 1.45; }
.modal-panel .muted { color: var(--muted); font-size: .82rem; }
.modal-panel .actions { margin-top: 16px; }
.link.p2p { color: #b98cff; } .link.hosting { color: var(--yellow); }

/* passive slot + buffs/debuffs in the HUD */
.passive-slot { position: relative; width: 38px; height: 38px; border-radius: 10px; border: 2px solid #b98cff; background: rgba(185,140,255,.12); font-size: 20px; line-height: 1; cursor: help; padding: 0; color: var(--text); }
.passive-slot.lit { box-shadow: 0 0 12px rgba(185,140,255,.8); }
.passive-slot b { position: absolute; right: -6px; bottom: -6px; min-width: 18px; height: 18px; padding: 0 4px; border-radius: 9px; background: #b98cff; color: #160f22; font: 900 11px/18px Inter, sans-serif; }
.eff-row { display: flex; gap: 6px; align-items: center; }
.eff-row:empty { display: none; }
.eff-chip { position: relative; width: 32px; height: 32px; border-radius: 50%; display: grid; place-items: center; font-size: 16px; background: rgba(120,220,180,.15); border: 2px solid #78dcb4; cursor: help; }
.eff-chip.bad { background: rgba(239,76,36,.15); border-color: #ef4c24; }
.eff-chip i { position: absolute; left: 50%; bottom: -14px; transform: translateX(-50%); font: 800 10px/1 Inter, sans-serif; font-style: normal; color: var(--muted); white-space: nowrap; }
.eff-chip b { position: absolute; right: -5px; top: -5px; min-width: 16px; height: 16px; padding: 0 3px; border-radius: 8px; background: #231f20; border: 1px solid var(--line); font: 900 10px/14px Inter, sans-serif; }
.skill-list .sk.passive { border-color: rgba(185,140,255,.45); background: rgba(185,140,255,.07); }
.skill-list .sk.passive small { color: #b98cff; }
body.touch-ui .passive-slot { width: 30px; height: 30px; font-size: 16px; }
body.touch-ui .eff-chip { width: 26px; height: 26px; font-size: 13px; }

/* ⓘ: your skills, passive and current effects during a match */
.info-panel { position: absolute; z-index: 45; top: calc(var(--sa-t) + 56px); left: calc(var(--sa-l) + 12px); width: min(360px, calc(100vw - 24px)); max-height: calc(100% - 130px); overflow-y: auto;
  padding: 14px; border-radius: 16px; background: rgba(17,17,17,.94); border: 1px solid var(--line); box-shadow: 0 12px 30px rgba(0,0,0,.5); }
.info-panel h4 { margin: 0 0 10px; font: 900 .95rem/1.2 Inter, sans-serif; display: flex; align-items: center; gap: 8px; }
.info-panel h4 img { width: 30px; height: 30px; object-fit: contain; }
.info-panel .skill-list { display: grid; gap: 8px; }
.info-panel .eff-now { margin-top: 10px; font-size: .8rem; color: var(--muted); }
.info-panel .eff-now div { display: flex; gap: 8px; align-items: flex-start; margin-top: 6px; color: var(--text); }

/* ===== review round 3 (game UI) ===== */
/* the host dialog keeps its own look on phones (the phone .panel rules made it a bare full-height column) */
.modal .panel.modal-panel { min-height: 0; height: auto; display: block; width: min(440px, 100%); background: #1a1718; border: 1px solid var(--line); border-radius: 18px; padding: 22px; box-shadow: 0 20px 50px rgba(0,0,0,.6); }
.modal .modal-panel .actions { display: flex; }
/* event lines outside a match sit low, not over the lobby header / results */
#app:not(.in-game) .chat-log, body.touch-ui #app:not(.in-game) .chat-log { top: auto; bottom: calc(var(--sa-b) + 96px); }
/* an open chat box pushes the history below it instead of covering it */
#app:has(.chat-box:not(.hidden)) .chat-log { top: calc(var(--sa-t) + 150px); }
.chat-log { background: rgba(11,11,11,.35); border-radius: 10px; }
/* landscape hall: the buttons scroll with the page so the character drawer stays readable */
@media (orientation: landscape) and (max-height: 520px) and (min-width: 560px) {
  .menu-panel .cta { position: static; background: none; }
  .over-panel .actions { position: sticky; bottom: 0; padding: 8px 0 calc(var(--sa-b) + 8px); background: linear-gradient(180deg, rgba(17,17,17,0), var(--bg) 30%); }
  .podium li { padding: 6px 10px; }
}
/* host crown: just the crown */
.roster .host, .roster li .host { background: none; padding: 0; font-size: 16px; border-radius: 0; }
/* room name: reads as a title; the host sees an edit cue */
.room-title { color: var(--text); }
.room-title:not([readonly]) { padding-right: 24px; background: no-repeat right 2px center / 16px url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M4 20h4L19 9l-4-4L4 16z' fill='none' stroke='%23a9a3a4' stroke-width='2' stroke-linejoin='round'/%3E%3C/svg%3E"); }
/* room code: labelled, tap to copy */
.code-wrap { display: inline-flex; flex-direction: column; align-items: flex-start; gap: 2px; background: none; border: 0; padding: 0; cursor: copy; color: inherit; }
.code-wrap small { font: 700 .66rem/1 Inter, sans-serif; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); }
.code-wrap.copied small::after { content: " · đã sao chép"; color: #78dcb4; }
.hosting-chip { font-size: .72rem; font-weight: 700; color: var(--yellow); background: rgba(249,222,11,.1); border: 1px solid rgba(249,222,11,.35); border-radius: 999px; padding: 5px 10px; }
.where-hint { flex-basis: 100%; font-size: .75rem; color: var(--muted); font-weight: 500; }
/* character tile on the hall: the name stays inside it */
.me-char .me-char-name { max-width: 60px; }
.char-drawer .chars { margin-left: 0; margin-right: 0; width: 100%; }
/* touch targets */
.roster .kick { min-width: 40px; min-height: 36px; }
body.touch-ui .snd-btn, body.touch-ui .mic-btn, .icon-btn, .roster .kick { position: relative; }
body.touch-ui .snd-btn::after, body.touch-ui .mic-btn::after, .icon-btn::after, .roster .kick::after { content: ""; position: absolute; inset: -6px; }
body.touch-ui .create-row select { min-height: 40px; }
body.touch-ui .create-row .chk input { width: 22px; height: 22px; }
/* small HUD text a bit larger */
.slot-cell .nm { font-size: 11px; }
#app.in-game .netstat > span { font-size: 11px; }
/* the hosting note gets its own line under the code */
.code-row .hosting-chip { order: 9; flex: 1 1 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; text-align: center; }
@media (orientation: landscape) and (max-height: 520px) and (min-width: 560px) { .code-row { flex-wrap: wrap; } }

/* spectating after a knock-out: who we watch, ◀ ▶ to switch */
.spec-bar { position: absolute; left: 50%; top: 58px; transform: translateX(-50%); z-index: 21; display: flex; align-items: center; gap: 6px; pointer-events: auto;
  padding: 4px; border-radius: 999px; background: rgba(17,17,17,.82); border: 1px solid rgba(76,195,255,.55); box-shadow: 0 6px 18px rgba(0,0,0,.4); }
.spec-bar .sp-txt { padding: 0 8px; font: 700 .86rem Inter, sans-serif; color: var(--text, #f4f2f2); white-space: nowrap; }
.spec-bar .sp-txt small { color: #a9a3a4; font-weight: 600; }
.spec-bar .sp-btn { width: 34px; height: 34px; border-radius: 50%; border: 1px solid rgba(255,255,255,.18); background: #232021; color: #fff; font-size: 13px; cursor: pointer; }
.spec-bar .sp-btn:hover { border-color: #4cc3ff; }
.spec-bar .sp-btn.hidden { display: none; }
body.touch-ui .spec-bar { top: auto; bottom: 14px; }
/* knocked out: nothing on the hotbar / passive can be used */
body.me-dead .hotbar .slot-cell, body.me-dead .passive-slot { filter: grayscale(1) brightness(.75); opacity: .45; }
body.me-dead .hotbar .slot-cell .cd, body.me-dead .hotbar .slot-cell .cdt { visibility: hidden; }
/* the passive's own cooldown (when it has one) and a once-a-round passive already used */
.passive-slot.cooling::after { content: attr(data-cdt); position: absolute; inset: 0; border-radius: 8px; display: grid; place-items: center;
  font: 900 14px Inter, sans-serif; color: #fff; text-shadow: 0 1px 0 #000; background: linear-gradient(to bottom, rgba(0,0,0,.62) var(--pcd, 0%), rgba(0,0,0,.25) var(--pcd, 0%)); }
.passive-slot.spent { filter: grayscale(1); opacity: .5; }

/* PC layout: HP / JET in the bottom-left corner, the skill buttons in the bottom-right one (the middle stays clear) */
body:not(.touch-ui) .hud-bottom { left: calc(var(--sa-l) + 12px); right: auto; bottom: 12px; transform: none; }
body:not(.touch-ui) .hotbar { left: auto; right: calc(var(--sa-r) + 12px); bottom: 12px; transform: none; }
body:not(.touch-ui) .skill-card { left: auto; right: calc(var(--sa-r) + 12px); bottom: 96px; transform: none; }
body:not(.touch-ui) .ghost-hint { bottom: 22px; }
@media (max-width: 1060px) and (pointer: fine) {
  body:not(.touch-ui) .hotbar { transform: scale(.82); transform-origin: bottom right; }
  body:not(.touch-ui) .hud-bottom { bottom: 84px; }
  body:not(.touch-ui) .chat-dock { bottom: 156px; }
}

/* ===== top tools in groups: [✕ fullscreen] [music effects] [mic listen chat] [ⓘ] — one pill per group ===== */
.top-tools { gap: 8px; }
.top-tools .tgroup { display: flex; align-items: center; gap: 2px; padding: 3px; border-radius: 999px; background: rgba(17,17,17,.82); border: 1px solid rgba(255,255,255,.12); }
.top-tools .tgroup:not(:has(> :not(.hidden):not(.noroom))) { display: none; }
.top-tools .tgroup > button, #app.in-game .top-tools .tgroup > button { position: static; width: 32px; height: 32px; padding: 0; margin: 0; border: 0; border-radius: 999px; background: transparent;
  display: inline-grid; place-items: center; box-shadow: none; font-size: 15px; line-height: 1; }
.top-tools .tgroup > button.hidden, .top-tools .tgroup > button.noroom { display: none; }
.top-tools .tgroup > button:hover { background: rgba(255,255,255,.09); }
.top-tools .tgroup > .mic-btn.on { background: #78dcb4; color: #231f20; }
.top-tools .tgroup > .exit { color: var(--text, #f4f2f2); }

#app.in-game .top-tools, body.touch-ui #app.in-game .top-tools { left: calc(var(--sa-l) + 8px); right: auto; }
#app.in-game .hud-top { left: calc(var(--sa-l) + 256px); }
body.touch-ui .top-tools .tgroup > button, body.touch-ui #app.in-game .top-tools .tgroup > button { width: 28px; height: 28px; }
body.touch-ui #app.in-game .top-tools { gap: 5px; }
body.touch-ui #app.in-game .hud-top { left: calc(var(--sa-l) + 222px); }

/* ===== chat: one soft panel for the whole log (darker while typing), the input right under it ===== */
.chat-dock { position: absolute; z-index: 35; left: calc(var(--sa-l) + 12px); bottom: 150px; width: min(380px, 42vw); display: flex; flex-direction: column; gap: 6px; pointer-events: none; }
body:not(.touch-ui) .chat-dock { bottom: 86px; }
#app:not(.in-game) .chat-dock { bottom: 16px; }
.chat-dock .chat-log, body.touch-ui .chat-dock .chat-log, #app:not(.in-game) .chat-dock .chat-log { position: static; width: auto; top: auto; bottom: auto; padding: 6px 9px; border-radius: 10px; background: transparent; transition: background .25s; gap: 2px; }
.chat-dock .chat-log:empty { display: none; }
.chat-dock .chat-log:has(> .chat-line:not(.old)) { background: rgba(17,17,17,.1); } /* (idle: barely there) */
.chat-dock .chat-log.open { background: rgba(17,17,17,.8) !important; } /* (beats the :has() rule above) */
.chat-line.kill, .chat-line.kill.mine { padding: 0; background: none; border: 0; box-shadow: none; border-radius: 0; }
.chat-line.kill.mine { text-decoration: underline; text-decoration-color: rgba(249,222,11,.6); }
.chat-dock .chat-box, body.touch-ui .chat-dock .chat-box { position: static; transform: none; width: auto; left: auto; top: auto; bottom: auto; pointer-events: auto;
  padding: 6px; border-radius: 10px; background: rgba(17,17,17,.9); border: 1px solid rgba(249,222,11,.35); }
.chat-dock .chat-quick button { padding: 4px 8px; font-size: 11.5px; }
body.touch-ui .chat-dock { bottom: auto; top: calc(var(--sa-t) + 46px); width: min(300px, 40vw); }
body.touch-ui .chat-dock .chat-log { max-height: 112px; font-size: 11.5px; }
.chat-line.round { padding: 0; background: none; border: 0; border-radius: 0; letter-spacing: normal; font-family: inherit; font-size: .92em; white-space: normal; } /* (not the HUD's round pill) */
/* chat input: just the text box and the send button (no quick phrases, no frame around them) */
.chat-dock .chat-box, body.touch-ui .chat-dock .chat-box { padding: 0; background: none; border: 0; }
.chat-dock .chat-quick { display: none; }
.chat-dock .chat-row input { background: rgba(17,17,17,.88); border-color: rgba(249,222,11,.4); }
/* the Chat button under the log (it gives way to the text box while typing) */
.chat-dock .chat-open { align-self: flex-start; pointer-events: auto; display: inline-flex; align-items: center; gap: 6px; height: 30px; padding: 0 12px 0 10px; border-radius: 999px; cursor: pointer;
  color: var(--yellow); background: rgba(17,17,17,.78); border: 1px solid rgba(249,222,11,.35); font: 700 12px Inter, system-ui, sans-serif; }
.chat-dock .chat-open svg { width: 16px; height: 16px; }
.chat-dock .chat-open:hover { border-color: var(--yellow); }
.chat-dock.typing .chat-open { display: none; }
body.touch-ui .chat-dock .chat-open { height: 26px; padding: 0 9px 0 7px; font-size: 11px; }
/* ⓘ (skills & passive info) sits with the skill buttons: left of the hotbar on PC, above the skill cluster on phones */
.hotbar > #btnInfo { order: -1; align-self: center; width: 38px; height: 38px; flex: none; pointer-events: auto; }
#touch > #btnInfo { position: absolute; pointer-events: auto; right: calc(max(22px, var(--sa-r)) + 22px); bottom: 204px; width: 34px; height: 34px; }
#touch > #btnInfo svg { width: 18px; height: 18px; }

/* ===== the buttons under the chat: Chat · Emoji · Động tác · Ping ===== */
.chat-actions { display: flex; gap: 6px; pointer-events: auto; align-self: flex-start; }
.chat-dock .chat-actions .chat-open { align-self: auto; }
.emo-btn { width: 30px; height: 30px; padding: 0; border-radius: 999px; cursor: pointer; display: grid; place-items: center; font-size: 15px; line-height: 1;
  background: rgba(17,17,17,.78); border: 1px solid rgba(249,222,11,.35); }
.emo-btn:hover, .emo-btn.on { border-color: var(--yellow); background: rgba(249,222,11,.16); }
.chat-dock:not(.in-match) .emo-btn.in-match { display: none; }
body.touch-ui .emo-btn { width: 26px; height: 26px; font-size: 13px; }
/* the picker: beside the button row */
.emo-pop { position: absolute; z-index: 46; left: calc(100% + 8px); bottom: 0; pointer-events: auto; min-width: 200px; padding: 8px; border-radius: 12px;
  background: rgba(17,17,17,.94); border: 1px solid rgba(249,222,11,.4); box-shadow: 0 10px 28px rgba(0,0,0,.45); font-family: Inter, system-ui, sans-serif; }
.emo-pop .pop-title { font: 800 11px Inter, system-ui, sans-serif; color: #a9a3a4; text-transform: uppercase; letter-spacing: .06em; margin: 0 2px 6px; }
.emo-pop .pop-grid { display: grid; grid-template-columns: repeat(4, 44px); gap: 6px; }
.emo-pop.pop-dance .pop-grid, .emo-pop.pop-ping .pop-grid { grid-template-columns: repeat(2, 128px); }
.emo-pop .pop-item { display: flex; align-items: center; gap: 7px; height: 44px; padding: 0 8px; border-radius: 10px; cursor: pointer; color: #fff; justify-content: center;
  background: #232021; border: 1px solid rgba(255,255,255,.1); font: 700 12px Inter, system-ui, sans-serif; }
.emo-pop.pop-dance .pop-item, .emo-pop.pop-ping .pop-item { justify-content: flex-start; height: 38px; }
.emo-pop .pop-item:hover { border-color: var(--pc, var(--yellow)); background: #2d2829; }
.emo-pop .pi-ic { font-size: 22px; line-height: 1; }
.emo-pop.pop-dance .pi-ic, .emo-pop.pop-ping .pi-ic { font-size: 18px; }
.emo-pop.pop-ping .pop-item { border-left: 3px solid var(--pc); }
.emo-pop .pop-tip { margin: 7px 2px 0; font: 600 11px Inter, system-ui, sans-serif; color: #a9a3a4; }
body.touch-ui .emo-pop { left: calc(100% + 6px); top: 0; bottom: auto; }
body.touch-ui .emo-pop .pop-grid { grid-template-columns: repeat(4, 40px); }
body.touch-ui .emo-pop.pop-dance .pop-grid, body.touch-ui .emo-pop.pop-ping .pop-grid { grid-template-columns: repeat(2, 118px); }
.chat-line .emo { font-size: 1.35em; line-height: 1; vertical-align: -2px; }
/* the PC wheel: hold T / B / G and move the mouse */
.wheel { position: absolute; z-index: 60; width: 0; height: 0; pointer-events: none; }
.wheel::before { content: ""; position: absolute; left: -122px; top: -122px; width: 244px; height: 244px; border-radius: 50%; background: radial-gradient(circle, rgba(17,17,17,.7) 0 36%, rgba(17,17,17,.45) 37% 70%, transparent 71%); }
.wheel .wh-item { position: absolute; width: 46px; height: 46px; margin: -23px 0 0 -23px; border-radius: 50%; display: grid; place-items: center; font-size: 24px; line-height: 1;
  background: rgba(35,32,33,.95); border: 2px solid var(--pc, rgba(255,255,255,.18)); transition: transform .08s; }
.wheel .wh-item.on { transform: scale(1.22); border-color: var(--pc, var(--yellow)); box-shadow: 0 0 14px var(--pc, rgba(249,222,11,.7)); }
.wheel .wh-center { position: absolute; transform: translate(-50%, -50%); white-space: nowrap; font: 800 12px Inter, system-ui, sans-serif; color: #fff; text-shadow: 0 1px 3px #000; }
/* ping placement: the whole field takes the next click / tap */
.ping-layer { position: absolute; inset: 0; z-index: 30; cursor: crosshair; touch-action: none; }
.ping-layer .ping-hint { position: absolute; left: 50%; top: 58px; transform: translateX(-50%); padding: 8px 14px; border-radius: 999px; white-space: nowrap; pointer-events: none;
  font: 700 12.5px Inter, system-ui, sans-serif; color: #fff; background: rgba(17,17,17,.88); border: 1px solid rgba(249,222,11,.5); }

/* the browser's autofill must not paint the box light (dark like the page) */
input:-webkit-autofill, input:-webkit-autofill:hover, input:-webkit-autofill:focus { -webkit-box-shadow: 0 0 0 100px #0f0d0e inset !important; -webkit-text-fill-color: #f4f2f2 !important; caret-color: #f4f2f2; transition: background-color 99999s; }
/* the Chat button opens into the text box + Gửi in the same row; Emoji · Động tác · Ping move along to the right */
.chat-actions { align-items: center; }
.chat-dock.typing .chat-actions { align-self: stretch; }
.chat-actions .chat-box, body.touch-ui .chat-dock .chat-actions .chat-box { flex: 1 1 auto; min-width: 0; }
.chat-actions .chat-row { gap: 5px; }
.chat-actions .chat-row input { height: 30px; padding: 0 10px; font-size: 14px; }
.chat-actions .chat-row .btn { height: 30px; padding: 0 12px; min-height: 0; font-size: 12px; }
body.touch-ui .chat-actions .chat-row input, body.touch-ui .chat-actions .chat-row .btn { height: 26px; font-size: 12px; }
/* the zoom level, for a moment while it changes */
.zoom-chip { position: absolute; z-index: 50; left: 50%; top: 96px; transform: translateX(-50%); padding: 6px 12px; border-radius: 999px; pointer-events: none;
  font: 800 12.5px Inter, system-ui, sans-serif; color: #fff; background: rgba(17,17,17,.85); border: 1px solid rgba(255,255,255,.18); }

/* chat: the panel darkens under the mouse, darkest while typing; our own thin scrollbar */
.chat-dock .chat-log.hover { background: rgba(17,17,17,.6) !important; }
.chat-dock .chat-log { scrollbar-width: thin; scrollbar-color: rgba(249,222,11,.45) transparent; }
.chat-dock .chat-log::-webkit-scrollbar { width: 6px; }
.chat-dock .chat-log::-webkit-scrollbar-track { background: transparent; }
.chat-dock .chat-log::-webkit-scrollbar-thumb { background: rgba(249,222,11,.4); border-radius: 6px; }
.chat-dock .chat-log::-webkit-scrollbar-thumb:hover { background: rgba(249,222,11,.7); }
.chat-line .ts { display: none; }
/* × folds the text box back into the Chat button */
.chat-close { flex: none; width: 30px; height: 30px; padding: 0; border-radius: 999px; cursor: pointer; display: grid; place-items: center; font-size: 12px; line-height: 1;
  color: #f4f2f2; background: rgba(17,17,17,.85); border: 1px solid rgba(255,255,255,.18); }
.chat-close:hover { border-color: var(--yellow); color: var(--yellow); }
body.touch-ui .chat-close { width: 26px; height: 26px; }
/* hotkey badges in the corner of the chat-row buttons (like the skill slots) */
.chat-actions .chat-open, .chat-actions .emo-btn { position: relative; }
.chat-actions .hk { position: absolute; right: -3px; bottom: -3px; min-width: 12px; height: 13px; padding: 0 3px; border-radius: 4px; display: grid; place-items: center;
  font: 700 8px/1 Inter, system-ui, sans-serif; color: rgba(244,242,242,.8); background: #0f0d0e; border: 1px solid rgba(255,255,255,.22); pointer-events: none; }
body.touch-ui .chat-actions .hk { display: none; }
/* our tooltip */
.tip { position: absolute; z-index: 80; max-width: 260px; padding: 6px 10px; border-radius: 8px; pointer-events: none; font: 600 12px/1.35 Inter, system-ui, sans-serif;
  color: #f4f2f2; background: rgba(17,17,17,.95); border: 1px solid rgba(249,222,11,.4); box-shadow: 0 6px 18px rgba(0,0,0,.45); }
/* the passive slot and the effect chips take the mouse (their info card), though the HUD around them doesn't */
.passive-slot, .hud-bottom .eff-chip { pointer-events: auto; }
/* the top tools sit top-left on every screen (lobby, room and match alike) */
#app:not(.in-game) .top-tools { left: calc(var(--sa-l) + 12px); right: auto; top: calc(var(--sa-t) + 12px); }
/* ✕ shows on every screen: leave the room, or (main menu) back to the RiseOn site */
#app:not(.in-game) .top-tools .exit { display: inline-grid; }
/* leaving a room is the ✕ in the top tools now (lobby and results too) */
#btnLeave, #btnOverLeave { display: none !important; }
#btnStart, #btnAgain { grid-column: 1 / -1; flex: 1 1 100%; width: 100%; }
/* warning: a Vietnamese input method is changing the control keys */
.ime-warn { position: absolute; z-index: 70; left: 50%; top: 64px; transform: translateX(-50%); width: min(520px, 92vw); display: grid; grid-template-columns: 1fr auto; gap: 2px 10px;
  padding: 10px 12px 10px 14px; border-radius: 12px; background: rgba(40,14,10,.95); border: 1px solid rgba(239,76,36,.8); box-shadow: 0 10px 28px rgba(0,0,0,.5);
  font: 600 12.5px/1.4 Inter, system-ui, sans-serif; color: #f4f2f2; pointer-events: auto; }
.ime-warn b { grid-column: 1; color: #ffb3a3; font-weight: 800; font-size: 13.5px; }
.ime-warn span { grid-column: 1; }
.ime-warn button { grid-column: 2; grid-row: 1 / span 2; align-self: start; width: 26px; height: 26px; border-radius: 999px; border: 1px solid rgba(255,255,255,.2); background: transparent; color: #fff; cursor: pointer; }
/* hotkey badges on the top tools and ⓘ (drawn by CSS: some of these buttons redraw their icon) */
[data-hk] { position: relative; }
.top-tools .tgroup > button[data-hk] { position: relative; }
body:not(.touch-ui) [data-hk]::after { content: attr(data-hk); position: absolute; right: -3px; bottom: -3px; min-width: 12px; height: 13px; padding: 0 3px; border-radius: 4px;
  display: grid; place-items: center; font: 700 8px/1 Inter, system-ui, sans-serif; letter-spacing: .02em; color: rgba(244,242,242,.8); background: #0f0d0e; border: 1px solid rgba(255,255,255,.22); pointer-events: none; z-index: 2; }
body:not(.touch-ui) .top-tools .tgroup { overflow: visible; }
#app .top-tools .tgroup > button[data-hk], body:not(.touch-ui) #app #btnInfo[data-hk] { position: relative; top: auto; left: auto; right: auto; bottom: auto; }
/* one main button on the menu now: Tạo phòng, full width */
#hallActions #btnCreate { flex: 1 1 100%; }

/* ===== phones in a room's lobby: a chat button in the top tools, a bubble on new messages, the chat as a window ===== */
#btnChatMini { display: none; position: relative; }
body.chat-mini #btnChatMini:not(.noroom) { display: inline-grid; }
#btnChatMini .unread { position: absolute; top: 2px; right: 2px; width: 8px; height: 8px; border-radius: 50%; background: #ef4c24; box-shadow: 0 0 0 2px #111; }
body.chat-mini .chat-dock:not(.modal) { display: none; }
.chat-modal-close { display: none; }
.chat-peek { position: absolute; z-index: 60; max-width: min(300px, 80vw); padding: 7px 11px; border-radius: 12px; pointer-events: none;
  font: 600 12.5px/1.35 Inter, system-ui, sans-serif; color: #fff; background: rgba(17,17,17,.95); border: 1px solid rgba(249,222,11,.5); box-shadow: 0 8px 22px rgba(0,0,0,.5);
  animation: chatIn .2s ease-out; }
.chat-peek::before { content: ""; position: absolute; top: -7px; left: 18px; border: 7px solid transparent; border-top: 0; border-bottom-color: rgba(249,222,11,.5); }
.chat-peek .emo { font-size: 1.3em; }
body.chat-mini .chat-dock.modal, body.touch-ui .chat-dock.modal { position: absolute; z-index: 90; left: 50%; top: 50%; bottom: auto; transform: translate(-50%, -50%);
  width: min(440px, 92vw); max-height: 82%; padding: 38px 12px 12px; border-radius: 14px; pointer-events: auto;
  background: rgba(17,17,17,.97); border: 1px solid rgba(249,222,11,.45); box-shadow: 0 0 0 100vmax rgba(0,0,0,.5), 0 14px 40px rgba(0,0,0,.6); }
.chat-dock.modal .chat-modal-close { display: grid; place-items: center; position: absolute; top: 8px; right: 8px; width: 28px; height: 28px; border-radius: 999px; cursor: pointer;
  color: #fff; background: #232021; border: 1px solid rgba(255,255,255,.2); font-size: 12px; }
.chat-dock.modal .chat-log { max-height: none; flex: 1 1 auto; min-height: 120px; overflow-y: auto; background: transparent !important; padding: 0 2px; font-size: 13px; }
.chat-dock.modal .chat-log .chat-line.old { opacity: 1; }
.chat-dock.modal .chat-open, .chat-dock.modal .chat-close { display: none; }
.chat-dock.modal .chat-actions { align-self: stretch; }
/* phones on the menus: the top tools float over the screen; keep the screen's top clear of them */
body.touch-ui #app:not(.in-game) .screen { top: calc(var(--sa-t) + 54px); padding-top: 0; }
body.touch-ui #app:not(.in-game)::after { content: ""; position: absolute; left: 0; right: 0; top: 0; height: calc(var(--sa-t) + 54px); z-index: 9; background: var(--bg); pointer-events: none; }
/* hotkey labels: small text just under each button, outside it (never over the icon) */
body:not(.touch-ui) [data-hk]::after { right: 50%; left: auto; top: auto; bottom: -15px; transform: translateX(50%); min-width: 0; height: auto; padding: 0;
  border: 0; border-radius: 0; background: none; box-shadow: none; display: block; white-space: nowrap;
  font: 700 8.5px/1 Inter, system-ui, sans-serif; letter-spacing: .03em; color: rgba(244,242,242,.62); text-shadow: 0 1px 2px #000, 0 0 3px #000; }
.chat-actions .hk { right: 50%; left: auto; top: auto; bottom: -13px; transform: translateX(50%); min-width: 0; height: auto; padding: 0; border: 0; border-radius: 0; background: none; box-shadow: none;
  display: block; white-space: nowrap; font: 700 8.5px/1 Inter, system-ui, sans-serif; letter-spacing: .03em; color: rgba(244,242,242,.62); text-shadow: 0 1px 2px #000, 0 0 3px #000; }
#app .top-tools .tgroup > #btnChatMini { display: none; }
body.chat-mini #app .top-tools .tgroup > #btnChatMini:not(.noroom) { display: inline-grid; position: relative; }
.chat-dock.modal .chat-log:empty { display: flex; }
.chat-dock.modal .chat-log:empty::before { content: "Chưa có tin nhắn nào — nói gì đó đi! 👋"; margin: auto; color: #a9a3a4; font: 600 13px Inter, system-ui, sans-serif; }
body.chat-mini .chat-dock.modal, body.touch-ui .chat-dock.modal { height: min(70%, 520px); }
/* Tạo phòng while the room is being made: dimmed, with a spinner */
.btn.loading { opacity: .65; cursor: wait; position: relative; padding-left: 38px; }
.btn.loading::before { content: ""; position: absolute; left: 16px; top: 50%; width: 14px; height: 14px; margin-top: -9px; border-radius: 50%;
  border: 2.5px solid rgba(35,31,32,.35); border-top-color: #231f20; animation: spin .7s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
/* PC: the cancel-the-cast drop zone sits right above the skill buttons (bottom-right), not mid-screen */
body:not(.touch-ui) .pc-cancel { left: auto; right: calc(var(--sa-r) + 12px); bottom: 96px; transform: none; }
body:not(.touch-ui) .top-tools [data-hk]::after { bottom: -19px; } /* (fully below the group's pill) */
/* hotkey labels: a small key cap centred on the button's bottom edge (half in, half out) */
body:not(.touch-ui) [data-hk]::after, body:not(.touch-ui) .top-tools [data-hk]::after { left: 50%; right: auto; top: auto; bottom: -6px; transform: translateX(-50%);
  min-width: 14px; height: 12px; padding: 0 3px; border-radius: 3px; display: grid; place-items: center; background: #0f0d0e; border: 1px solid rgba(255,255,255,.25);
  font: 700 8px/1 Inter, system-ui, sans-serif; letter-spacing: .02em; color: rgba(244,242,242,.85); text-shadow: none; box-shadow: 0 1px 2px rgba(0,0,0,.6); }
.chat-actions .hk { left: 50%; right: auto; top: auto; bottom: -6px; transform: translateX(-50%); min-width: 14px; height: 12px; padding: 0 3px; border-radius: 3px; display: grid; place-items: center;
  background: #0f0d0e; border: 1px solid rgba(255,255,255,.25); font: 700 8px/1 Inter, system-ui, sans-serif; color: rgba(244,242,242,.85); text-shadow: none; box-shadow: 0 1px 2px rgba(0,0,0,.6); }
/* hotkey labels: just the letters, outlined (no box) */
body:not(.touch-ui) [data-hk]::after, body:not(.touch-ui) .top-tools [data-hk]::after, .chat-actions .hk {
  background: none; border: 0; box-shadow: none; padding: 0; min-width: 0; height: auto; border-radius: 0;
  font: 800 9px/1 Inter, system-ui, sans-serif; letter-spacing: .03em; color: #fff;
  text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000, 0 -1px 0 #000, 0 1px 0 #000, -1px 0 0 #000, 1px 0 0 #000; }
/* centred on the visible edge: the group's pill (3 px padding + 1 px border under the button) / the button's own border */
body:not(.touch-ui) .top-tools [data-hk]::after { bottom: -9px; }
.chat-actions .hk, body:not(.touch-ui) #btnInfo[data-hk]::after { bottom: -5px; }
/* the info window's close button */
.info-panel h4 { position: relative; padding-right: 36px; }
.info-close { position: absolute; right: 0; top: 50%; transform: translateY(-50%); width: 28px; height: 28px; padding: 0; border-radius: 999px; cursor: pointer;
  display: grid; place-items: center; font-size: 12px; line-height: 1; color: #f4f2f2; background: #232021; border: 1px solid rgba(255,255,255,.18); pointer-events: auto; }
.info-close:hover { border-color: var(--yellow); color: var(--yellow); }
/* the chat window: the messages take all the room above the input (a phone rule capped them at 112 px) */
body .chat-dock.modal .chat-log, body.touch-ui .chat-dock.modal .chat-log { max-height: none !important; flex: 1 1 0; min-height: 0; }
body .chat-dock.modal .chat-actions { flex: none; margin-top: 4px; }
/* chat: the lines stay (only the panel's background fades) */
.chat-dock .chat-line.old { opacity: 1; }
/* phones: ⓘ above the skill buttons (the PC rules don't apply) */
body.touch-ui #touch > #btnInfo { position: absolute; top: auto; left: auto; right: calc(max(22px, var(--sa-r)) + 22px); bottom: 204px; z-index: 7; }
/* "press Esc again" */
.esc-toast { position: absolute; z-index: 90; left: 50%; bottom: 28px; transform: translateX(-50%); padding: 8px 14px; border-radius: 999px; pointer-events: none;
  font: 700 12.5px Inter, system-ui, sans-serif; color: #fff; background: rgba(17,17,17,.92); border: 1px solid rgba(249,222,11,.5); }
/* the ammo count: top-left of the attack button (the thumb covers the bottom-right corner) */
body .tbtn.t-attack[data-ammo]:not([data-ammo=""])::after { left: 6px; top: 6px; right: auto; bottom: auto; }
/* match end: the throne scene owns the screen (only the canvas and its skip button) */
body.cutscene #app > *:not(#game):not(.cut-skip) { visibility: hidden !important; }
.cut-skip { position: absolute; right: calc(var(--sa-r) + 16px); bottom: calc(var(--sa-b) + 16px); z-index: 90;
  font: 800 14px/1 Inter, system-ui, sans-serif; color: #f4f2f2; background: rgba(17,17,17,.7); border: 1px solid rgba(255,255,255,.28);
  border-radius: 999px; padding: 10px 18px; cursor: pointer; }
.cut-skip:hover { border-color: #f9de0b; color: #f9de0b; }
/* the mic switched on looks the same everywhere (the match's transparent tool buttons used to win over it) */
#app .top-tools .tgroup > .mic-btn.on, #app.in-game .top-tools .tgroup > .mic-btn.on { background: #78dcb4; color: #231f20; }
#app .top-tools .tgroup > .mic-btn.on:hover { background: #8fe6c3; }
/* the ammo count sits on the button's rim at the top-left (half in, half out), solid, with a dark ring so it reads on anything */
body #app .tbtn.t-attack { overflow: visible; } /* (.tbtn clips its content: the count would be cut in half) */
body #app .tbtn.t-attack[data-ammo]:not([data-ammo=""])::after { left: -3px; top: 1px; right: auto; bottom: auto; z-index: 4;
  background: #f9de0b; color: #231f20; box-shadow: 0 0 0 2px rgba(17,17,17,.9); min-width: 24px; font-size: 13px; }
/* phones: the spectating bar sits just above the HP / JET bar (it used to cover it) */
body.touch-ui #app .spec-bar { top: auto; bottom: calc(var(--sa-b) + 68px); }
/* joining a room: the other rooms wait, dimmed; the pressed button spins (press again to cancel) */
.room-list.joining .room-item:not(.joining-this) { opacity: .4; pointer-events: none; }
.room-list .room-item .btn.loading { opacity: 1; cursor: pointer; }
/* the joystick: its own compositor layers, so moving the knob is not a repaint (it has a blurred shadow) */
.stick-knob, .stick-base { will-change: transform; }
/* the loading window (making / joining / getting back into a room) */
.busy-modal { z-index: 95; }
.busy-panel { width: min(380px, 100%); text-align: center; }
.busy-panel .busy-step { color: var(--muted); min-height: 1.4em; }
.busy-bar { height: 8px; margin: 4px 0 18px; border-radius: 999px; background: rgba(255,255,255,.1); overflow: hidden; }
.busy-bar i { display: block; height: 100%; width: 0; border-radius: inherit; background: linear-gradient(90deg, var(--amber, #f6ad13), var(--yellow, #f9de0b)); transition: width .3s ease; }
.busy-panel .actions { justify-content: center; }
/* touch buttons, cheaper to redraw: the cooling icon is dimmed (no colour filter), the "ready" pop is a scale
   animation the GPU runs (the box-shadow pulse repainted the button every frame) */
.tbtn.cooling .ic { filter: none; opacity: .42; }
.tbtn.ready { animation: btnReadyPop .32s ease-out; }
@keyframes btnReadyPop { 0% { transform: scale(1); } 40% { transform: scale(1.12); } 100% { transform: scale(1); } } /* (on top of the buttons' own scale on phones) */
/* in a match on phones: scrolling still works (the chat), page zoom doesn't — without a blocking touch listener */
body.touch-ui #app.in-game { touch-action: pan-x pan-y; }
/* the joystick's touch area: the left third, not up to the middle (the joystick appears under the thumb anyway) */
body.touch-ui #app .stick-zone { width: min(30%, 300px); }

/* ===== notifications: a card dropping in from the top centre (like the phone's own), swiped away or gone by itself ===== */
#menuStatus { display: none; }
.toasts { position: absolute; z-index: 130; left: 50%; top: calc(var(--sa-t) + 10px); transform: translateX(-50%); width: min(440px, calc(100% - 24px));
  display: flex; flex-direction: column; align-items: center; gap: 8px; pointer-events: none; }
.toast { pointer-events: auto; touch-action: none; user-select: none; -webkit-user-select: none; cursor: pointer; display: flex; align-items: center; gap: 10px; max-width: 100%;
  padding: 10px 16px 10px 10px; border-radius: 20px; color: #f4f2f2; font: 600 13.5px/1.35 Inter, system-ui, sans-serif;
  background: rgba(30,27,28,.94); border: 1px solid rgba(255,255,255,.13); box-shadow: 0 12px 32px rgba(0,0,0,.5), 0 2px 6px rgba(0,0,0,.3);
  -webkit-backdrop-filter: blur(16px) saturate(1.5); backdrop-filter: blur(16px) saturate(1.5);
  transition: transform .32s cubic-bezier(.2,.9,.3,1), opacity .32s ease; animation: toastIn .5s cubic-bezier(.18,1.25,.4,1) both; }
.toast.drag { transition: none; animation: none; }
.toast.out { animation: none; pointer-events: none; }
.toast.bump { animation: toastBump .32s ease; }
.toast .ti { flex: none; width: 24px; height: 24px; border-radius: 50%; display: grid; place-items: center; font: 900 13px/1 Inter, system-ui, sans-serif; }
.toast.error .ti { background: #ef4c24; color: #fff; }
.toast.info .ti { background: #f9de0b; color: #231f20; }
.toast.ok .ti { background: #25af50; color: #fff; }
.toast .tt { overflow-wrap: anywhere; }
@keyframes toastIn { from { transform: translateY(-130%) scale(.94); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes toastBump { 40% { transform: scale(1.04); } }
.esc-toast { display: none !important; }
/* the loading window is the right size; the host question sits above it */
.modal .panel.busy-panel { width: min(380px, 100%); }
#hostAsk { z-index: 97; }
/* touch buttons: the "denied" shake wins over the ready pop */
.tbtn.ready.deny, .tbtn.deny { animation: btnDeny .3s ease; }
/* the ammo count moves to ::before, so ::after is the cooldown sweep again while holding a gun */
body #app .tbtn.t-attack[data-ammo]:not([data-ammo=""])::after { content: ""; inset: 0; left: 0; top: 0; right: 0; bottom: 0; width: auto; height: auto; min-width: 0; padding: 0;
  border-radius: 50%; box-shadow: none; z-index: auto; background: conic-gradient(rgba(0,0,0,.66) var(--cd, 0%), transparent 0); }
body #app .tbtn.t-attack[data-ammo]:not([data-ammo=""])::before { content: attr(data-ammo); position: absolute; left: -3px; top: 1px; z-index: 4; min-width: 24px; padding: 1px 5px;
  border-radius: 999px; background: #f9de0b; color: #231f20; font: 900 13px/1.4 Inter, system-ui, sans-serif; text-align: center; box-shadow: 0 0 0 2px rgba(17,17,17,.9); }
/* ===== the keyboard in a match: the chat sits in what still shows above it (the match itself doesn't move) ===== */
body.kbd-open #app.in-game:not(.rot):not(.rot-ccw) .chat-dock { top: calc(var(--vis-top, 0px) + var(--sa-t) + 46px); }
body.kbd-open #app.in-game:not(.rot):not(.rot-ccw) .chat-dock .chat-log { max-height: max(0px, calc(var(--vis-h, 300px) - 46px - 46px)); }
/* the chat window (phones, room lobby) with the keyboard up: the whole strip above it */
body.kbd-open #app:not(.in-game) .chat-dock.modal { top: 6px; bottom: 6px; height: auto; max-height: none; transform: translateX(-50%); }
/* its emoji picker opens inside the window, above the text box (it used to open off the right edge) */
#app .chat-dock.modal .emo-pop { left: 10px; right: 10px; top: auto; bottom: 54px; min-width: 0; }
#app .chat-dock.modal .emo-pop .pop-grid { justify-content: center; }
body.kbd-open #app.in-game.kbd-tight .chat-dock .chat-log { display: none; }
/* ===== review round 2: phone layout ===== */
/* the chat in a match is sized by the match area (#app), not the real screen (upright phones turn the match) */
body.touch-ui .chat-dock { width: min(300px, 40%); }
body.touch-ui .chat-dock.typing:not(.modal) { width: min(380px, 62%); }
body.kbd-open #app.in-game:not(.rot):not(.rot-ccw) .chat-dock { top: calc(var(--vis-top, 0px) + var(--sa-t) + var(--chat-top, 46px)); }
body.kbd-open #app.in-game:not(.rot):not(.rot-ccw) .chat-dock .chat-log { max-height: max(0px, calc(var(--vis-h, 300px) - var(--chat-top, 46px) - 46px)); }
/* notifications: below the top buttons on the menus (never over them); in a match they don't take game taps */
body.touch-ui #app:not(.in-game) .toasts { top: calc(var(--sa-t) + 54px); }
#app.in-game .toasts { top: calc(var(--sa-t) + 52px); width: min(420px, 56%); }
#app.in-game .toast { pointer-events: none; }
.toast.in { animation: none; }
.toast.in.bump { animation: toastBump .32s ease; }
/* the emoji picker with the keyboard up: one compact row that fits the short strip */
body.kbd-open .chat-dock .emo-pop .pop-title, body.kbd-open .chat-dock .emo-pop .pop-tip { display: none; }
body.kbd-open .chat-dock .emo-pop { padding: 6px; }
body.kbd-open .chat-dock .emo-pop:not(.pop-dance):not(.pop-ping) .pop-grid { grid-template-columns: repeat(8, 34px); gap: 4px; }
body.kbd-open .chat-dock .emo-pop .pop-item { height: 34px; }
body.kbd-open #app:not(.in-game) .chat-dock.modal { padding-top: 34px; }
body.kbd-open #app:not(.in-game) .chat-dock.modal .emo-pop { bottom: 48px; }
/* ===== review round 3: phone layout ===== */
/* typing in a match: the top buttons step aside (the chat sits up there when the strip is short) */
#app.in-game.chat-top .top-tools { visibility: hidden; } /* (only when the chat needs their spot: a very short strip above the keyboard) */
/* the HP / JET pill: left of centre (clear of Jump), effect chips above it, never on the home bar */
body.touch-ui .hud-bottom { left: calc(50% - 26px); bottom: max(8px, var(--sa-b)); }
body.touch-ui .hud-bottom .eff-row { position: absolute; left: 50%; bottom: calc(100% + 16px); transform: translateX(-50%); }
@media (max-width: 700px) { body.touch-ui .hud-bottom .bar { width: 46px; } }
.t-jump { bottom: max(14px, var(--sa-b)); }
/* the score strip stays on one line (it switches to the compact form when it doesn't fit); the modifier chip under it, centred with it */
#app.in-game .pips { flex-wrap: nowrap; }
body.touch-ui #app.in-game .mod-chip { left: calc(50% + 32px); }
body:not(.touch-ui) #app.in-game .mod-chip { left: calc(50% + 17px); }
/* very short landscape (Chrome on a small phone before fullscreen, in-app browsers): smaller minimap and chat, ⓘ clear of it */
/* a match 320 px tall or less */
@supports (display: block) {
  body.touch-ui #app.in-game.vh320 .minimap { width: 112px; height: 63px; }
  body.touch-ui #app.in-game.vh320 .chat-dock .chat-log { max-height: 56px; }
  body.touch-ui #app.in-game.vh320 #touch > #btnInfo { bottom: auto; top: calc(var(--sa-t) + 8px); right: calc(var(--sa-r) + 122px); } /* (left of the minimap, above the dodge button) */
}
/* knocked out: the dimmed buttons step out of the way of the spectating bar */
.touch.dead .tbtn { visibility: hidden; }
/* phone menus: one top clearance (the screen's), not two */
@media (max-width: 600px) { body.touch-ui #app:not(.in-game) .panel, body.touch-ui #app:not(.in-game) .lobby-panel { padding-top: 16px; } }
body.touch-ui .over-panel { padding-top: 4px; }
@media (orientation: landscape) and (max-height: 520px) and (min-width: 560px) {
  body.touch-ui .menu-panel > label.field, body.touch-ui .menu-panel > .rooms-head, body.touch-ui .lobby-panel > .lobby-me { margin-top: 0; }
}
/* ✕ is the same height as the other top buttons */
.top-tools .tgroup > .exit { min-height: 0; }
/* the emoji picker while typing in a match: under the text box, inside the match area */
body.touch-ui .chat-dock.typing:not(.modal) .emo-pop { left: 0; right: auto; top: calc(100% + 4px); bottom: auto; }
/* the perk cards keep clear of the dodge button on 640–700 px screens */
body.touch-ui .card-pick { width: min(520px, calc(100% - 270px)); }
/* top button tap areas don't steal from their neighbours */
body.touch-ui .snd-btn::after, body.touch-ui .mic-btn::after, .icon-btn::after { inset: -6px -1px; }
/* the throne scene hides the game UI, not a loading window or a notice */
body.cutscene #app > .toasts, body.cutscene #app > .modal:not(.hidden) { visibility: visible !important; }
/* aiming a skill: notices fade so the cancel target is clear */
body:has(.touch.aiming) .toasts { opacity: .2; }
/* the keyboard up on the menus: notices at the very top of the strip above it */
body.kbd-open #app:not(.in-game) .toasts { top: calc(var(--sa-t) + 4px); }
/* the lobby chat bubble's arrow points at the chat button */
.chat-peek::before { left: calc(var(--ax, 25px) - 7px); }
/* the room list: a drag on it scrolls the page when the list itself has nothing to scroll (an empty list was a dead spot) */
.room-list { overscroll-behavior-y: auto; }
@media (max-width: 599px), (max-height: 500px) { .room-list { overflow-y: visible; } } /* (shown in full there: the page scrolls) */
/* the menus (not a match): pull down to reload works again (the match keeps it off: no reload by a stray swipe) */
html.ptr, html.ptr body { overflow: visible; overscroll-behavior-y: auto; } /* (a root that can't scroll gets no pull-to-refresh) */
html.ptr .chat-dock .chat-log, html.ptr .modal, html.ptr .room-list { overscroll-behavior-y: contain; }
@media (max-width: 599px), (max-height: 500px) { html.ptr .room-list { overscroll-behavior-y: auto; } } /* (not a scroll box there) */
/* typing on the menus with little room above the keyboard: the field gets the whole strip (top buttons back when it closes) */
body.kbd-short #app:not(.in-game) .top-tools { visibility: hidden; }
body.touch-ui.kbd-short #app:not(.in-game) .screen { top: 0; }
body.kbd-short #app:not(.in-game)::after { display: none; }
/* ===== review round 4: layout ===== */
/* knocked out / watching: the paper hint sits low (above the spectating bar), clear of the round banner and calls */
body.touch-ui .ghost-hint { top: auto; bottom: calc(var(--sa-b) + 120px); }
body:not(.touch-ui) .ghost-hint { bottom: 96px; }
@media (max-width: 1060px) { body:not(.touch-ui) .ghost-hint { bottom: 150px; } }
/* landscape phones: the lobby / hall columns take their content's height, so the main buttons stay on screen */
@media (orientation: landscape) and (max-height: 520px) and (min-width: 560px) {
  .lobby-panel { grid-template-rows: repeat(5, max-content) 1fr; }
  .menu-panel { grid-template-rows: repeat(5, max-content) 1fr; }
}
/* laptops: the room-lobby / results chat stays left of the centred panel */
body:not(.touch-ui) #app:not(.in-game) .chat-dock:not(.modal) { width: clamp(200px, calc(50% - 364px), 380px); }
/* round end on phones: the perk cards take the banner's place; the chat log fades under the banner and calls */
#app:has(.card-pick:not(.hidden)) #hudBanner { visibility: hidden; }
body.touch-ui #app:has(#hudBanner:not(.hidden)) .chat-dock:not(.typing) .chat-log, body.touch-ui #app:has(#announce:not(.hidden)) .chat-dock:not(.typing) .chat-log { opacity: .2; }
/* the round title keeps a readable width */
#app.in-game .hud-top .round, #hudRound { min-width: 72px; }
/* the lobby chat window isn't a dialog box (it shared the .modal name: centred, squeezed log) */
.chat-dock.modal { place-items: normal; align-items: stretch; backdrop-filter: none; -webkit-backdrop-filter: none; }
.chat-dock.modal .chat-log { align-self: stretch; }
/* the emoji picker in a match opens under the chat row, clear of the action buttons */
body.touch-ui .chat-dock:not(.modal) .emo-pop { left: 0; right: auto; top: calc(100% + 4px); bottom: auto; }
/* dialogs scroll when the screen is shorter than they are */
.modal { overflow-y: auto; }
/* form controls follow the dark theme */
:root { color-scheme: dark; }
/* ===== typing in a match turned 90° (phone held upright; iPhone Safari always): the chat stands upright along the top of
   the real screen, above the keyboard, like the keyboard itself. The dock is turned back by the match's turn; --pw / --ph
   are the real screen's width / height (they stay put while the keyboard is up). ===== */
body.kbd-open #app.in-game.rot .chat-dock.typing, body.kbd-open #app.in-game.rot-ccw .chat-dock.typing {
  left: 0; top: 0; right: auto; bottom: auto; transform-origin: 0 0; width: calc(var(--pw) - 16px); max-width: none; z-index: 45;
  padding: 6px; border-radius: 12px; background: rgba(17,17,17,.92); box-shadow: 0 8px 24px rgba(0,0,0,.5); }
body.kbd-open #app.in-game.rot .chat-dock.typing { transform: translateY(var(--pw)) rotate(-90deg) translate(8px, calc(var(--vis-top, 0px) + env(safe-area-inset-top, 0px) + 8px)); }
body.kbd-open #app.in-game.rot-ccw .chat-dock.typing { transform: translateX(var(--ph)) rotate(90deg) translate(8px, calc(var(--vis-top, 0px) + env(safe-area-inset-top, 0px) + 8px)); }
body.kbd-open #app.in-game.rot .chat-dock.typing .chat-log, body.kbd-open #app.in-game.rot-ccw .chat-dock.typing .chat-log { max-height: max(0px, calc(var(--vis-h, 300px) - 76px)); }
body.kbd-open #app.in-game.rot .chat-dock.typing .emo-pop, body.kbd-open #app.in-game.rot-ccw .chat-dock.typing .emo-pop { top: auto; bottom: auto; left: 0; right: 0; position: relative; margin-top: 6px; }
/* the turned match's top buttons sit along that edge: out of the way while typing */
body.kbd-open #app.in-game.rot:has(.chat-dock.typing) .top-tools, body.kbd-open #app.in-game.rot-ccw:has(.chat-dock.typing) .top-tools { visibility: hidden; }
/* ===== review round 5: layout ===== */
/* #2 the score strip shrinks inside its area (the JS then switches it to the compact form) instead of running under the tools / minimap */
#app.in-game .hud-top .pips { min-width: 0; overflow: hidden; justify-content: flex-start; }
#app.in-game .hud-top .pips.compact { flex-shrink: 0; }
#app.in-game .hud-top #hudRound { min-width: 48px; }
/* #3 PC windows 1060 px wide or less: the chat row stays above the HP / JET bar */
@media (max-width: 1060px) and (pointer: fine) { body:not(.touch-ui) #app.in-game .chat-dock { bottom: 156px; } }
/* #4 phones: a call at the start of a modified round sits under the modifier chip, not on it */
body.touch-ui #app:has(#modChip:not(.hidden)) .announce { top: calc(var(--sa-t) + 74px); }
/* #5 PC: the spectating bar under the modifier chip, calls under the spectating bar */
body:not(.touch-ui) #hud:has(.mod-chip:not(.hidden)) .spec-bar { top: calc(var(--sa-t) + 86px); }
body:not(.touch-ui) #app:has(.spec-bar:not(.hidden)) .announce { top: calc(var(--sa-t) + 110px); }
body:not(.touch-ui) #app:has(.mod-chip:not(.hidden)):has(.spec-bar:not(.hidden)) .announce { top: calc(var(--sa-t) + 138px); }
/* #6 #8 landscape phones (incl. 568–600 px wide): "Cách chơi" in the left column, skill cards clear of the bottom edge,
   no portrait-only edge-to-edge margins in the two-column layout */
@media (orientation: landscape) and (max-height: 520px) and (min-width: 560px) {
  .lobby-panel > .howto-box { grid-column: 1; }
  #lobbySkills { padding-bottom: calc(var(--sa-b) + 12px); }
  .cta { margin: 0; }
  .chars, .chars.small { margin: 0; padding: 2px 2px 8px; width: auto; max-width: 100%; scroll-padding: 0; }
  .limit-row { gap: 10px; }
  .lobby-panel > .eyebrow { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
}
/* #7 PC windows: the menus start below the top buttons; notices below them too */
body:not(.touch-ui) #app:not(.in-game) .screen { padding-top: calc(var(--sa-t) + 64px); }
body:not(.touch-ui) #app:not(.in-game) .toasts { top: calc(var(--sa-t) + 60px); }
/* #10 phones: the perk cards take the corner; the chat row steps aside unless someone is typing */
body.touch-ui #app:has(#cardPick:not(.hidden)) .chat-dock:not(.typing) { visibility: hidden; }
/* #11 very short matches: the emoji picker is one compact row */
body.touch-ui #app.vh320 .chat-dock .emo-pop .pop-title, body.touch-ui #app.vh320 .chat-dock .emo-pop .pop-tip { display: none; }
body.touch-ui #app.vh320 .chat-dock .emo-pop:not(.pop-dance):not(.pop-ping) .pop-grid { grid-template-columns: repeat(8, 34px); gap: 4px; }
body.touch-ui #app.vh320 .chat-dock .emo-pop .pop-item { height: 34px; }
/* #13 PC: the oldest chat line fades out at the top of the log instead of being cut */
.chat-dock .chat-log:not(.open) { -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 16px); mask-image: linear-gradient(to bottom, transparent 0, #000 16px); }
/* ===== review round 6: layout (each fix measured by the reviewer in a headless browser) ===== */
/* a big call never prints over the knocked-out banner */
#app:has(#hudBanner:not(.hidden)) .announce { visibility: hidden; }
/* 568–600 px wide very short matches: the score strip without the round title; HP / JET pill clear of Jump; chat row faded under the banner */
@media (max-width: 600px) { body.touch-ui #app.in-game.vh320 .hud-top #hudRound { display: none; } }
body.touch-ui #app.in-game .hud-bottom { left: min(calc(50% - 26px), calc(100% - 340px)); }
body.touch-ui #app.vh320:has(#hudBanner:not(.hidden)) .chat-dock:not(.typing) .chat-actions { opacity: .2; }
/* perk cards under the modifier chip */
body.touch-ui #app:has(#modChip:not(.hidden)) .card-pick { top: calc(var(--sa-t) + 74px); }
/* PC / tablet hall: the room list leaves room for Tạo phòng / Vào phòng; PC room lobby: Bắt đầu stays reachable */
@media (min-width: 601px) and (min-height: 561px) { #menu .room-list { max-height: clamp(124px, calc(100dvh - 556px), 330px); } }
@media (min-width: 601px) and (min-height: 521px) { body:not(.touch-ui) .lobby-panel > .cta { position: sticky; bottom: 0; z-index: 2; margin: 0 -32px; padding: 14px 32px 16px; border-radius: 0 0 24px 24px; background: linear-gradient(180deg, rgba(29,26,27,0), rgba(29,26,27,.97) 26%); } }
/* 568–620 px landscape: room code placeholder, create button and limit text fit */
@media (orientation: landscape) and (max-height: 520px) and (max-width: 620px) { .join input::placeholder { letter-spacing: .12em; } #createBox .actions .btn { white-space: nowrap; padding-left: 8px; padding-right: 8px; } .limit-row > span { white-space: nowrap; } }
/* ===== review round 7: layout (each fix measured by the reviewer in a headless browser) ===== */
/* #1 typing in a match on touch screens: a big call never prints over the chat box / log (it shows again once the chat closes) */
body.touch-ui #app.in-game:has(.chat-dock.typing) .announce { visibility: hidden; }
/* #2 matches 321–340 px tall: ⓘ sits just under the FPS · UDP · ping line (it covered "UDP"), clear of the skill-2 button */
body.touch-ui #app.in-game.vh400:not(.vh320) #touch > #btnInfo { bottom: min(204px, calc(100% - var(--sa-t) - 136px)); }
@media (max-height: 340px) { body.touch-ui #app.in-game.vh400:not(.vh320):not(.rot):not(.rot-ccw) #touch > #btnInfo { right: calc(max(22px, var(--sa-r)) + 8px); } }
/* #3 touch tablets (1024×600 …): the room lobby's Bắt đầu stays on screen like on PC */
@media (min-width: 601px) and (min-height: 521px) { body.touch-ui:not(.kbd-open) .lobby-panel > .cta { position: sticky; bottom: 0; z-index: 2; margin: 0 -32px; padding: 14px 32px calc(var(--sa-b) + 16px); border-radius: 0 0 24px 24px; background: linear-gradient(180deg, rgba(29,26,27,0), rgba(29,26,27,.97) 26%); } }
/* #4 very short landscape phones (568×320, 592×320, 640×280): the room lobby's Bắt đầu stays on screen */
@media (orientation: landscape) and (max-height: 340px) and (min-width: 560px) { body:not(.kbd-open) .lobby-panel > .cta { position: sticky; bottom: 0; z-index: 2; padding: 10px 0 calc(var(--sa-b) + 6px); background: linear-gradient(180deg, rgba(17,17,17,0), var(--bg) 18%); } .lobby-panel > .cta .status { margin-top: 4px; font-size: .74rem; } }
/* #5 hall on short tablets / laptops (1024×600, 1366×657): no tagline, smaller logo, so Tạo phòng and Vào phòng fit without scrolling */
@media (min-width: 601px) and (min-height: 521px) and (max-height: 700px) { #menu .menu-panel .sub { display: none; } #menu .menu-panel .logo { width: 150px; } }
/* #6 568–620 px landscape: "Giới hạn" on one line (round 6 nowrapped the count span, the label was the one wrapping) */
@media (orientation: landscape) and (max-height: 520px) and (max-width: 620px) { .limit-row, .limit-row label { gap: 6px; } .limit-row label { white-space: nowrap; } .limit-row select { padding-left: 6px; padding-right: 2px; } }
/* #7 568–700 px landscape phones: the create-room checkboxes stay one line each ("Riêng / tư", "Chạy trên máy của / tôi" were split word by word); the grey hints go, the box gets 20 px shorter */
@media (orientation: landscape) and (max-height: 520px) and (max-width: 700px) { .create-row .chk small { display: none; } .create-row .chk { white-space: nowrap; } }
/* #8 phones: the perk cards pop in place (the shared annIn keyframe slid them in from half off the left edge) */
body.touch-ui .card-pick { animation-name: cpIn; }
@keyframes cpIn { from { transform: scale(.6); opacity: 0; } }
/* #9 the round / knock-out banner is as wide as its text (left:50% capped it at half the match: 16-letter winner names broke onto 2 lines at 568–620 px and touched the top buttons) */
.banner { width: max-content; max-width: calc(100% - 24px); }

/* ===== review round 8: layout (each fix measured by the reviewer in a headless browser) ===== */
/* #1 touch screens: a call (the round modifier's "MƯA VŨ KHÍ …") never sits under the perk cards; game.js holds it in the queue until the cards close */
body.touch-ui #app:has(#cardPick:not(.hidden)) .announce { visibility: hidden; }
/* #2 PC: the chat log keeps left of the perk cards (lines ran under them at 1024–1366 px) */
body:not(.touch-ui) #app:has(#cardPick:not(.hidden)) .chat-dock .chat-log { max-width: max(160px, calc(50vw - 322px)); }
/* #3 PC / tablet room lobby: the sticky Bắt đầu bar sits on the bottom edge (it floated 16 px up, the skill list showed under it) */
@media (min-width: 601px) and (min-height: 521px) { body:not(.touch-ui) .lobby-panel > .cta, body.touch-ui:not(.kbd-open) .lobby-panel > .cta { bottom: -16px; } }
/* #4 PC / tablet hall: Tạo phòng / Vào phòng stay on screen while the character drawer is open */
@media (min-width: 601px) and (min-height: 521px) { body:not(.kbd-open) #menu .menu-panel > .cta { position: sticky; bottom: -16px; z-index: 2; margin: 0 -32px -16px; padding: 0 32px calc(var(--sa-b) + 16px); border-radius: 0 0 24px 24px; background: rgba(29,26,27,.97); } body:not(.kbd-open) #menu .menu-panel > .cta::before { content: ""; position: absolute; left: 0; right: 0; bottom: 100%; height: 16px; background: linear-gradient(180deg, rgba(29,26,27,0), rgba(29,26,27,.97)); pointer-events: none; } }
/* #5 landscape ≤ 300 px tall (640×280, 568×300): the create-room form fits, Tạo phòng / Hủy no longer cut at the bottom */
@media (orientation: landscape) and (max-height: 300px) { #createBox { padding: 8px 10px; } #createBox .field { margin-bottom: 8px; } #createBox .field > span { display: none; } #createBox .create-row { row-gap: 6px; } #createBox .actions { margin-top: 8px; } }

/* ===== review round 9: layout (each fix measured by the reviewer in a headless browser) ===== */
/* #1 landscape phones (568–932 × 320–430): with the character drawer open, Tạo phòng / Vào phòng stay on screen; the drawer takes the right column (in place of the room list) and scrolls inside it */
@media (orientation: landscape) and (max-height: 520px) and (min-width: 560px) {
  #menu .menu-panel > .char-drawer { grid-column: 2; grid-row: 1 / span 6; align-self: stretch; contain: size; overflow-y: auto; overscroll-behavior: contain; margin: 0 0 calc(var(--sa-b) + 10px); }
  #menu .menu-panel:has(> .char-drawer:not(.hidden)) > .rooms-head, #menu .menu-panel:has(> .char-drawer:not(.hidden)) > .room-list { display: none; }
}
/* #2 the pinned button bars are opaque where text sits (at .96–.97 the lines scrolled under them showed through: skill names under "Gửi link mời…", "Phòng đang mở" between Tạo phòng and Vào phòng) */
@media (max-width: 600px) and (min-height: 521px) { .cta { background: linear-gradient(180deg, rgba(17,17,17,0), var(--bg) 22%); } }
@media (min-width: 601px) and (min-height: 521px) {
  body:not(.touch-ui) .lobby-panel > .cta, body.touch-ui:not(.kbd-open) .lobby-panel > .cta { background: linear-gradient(180deg, rgba(29,26,27,0), #1d1a1b 26%); }
  body:not(.kbd-open) #menu .menu-panel > .cta { background: #1d1a1b; }
  body:not(.kbd-open) #menu .menu-panel > .cta::before { background: linear-gradient(180deg, rgba(29,26,27,0), #1d1a1b); }
}
/* #3 create-room form open (phones, touch tablets 1024×600): the form keeps a margin above the bottom edge / home indicator (the stretched panel kept the screen's height, so the form overflowed it and its scroll-into-view left it flush on the edge; on iPhone landscape Tạo phòng / Hủy were 10 px inside the home-indicator band) */
#createBox { scroll-margin-bottom: calc(var(--sa-b) + 16px); }
@media (max-width: 600px) { #menu.creating { align-items: start; } #menu.creating .menu-panel { padding-bottom: calc(var(--sa-b) + 16px); } }
@media (orientation: landscape) and (max-height: 520px) and (min-width: 560px) { #menu.creating { align-items: start; } #menu.creating .menu-panel { padding-bottom: calc(var(--sa-b) + 12px); } #createBox { scroll-margin-bottom: calc(var(--sa-b) + 12px); } }
/* #4 touch matches 568–600 px wide (iPhone SE sideways or upright): the ⓘ panel stays left of the action buttons (it covered the grenade button) */
body.touch-ui #app.in-game .info-panel { width: min(360px, calc(100% - 256px)); }
/* #5 iPhone landscape: the joystick's resting ring stays out of the notch / rounded-corner band (13 px inside it at 844×390, 25 px at 932×430) */
body.touch-ui .stick-zone { left: max(0px, calc(var(--sa-l) - 26px)); }
/* #6 PC windows: the perk cards stay above the HP / JET bar (they covered its top 6 px at 1024×768, 36 px at 800×600); under 980 px wide they sit right of the chat column (at 800×600 they covered the chat lines, the Chat / Emoji buttons and the HP bar) */
body:not(.touch-ui) .card-pick { bottom: max(18%, 156px); }
@media (max-width: 980px) { body:not(.touch-ui) .card-pick { left: auto; right: 12px; transform: none; width: min(620px, calc(100% - 214px)); animation-name: cpIn; } }
/* #7 landscape phones with the browser bar showing (≤ 310 px tall: Chrome 740×304, 800×300, 640×280, Safari 568×270): logo and ARENA side by side (and ≤ 290 px a slimmer character tile and buttons), so the hall's Vào phòng row is on screen (it was cut 1–39 px at the bottom edge) */
@media (orientation: landscape) and (max-height: 310px) and (min-width: 560px) { #menu .menu-brand { display: flex; align-items: center; gap: 12px; } #menu .menu-brand h1 { margin: 0; } }
@media (orientation: landscape) and (max-height: 290px) and (min-width: 560px) { #menu .me-char img { width: 36px; height: 30px; } #menu .me-row { margin-bottom: 6px; } #menu .menu-panel > .cta { padding-top: 4px; } #menu .menu-panel > .cta .btn { padding-top: 8px; padding-bottom: 8px; } #menu .join { margin-top: 6px; } #menu .join input { padding-top: 6px; padding-bottom: 6px; } }
/* #7b the round-8 #5 compact create-room form also at 301–310 px tall (Chrome 740×304, 667×310: the form was 4 px taller than the screen, its bottom edge cut) — in style.css just raise that rule's max-height from 300px to 310px */
@media (orientation: landscape) and (max-height: 310px) { #createBox { padding: 8px 10px; } #createBox .field { margin-bottom: 8px; } #createBox .field > span { display: none; } #createBox .create-row { row-gap: 6px; } #createBox .actions { margin-top: 8px; } }
/* #8 phones under 360 px wide (320×568): the lobby's "PHÒNG CHƠI · THẮNG 3 ROUND ĐỂ VÔ ĐỊCH" stays on one line ("ĐỊCH" dropped alone onto a second line) */
@media (max-width: 359px) { .lobby-panel .eyebrow { letter-spacing: .06em; } }
/* #9 touch matches 568–620 px wide: a call's second line ("Nguyễn Tuấn Anh1 vs Bot số 1 tên dài") wraps between the Chat · Emoji · Động tác · Ping row and the Né lướt button (it printed over both: 17 px over Ping, 25 px over Né lướt at 568×320) */
body.touch-ui #app.in-game:not(.rot):not(.rot-ccw) .ann-sub { max-width: max(180px, calc(var(--pw) - 380px)); margin: 0 auto; }
body.touch-ui #app.in-game.rot .ann-sub, body.touch-ui #app.in-game.rot-ccw .ann-sub { max-width: max(180px, calc(var(--ph) - 380px)); margin: 0 auto; }

/* ===== review round 10: layout (each fix measured by the reviewer in a headless browser) ===== */
/* #1 results: Về phòng chờ stays on screen with many players / awards (up to 5 awards and 16 players: with 4 players + 5 awards it was 105 px below the edge at 1366×657, 49 px at 1280×720, 3 px at 1024×768 touch, 140 px at 360×640, 66 px at 390×844) */
@media (max-width: 600px) and (min-height: 521px) {
  #over .over-panel > .actions { position: sticky; bottom: 0; z-index: 2; margin: 8px -16px 0; padding: 12px 16px calc(var(--sa-b) + 12px); background: linear-gradient(180deg, rgba(17,17,17,0), var(--bg) 14px); }
}
@media (min-width: 601px) and (min-height: 521px) {
  #over .over-panel > .actions { position: sticky; bottom: -16px; z-index: 2; margin: 8px -32px 0; padding: 14px 32px calc(var(--sa-b) + 16px); background: linear-gradient(180deg, rgba(29,26,27,0), #1d1a1b 14px); }
}
/* #2 touch tablets (1024×600, 1024×768, 768×1024, 820×1180 …): the results card gets its top padding back (the phone rule left 4 px: "KẾT THÚC TRẬN" 5 px under the card's top border, 32 px of padding at the bottom) */
@media (min-width: 601px) and (min-height: 521px) { body.touch-ui .over-panel { padding-top: 32px; } }
/* #3 landscape phones ≤ 310 px tall (568×270 … 800×300): opening the character drawer no longer pulls the character tile up against the logo (gap 15 → 0 px, the left column jumped 15 px); the room-list heading keeps its row, hidden */
@media (orientation: landscape) and (max-height: 520px) and (min-width: 560px) {
  #menu .menu-panel:has(> .char-drawer:not(.hidden)) > .rooms-head { display: flex; visibility: hidden; }
}
/* #4 phones: the character name keeps 4 px inside the tile ("Siêu sao…", "Họa Sĩ D…" touched the tile's border on both sides) */
@media (max-width: 599px), (max-height: 500px) { .me-char .me-char-name { max-width: 52px; } }
/* #5 touch menus: the band behind the top buttons overlaps the screen by 1 px (at 2.625× a device-pixel row between them showed the game canvas: a dashed orange hairline under the buttons) */
body.touch-ui #app:not(.in-game)::after { height: calc(var(--sa-t) + 55px); }
/* #6 landscape ≤ 340 px tall: the pinned Bắt đầu bar reaches 2 px past its column (the roster's borders bled through its anti-aliased edges as two 9 px vertical lines beside the button) */
@media (orientation: landscape) and (max-height: 340px) and (min-width: 560px) { body:not(.kbd-open) .lobby-panel > .cta { margin-left: -2px; margin-right: -2px; padding-left: 2px; padding-right: 2px; } }
/* #7 PC windows 981–1023 px wide: the perk cards dock right too (centred, they covered the Chat · Emoji row by 13 px at 981 px and kept under 8 px from it up to 1023 px) — in style.css just raise round 9 #6 max-width from 980px to 1023px */
@media (min-width: 981px) and (max-width: 1023px) { body:not(.touch-ui) .card-pick { left: auto; right: 12px; transform: none; width: min(620px, calc(100% - 214px)); animation-name: cpIn; } }
/* #8 the how-to lines don't leave one word alone on the last line ("Q vứt vũ / khí" on PC) */
.howto > span { text-wrap: pretty; }
/* #9 PC room lobby / results (≥ 1150 px): the emoji picker opens above the chat row, inside the chat column (beside it, it covered the left of Bắt đầu and the status line) */
body:not(.touch-ui) #app:not(.in-game) .chat-dock:not(.modal) .emo-pop { left: 0; bottom: 38px; }
/* #10 landscape phones: the character drawer shows that it scrolls (at 568×320 the third skill sat wholly below the drawer's edge, nothing hinted at it) */
@media (orientation: landscape) and (max-height: 520px) and (min-width: 560px) {
  #menu .menu-panel > .char-drawer > .skill-list { margin-bottom: 18px; }
  #menu .menu-panel > .char-drawer::after { content: ""; position: sticky; bottom: -10px; display: block; height: 18px; margin: -18px -10px -10px; background: linear-gradient(180deg, rgba(19,17,18,0), #131112); pointer-events: none; }
}

/* ===== review round 11: layout ===== */
/* #1 results on phones (portrait and landscape: the card is a flex column there): "🏆 Bạn là nhà vô địch!" comes before the pinned Về phòng chờ bar
   (it sat after it, flush with the bottom edge once the list scrolled: 0 px below it at 360×640, inside the 34 px home-indicator band at 390×844 iPhone
   and the 21 px band at 844×390); an empty status line no longer leaves 32 px under the bar. On PC / tablets (block card) the order is unchanged. */
#over .over-panel > .actions { order: 1; }
#over .over-panel > .status:empty { display: none; }
/* #2 every gradient button (Tạo phòng, Bắt đầu, Về phòng chờ, Gửi …): the gradient starts at the border edge. Its 1 px transparent border showed the
   tile's wrapped-around end colours: a red crescent down the left edge and a yellow one down the right edge of each yellow→red pill (3 device px at 2.625×) */
.btn.primary { background-origin: border-box; }

/* ===== review round 12: layout ===== */
/* #2 room lobby: a wide player name (16 × W / M, full-width letters …) no longer stretches the player list past the card. One such name widened its
   whole column: 242 px past the card's edge on PC / tablets (1366×657 … 768×1024), 16–107 px on landscape phones (844×390 … 640×360), the ✕ (kick)
   buttons of every row in that column pushed out of view and a sideways scrollbar in the list. Now such a name wraps inside its row like any other
   name does on PC ("Trần Ngọc / Phương"; where rows are one line — short landscape phones — it ends in "…" as before); the skills, crown and ✕ stay. */
.roster li { min-width: 0; }
.roster li > span:not(.mini-skills):not(.host) { min-width: 0; overflow-wrap: anywhere; }
.roster li > .mini-skills, .roster li > .host, .roster li > .kick { flex: none; }
/* #3 hall room list: the line under the name splits into two even halves at a " · " (game.js keeps each part together): it ended with the room code
   alone on line 2 at 360–844 px wide ("… 3/16 người ·" / "5FRV"), and started line 2 with "·" at 320 / 568 px ("Đang đấu · round 4" / "· 3/16 người · 5FRV") */
.ri-text small { text-wrap: balance; }
/* #4 touch, aiming a skill: the round's modifier chip ("🌧 Mưa vũ khí", "🗿 Đầu bự" …) and a big call ("⚠️ DUNG NHAM SẮP DÂNG") fade like the
   notices already do, so the "✕ Hủy" target reads. Both sat on top of it on every touch size (chip over the target 52×22 px, the call's title 64×36 px
   at 568×320, 844×390, 932×430, 1024×768, 360×640 turned): "Hủy" was printed across the yellow chip and the red title. filter, not opacity: the call
   animates its own opacity. */
body:has(.touch.aiming) #app.in-game .mod-chip, body:has(.touch.aiming) #app.in-game .announce { filter: opacity(.2); transition: filter .15s; }
/* #5 (trivial) character tiles (.char in the lobby, the hall's .me-char): the vertical tile gradient starts at the border edge like .btn.primary
   (round 11 #2). Under the 2 px translucent border the gradient's far end showed: a darker 2 px top edge and a lighter bottom edge (#141213 / #2a2526
   under 10 % white). Hardly visible; listed for completeness. */
.char, .me-char { background-origin: border-box; }

/* ===== review round 13: layout ===== */
/* #1 landscape phones 341–520 px tall (640×360, 667×375, 740×360, 844×390 iPhone, 932×430 iPhone): the room lobby's Bắt đầu (a guest's
   "Chờ chủ phòng bắt đầu…" and the status line) stays on screen once players join, like round 7 #4 already does at ≤ 340 px.
   The left column grows with the player list: with 2 players Bắt đầu was cut at the bottom edge (640×360: 352–395 / 360, 667×375: 352–395 / 375),
   with 4+ players it was wholly below it at 640×360 / 667×375 / 740×360 and only its top 16 px showed above the home-indicator band at 844×390.
   The bar reaches 2 px past its column like round 10 #6 (the roster's borders don't bleed past its edges). */
@media (orientation: landscape) and (max-height: 520px) and (min-width: 560px) {
  body:not(.kbd-open) .lobby-panel > .cta { position: sticky; bottom: 0; z-index: 2; margin-left: -2px; margin-right: -2px; padding: 10px 2px calc(var(--sa-b) + 6px); background: linear-gradient(180deg, rgba(17,17,17,0), var(--bg) 18%); }
  .lobby-panel > .cta .status { margin-top: 4px; font-size: .74rem; }
}
/* #2 (trivial) hall room list: a room whose host's character isn't known here (host seat reconnecting: "", or a character newer than this page) shows
   no picture instead of Chrome's grey 40×40 broken-image frame */
.room-item img:not([src]) { visibility: hidden; }
/* #3 room lobby: a room name wider than its line ends in "…" (it was chopped mid-letter at the edge / under the ✎: the default
   "Phòng của Nguyễn Tuấn An" by 15 px at 568×320, a 24-letter wide name by 61–214 px on every size; guests can't scroll the read-only field) */
.room-title:not(:focus) { text-overflow: ellipsis; }
/* #4 (trivial) the status line under Bắt đầu / Về phòng chờ splits into even lines (a guest's "Trận vừa kết thúc — chờ chủ phòng mở ván" / "mới…"
   left one word alone at 360 px; the host's "Gửi link mời … — bấm link là vào thẳng" / "phòng." at 360–412 px and on landscape phones) */
.cta .status, #over .status { text-wrap: balance; }
/* #5 typing in a match on a landscape phone, emoji picker opened from the chat row (the keyboard stays up): the chat log steps aside while the picker is
   open, so the picker sits in the strip above the keyboard. Under the log it ran 21 px under the keyboard at 568×320 / 640×360 (strip 170 px: only the
   top 21 px of the emoji row showed, the faces cut in half) and 11 px at 740×360. The log comes back when the picker closes. */
body.kbd-open #app.in-game:not(.rot):not(.rot-ccw) .chat-dock.typing:has(> .emo-pop:not(.hidden)) .chat-log { display: none; }

/* ===== review round 14: layout ===== */
/* #1 is in game.js (game_patched.js / mkpatch.js): the chat log keeps its newest line in view when it changes size or comes back */
/* #2 phones (portrait and landscape): the open "Cách chơi" box ends clear of the bottom edge / home indicator. Its last line ("Súng rơi từ trời — chạm
   vào để nhặt") sat flush on the bottom edge at the end of the scroll (0 px at 360×640, 568×320, 640×360) and wholly inside the home-indicator band on
   iPhones (844×390: line 375–390 in the 21 px band, 932×430: 415–430, 390×844: 829–844 in the 34 px band). The panel is as tall as the screen and its
   content runs past it, so a margin under the box does not count toward the scroll; padding does. Only while open: closed, the "Cách chơi" row
   keeps its place (padding on the closed row pushed it 10 px under the bottom edge at 412×915, where the lobby fits without scrolling). */
@media (max-width: 600px), (orientation: landscape) and (max-height: 520px) and (min-width: 560px) {
  .lobby-panel > .howto-box[open] { margin-bottom: 0; padding-bottom: calc(var(--sa-b) + 14px); }
}
/* #3 touch matches 600–700 px wide (640×360, 667×375, 600×340): the knocked-out banner's second line ("Văng khỏi bản đồ · chờ round sau",
   "bởi <tên người hạ> · chờ round sau") wraps in the middle lane instead of running into the Chat · Emoji · Động tác · Ping row: with a 16-letter
   name it covered the 📍 button by 19 px at 640×360, 5 px at 667×375, 16 px at 600×340 even with no name; with 4–5 chat lines the row sits on the
   same height as that line. game.js (#3 in mkpatch.js) lets it break only after the " · ". */
body.touch-ui #app.in-game:not(.rot):not(.rot-ccw) .banner small { max-width: max(180px, calc(var(--pw) - 2 * var(--sa-l) - 380px)); margin-left: auto; margin-right: auto; text-wrap: balance; }
body.touch-ui #app.in-game.rot .banner small, body.touch-ui #app.in-game.rot-ccw .banner small { max-width: max(180px, calc(var(--ph) - 380px)); margin-left: auto; margin-right: auto; text-wrap: balance; }
body.touch-ui #app.in-game .banner small { overflow-wrap: anywhere; }
/* #4 PC hotbar: a skill name too long for its slot takes two lines instead of ending in "…" (14 of the 38 skills were cut: "Mày nghĩ t…",
   "Hộp quà b…", "Chùm bóng b…", "Khiên Hylia…" by 1 px …). Icons keep their place (top-aligned at the height they had), two lines leave 3 px. */
.slot-cell { justify-content: flex-start; padding-top: 13px; }
.slot-cell .nm { white-space: normal; text-wrap: balance; line-height: 1.08; max-width: 66px; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; }
/* #5 (trivial) a call's second line splits evenly ("Nguyễn Tuấn Anh" / "vs Bot số 1 tên dài"; at 568×320 it was "Nguyễn Tuấn Anh vs Bot" /
   "số 1 tên dài", 170 / 76 px, a name broken in two) */
.ann-sub { text-wrap: balance; }

/* ===== review round 15: layout ===== */
/* #1 the banner's second line: each " · " part is one inline-block (game.js #1 in mkpatch.js), so the line breaks after a separator, or between words
   inside a part too long for the lane, never mid-word ("Bấm ✕ lần nữa để rời t / rận" at 568×320, "bởi Nguyễn Hoàng Anh Tu / ấn" at 600×340) */
.banner small .seg { display: inline-block; max-width: 100%; }
/* #2 is in game.js (#2 in mkpatch.js): closing the chat while reading back shows the newest lines again */
/* #3 PC windows ≤ 900 px wide (the 60 × 60 hotbar, scaled to .82): a two-line skill name fits its cell. The round-14 two-line names ran 9 px past the
   cell's inner edge there, the second line sliced through the middle ("Mày nghĩ / tao sợ?", "Hộp quà / bất ngờ", "Khiên / Hylian": 17 of 24 px shown)
   at 683×700, 800×600, 900×… The cell grows 6 px (5 px on screen) and the name drops to 10 px; icons and key labels keep their place. */
@media (max-width: 900px) {
  body:not(.touch-ui) .hotbar .slot-cell { height: 66px; }
  body:not(.touch-ui) .hotbar .slot-cell .nm { font-size: 10px; line-height: 1.05; }
}

/* ===== review round 16: layout ===== */
/* #1 is in game.js (#1 in mkpatch.js): at round end the camera puts the winner's name tag, HP bar, emoji bubble, leader crown and ▼ marker below the
   "TÊN / thắng round này!" banner instead of behind it */
/* #2 (trivial) the picked character tile: the 6 % zoom grows from the tile's floor, so the head stays on it instead of sinking 1.6-2.2 px under the
   tile's bottom edge (the rose bouquet of Lãng Tử Hoa Hồng, the chins of the others); the top has 8-14 px to spare */
.char[aria-checked="true"] img { transform-origin: 50% 100%; }

/* ===== review round 20: layout ===== */
/* #1 is in game.js (#1 in mkpatch.js -> game_patched.js): touch, aiming: a long label beside the ✕ Hủy ring ("Nháy mắt đốn tim · đang hồi")
   that reaches the minimap column was dropped "under the minimap" = onto the FPS · UDP · ping line (640×360: 24×8 px of text on "180 FPS"
   for the whole aim). The column now ends under that line. */

/* #2 touch, in a match: the 10 s "Micro đang bị chặn…" toast could not be swiped or tapped away (in-game toasts ignore the pointer) and,
   3–4 lines tall, it hid the chat lines, the 📍 / 💃 buttons and, at 568×320, 48×46 px of the Né lướt button (640×360: 6 px) for 10 s.
   On touch the in-game toast takes swipes / taps again (it sits under the top bar, away from the stick and the buttons' own touches,
   and an aim that is already running keeps its finger), and on short screens it is set tighter: 3 lines from 640 px up (77 → 63 px),
   4 at 568 px (95 → 78 px). PC keeps the click-through toast (a click there is an attack). */
body.touch-ui #app.in-game .toast { pointer-events: auto; }
body.touch-ui #app.vh400.in-game .toast { font-size: 12px; line-height: 1.3; padding: 7px 12px 7px 8px; gap: 8px; }
body.touch-ui #app.vh400.in-game .toast .ti { width: 20px; height: 20px; font-size: 12px; }
