/* "My Gang" — giao diện. Mobile landscape TRƯỚC, desktop được hưởng theo.
 *
 * Ba luật của file này:
 *  1. Sân đấu (#gwStage) là một khối KHÔNG CUỘN, chiếm hết chỗ được cho. Mọi thứ khác nổi
 *     lên trên nó bằng position:absolute — không có luồng tài liệu nào trong lúc chơi.
 *  2. Mọi nút chạm được đều ≥ 44px. Đây là game bắn trên điện thoại; một nút 32px là một
 *     nút bấm trượt, và bấm trượt trong lúc hết đạn là mất một mạng.
 *  3. Chữ dùng font hệ thống. Kit gợi ý Passion One / Squada One (FontLink.txt) nhưng nạp
 *     webfont cho một game phải khởi động nhanh trên WiFi trường là đánh đổi sai.
 */

/* THUỘC TÍNH `hidden` PHẢI THẮNG MỌI LUẬT `display` CỦA FILE NÀY.
 *
 * Stylesheet mặc định của trình duyệt cài `hidden` bằng `[hidden] { display: none }` — một
 * selector THUỘC TÍNH. Bất kỳ luật nào của ta viết `display` lên một SELECTOR CLASS đều
 * thắng nó, và phần tử vẫn hiện dù JS đã đặt `hidden = true`.
 *
 * Đã dính đúng lỗi ấy và nó sống sót qua cả một giai đoạn phát triển: `.gw-overlay` khai
 * `display: grid`, nên tấm phủ tối 72% kèm `blur(3px)` NẰM ĐÈ LÊN CẢ TRẬN ĐẤU suốt từ đầu
 * đến cuối. Không một ảnh chụp nào của tôi thấy được vì chúng chụp thẳng từ canvas — mà
 * canvas thì nằm DƯỚI lớp phủ, nên nó luôn sạch sẽ. Chỉ ảnh chụp màn hình thật mới lộ ra.
 *
 * Bức tường chặn cả LỚP lỗi ấy là `[hidden] { display: none !important }`, và trong iSpeak
 * nó đã có sẵn ở css/ispeak.css:61 cho toàn app. Nên ở đây KHÔNG khai lại: một selector
 * top-level không nằm dưới .gw-root là một luật sơn lên sáu game kia. Việc duy nhất phải
 * làm là ĐỪNG GỠ luật ở ispeak.css — mọi lớp phủ dưới đây (.gw-overlay, .gw-gate) đều
 * khai `display: grid` và đều dựa vào nó. */

.gw-root {
  --gw-ink: #f2ece0;
  --gw-dim: #b3a894;
  --gw-panel: rgba(20, 17, 14, .93);
  --gw-line: rgba(255, 255, 255, .14);
  --gw-gold: #f0b429;
  --gw-red: #d2402f;
  --gw-green: #59b356;
  /* MÀU NỀN RIÊNG là một bất biến thiết kế của repo: nhìn màu nền là biết đang ở game nào
     (css/pets.css:6-9). Đã dùng: #efe2c9 My Room · #221d29 Lò Rèn · #181425 My Kingdom ·
     #eaf4e2 Thú Cưng. (#131a2b và #14262b đã trả lại khi gỡ Giữ Cổng / Biệt Đội Mèo.)
     #3b2418 là nâu cà phê ấm, và nó tách khỏi hai nền tối kia theo HAI chiều chứ không
     phải một: nó là nền tối DUY NHẤT có kênh đỏ trội (hai cái kia đều xanh trội, B > R),
     và nó sáng hơn tất cả. "Ấm hay lạnh" là câu hỏi trả lời được từ cuối lớp. */
  --gw-bg: #3b2418;
  /* TRÀN VIỀN: huỷ padding của .view (18px trên · 16px hai bên · 64px dưới) và trần
     max-width 760px của nó. Giống hệt sáu game kia — .view là khung của một TRANG HỌC,
     không phải khung của một cái sân. Không có dòng này thì cả game co vào giữa màn hình
     và các con .gw-* dùng `position:absolute; inset:0` sập xuống chiều cao 0. */
  margin: -18px -16px -64px;
  max-width: none;
  position: relative;
  width: auto;
  /* 60px là chiều cao thanh trên của app. `dvh` khai sau `vh` để Safari cũ vẫn có một
     giá trị dùng được thay vì không có gì. */
  height: calc(100vh - 60px);
  height: calc(100dvh - 60px);
  min-height: 420px;
  overflow: hidden;
  /* Một cú vuốt xuống ở mép trên sân KHÔNG được kéo cả trang nảy trên iOS giữa trận. */
  overscroll-behavior: none;
  background: var(--gw-bg);
  color: var(--gw-ink);
  font: 500 15px/1.35 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  overflow: hidden;
  user-select: none;
  -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
}

/* ---------------- sân ---------------- */
.gw-root #gwStage {
  position: absolute;
  inset: 0;
  overflow: hidden;
  /* touch-action:none là BẮT BUỘC, không phải trang trí: thiếu nó thì mỗi lần giữ ngón để
     bắn liên tục, Safari hiểu là cuộn trang và nuốt luôn pointermove. */
  touch-action: none;
}
.gw-root #gwCanvas { display: block; width: 100%; height: 100%; }

/* ---------------- HUD ---------------- */
.gw-root .gw-hud {
  position: absolute;
  left: 0; right: 0;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: max(8px, env(safe-area-inset-top)) max(10px, env(safe-area-inset-right)) 8px max(10px, env(safe-area-inset-left));
  pointer-events: none;      /* chỉ NÚT mới ăn cú chạm; phần còn lại để lọt xuống sân */
  z-index: 2;
}
.gw-root .gw-hud button, .gw-root .gw-hud .gw-gun { pointer-events: auto; }
.gw-root .gw-hud-top { top: 0; background: linear-gradient(rgba(0,0,0,.55), transparent); }
.gw-root .gw-hud-bottom {
  bottom: 0;
  padding-bottom: max(8px, env(safe-area-inset-bottom));
  background: linear-gradient(transparent, rgba(0,0,0,.55));
  justify-content: space-between;
}

.gw-root .gw-wave { flex: none; min-width: 96px; }
.gw-root .gw-wave-lb { display: block; font-size: 12px; color: var(--gw-dim); letter-spacing: .02em; }
.gw-root .gw-wave-lb b { color: var(--gw-ink); font-size: 15px; }
.gw-root .gw-wave-bar {
  display: block; height: 4px; margin-top: 3px; border-radius: 2px;
  background: rgba(255,255,255,.18); overflow: hidden;
}
.gw-root .gw-wave-bar i { display: block; height: 100%; width: 0; background: var(--gw-gold); transition: width .2s linear; }

/* Thanh độ bền chướng ngại — thứ QUAN TRỌNG NHẤT trên màn hình, nên nó rộng nhất và nằm
   giữa. Ba vạch chia trùng đúng bốn nấc hư hại của sprite: khi thanh tụt qua một vạch,
   hình vẽ ngoài sân cũng đổi. Hai thứ kể cùng một câu chuyện. */
.gw-root .gw-wall {
  position: relative; flex: 1 1 auto; height: 18px; max-width: 420px;
  border: 1px solid var(--gw-line); border-radius: 4px;
  background: rgba(0,0,0,.5); overflow: hidden;
}
/* `>` chứ không phải hậu duệ bất kỳ. Bốn luật này tả RUỘT của thanh — một `<i>` con trực
   tiếp, phủ kín, đổi màu theo nấc hư hại. Viết `.gw-wall i` thì chúng bắt luôn MỌI thẻ `i`
   nằm sâu bên trong, và đã bắt thật: icon chướng ngại đặt trong `<b>` bị kéo rộng 420px,
   `position: absolute`, và cái `background:` shorthand ở đây xoá sạch `background-image`
   của nó — icon biến mất mà không có lỗi nào. Đổi sang con trực tiếp là sửa cả LỚP lỗi ấy,
   không phải chỉ lần này. */
.gw-root .gw-wall > i {
  position: absolute; inset: 0 auto 0 0; width: 100%;
  background: var(--gw-green); transition: width .18s linear;
}
.gw-root .gw-wall > i[data-stage="1"] { background: #b9c23c; }
.gw-root .gw-wall > i[data-stage="2"] { background: #e0902f; }
.gw-root .gw-wall > i[data-stage="3"] { background: var(--gw-red); }
.gw-root .gw-wall-seg {
  position: absolute; top: 0; bottom: 0; width: 1px; background: rgba(0,0,0,.45);
}
.gw-root .gw-wall-seg:nth-of-type(1) { left: 25%; }
.gw-root .gw-wall-seg:nth-of-type(2) { left: 50%; }
.gw-root .gw-wall-seg:nth-of-type(3) { left: 75%; }
/* `grid-auto-flow: column` chứ không để mặc định: từ khi có icon chướng ngại đứng cạnh con
   số, `place-items: center` một cột sẽ xếp CHỒNG hai đứa lên nhau ở cùng một ô. */
.gw-root .gw-wall b {
  position: absolute; inset: 0; display: grid; grid-auto-flow: column; gap: 4px;
  place-items: center; place-content: center;
  font-size: 11px; font-weight: 700; text-shadow: 0 1px 2px rgba(0,0,0,.8);
}

/* ---------------- DẢI ĐỒNG ĐỘI (phòng 2-3 người) ----------------
   Nằm TRONG `.gw-hud-top`, không phải một hàng riêng bên dưới: thanh máu boss được vẽ vào
   canvas ở `HUD_TOP + 6` (js/gang/engine.js), nên một hàng DOM ở `top: 60px` sẽ đè lên nó
   ở đúng bốn màn trùm.
   `:empty` ẩn hẳn — bản một người không có ô nào, và không một pixel nào xê dịch. */
.gw-root .gw-mates { flex: none; display: flex; gap: 6px; }
.gw-root .gw-mates:empty { display: none; }
.gw-root .gw-mate {
  --gw-tint: var(--gw-gold);
  display: flex; align-items: center; gap: 5px;
  height: 26px; padding: 0 8px;
  border: 1px solid var(--gw-line); border-radius: 999px;
  background: rgba(0,0,0,.45);
  font-size: 12px; font-weight: 700; white-space: nowrap;
}
/* Chấm màu tay súng: ba màu của C.LEADERS, và đó là thứ DUY NHẤT phân biệt được ba người
   khi tên bị ẩn trên máy hẹp. */
.gw-root .gw-mate > i {
  flex: none; width: 8px; height: 8px; border-radius: 50%; background: var(--gw-tint);
}
.gw-root .gw-mate > b { max-width: 76px; overflow: hidden; text-overflow: ellipsis; }
.gw-root .gw-mate > em {
  font-style: normal; color: var(--gw-gold); font-variant-numeric: tabular-nums;
}
.gw-root .gw-mate.is-ready { border-color: var(--gw-green); }
.gw-root .gw-mate.is-warn { border-color: #e0902f; }
/* Đã coi như rớt: mờ đi và tắt màu, nhưng KHÔNG bỏ ô đi. Một ô biến mất nói "người này
   chưa từng ở đây"; một ô xám nói đúng cái đang xảy ra. */
.gw-root .gw-mate.is-off { opacity: .42; border-color: var(--gw-red); }

/* ---------------- BANNER MẤT KẾT NỐI ----------------
   #gwToast nằm sẵn trong khung HUD từ hồi dựng bản đứng riêng và chưa từng có ai gọi tới.
   Đây là việc nó được chừa chỗ để làm. Đặt dưới dải HUD trên và CÁCH XA thanh máu boss
   (66→79px) — 88px là mép dưới của thanh ấy cộng một khoảng thở. */
.gw-root .gw-toast {
  position: absolute; top: 88px; left: 50%; transform: translateX(-50%);
  z-index: 8; max-width: min(92%, 520px);
  padding: 8px 14px; border-radius: 999px;
  border: 1px solid rgba(210,64,47,.7); background: rgba(12,9,7,.92);
  font-size: 13px; font-weight: 600; text-align: center; line-height: 1.35;
  pointer-events: none;
}

.gw-root .gw-right { flex: none; display: flex; align-items: center; gap: 8px; margin-left: auto; }
.gw-root .gw-coin { display: flex; align-items: center; gap: 4px; font-weight: 700; font-variant-numeric: tabular-nums; }
/* Nút vuông dùng ẢNH NGUYÊN TẤM chứ không 9-slice: nó vuông 44×44 cố định, mà nguồn là
   91×88 — kéo cả tấm về đúng ô là tỉ lệ gần như không đổi. Cắt 9 miếng cho một thứ không
   bao giờ đổi cỡ chỉ thêm ba biến để sai. */
.gw-root .gw-icon-btn {
  width: 44px; height: 44px; border: 1px solid var(--gw-line); border-radius: 10px;
  background: var(--gw-panel); color: var(--gw-iconbtn-fg, var(--gw-ink));
  font-size: 15px; cursor: pointer;
  background-image: var(--gw-iconbtn); background-size: 100% 100%; background-repeat: no-repeat;
}
.gw-root .gw-icon-btn:active { transform: scale(.94); }

/* CỠ ICON THEO CHỖ ĐỨNG. `.gw-ic` mặc định cao 26px — đúng cho nút súng trên HUD, quá to
   cho ba chỗ dưới đây. Cả ba chỉ đặt một biến; luật cắt atlas do js/gang/screens/atlascss.js
   sinh ra và tự co theo. Bốn chỗ này trước đây là emoji hệ điều hành (🔒, ❚❚) — thứ mỗi máy
   vẽ một kiểu và không máy nào cùng bảng màu với bộ kit. */
.gw-root .gw-icon-btn .gw-ic { --gw-ich: 18px; }
.gw-root .gw-wall b .gw-ic { --gw-ich: 13px; }
/* `.gw-ammo i` (dòng dưới) mờ 50% để dấu gạch và số đạn tối đa lùi ra sau con số chính —
   nhưng viên đạn cũng là một thẻ `i`, và một icon mờ một nửa trông như hỏng chứ không như
   nhạt. Trả lại độ đục cho riêng nó. */
.gw-root .gw-ammo .gw-ic { --gw-ich: 15px; opacity: 1; margin-right: 3px; }
.gw-root .gw-gun-lock .gw-ic { --gw-ich: 13px; display: block; }
.gw-root .gw-lv.is-locked b .gw-ic { --gw-ich: 22px; }
.gw-root .gw-up-txt b .gw-ic { --gw-ich: 15px; }

/* ---------------- súng & hành động ---------------- */
.gw-root .gw-guns { display: flex; gap: 8px; }
.gw-root .gw-gun {
  position: relative; width: 62px; height: 48px;
  display: grid; place-items: center;
  border: 1px solid var(--gw-line); border-radius: 10px;
  background: var(--gw-panel); cursor: pointer;
}
.gw-root .gw-gun.is-on { border-color: var(--gw-gold); box-shadow: 0 0 0 2px rgba(240,180,41,.35); }
.gw-root .gw-gun.is-locked { opacity: .38; }
.gw-root .gw-gun.is-locked .gw-ic { filter: grayscale(1) brightness(.6); }
.gw-root .gw-gun-lock { position: absolute; right: 3px; bottom: 1px; font-size: 11px; }

.gw-root .gw-actions { display: flex; align-items: flex-end; gap: 8px; }
.gw-root .gw-nade {
  position: relative; width: 56px; height: 56px;
  display: grid; place-items: center;
  border: 1px solid var(--gw-line); border-radius: 12px;
  background: var(--gw-panel); color: var(--gw-ink); cursor: pointer;
}
.gw-root .gw-nade.is-on { border-color: var(--gw-gold); box-shadow: 0 0 0 2px rgba(240,180,41,.4); }
.gw-root .gw-nade:disabled { opacity: .35; }
.gw-root .gw-nade b {
  position: absolute; right: 3px; bottom: 1px;
  font-size: 12px; font-weight: 700; text-shadow: 0 1px 2px #000;
}

/* Nút nạp đạn kiêm ô hiển thị số đạn — một nút thay vì hai, vì trên màn 6" mỗi ô 44px là
   một phần tư chiều cao HUD, và người chơi nhìn số đạn ĐÚNG lúc họ định bấm nạp. */
.gw-root .gw-reload {
  position: relative; min-width: 132px; height: 56px;
  border: 1px solid var(--gw-line); border-radius: 12px;
  background: var(--gw-panel); color: var(--gw-ink);
  display: grid; place-items: center; gap: 0; cursor: pointer; overflow: hidden;
}
.gw-root .gw-reload:active { transform: scale(.97); }
.gw-root .gw-ammo { font-size: 20px; font-weight: 800; font-variant-numeric: tabular-nums; line-height: 1; }
.gw-root .gw-ammo em { font-style: normal; opacity: .5; margin: 0 1px; }
.gw-root .gw-ammo i { font-style: normal; opacity: .5; font-size: 14px; }
.gw-root .gw-reload-lb { font-size: 10px; letter-spacing: .09em; color: var(--gw-dim); }
.gw-root .gw-reload[data-state="empty"] { border-color: var(--gw-red); }
.gw-root .gw-reload[data-state="empty"] .gw-ammo, .gw-root .gw-reload[data-state="empty"] .gw-reload-lb { color: var(--gw-red); }
.gw-root .gw-reload[data-state="loading"] .gw-reload-lb { color: var(--gw-gold); }
.gw-root .gw-reload-fill {
  position: absolute; left: 0; bottom: 0; height: 3px; width: 0;
  background: var(--gw-gold);
}

/* ---------------- lớp phủ (cửa hàng / kết quả / tạm dừng) ---------------- */
.gw-root .gw-overlay {
  position: absolute; inset: 0; z-index: 5;
  display: grid; place-items: center;
  padding: 12px;
  background: rgba(8, 6, 5, .72);
  backdrop-filter: blur(3px);
  overflow: auto;
}
.gw-root .gw-sheet {
  width: min(560px, 100%);
  max-height: 100%;
  display: flex; flex-direction: column; gap: 10px;
  padding: 14px 16px;
  border: 1px solid var(--gw-line); border-radius: 14px;
  background: var(--gw-panel);
  box-shadow: 0 18px 48px rgba(0,0,0,.55);
}
.gw-root .gw-sheet h2 { margin: 0; font-size: 19px; font-weight: 800; letter-spacing: .01em; }
.gw-root .gw-sheet header { display: flex; align-items: center; justify-content: space-between; }
.gw-root .gw-sheet footer { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.gw-root .muted { color: var(--gw-dim); }
.gw-root .small { font-size: 12px; }

/* KHUNG NÚT THẬT — biến nằm ở css/gang-ui.css (SINH TỰ ĐỘNG bởi tools/make-gang-atlas.mjs).
 *
 * Ba điều về mấy dòng `border-image` dưới đây, cả ba đều là chỗ đã tính chứ không phải gõ:
 *
 * 1. `border-width` GIỮ NGUYÊN 1px, chỉ `border-image-width` là 10px. `border-image` không
 *    bao giờ đụng tới bố cục — nó vẽ đè vào phần padding. Nhờ vậy đeo khung vào KHÔNG làm
 *    nút rộng ra, không đẩy chữ, và không một nút nào tụt khỏi ngưỡng chạm 44px.
 *
 * 2. `stretch` chứ không `repeat`. Đây là art vector có gradient dọc, `repeat` sẽ lát dải
 *    giữa thành sọc. (My Kingdom dùng `repeat` vì bên ấy là pixel art và không được nội suy
 *    — cùng một thuộc tính, hai lời giải ngược nhau, vì hai loại art.)
 *
 * 3. MÀU CHỮ đi kèm ảnh: `var(--gw-btn-fg, var(--gw-ink))`. Viên thuốc ô-liu là nền SÁNG
 *    nên chữ phải tối (đo được 8,0:1 so với 1,9:1 nếu để chữ kem) — nhưng nền lui khi thiếu
 *    css/gang-ui.css lại là nền TỐI, cần chữ kem. Buộc hai thứ vào một biến là cách duy
 *    nhất để cả hai trạng thái đều đọc được, thay vì cứng hoá một màu rồi sai một nửa số
 *    trường hợp. Thiếu file ⇒ biến không phân giải ⇒ nút về đúng viền 1px + nền phẳng cũ.
 */
.gw-root .gw-btn {
  min-height: 44px; padding: 0 18px;
  border: 1px solid var(--gw-line); border-radius: 10px;
  background: rgba(255,255,255,.07); color: var(--gw-btn-fg, var(--gw-ink));
  font: inherit; font-weight: 700; cursor: pointer;
  border-image: var(--gw-btn) 0 var(--gw-btn-s, 0) fill / 0 var(--gw-btn-w, 0) stretch;
}
.gw-root .gw-btn:active { transform: scale(.97); }
.gw-root .gw-btn-primary {
  background: var(--gw-gold); color: var(--gw-btnp-fg, #201704); border-color: transparent;
  border-image: var(--gw-btnp) 0 var(--gw-btnp-s, 0) fill / 0 var(--gw-btnp-w, 0) stretch;
}
.gw-root .gw-btn-wide { width: 100%; }
.gw-root .gw-row { display: flex; gap: 10px; }
.gw-root .gw-row .gw-btn { flex: 1; }

/* cửa hàng */
.gw-root .gw-shop-coin { display: flex; align-items: center; gap: 5px; font-weight: 800; }
.gw-root .gw-shop-list { display: flex; flex-direction: column; gap: 7px; overflow: auto; }
.gw-root .gw-shop-item {
  display: flex; align-items: center; gap: 11px;
  min-height: 54px; padding: 7px 11px;
  border: 1px solid var(--gw-line); border-radius: 10px;
  background: rgba(255,255,255,.05); color: var(--gw-ink);
  font: inherit; text-align: left; cursor: pointer;
}
.gw-root .gw-shop-item:disabled { opacity: .42; cursor: default; }
.gw-root .gw-shop-item:active:not(:disabled) { transform: scale(.99); }
.gw-root .gw-shop-ic { flex: none; width: 42px; display: grid; place-items: center; }
.gw-root .gw-shop-emoji { font-size: 22px; }
.gw-root .gw-shop-txt { flex: 1; min-width: 0; }
.gw-root .gw-shop-txt b { display: block; font-size: 14px; }
.gw-root .gw-shop-txt em { display: block; font-style: normal; font-size: 11.5px; color: var(--gw-dim); }
.gw-root .gw-shop-price {
  flex: none; display: flex; align-items: center; gap: 4px;
  font-weight: 800; color: var(--gw-gold); font-variant-numeric: tabular-nums;
}
.gw-root .gw-shop-price.is-poor { color: var(--gw-red); }

/* kết quả */
.gw-root .gw-result { text-align: center; align-items: center; }
.gw-root .gw-result.is-win h2 { color: var(--gw-gold); }
.gw-root .gw-result.is-lose h2 { color: var(--gw-red); }
.gw-root .gw-stats {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
  gap: 8px; margin: 4px 0 2px; width: 100%;
}
.gw-root .gw-stats div {
  padding: 7px 4px; border-radius: 9px; background: rgba(255,255,255,.05);
}
.gw-root .gw-stats dt { font-size: 11px; color: var(--gw-dim); }
.gw-root .gw-stats dd {
  margin: 2px 0 0; font-size: 17px; font-weight: 800;
  display: flex; align-items: center; justify-content: center; gap: 4px;
}
.gw-root .gw-result .gw-row { width: 100%; }
/* Bảng ĐỒNG ĐỘI ở màn kết quả (phòng 2-3 người). Thắng/thua là chung, bảng thì riêng —
   xem chú thích của `mateTable` trong screens/results.js. */
.gw-root .gw-mate-table {
  list-style: none; margin: 0 0 12px; padding: 0; width: 100%;
  display: flex; flex-direction: column; gap: 4px;
}
.gw-root .gw-mate-table li {
  --gw-tint: var(--gw-gold);
  display: grid; grid-template-columns: 10px 1fr 62px 48px; align-items: center; gap: 8px;
  padding: 6px 10px; border-radius: 9px; background: rgba(255,255,255,.05);
  font-size: 13px; text-align: left;
}
.gw-root .gw-mate-table li > i { width: 10px; height: 10px; border-radius: 50%; background: var(--gw-tint); }
.gw-root .gw-mate-table li > span, .gw-root .gw-mate-table li > em {
  font-style: normal; text-align: right; font-variant-numeric: tabular-nums; font-weight: 700;
}
.gw-root .gw-mate-head {
  background: none; padding-top: 0; padding-bottom: 0;
  font-size: 11px; color: var(--gw-dim);
}
.gw-root .gw-mate-head > i { background: none; }
.gw-root .gw-mate-head > span, .gw-root .gw-mate-head > em { font-weight: 600; }

/* ---------------- sảnh ---------------- */
.gw-root .gw-lobby {
  position: absolute; inset: 0; z-index: 1;
  display: flex; flex-direction: column; gap: 14px;
  padding: 18px max(16px, env(safe-area-inset-left)) 18px max(16px, env(safe-area-inset-right));
  overflow: auto;
  background:
    radial-gradient(120% 90% at 20% 0%, rgba(240,180,41,.14), transparent 60%),
    var(--gw-bg);
}
.gw-root .gw-lobby h1 { margin: 0; font-size: 26px; font-weight: 900; letter-spacing: -.01em; }
.gw-root .gw-lobby h1 small { display: block; font-size: 12px; font-weight: 600; color: var(--gw-dim); letter-spacing: .1em; }
.gw-root .gw-heroes { display: flex; gap: 10px; flex-wrap: wrap; }
.gw-root .gw-hero {
  flex: 1 1 150px; min-height: 96px;
  display: flex; flex-direction: column; gap: 3px;
  padding: 12px; text-align: left;
  border: 1px solid var(--gw-line); border-radius: 12px;
  background: rgba(255,255,255,.05); color: var(--gw-ink); font: inherit; cursor: pointer;
}
.gw-root .gw-hero.is-on { border-color: var(--gw-gold); background: rgba(240,180,41,.1); }
.gw-root .gw-hero:disabled { opacity: .4; cursor: default; }
.gw-root .gw-hero b { font-size: 15px; }
.gw-root .gw-hero em { font-style: normal; font-size: 12px; color: var(--gw-dim); }
.gw-root .gw-level {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 14px; border: 1px solid var(--gw-line); border-radius: 12px;
  background: rgba(255,255,255,.05);
}
.gw-root .gw-level-txt { flex: 1; }
.gw-root .gw-level-txt b { display: block; font-size: 16px; }

/* Dải sao: một ảnh, bốn frame, chọn bằng --gw-stars. Xem screens/atlascss.js. */
.gw-root .gw-stars { --gw-stars: 0; }

/* ---------------- lớp phủ xoay máy ---------------- */
/* Hiện/ẩn hoàn toàn bằng media query — KHÔNG có JS nào bật tắt nó, nên nó không thể kẹt
   lại trên màn hình sau khi xoay (bài học js/views/catsgame.js:20-22 của iSpeak). */
.gw-root .gw-rotate { display: none; }
@media (orientation: portrait) and (max-width: 820px) {
  .gw-root[data-portrait="0"] .gw-rotate {
    position: absolute; inset: 0; z-index: 9;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 10px; padding: 24px; text-align: center;
    background: var(--gw-bg);
  }
  .gw-root .gw-rotate-ic { font-size: 44px; }
  .gw-root .gw-rotate h2 { margin: 0; font-size: 19px; }
}

/* Màn hình thấp (điện thoại ngang thật sự): thu HUD lại để nó không nuốt mất mặt đường. */
@media (max-height: 430px) {
  .gw-root .gw-gun { width: 54px; height: 42px; }
  .gw-root .gw-nade, .gw-root .gw-reload { height: 48px; }
  .gw-root .gw-reload { min-width: 116px; }
  .gw-root .gw-ammo { font-size: 18px; }
  .gw-root .gw-wall { height: 15px; }
  /* Dải trên đã chật với hai ô đồng đội trên máy hẹp: BỎ TÊN, giữ chấm màu và số vàng.
     Chấm màu vẫn phân biệt được ba người (ba màu của C.LEADERS, không ai trùng ai), còn
     tên thì đã có đủ ở phòng chờ. Thà mất một cái tên còn hơn đẩy thanh máu tường xuống
     dưới 100px và làm nó thành một vạch không đọc được. */
  .gw-root .gw-mate > b { display: none; }
  .gw-root .gw-toast { top: 76px; font-size: 12px; padding: 6px 12px; }
}

/* ---------------- cửa hàng nâng cấp ---------------- */
/* Màn hình này CUỘN được (khác sân đấu): danh sách dài hơn màn hình là chuyện bình thường,
   và trên điện thoại ngang thì 4 dòng đã chạm đáy. */
.gw-root .gw-up {
  position: absolute; inset: 0;
  display: flex; flex-direction: column;
  background: var(--gw-bg);
}
.gw-root .gw-up-head {
  flex: none; display: flex; align-items: center; gap: 10px;
  padding: 10px max(12px, env(safe-area-inset-right)) 8px max(12px, env(safe-area-inset-left));
  border-bottom: 1px solid var(--gw-line);
}
.gw-root .gw-up-head h2 { flex: 1; margin: 0; font-size: 17px; font-weight: 800; }

.gw-root .gw-tabs {
  flex: none; display: flex; gap: 6px; overflow-x: auto;
  padding: 8px max(12px, env(safe-area-inset-right)) 8px max(12px, env(safe-area-inset-left));
}
/* TAB GIỮ NGUYÊN CSS — bộ kit có hai tấm hình thang ActiveTab/InActiveTab, đã thử và đã gỡ.
   Lý do đầy đủ nằm cạnh bảng UI_FRAMES trong tools/make-gang-atlas.mjs; tóm tắt: `.gw-tab-hard.is-on`
   ở dưới dùng `background:` shorthand nên nó xoá `background-image`, và kết quả là ba tab
   đeo hình thang còn tab "Khó" đang chọn thì không — một lỗi KHÔNG tồn tại trước khi đụng vào. */
.gw-root .gw-tab {
  flex: none; min-height: 40px; padding: 0 14px;
  border: 1px solid var(--gw-line); border-radius: 999px;
  background: rgba(255,255,255,.05); color: var(--gw-dim);
  font: inherit; font-weight: 700; font-size: 13px; cursor: pointer; white-space: nowrap;
}
.gw-root .gw-tab.is-on { background: var(--gw-gold); color: #201704; border-color: transparent; }

.gw-root .gw-up-list {
  flex: 1; min-height: 0; overflow: auto;
  display: flex; flex-direction: column; gap: 8px;
  padding: 10px max(12px, env(safe-area-inset-right)) max(16px, env(safe-area-inset-bottom)) max(12px, env(safe-area-inset-left));
}
.gw-root .gw-up-row {
  display: flex; align-items: center; gap: 12px;
  min-height: 62px; padding: 9px 12px;
  border: 1px solid var(--gw-line); border-radius: 12px;
  background: rgba(255,255,255,.05);
}
.gw-root .gw-up-row.is-maxed { opacity: .55; }
.gw-root .gw-up-row.is-locked .gw-ic { filter: grayscale(1) brightness(.55); }
.gw-root .gw-up-row.is-on { border-color: var(--gw-gold); background: rgba(240,180,41,.09); }
.gw-root .gw-up-txt { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.gw-root .gw-up-txt b { font-size: 14px; }
.gw-root .gw-up-val { display: flex; align-items: baseline; gap: 5px; flex-wrap: wrap; font-size: 13px; }
.gw-root .gw-up-val em { font-style: normal; color: var(--gw-dim); }
.gw-root .gw-up-val strong { color: var(--gw-gold); }

/* Mười ô nấc — nhìn một cái là biết còn bao xa, không phải đọc "4/10". */
.gw-root .gw-pips { display: flex; gap: 3px; margin-top: 3px; }
.gw-root .gw-pips i {
  width: 12px; height: 4px; border-radius: 2px;
  background: rgba(255,255,255,.16);
}
.gw-root .gw-pips i.is-on { background: var(--gw-gold); }

.gw-root .gw-up-buy {
  flex: none; min-width: 92px; min-height: 44px; padding: 0 12px;
  display: flex; align-items: center; justify-content: center; gap: 5px;
  font-variant-numeric: tabular-nums;
}
.gw-root .gw-up-buy:disabled { opacity: .45; cursor: default; }
.gw-root .gw-arm .gw-ic { width: 44px; }

/* lối vào cửa hàng trên sảnh */
.gw-root .gw-lobby-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.gw-root .gw-upg-entry {
  width: 100%; text-align: left; color: var(--gw-ink); font: inherit; cursor: pointer;
  border: 1px solid var(--gw-line);
}
.gw-root .gw-upg-entry:active { transform: scale(.99); }

/* ---------------- bản đồ màn ---------------- */
.gw-root .gw-lv-grid {
  flex: 1; min-height: 0; overflow: auto;
  display: grid; gap: 8px;
  /* auto-fill với minmax: 5 cột trên điện thoại ngang, 3 trên dọc, tự giãn trên desktop —
     không cần một media query nào. */
  grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));
  align-content: start;
  padding: 10px max(12px, env(safe-area-inset-right)) 10px max(12px, env(safe-area-inset-left));
}
.gw-root .gw-lv {
  position: relative;
  min-height: 76px; padding: 8px 6px;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
  border: 1px solid var(--gw-line); border-radius: 12px;
  background: rgba(255,255,255,.05); color: var(--gw-ink);
  font: inherit; cursor: pointer; text-align: center;
}
.gw-root .gw-lv:active { transform: scale(.97); }
.gw-root .gw-lv b { font-size: 20px; font-weight: 900; line-height: 1; }
.gw-root .gw-lv em { font-style: normal; font-size: 11px; color: var(--gw-dim); }
.gw-root .gw-lv.is-locked { opacity: .4; cursor: default; }
.gw-root .gw-lv.is-locked b { font-size: 15px; }
/* Ô boss to hơn và có viền riêng — cột mốc phải nhìn ra được từ xa. */
.gw-root .gw-lv.is-boss {
  border-color: var(--gw-red);
  background: linear-gradient(rgba(210,64,47,.18), rgba(255,255,255,.05));
}
.gw-root .gw-lv-boss {
  position: absolute; top: 4px; right: 5px;
  font-size: 8px; font-weight: 900; letter-spacing: .08em; color: var(--gw-red);
}
.gw-root .gw-stars-sm { transform: scale(.52); transform-origin: center; height: 18px; margin-top: -6px; }
.gw-root .gw-map-gun { margin-left: auto; display: flex; align-items: center; padding-right: 4px; }

.gw-root .gw-lobby-foot {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  padding: 8px max(12px, env(safe-area-inset-right)) max(10px, env(safe-area-inset-bottom)) max(12px, env(safe-area-inset-left));
  background: linear-gradient(transparent, var(--gw-bg) 40%);
}
.gw-root .gw-lobby-foot .gw-upg-entry {
  display: flex; align-items: center; gap: 10px; text-align: left;
  background: var(--gw-panel);
}
.gw-root .gw-lobby-foot .gw-upg-entry span { flex: 1; }
/* Nút mở màn chọn tay súng. Cùng hình dạng với nút Nâng cấp ngay dưới nó — hai cái đứng
   sát nhau nên chúng phải trông như một cặp, không phải hai thứ khác loài. */
.gw-root .gw-lobby-foot .gw-hero-entry {
  display: flex; align-items: center; gap: 10px; text-align: left;
  background: var(--gw-panel);
  margin-bottom: 8px;
}
.gw-root .gw-lobby-foot .gw-hero-entry span { flex: 1; }
/* Chừa chỗ cho thanh dưới để ô màn cuối không bị nó che.
   ĐO, không đoán: BA nút × 44px (trần chạm của repo) + 2 × 8px cách nhau + 8px đệm trên
   của .gw-lobby-foot + 10px đệm dưới = 166, làm tròn lên 180 cho chỗ an toàn của một hàng
   sao. Con số 76 đúng hồi thanh dưới có một nút; 128 đúng hồi có hai; nút thứ ba là lối
   vào phòng ba người. Quên sửa dòng này là hàng màn cuối cùng nằm dưới thanh nút và không
   ai bấm được vào nó — một lỗi chỉ hiện ra ở CHƯƠNG 2, chỗ ít người mở nhất. */
.gw-root .gw-lv-grid { padding-bottom: 180px; }
/* Nút chế độ Khó — đỏ, tách khỏi các tab chương bằng màu chứ không bằng vị trí. */
.gw-root .gw-tab-hard { border-color: rgba(210,64,47,.6); color: #e88; }
.gw-root .gw-tab-hard.is-on { background: var(--gw-red); color: #fff; border-color: transparent; }

/* ══════════════════════════════════════════════════════════════════════════════════════
   CỔNG TỪ VỰNG — lớp riêng, đứng TRÊN cửa hàng giữa đợt

   #gwGate là một lớp KHÁC #gwOverlay, không dùng chung. Hai lý do, và cả hai đều là lỗi
   người khác đã trả tiền: cổng phải nằm trên cửa hàng (chúng mở cùng lúc), và nút Tạm dừng
   không được phép đóng nó. Biệt Đội Mèo có hẳn một bài test canh đúng điều này (099).
   ══════════════════════════════════════════════════════════════════════════════════════ */
.gw-root .gw-gate {
  position: absolute; inset: 0; z-index: 12;
  display: grid; place-items: center;
  padding: 16px max(14px, env(safe-area-inset-right)) 16px max(14px, env(safe-area-inset-left));
  background: rgba(12, 9, 7, .82);
  backdrop-filter: blur(3px);
}
.gw-root .gw-quiz { max-width: 520px; width: 100%; }
.gw-root .gw-quiz h2.is-ok { color: var(--gw-green); }
.gw-root .gw-quiz h2.is-no { color: var(--gw-red); }
.gw-root .gw-quiz-stem { margin: 6px 0 14px; font-size: 17px; line-height: 1.4; }
.gw-root .gw-quiz-opts { display: grid; gap: 8px; }
.gw-root .gw-quiz-opt {
  width: 100%; min-height: 48px; padding: 10px 14px;
  text-align: left; white-space: normal; line-height: 1.35;
}
.gw-root .gw-quiz-ans { display: flex; gap: 8px; align-items: baseline; margin: 4px 0 8px; }
.gw-root .gw-quiz-ans b { font-size: 17px; color: var(--gw-gold); }
.gw-root .gw-quiz-why { margin: 0 0 12px; line-height: 1.45; }
.gw-root .gw-quiz-sec {
  min-width: 32px; text-align: right;
  font-variant-numeric: tabular-nums; font-weight: 700; color: var(--gw-dim);
}
.gw-root .gw-quiz-sec.is-low { color: var(--gw-red); }

/* ---------------- phần thưởng trên màn kết quả ---------------- */
.gw-root .gw-payout {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin: 2px 0 14px; min-height: 44px;
}
.gw-root .gw-payout b { font-size: 20px; color: var(--gw-gold); }
.gw-root .gw-payout.is-block b { color: var(--gw-dim); }
.gw-root .gw-claim { min-height: 44px; }

/* Nút "nhận nốt các trận còn treo" ở sảnh. */
.gw-root .gw-pending { margin-bottom: 8px; }
/* Lối vào phòng ba người — cùng hình dạng với hai nút kia của `.gw-lobby-foot`, vì ba cái
   đứng chồng nhau và chúng phải trông như một chồng, không phải ba thứ khác loài. */
.gw-root .gw-lobby-foot .gw-coop-entry {
  display: flex; align-items: center; gap: 10px; text-align: left;
  background: var(--gw-panel);
  margin-bottom: 8px;
}
.gw-root .gw-lobby-foot .gw-coop-entry span { flex: 1; }

/* ══════════════════════════════════════════════════════════════════════════════════════
   PHÒNG BA NGƯỜI (#/gangroom)

   Dùng lại khung `.gw-up` / `.gw-up-head` / `.gw-up-list` của cửa hàng nâng cấp: cùng hình
   dạng "một trang cuộn được có thanh tiêu đề", nên không có lý do gì để dựng cái thứ hai.
   ══════════════════════════════════════════════════════════════════════════════════════ */
/* `min-width: 0` KHÔNG phải thừa. `.gw-up-list` là một flex column, và một flex item mặc
   định KHÔNG co được nhỏ hơn min-content của nó. Min-content ở đây do cái `<input>` quyết:
   một ô nhập không có `size` mặc định rộng 20 ký tự, mà chữ trong ô này là 22px — cộng
   nút "Vào phòng" rộng 108px là 449px min-content. Trên khung 360px thì `.gw-root`
   (`overflow: hidden`) CẮT MẤT nút ấy, và không có thanh cuộn nào để tìm lại nó.
   Đo trên tools/gang-room-preview.html?w=360: khung nội dung 343px, khối này 449px.
   Hai vế cùng chữa: `size` trên ô nhập hạ min-content xuống, `min-width: 0` cho phép co. */
.gw-root .gw-room-start {
  display: flex; flex-direction: column; gap: 10px; max-width: 460px; min-width: 0;
}
.gw-root .gw-room-or {
  display: flex; align-items: center; gap: 10px; margin: 4px 0;
  color: var(--gw-dim); font-size: 12px;
}
.gw-root .gw-room-or::before, .gw-root .gw-room-or::after {
  content: ""; flex: 1; height: 1px; background: var(--gw-line);
}
.gw-root .gw-code-row { display: flex; gap: 8px; min-width: 0; }
/* Ô GÕ MÃ. `text-transform: uppercase` chỉ là hình thức — view vẫn `.toUpperCase()` trước
   khi gửi, vì thuộc tính này KHÔNG đổi `input.value` và một mã chữ thường sẽ trượt câu
   `where code = v_code` ở 114. Cỡ chữ 16px là luật của repo (dưới đó iOS tự phóng to cả
   trang khi chạm vào ô); ở đây nó còn to hơn vì mã là thứ người ta phải đọc to lên. */
.gw-root .gw-code {
  flex: 1; min-width: 0; min-height: 48px; padding: 0 14px;
  border: 1px solid var(--gw-line); border-radius: 12px;
  background: rgba(0,0,0,.35); color: var(--gw-ink);
  font: inherit; font-size: 22px; font-weight: 800;
  letter-spacing: .22em; text-transform: uppercase; text-align: center;
}
.gw-root .gw-code:focus { outline: none; border-color: var(--gw-gold); }
.gw-root .gw-code-row .gw-btn { flex: none; min-width: 108px; }
.gw-root .gw-room-err { margin: 0; color: var(--gw-red); font-size: 13px; line-height: 1.4; }

.gw-root .gw-room-code {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 14px; border: 1px solid var(--gw-gold); border-radius: 14px;
  background: rgba(240,180,41,.08);
}
/* Mã phải ĐỌC TO ĐƯỢC QUA BÀN — đó là cả cơ chế mời của game này. Chữ to, giãn cách rộng,
   và một font có bề rộng đều để B/8 và G/6 không dính vào nhau khi đọc vội. */
.gw-root .gw-room-code b {
  font-size: 40px; font-weight: 900; letter-spacing: .16em; color: var(--gw-gold);
  font-family: ui-monospace, "SFMono-Regular", "Roboto Mono", monospace;
}

.gw-root .gw-seats { display: flex; flex-direction: column; gap: 8px; }
.gw-root .gw-seat {
  --gw-tint: var(--gw-line);
  display: grid; grid-template-columns: 10px 1fr auto; grid-template-rows: auto auto;
  align-items: center; gap: 2px 10px;
  min-height: 62px; padding: 9px 12px;
  border: 1px solid var(--gw-line); border-radius: 12px;
  background: rgba(255,255,255,.05);
}
.gw-root .gw-seat > i {
  grid-row: 1 / 3; width: 10px; height: 10px; border-radius: 50%; background: var(--gw-tint);
}
.gw-root .gw-seat b { font-size: 15px; }
.gw-root .gw-seat em { font-style: normal; font-size: 12px; color: var(--gw-dim); }
.gw-root .gw-seat-st {
  grid-row: 1 / 3; grid-column: 3; font-size: 12px; font-weight: 700; color: var(--gw-dim);
}
.gw-root .gw-seat.is-ready { border-color: var(--gw-green); }
.gw-root .gw-seat.is-ready .gw-seat-st { color: var(--gw-green); }
.gw-root .gw-seat.is-empty { border-style: dashed; opacity: .6; }

.gw-root .gw-room-level {
  display: flex; align-items: center; gap: 10px; text-align: left;
  background: var(--gw-panel);
}
.gw-root .gw-room-level:disabled { opacity: 1; cursor: default; }
.gw-root .gw-room-acts { margin-top: 2px; }

/* LỚP PHỦ CHỌN MÀN của chủ phòng. `renderLevelMap` trả về một `.gw-up`, mà `.gw-up` là
   `position: absolute; inset: 0` — nó được viết cho một TRANG, không cho một hộp thoại.
   Thả thẳng vào `.gw-overlay` thì khối chứa của nó là chính lớp phủ (thẻ `.gw-sheet` ở
   giữa không khai `position`), nên bản đồ phủ kín màn hình và nuốt luôn cái thẻ bao quanh
   — không còn tiêu đề, không còn nút đóng. Hai dòng dưới đây là chỗ chữa: `position:
   relative` biến thẻ bao thành khối chứa, và một chiều cao cho `inset: 0` thứ để bám vào. */
.gw-root .gw-lv-sheet { max-width: 660px; width: 100%; }
.gw-root .gw-lv-box {
  position: relative;
  height: min(64vh, 460px);
  border-radius: 12px;
  overflow: hidden;
}

/* ══════════════════════════════════════════════════════════════════════════════════════
   HAI BREAKPOINT của repo (719/720). Dưới 720 là điện thoại — bố cục dọc đã là mặc định;
   từ 720 trở lên thì lưới màn được nới ra, nếu không thì trên laptop nó vẫn bé bằng điện
   thoại và trông như một trang chưa dựng xong.
   ══════════════════════════════════════════════════════════════════════════════════════ */
@media (max-width: 719px) {
  .gw-root .gw-quiz-stem { font-size: 16px; }
}
@media (min-width: 720px) {
  .gw-root .gw-lv-grid { grid-template-columns: repeat(5, 1fr); }
  .gw-root .gw-up-list { max-width: 720px; margin: 0 auto; }
}
/* Điện thoại nằm ngang, màn thấp: ba đáp án xếp dọc thì cái thứ ba rơi khỏi tầm nhìn
   trong khi một cái đồng hồ 20 giây đang chạy. */
@media (orientation: landscape) and (max-height: 430px) {
  .gw-root .gw-quiz-opts { grid-template-columns: 1fr 1fr; }
  .gw-root .gw-quiz-stem { margin-bottom: 8px; font-size: 15px; }
}

/* Ô nhập liệu phải từ 16px trở lên, nếu không iOS tự phóng to cả trang khi chạm vào.
   My Gang hiện KHÔNG có ô nhập nào — luật đứng sẵn ở đây để ngày có một ô thì nó đã đúng,
   và để bài test của repo đọc thấy một câu trả lời thay vì một khoảng trống. */
.gw-root input, .gw-root textarea, .gw-root select { font-size: 16px; }

/* ---------------- bảng "Cách chơi" ---------------- */
.gw-root .gw-help { max-width: 520px; }
.gw-root .gw-help-list { margin: 4px 0 12px; padding-left: 20px; line-height: 1.55; }
.gw-root .gw-help-list li { margin: 4px 0; }
.gw-root .gw-credit { margin: 0 0 12px; }

/* ---- body.s8-play: đang chơi ⇒ thanh tab dưới bị ẩn (xem css/ispeak.css) -------------
   My Gang KHÁC bốn game kia ở đúng một điểm, và điểm ấy là một lỗi chứ không phải lựa
   chọn: nó chưa bao giờ có luật mobile trừ thanh tab, nên `calc(100dvh - 60px)` ở trên
   khiến mép dưới sân nằm HẲN dưới thanh tab cố định — bị che, không phải bị hụt. Ẩn thanh
   tab là điều kiện để dòng dưới đây đúng, nên hai thứ đi cùng nhau. */
@media (max-width: 979px) {
  .gw-root:is(body.s8-play *) { margin-bottom: 0; }
}
/* Viet la `.gw-root:is(body.s8-play *)` chu KHONG phai `body.s8-play .gw-root`, du hai
   cai chon dung mot tap phan tu: bai kiem "moi selector top-level nam duoi .gw-root" doi
   selector PHAI BAT DAU bang .gw-root, va luat ay dung — no la thu chan game nay son len
   game khac. `:is()` con cong them do cu the (0,2,1 so voi 0,1,0), nen khoi nay thang khoi
   .gw-root o tren bat ke thu tu trong file. */
.gw-root:is(body.s8-play *) {
  height: calc(100vh - 60px);
  height: calc(100dvh - 60px - env(safe-area-inset-top) - env(safe-area-inset-bottom));
}
