/* ==========================================================================
   "Hero Forge" — Lò Rèn Anh Hùng (#/forge). Cùng kỹ thuật với .rm-root ở trên:
   mọi luật nằm dưới .fg-root, biến màu tự khai lại nên không rò ra phần còn lại
   của app, và full-bleed bằng margin âm huỷ padding của .view.
   KHÁC ở tông màu: My Room là buổi chiều ấm trong nhà, Lò Rèn là chiến trường tối —
   thanh máu và số sát thương phải nổi lên trên nền, không hoà vào nền.
   ========================================================================== */
.fg-root {
  --bg: #221d29; --panel: #2f2839; --panel2: #3a3247; --ink: #f0e9dd; --line: #4b4159;
  --accent: #7cc4a6; --gold: #ffcf4d; --dim: #a79ab8;
  --shadow: 0 3px 0 rgba(0,0,0,.35);

  /* ---- THANG, thêm sau khi ĐO ------------------------------------------------------
     File này từng có 15 cỡ chữ và 13 giá trị bo góc rải bằng số cứng, không một biến nào.
     Hệ quả không phải là xấu ngay — mà là mỗi component tự quyết một mình, nên không có
     nhịp nào để mắt bám vào, và sửa "cho đều" là sửa 30 chỗ.

     HAI THANG CHỮ, KHÔNG PHẢI MỘT — đây là chỗ dễ làm hỏng nhất.
     `--fs-card` (9px) là nhãn PHỦ TRÊN ART: dải sao, chip bậc, cấp, badge mảnh, dải chỉ số
     chân thẻ. Thẻ rộng ~110px và chữ nằm đè lên chân dung; đó là khuôn của cả thể loại
     (thẻ nhân vật nào cũng có chữ nhỏ trên art), và nâng nó lên là làm vỡ đúng component
     duy nhất đang đẹp. Đo được: 8 selector dùng 9px, gần như tất cả nằm trong .fg-card.
     `--fs-1` (11px) là SÀN của chữ trong VỎ — panel, nút, tab, danh sách. Đây mới là chỗ
     người ta đọc, và là chỗ 10px không đủ trên điện thoại cũ.

     BÓNG: `--sh-1` giữ nguyên bóng KHỐI của nếp nhà (0 3px 0, không blur — chung với
     My Room / RPG / Cats). `--sh-2` là bóng MỀM, chỉ cho tầng nổi thật sự (modal đã dùng
     một bản riêng từ trước; giờ nó có tên).

     `--dimmed`: sáu giá trị opacity khác nhau (.45/.5/.55) từng mô tả cùng một ý "mờ/khoá".
     Một giá trị. NGOẠI LỆ `tr.fg-hidden td` giữ .55 — tools/test.mjs khoá nó để ba bảng
     xếp hạng của app nói cùng một ngôn ngữ. */
  --fs-card: 9px; --fs-1: 11px; --fs-2: 13px; --fs-3: 15px; --fs-4: 19px;
  --r-sm: 8px; --r-md: 12px; --r-lg: 16px;
  --sh-1: var(--shadow);
  --sh-2: 0 6px 16px rgba(0,0,0,.45);
  --dimmed: .5;
  /* Mượn từ ispeak.css:1145 (.rm-pop) — cùng app thì cùng một cảm giác nảy. */
  --ease-pop: cubic-bezier(.34,1.56,.64,1);
  /* Chữ trên nền accent/gold. Lặp 6 lần bằng số cứng #10352a trước khi có tên. */
  --on-accent: #10352a;
  /* Nền "hàng của tôi / đang chọn" trong bảng và danh sách. Hardcode #3f4a44 hai chỗ. */
  --mine: #3f4a44;

  margin: -18px -16px -64px;
  color: var(--ink); background: var(--bg);
  font-family: system-ui, "Segoe UI", Roboto, sans-serif;
  -webkit-user-select: none; user-select: none;
}
.fg-root #fgApp {
  display: flex; flex-direction: column; max-width: 900px; margin: 0 auto;
  height: calc(100vh - 60px);
  height: calc(100dvh - 60px);
  overflow: hidden;
}
@media (max-width: 719px) {
  /* Cùng phép tính (và cùng lý do) với .rm-root: hằng số 124 sai trên iPhone tai thỏ
     chạy standalone, nên cộng thẳng hai safe-area inset vào thay vì đoán. */
  .fg-root { margin-bottom: calc(-72px - env(safe-area-inset-bottom)); }
  .fg-root #fgApp { height: calc(100vh - 124px); }
  .fg-root #fgApp {
    height: calc(100dvh - 60px - 56px - env(safe-area-inset-top) - env(safe-area-inset-bottom));
  }
}

/* ---- Header tài nguyên (screens/shell.js) -------------------------------------------
   CHỈ chứa tài nguyên + bốn nút hệ thống. Không tiêu đề, không dòng phụ: mỗi màn hình đã
   tự in tiêu đề của nó, và một dòng "Lò Rèn Anh Hùng" đứng mãi trên đầu chỉ ăn chiều cao
   của khung chơi để nói một điều người chơi đã biết.
   Dải pill CUỘN NGANG còn hàng nút thì không: trên màn 339px, bốn pill + bốn nút không đủ
   chỗ, và thứ được phép tràn phải là thứ đọc-để-biết, không phải thứ bấm-để-làm. */
/* Header có RANH GIỚI. Trước đây nó cùng màu `--bg` với thân màn hình, nên dải pill trôi
   lơ lửng và không có gì nói "đây là thanh trạng thái, dưới kia là nội dung". Gradient nhẹ
   + một vạch dưới: cùng ý mà `rpg.css` dùng cho HUD của nó, và rẻ hơn một đường viền đặc
   vì nó không cắt ngang màn hình bằng một nét cứng. */
.fg-root #fgTop { display: flex; align-items: center; gap: 8px; padding: 8px 10px; min-width: 0;
  background: linear-gradient(var(--panel), var(--bg));
  border-bottom: 2px solid var(--line);
  /* safe-area NGANG: máy tai thỏ xoay ngang cắt mất mép trái/phải. Bốn game anh em đã
     cộng inset này (cats.css, rpg.css); Lò Rèn mới chỉ cộng `bottom`. */
  padding-left: calc(10px + env(safe-area-inset-left));
  padding-right: calc(10px + env(safe-area-inset-right)); }
.fg-root .fg-res { display: flex; gap: 6px; flex: 1; min-width: 0; overflow-x: auto;
  -webkit-overflow-scrolling: touch; scrollbar-width: none; }
.fg-root .fg-res::-webkit-scrollbar { display: none; }
.fg-root .fg-pill { flex: 0 0 auto; display: inline-flex; align-items: center; gap: 5px;
  background: var(--panel); border: 2px solid var(--line); border-radius: var(--r-md);
  padding: 4px 9px; font-size: var(--fs-2); color: var(--dim); }
.fg-root .fg-pill b { font-size: var(--fs-3); font-weight: 800; color: var(--ink);
  font-variant-numeric: tabular-nums; }
.fg-root .fg-c { width: 13px; height: 13px; border-radius: 50%; flex: 0 0 auto;
  background: radial-gradient(circle at 35% 30%, #ffe89a, var(--gold) 60%, #e6a92e); border: 2px solid #e6a92e; }
.fg-root .fg-top-actions { display: flex; gap: 6px; flex: 0 0 auto; }
/* flex:0 0 auto vì cùng lý do đã ghi ở .rm-tbtn — hàng nút không được co lại khi
   tiêu đề dài đẩy #fgMid ra, nếu không emoji bị cắt trên màn 339px. */
.fg-root .fg-tbtn { flex: 0 0 auto; position: relative; width: 38px; height: 38px; border-radius: var(--r-md);
  border: 2px solid var(--line); background: var(--panel); font-size: 17px; font-weight: 800;
  cursor: pointer; display: grid; place-items: center; color: var(--ink); box-shadow: var(--shadow); }
.fg-root .fg-tbtn:active { transform: translateY(2px); box-shadow: none; }
/* Vùng chạm 44px cho bốn nút hệ thống, bằng lớp ảo — cùng cách và cùng lý do với `.fg-orb`.
   Nới cỡ THẬT lên 44 thì bốn nút + dải pill không còn lọt hàng ở 339px, đúng thứ mà chú
   thích `flex: 0 0 auto` ngay trên vừa cảnh báo. 38 + 3×2 = 44.
   `position: relative` nằm trong luật gốc ở trên, không phải một luật thứ hai: khai lại
   cùng một selector ở tầng gốc là hai luật GỘP vào nhau, và tools/test.mjs cấm đúng điều đó. */
.fg-root .fg-tbtn::after { content: ""; position: absolute; inset: -3px; }
.fg-root #fgBtnLang { font-size: var(--fs-2); }

/* Bản đồ và sân đấu chồng lên nhau trong cùng một khung; mỗi lúc chỉ một cái hiện.
   Đặt tuyệt đối nên bản đồ cuộn được mà canvas vẫn lấp đầy đúng khung. */
.fg-root #fgStage { flex: 1; min-height: 0; position: relative; }
/* VIGNETTE quanh sân đấu. Canvas trải `inset: 0` trần trụi, nên nền procedural chạy thẳng
   ra bốn mép và trận đấu trông như một mảng màu bị cắt ngang chứ như một sân khấu.
   Làm bằng CSS chứ không vẽ trong canvas: nó là một lớp TĨNH, nên vẽ lại nó 30 lần mỗi
   giây là trả tiền cho một hình không đổi (js/rpg/render.js làm trong canvas vì nền của
   nó động). `pointer-events: none` để không cướp cú chạm nào của canvas, vốn đang giữ
   `touch-action: none` cho riêng mình.
   Chỉ hiện khi canvas hiện: `#fgStage:has()` tránh một lớp tối phủ lên BẢN ĐỒ. */
.fg-root #fgStage::after {
  content: ""; position: absolute; inset: 0; pointer-events: none; opacity: 0;
  background: radial-gradient(120% 85% at 50% 45%, transparent 55%, rgba(0,0,0,.55) 100%);
}
.fg-root #fgStage:has(#fgCanvas:not([hidden]))::after { opacity: 1; }
.fg-root #fgMap { position: absolute; inset: 0; overflow-y: auto; padding: 0 10px 12px;
  -webkit-overflow-scrolling: touch; }
.fg-root #fgCanvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block;
  image-rendering: pixelated; touch-action: none; }
.fg-root #fgCanvas[hidden], .fg-root #fgMap[hidden], .fg-root #fgBar[hidden] { display: none; }

/* PANEL — hộp chứa gần như mọi thứ ngoài trận, dùng 27 lần trên 6 màn hình.
   Bản trước: nền đặc + viền 2px, KHÔNG bóng. Hậu quả đo được ở màn hero — sáu panel giống
   hệt nhau xếp dọc, và cái cao 888px trông y hệt cái cao 140px. Không phải xấu, mà là
   KHÔNG CÓ NHỊP: mắt không có mốc nào để biết mình đang ở khối thứ mấy.
   Một dòng bóng khối `--sh-1` tách nó khỏi nền cho cả 27 chỗ. Bóng KHỐI chứ không mềm —
   đó là nếp chung với My Room / RPG / Cats, và nó không tốn blur trên máy yếu. */
.fg-root .fg-panel { background: var(--panel); border: 2px solid var(--line); border-radius: var(--r-md);
  padding: 10px 12px; margin-bottom: 10px; box-shadow: var(--sh-1); }
/* Dải màu bên trái tiêu đề: mốc để MẮT bắt ranh giới giữa các khối mà không phải đọc chữ.
   `--rc` khi panel có rank (khối danh tính hero), rơi về accent ở mọi panel khác. */
.fg-root .fg-panel h3 { margin: 0 0 8px; font-size: var(--fs-3); font-weight: 800;
  border-left: 3px solid var(--rc, var(--accent)); padding-left: 8px; line-height: 1.25; }

/* ---- TRẠNG THÁI TƯƠNG TÁC, dùng chung ------------------------------------------------
   Trước khối này cả file có ĐÚNG 0 luật `:hover` và 0 luật `:focus`. Hệ quả: trên desktop
   không nút nào phản hồi con trỏ, và đi bằng bàn phím thì không thấy mình đang ở đâu —
   một màn hình 42 thẻ bài mà không có vòng focus là một màn hình không dùng được bằng Tab.

   VÌ SAO KHÔNG CÓ `transition`: engine vẽ lại toàn màn bằng `elMap.innerHTML = html`
   (engine.js), nên không phần tử nào sống qua hai lượt vẽ — một transition trên đổi trạng
   thái sẽ không bao giờ có khung đầu để chạy từ đó. `:hover`/`:active`/`:focus-visible` thì
   khác: chúng đổi trên CÙNG một phần tử đang sống, nên chúng là thứ duy nhất ăn ở đây.

   `:focus-visible` chứ không `:focus`: chuột bấm vào nút không được để lại vòng sáng.
   Selector nhóm — mỗi vế tự mở bằng `.fg-root` vì tools/test.mjs cấm selector tầng gốc
   không bắt đầu bằng nó. */
.fg-root button:focus-visible,
.fg-root .fg-card:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px;
}
/* HOVER chỉ trên máy CÓ con trỏ. Trên cảm ứng, `:hover` dính lại sau khi chạm và biến một
   nút vừa bấm thành một nút "đang chọn" giả — đúng loại lỗi mà người dùng không báo được. */
@media (hover: hover) {
  .fg-root .fg-up:hover:not(:disabled),
  .fg-root .fg-mbtn:hover:not(:disabled),
  .fg-root .fg-sbtn:hover,
  .fg-root .fg-sub:hover,
  .fg-root .fg-tbtn:hover,
  .fg-root .fg-stage:hover:not(.locked) {
    border-color: var(--accent);
  }
  .fg-root .fg-orb:hover { opacity: 1; }
  .fg-root button.fg-card:hover { transform: translateY(-2px); }
}
.fg-root .fg-muted { color: var(--dim); font-size: var(--fs-2); margin: 4px 0; }
.fg-root .fg-list { margin: 4px 0; padding-left: 18px; font-size: var(--fs-2); line-height: 1.6; }

.fg-root .fg-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.fg-root .fg-chip { display: inline-flex; gap: 5px; align-items: baseline; font-size: var(--fs-2);
  border: 2px solid var(--line); border-radius: var(--r-md); padding: 3px 8px; background: var(--panel2); }
.fg-root .fg-chip i { font-style: normal; color: var(--dim); font-size: var(--fs-1); }

/* auto-fill (không phải auto-fit): với 3–4 màn còn lại, auto-fit kéo giãn ô ra full
   width và thẻ "Màn 10" rộng bằng cả màn hình. auto-fill giữ nguyên khổ ô. */
.fg-root .fg-stages { display: grid; gap: 8px; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); }
.fg-root .fg-stage { position: relative; border: 2px solid var(--line); border-radius: var(--r-md);
  background: var(--panel2); color: var(--ink); padding: 10px 6px; cursor: pointer;
  display: grid; gap: 2px; font: inherit; box-shadow: var(--shadow); }
.fg-root .fg-stage b { font-size: var(--fs-3); font-weight: 800; }
.fg-root .fg-stage span { font-size: var(--fs-1); color: var(--dim); }
.fg-root .fg-stage:active { transform: translateY(2px); box-shadow: none; }
.fg-root .fg-stage.locked { opacity: var(--dimmed); cursor: default; box-shadow: none; }
.fg-root .fg-stage.done { border-color: var(--accent); }
.fg-root .fg-boss { font-style: normal; font-size: var(--fs-1); font-weight: 900; color: #10202a;
  background: var(--gold); border-radius: var(--r-sm); padding: 1px 5px; justify-self: center; }
/* Thưởng lần đầu trên thẻ màn. Vàng như đồng xu ở My Room — cùng một ví, phải cùng một màu. */
.fg-root .fg-stage .fg-rw { font-size: var(--fs-1); font-weight: 800; color: var(--gold); }
/* Chìa khoá phá khiên của trùm. Xanh như thanh khiên trên sân đấu, để hai chỗ nói cùng
   một thứ bằng cùng một màu. */
.fg-root .fg-stage .fg-key { font-size: var(--fs-1); font-weight: 800; color: #c4d6f2; }
.fg-root .fg-ch-locked { opacity: var(--dimmed); }
.fg-root .fg-chip-boss { border-color: var(--gold); }

/* ---- Thanh tab dưới đáy (screens/shell.js) ------------------------------------------
   Ở ĐÁY, không phải trên đầu: nút gần ngón cái là nút bấm được — cùng nguyên tắc "thumb
   zone" mà Honkai: Star Rail dùng khi đặt menu ở panel phải/dưới. Bản trước để hàng nút
   chế độ ở đầu trang, đá nhau với topbar của chính app. */
.fg-root #fgTabs { display: flex; gap: 2px; padding: 4px 6px calc(4px + env(safe-area-inset-bottom));
  background: var(--panel); border-top: 2px solid var(--line); flex: 0 0 auto; }
.fg-root #fgTabs[hidden] { display: none; }
.fg-root .fg-tab { position: relative; flex: 1 1 0; min-width: 0; display: grid; gap: 1px;
  justify-items: center; border: 0; background: none; color: var(--dim); font: inherit;
  padding: 6px 2px; border-radius: var(--r-md); cursor: pointer; }
.fg-root .fg-tab i { font-style: normal; font-size: 19px; line-height: 1; }
.fg-root .fg-tab span { font-size: var(--fs-1); font-weight: 800; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
/* Gạch chân tab đang chọn — khuôn của app (ispeak.css:866). Nền + màu chữ một mình là hai
   tín hiệu YẾU trên nền tối: `--panel2` chỉ sáng hơn `--panel` một nấc, và mắt phải so hai
   ô cạnh nhau mới thấy. Một vạch accent thì đọc được ngay cả bằng đuôi mắt.
   `inset` chứ không phải phần tử/pseudo riêng: không thêm gì vào DOM và không đụng chiều
   cao hàng tab, vốn đã phải chừa `env(safe-area-inset-bottom)`. */
.fg-root .fg-tab.on { color: var(--accent); background: var(--panel2);
  box-shadow: 0 -3px 0 var(--accent) inset; }
.fg-root .fg-tab:active { transform: translateY(1px); }
/* Một CHẤM, không phải một con số đỏ nhấp nháy: nó chỉ nói "chỗ này có thứ bấm được mà
   chưa bấm", không đếm ngược và không tạo hạn chót. Đây là app cho học sinh. */
.fg-root .fg-dot { position: absolute; top: 5px; right: 50%; margin-right: -16px;
  width: 7px; height: 7px; border-radius: 50%; background: var(--accent); }

/* Sub-tab của Phiêu Lưu: ba chế độ PvE là ba cách tiêu cùng một cái vé, nên chúng nằm
   TRONG một tab chứ không ngang hàng với Đấu Trường. */
.fg-root .fg-subs { display: flex; gap: 4px; padding: 8px 0 2px; }
.fg-root .fg-sub { flex: 1 1 0; min-height: 44px; display: inline-grid; place-items: center; border: 2px solid var(--line); background: var(--panel);
  color: var(--dim); border-radius: var(--r-md); padding: 6px 8px; font: inherit; font-size: var(--fs-2);
  font-weight: 800; cursor: pointer; }
.fg-root .fg-sub.on { color: var(--ink); background: var(--panel2); border-color: var(--accent); }
/* Nút nâng cấp. Nút không đủ tài nguyên vẫn HIỆN GIÁ chứ không biến mất — biết còn thiếu
   bao nhiêu là biết phải cày thêm bao lâu; giấu đi thì chỉ còn cách đoán. */
.fg-root .fg-ups { display: grid; gap: 6px; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); margin-bottom: 8px; }
.fg-root .fg-up { border: 2px solid var(--line); background: var(--panel2); color: var(--ink);
  border-radius: var(--r-md); padding: 6px 8px; font: inherit; cursor: pointer; display: grid; gap: 1px; text-align: left; }
.fg-root .fg-up b { font-size: var(--fs-2); font-weight: 800; }
.fg-root .fg-up span { font-size: var(--fs-1); color: var(--dim); }
.fg-root .fg-up.on { border-color: var(--accent); box-shadow: var(--sh-1); }
.fg-root .fg-up:disabled { opacity: var(--dimmed); cursor: default; }
/* PHẢN HỒI KHI CHẠM — nút bấm nhiều thứ hai của game trước đây không có gì cả: bấm vào,
   màn hình vẽ lại, và không có một khung hình nào nói "tao nhận rồi". Lún 2px + bỏ bóng là
   đúng cử chỉ mà `.fg-tbtn`/`.fg-stage` đã dùng từ đầu; ở đây nó chỉ chưa được nối. */
.fg-root .fg-up:active:not(:disabled) { transform: translateY(2px); box-shadow: none; }
/* (103) Nút GỘP BƯỚC. Cùng khuôn `fg-up` — nó cố ý là CÙNG MỘT CÂU ở một độ lớn khác
   ("Cấp 12 → 13" cạnh "Cấp 12 → 49"), nên nó phải trông như cùng một loại nút, không
   phải một tính năng khác. Chỉ nền đậm lên để mắt biết cái nào đi xa hơn.
   `.fg-ups` là lưới auto-fill nên nút thứ hai tự chen vào hàng mà không cần khai gì thêm;
   trong ô trang bị (`.fg-eq`, một cột) nó xuống dòng dưới nút một nấc, cũng đúng. */
.fg-root .fg-upmax { background: var(--panel); border-color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent); }
.fg-root .fg-eq .fg-upmax { background: var(--panel2); }
/* Nút THĂNG BẬC, chiếm đúng ô mà nút lên sao bỏ trống ở ⭐5. Cùng khuôn `fg-up` — nó nằm
   trong cùng lưới với cấp và sao, và một nút khác khuôn ở đó đọc ra là "thứ này thuộc về
   chỗ khác", đúng điều phép gộp vừa dọn đi. Chỉ viền vàng để mắt biết đây là rung đặc
   biệt: nghi lễ nằm ở màu, không nằm ở một panel riêng. */
.fg-root .fg-uptier.on { border-color: var(--gold); box-shadow: inset 0 0 0 1px var(--gold); }
.fg-root .fg-uptier b { color: var(--gold); }

/* ---- Thang nuôi: 15 nấc = 3 bậc × 5 sao (screens/hero.js:progLadder) -------------------
   KHOẢNG HỞ GIỮA BA CỤM là toàn bộ thông tin của hàng này. Nó nói cấu trúc `progOf` bằng
   hình: cụm = bậc, chấm = sao, và bước từ chấm cuối cụm này sang chấm đầu cụm sau chính là
   thăng bậc. Số chấm sáng không bao giờ giảm — đó là câu trả lời bằng mắt cho "sao về ⭐1
   có phải bước lùi không", và nó có mặt ở MỌI trạng thái chứ không chỉ lúc sắp bấm. */
.fg-root .fg-ladder { display: flex; align-items: center; gap: 8px; margin: 0 0 8px; flex-wrap: wrap; }
.fg-root .fg-lg { display: inline-flex; gap: 3px; }
.fg-root .fg-lg i { width: 9px; height: 9px; border-radius: 50%; background: var(--line);
  border: 1px solid var(--line); }
.fg-root .fg-lg i.on { background: var(--gold); border-color: var(--gold); }
.fg-root .fg-ladder b { font-size: var(--fs-1); font-weight: 800; color: var(--dim);
  font-variant-numeric: tabular-nums; }
.fg-root .fg-diffs { display: flex; gap: 6px; margin-bottom: 8px; }
.fg-root .fg-dbtn { min-height: 44px; display: inline-grid; place-items: center; border: 2px solid var(--line); background: var(--panel2); color: var(--ink);
  border-radius: var(--r-md); padding: 5px 12px; font: inherit; font-size: var(--fs-2); font-weight: 800; cursor: pointer; }
.fg-root .fg-dbtn.on { background: var(--gold); color: #10202a; border-color: var(--gold); }

/* Thanh điều khiển trận TÁCH khỏi sân đấu. Trước đây nó là một hàng nút trôi trên nền
   trang, dính liền canvas — nên mắt đọc nó như một phần của chiến trường. Nền panel + một
   vạch trên đặt nó về đúng chỗ: một thanh công cụ dưới sân khấu. Cùng nếp với thanh tab. */
.fg-root #fgBar { display: flex; gap: 6px; padding: 8px 10px; justify-content: center; flex-wrap: wrap;
  background: var(--panel); border-top: 2px solid var(--line); flex: 0 0 auto; }
.fg-root .fg-sbtn { border: 2px solid var(--line); background: var(--panel); color: var(--ink);
  border-radius: var(--r-md); padding: 7px 12px; font: inherit; font-size: var(--fs-2); font-weight: 800; cursor: pointer; }
.fg-root .fg-sbtn.on { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }

.fg-root .fg-mrow { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 10px; }
.fg-root .fg-mbtn { border: 2px solid var(--line); border-radius: var(--r-md); padding: 8px 12px;
  font: inherit; font-size: var(--fs-3); font-weight: 800; cursor: pointer; background: var(--panel2); color: var(--ink); }
.fg-root .fg-mbtn.go { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }

.fg-root .fg-hgrid { display: grid; gap: 8px; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); }
.fg-root .fg-hcard { text-align: left; border: 2px solid var(--line); border-radius: var(--r-md);
  background: var(--panel2); color: var(--ink); padding: 8px; cursor: pointer; font: inherit; display: grid; gap: 2px; }
.fg-root .fg-hcard b { font-size: var(--fs-2); }
.fg-root .fg-hcard span { font-size: var(--fs-1); color: var(--dim); }
.fg-root .fg-hcard em { font-style: normal; font-size: var(--fs-1); font-weight: 900; color: var(--accent); }
.fg-root .fg-hcard.on { background: var(--mine); }
/* (066) Đối thủ đã đấu hôm nay: mờ đi chứ KHÔNG disabled — trận sau vẫn đánh được, chỉ là
   không tính điểm. Cùng tinh thần "thử đội hình mới không bao giờ bị phạt" của vé. */
.fg-root .fg-hcard.fg-dim { opacity: var(--dimmed); }

/* (066) Bảng vàng. Bọc trong .fg-tablewrap để bảng tự cuộn ngang trên điện thoại thay vì
   đẩy cả màn hình rộng ra — cùng bài học với .rm-duel-row của 040. */
.fg-root .fg-tablewrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.fg-root .fg-board { width: 100%; border-collapse: collapse; font-size: var(--fs-2); }
.fg-root .fg-board th, .fg-root .fg-board td { padding: 6px 8px; text-align: right; white-space: nowrap; }
.fg-root .fg-board th:nth-child(2), .fg-root .fg-board td:nth-child(2) { text-align: left; white-space: normal; }
.fg-root .fg-board th { font-size: var(--fs-1); color: var(--dim); border-bottom: 2px solid var(--line); }
.fg-root .fg-board td { border-bottom: 1px solid var(--line); font-variant-numeric: tabular-nums; }
.fg-root .fg-board tr.fg-me td { background: var(--mine); font-weight: 800; }
/* (082) hàng đang ẩn — chỉ supervip nhận được hàng này từ forge_board. Cùng độ mờ .55
   với .lb-hidden (bảng học tập) và .rm-board-hidden (My Room): ba bảng phải trông giống
   nhau, nếu không thì "đang ẩn" ở chỗ này lại đọc như một trạng thái khác ở chỗ kia. */
.fg-root .fg-board tr.fg-hidden td { opacity: .55; }
.fg-root .fg-hidtag { font-size: var(--fs-1); font-weight: 800; opacity: .75; white-space: nowrap; }

.fg-root #fgModalWrap { position: fixed; inset: 0; background: rgba(10,6,16,.62); display: none;
  align-items: center; justify-content: center; padding: 18px; z-index: 60; }
.fg-root #fgModalWrap.on { display: flex; }
.fg-root #fgModal { position: relative; width: 100%; max-width: 400px; max-height: 84%; overflow-y: auto;
  overscroll-behavior: contain; background: var(--panel); border: 3px solid var(--line);
  border-radius: var(--r-lg); padding: 16px; box-shadow: 0 10px 30px rgba(0,0,0,.5); }
/* Nút Đóng phải thấy được mà không cần cuộn — bảng đội hình 20 hero đã dài hơn khung. */
.fg-root #fgModal h2 { position: sticky; top: -16px; z-index: 1; margin: -16px -16px 10px;
  padding: 14px 52px 10px 16px; font-size: var(--fs-4); background: var(--panel); border-radius: var(--r-md) 15px 0 0;
  box-shadow: 0 1px 0 var(--line); }
.fg-root .fg-unlock { margin: 10px 0 0; padding: 8px 10px; border-radius: var(--r-md); font-size: var(--fs-3);
  font-weight: 800; color: var(--on-accent); background: var(--accent); }
.fg-root .fg-x { position: absolute; top: 8px; right: 8px; width: 40px; height: 40px; z-index: 2;
  border: 2px solid var(--line); border-radius: var(--r-md); background: var(--panel2);
  font: inherit; font-size: 18px; font-weight: 900; line-height: 1; color: inherit; cursor: pointer; }
/* ---- (juice) Nghi lễ mở gói --------------------------------------------------------
   Lưng bài glow theo màu độ hiếm rồi tự lật sau ~0.65s. Máy bật prefers-reduced-motion
   thấy thẳng mặt bài — nghi lễ là gia vị, không phải nội dung. */
.fg-root .fg-reveal { position: relative; display: flex; justify-content: center;
  margin: 10px 0 2px; perspective: 600px; }
.fg-root .fg-rvcard { position: relative; width: 128px; height: 156px; }
.fg-root .fg-rvface, .fg-root .fg-rvback { position: absolute; inset: 0; border-radius: var(--r-md);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px;
  border: 3px solid var(--rc, var(--accent)); background: var(--panel2); text-align: center;
  padding: 8px; }
.fg-root .fg-rvface b { font-size: var(--fs-3); }
.fg-root .fg-rvface span { font-size: var(--fs-2); color: var(--rc, var(--dim)); font-weight: 800; }
.fg-root .fg-rvback { display: none; font-size: 42px; }
@media (prefers-reduced-motion: no-preference) {
  .fg-root .fg-rvcard { transform-style: preserve-3d; animation: fgFlip .5s ease .65s both; }
  .fg-root .fg-rvback { display: flex; backface-visibility: hidden;
    box-shadow: 0 0 22px var(--rc, var(--accent)); }
  .fg-root .fg-rvface { transform: rotateY(180deg); backface-visibility: hidden; }
  .fg-root .fg-reveal::after { content: ""; position: absolute; top: 64px; width: 10px;
    height: 10px; border-radius: 50%; background: var(--rc, var(--accent));
    animation: fgBurst .45s ease 1.1s both; opacity: 0; }
  @keyframes fgFlip { from { transform: rotateY(0); } to { transform: rotateY(180deg); } }
  @keyframes fgBurst { 0% { transform: scale(.4); opacity: .9; } 100% { transform: scale(9); opacity: 0; } }
}

/* ==========================================================================
   THẺ BÀI + các màn hình mới (screens/{card,roster,hero,team,summon,shell}.js)
   ==========================================================================
   Một khuôn thẻ, sáu bề mặt: lưới bộ sưu tập, ô đội hình, đầu màn chi tiết, nghi lễ mở
   gói, đối thủ đấu trường, hàng đợi lượt. Trước đây sáu chỗ ấy có sáu cách vẽ một con
   hero khác nhau, nên đổi màu viền theo rank phải sửa sáu nơi.
   ========================================================================== */

/* ---- Thang rank: MỘT biến --rc, bảy giá trị -----------------------------------------
   Năm bậc đầu là màu đặc. Celestial và Divine KHÔNG phải màu — chúng là gradient, nên
   dùng kỹ thuật hai lớp background (padding-box giữ nền, border-box vẽ viền). Đó cũng là
   lý do catalog.js chỉ khai màu đại diện: một bảng màu có chữ "rainbow" là bảng nói dối. */
.fg-root .fg-r-common    { --rc: #a8a095; }
.fg-root .fg-r-rare      { --rc: #8fd0e6; }
.fg-root .fg-r-epic      { --rc: #c4a6e0; --glow: 0 0 10px rgba(196,166,224,.45); }
.fg-root .fg-r-legendary { --rc: #ffcf4d; --glow: 0 0 12px rgba(255,207,77,.45); }
.fg-root .fg-r-mythic    { --rc: #e0655f; --glow: 0 0 14px rgba(224,101,95,.5); }
.fg-root .fg-r-celestial { --rc: #7ee0c4; --glow: 0 0 16px rgba(126,224,196,.5); }
.fg-root .fg-r-divine    { --rc: #fff0b0; --glow: 0 0 18px rgba(255,240,176,.6); }

/* ---- Thẻ bài ------------------------------------------------------------------------
   ART TRÀN VIỀN, chữ đè lên art trên một dải mờ. Không phải hộp ảnh trên + khối chữ dưới:
   trên một thẻ rộng ~110px, tách hai thứ ấy ra là cắt đôi diện tích của cả hai. Dải chỉ
   số ở chân là băng DUY NHẤT nằm ngoài art. */
.fg-root .fg-card { position: relative; display: grid; grid-template-rows: auto auto;
  gap: 0; padding: 0; overflow: hidden; text-align: left; font: inherit; color: var(--ink);
  background: #241f2e; border: 2px solid var(--rc, var(--line)); border-radius: var(--r-md);
  box-shadow: var(--glow, none); cursor: default; }
.fg-root button.fg-card { cursor: pointer; }
.fg-root button.fg-card:active { transform: translateY(2px); }
.fg-root .fg-card.fg-dim { opacity: var(--dimmed); }
.fg-root .fg-card.fg-on { outline: 2px solid var(--accent); outline-offset: -4px; }
.fg-root .fg-card.fg-locked { border-color: var(--line); box-shadow: none; }

/* HAI TRỤC, HAI HỌ CLASS — và đây là thay đổi của 077.
   `fg-r-*` nói DANH HIỆU: nó đặt --rc/--glow, tức MÀU.
   `fg-t-*` nói ĐẦU TƯ: nó mang CHUYỂN ĐỘNG.
   Trước 077 chuyển động bám vào TÊN RANK (.fg-r-celestial / .fg-r-divine), nên sau khi
   thang bậc mở ra cho mọi độ hiếm thì nó nói sai: một con Thường bậc 2 hiển thị "Sử Thi"
   và đứng im, trong khi một con Divine cũ lấp lánh — dù hai bên đã đầu tư ngang nhau.
   Viền conic và @keyframes dưới đây dùng var(--rc), nên chúng TỰ đổi màu theo rank mà
   không cần thêm một dòng màu nào cho bảy bậc. */
.fg-root .fg-t-1.fg-card:not(.fg-locked) {
  border-color: transparent;
  background:
    linear-gradient(#241f2e, #241f2e) padding-box,
    linear-gradient(120deg, var(--rc, #fff), #ffffff, var(--rc, #fff)) border-box;
}
.fg-root .fg-t-2.fg-card:not(.fg-locked) {
  border-color: transparent;
  background:
    linear-gradient(#241f2e, #241f2e) padding-box,
    linear-gradient(120deg, var(--rc, #fff), #ffffff, var(--rc, #fff), #ffffff) border-box;
  background-size: 100% 100%, 300% 100%;
}
@media (prefers-reduced-motion: no-preference) {
  .fg-root .fg-t-2.fg-card:not(.fg-locked) { animation: fgDivine 3.2s linear infinite; }
  @keyframes fgDivine { to { background-position: 0 0, 300% 0; } }
}

/* Khung art: TỈ LỆ cố định, không phải chiều cao cố định — khổ 3:4 là khổ chân dung mà
   art anime của Nấc D sẽ cắt theo, nên đổi nguồn ảnh sau này không phải đụng bố cục. */
.fg-root .fg-card-art { position: relative; display: block; overflow: hidden;
  aspect-ratio: 3 / 4;
  background:
    radial-gradient(ellipse at 50% 78%, color-mix(in srgb, var(--rc, #fff) 30%, transparent), transparent 68%),
    linear-gradient(#2f2839, #241f2e); }
.fg-root .fg-card-sm .fg-card-art { aspect-ratio: 1 / 1; }
/* Chân dung căn giữa phần THẤY ĐƯỢC (trừ dải chữ ở chân), nếu không sprite bị dải mờ ăn
   mất chân. */
.fg-root .fg-por { position: absolute; left: 0; right: 0; top: 0; bottom: var(--scrim, 30px);
  display: grid; place-items: center; }
.fg-root .fg-card-sm .fg-por { bottom: var(--scrim, 16px); }
/* Cắt một ô atlas bằng CSS thuần. --atlas do engine đặt từ ATLAS.file (atlas-map.js là
   nguồn DUY NHẤT biết tên file, kể cả khi make-atlas.mjs lên v9). */
/* CẮT Ô ATLAS BẰNG PHẦN TRĂM, không bằng px + transform. Hai lỗi đã cắn thật ở đây, và
   cách này chữa cả hai cùng lúc.

   LỖI 1 — chân dung lệch khỏi khung. Bản px cho `<i>` cỡ ô atlas làm hộp layout rồi thu
   nhỏ bằng `transform: scale()`. Transform co phần VẼ nhưng KHÔNG co hộp, nên hộp lớn hơn
   khung `.fg-por`; track của grid tự nới bằng chính nó và `place-items: center` không còn
   gì để căn — ảnh ghim vào góc trên-trái rồi bị `.fg-card-art { overflow: hidden }` cắt.
   Lệch = (hộp − khung) / 2, tỉ lệ THẲNG với cỡ ô: ô 141×128 (v10) lệch 16×7px, đủ nhỏ để
   trông bình thường suốt nhiều bản; ô 323×256 (v11) lệch 108×71px trên khung 108×114 và
   chân dung biến mất.

   LỖI 2 — chân dung không lớn theo thẻ. Hệ số phóng tính từ một chiều cao ĐÍCH cố định
   (28/76/122px), nên khi lưới giãn trên màn rộng thì thẻ to ra còn nhân vật đứng nguyên:
   ô đội hình ~250px với một chân dung 28px là một chấm giữa khoảng trống.

   Cả hai đều là hệ quả của việc trộn px của atlas với px của bố cục. Phần trăm không có
   vấn đề đó: `background-size`/`background-position` tính theo hộp của CHÍNH phần tử, còn
   chiều cao hộp do khung quyết định (`height: 100%`). card.js phát bốn tỉ lệ không đơn vị
   (--bw/--bh/--bx/--by) + `--ar` để giữ hình dạng ô. Đúng ở mọi khổ thẻ và mọi cỡ ô atlas,
   kể cả lần sinh sau. `.fg-por` đã `position: absolute` nên là containing block sẵn. */
.fg-root .fg-por i { position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  height: 100%; width: auto; aspect-ratio: var(--ar);
  background-image: var(--atlas); background-repeat: no-repeat;
  background-size: var(--bw) var(--bh); background-position: var(--bx) var(--by);
  filter: drop-shadow(0 3px 4px rgba(0,0,0,.55)); }
/* Atlas PIXEL phải tắt nội suy; atlas ART thì phải bật. Trước đây luật trên khai cứng
   `image-rendering: pixelated`, đúng cho pixel và SAI cho art — thu nhỏ một ô 256px bằng
   nearest-neighbour cho ra viền răng cưa. engine.js gắn cờ ở gốc (`fg-pixelart`) theo
   `ATLAS.art`, đúng cặp luật mà đường canvas đã có với imageSmoothingEnabled. */
.fg-root.fg-pixelart .fg-por i { image-rendering: pixelated; }
.fg-root .fg-por-none { font-size: 26px; font-weight: 900; color: var(--dim); }
.fg-root .fg-locked .fg-por i { filter: brightness(0) opacity(.42); }

/* Dải mờ ở chân art: sao + tên đè LÊN ảnh. Gradient chứ không phải nền đặc — nền đặc là
   một cái hộp thứ hai, đúng thứ vừa bỏ đi. */
.fg-root .fg-scrim { position: absolute; left: 0; right: 0; bottom: 0; display: grid;
  gap: 0; padding: 12px 6px 4px;
  background: linear-gradient(transparent, rgba(0,0,0,.72) 45%, rgba(0,0,0,.88)); }
.fg-root .fg-scrim b { font-size: var(--fs-1); font-weight: 800; line-height: 1.2;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fg-root .fg-card-lg .fg-scrim b { font-size: var(--fs-3); }
.fg-root .fg-rk { font-size: var(--fs-card); font-weight: 800; color: var(--rc, var(--dim)); }
.fg-root .fg-stars { font-size: var(--fs-1); color: var(--gold); letter-spacing: -1px; line-height: 1; }
.fg-root .fg-stars i { font-style: normal; color: rgba(255,255,255,.28); }
.fg-root .fg-st-t1 { color: #7ee0c4; }
.fg-root .fg-st-t2 { color: #fff0b0; text-shadow: 0 0 6px rgba(255,240,176,.9); }
/* Chip bậc. Dải 5 sao KHÔNG nói được rằng "⭐2 bậc 2" hơn "⭐2 bậc 0" đúng 10 nấc trên
   thang prog — nên con số ấy phải hiện thành chữ, ngay cạnh dải sao. */
.fg-root .fg-tchip { font-style: normal; font-size: var(--fs-card); font-weight: 900; margin-left: 3px;
  padding: 0 3px; border-radius: var(--r-sm); color: var(--on-accent); background: var(--rc, #fff); }
/* Badge Mảnh Hồn chưa tiêu. Đây là chỗ đắt giá nhất của cả nấc này: một lưới 42 ô lập tức
   nói "con nào đang có mảnh", thay vì phải mở 42 trang hero để đếm.
   Nội dung là PHÂN SỐ ("3/5") từ khi Mảnh Hồn thôi được trình bày như một cái ví — nên
   `min-width` chứ không để nó co theo chữ: một lưới 42 ô mà badge rộng hẹp so le thì
   không quét mắt được, và "10/8" chỉ dài hơn "3/5" đúng hai ký tự. */
.fg-root .fg-fragb { position: absolute; bottom: 3px; right: 3px; font-style: normal;
  font-size: var(--fs-card); font-weight: 900; line-height: 1; padding: 2px 4px; border-radius: var(--r-sm);
  color: var(--on-accent); background: var(--accent); z-index: 1;
  min-width: 22px; text-align: center; font-variant-numeric: tabular-nums; }
/* ĐỦ MẢNH CHO NẤC SAO KẾ TIẾP. Cùng vai trò với chấm `fg-dot` ở thanh tab — "chỗ này có
   thứ bấm được mà chưa bấm". Đổi bằng MÀU + viền, không bằng animation: một lưới 42 ô mà
   sáu ô cùng nhấp nháy là một màn hình không nhìn nổi. */
.fg-root .fg-fragb.on { background: var(--gold); color: #3a2600;
  box-shadow: 0 0 0 2px var(--panel), 0 0 6px var(--gold); }
/* Hàng sắp xếp: cùng khuôn orb nhưng chữ, nên cho nó co lại thay vì tròn. */
.fg-root .fg-sorts .fg-orb-w { font-size: var(--fs-1); padding: 0 8px; }

/* Badge góc: icon thay chữ. "Thích Khách" trên thẻ rộng 110px thì phải xuống dòng. */
.fg-root .fg-bd { position: absolute; top: 3px; font-style: normal; font-size: var(--fs-1);
  line-height: 1; padding: 3px; border-radius: var(--r-sm); background: rgba(0,0,0,.55); z-index: 1; }
.fg-root .fg-bd-el { left: 3px; box-shadow: 0 0 0 1px var(--ec, transparent) inset; }
.fg-root .fg-bd-cls { right: 3px; }
.fg-root .fg-tier { position: absolute; top: 26px; right: 4px; font-style: normal; font-size: var(--fs-3); z-index: 1; }
.fg-root .fg-tag { position: absolute; top: 26px; left: 3px; font-style: normal;
  font-size: var(--fs-card); font-weight: 900; color: var(--on-accent); background: var(--accent);
  border-radius: var(--r-sm); padding: 1px 5px; z-index: 1; }
/* Tấm cấp: cùng hàng với dải sao, trong dải mờ. Cùng chỗ mà mọi bộ giao diện tham chiếu
   đặt nó — và vì nó nằm TRONG luồng, dải mờ cao lên thì nó đi theo. */
.fg-root .fg-scrim-r { display: flex; align-items: center; justify-content: space-between;
  gap: 4px; min-width: 0; }
.fg-root .fg-lvl { font-style: normal; font-size: var(--fs-card); font-weight: 800; color: var(--ink);
  background: rgba(0,0,0,.55); border: 1px solid rgba(255,255,255,.2);
  border-radius: var(--r-sm); padding: 0 4px; white-space: nowrap; flex: 0 0 auto; }

/* Dải chỉ số ở chân thẻ: ba con số thay cho một con "Lực chiến" tổng. */
.fg-root .fg-card-foot { display: flex; gap: 2px; padding: 3px 4px;
  background: rgba(0,0,0,.3); border-top: 1px solid rgba(255,255,255,.07); }
.fg-root .fg-card-foot i { flex: 1 1 0; min-width: 0; font-style: normal; font-size: var(--fs-card);
  font-weight: 800; color: var(--ink); text-align: center; font-variant-numeric: tabular-nums;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Icon nhỏ hơn CHỮ, cố ý: ô rộng 33px và con số mới là thứ phải đọc được. */
.fg-root .fg-card-foot i b { font-weight: 400; opacity: .8; margin-right: 1px; font-size: var(--fs-card); }
.fg-root .fg-card-sub { display: block; color: var(--dim); font-size: var(--fs-1); text-align: center; }
.fg-root .fg-card-empty { border-style: dashed; border-color: var(--line); opacity: .7; }

/* Lưới thẻ. auto-fill (không auto-fit) vì cùng lý do đã ghi ở .fg-stages: với 3 thẻ còn
   lại, auto-fit kéo giãn mỗi thẻ ra cả màn hình. */
.fg-root .fg-cards { display: grid; gap: 8px; margin-bottom: 10px;
  grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)); }
.fg-root .fg-slots { display: grid; gap: 6px; grid-template-columns: repeat(5, 1fr); }
@media (max-width: 419px) { .fg-root .fg-slots { grid-template-columns: repeat(3, 1fr); } }

/* Dải đội hình trên màn chiến dịch: năm thẻ cỡ sm, cuộn ngang nếu chật. */
.fg-root .fg-squad { display: grid; gap: 6px; grid-template-columns: repeat(5, 1fr); }
.fg-root .fg-squad .fg-card { border-radius: var(--r-md); }
.fg-root .fg-squad .fg-scrim b { font-size: var(--fs-card); }

/* ---- Bộ lọc lưới: ORB TRÒN ----------------------------------------------------------
   Hình tròn tô màu hệ đọc được ở khổ 32px; một nút chữ nhật cùng khổ chỉ còn chỗ cho đúng
   cái icon và mất luôn tín hiệu màu. */
.fg-root .fg-filts { display: flex; gap: 6px; flex-wrap: wrap; margin: 8px 0; align-items: center; }
/* VÙNG CHẠM 44px MÀ KHÔNG ĐỔI CỠ NHÌN. 44 là ngưỡng chạm của cả app (ispeak.css:1181-1184),
   và Lò Rèn trước đây không có một `min-height` nút nào — orb là 32px, tức nhỏ hơn ngưỡng
   một phần ba. Nhưng nới THẬT ra 44 thì bốn hàng bộ lọc cao thêm ~48px, đúng chỗ đang phải
   nhường đất cho lưới 42 thẻ. Nên nới bằng một lớp ảo phủ ra ngoài: ngón tay bắt được 44px,
   mắt vẫn thấy đúng vòng tròn 32px cũ. Không phần tử DOM nào thêm, không byte HTML nào thêm.
   `inset: -6px` = 32 + 6×2 = 44. */
.fg-root .fg-orb { position: relative; width: 32px; height: 32px; flex: 0 0 auto; border-radius: 50%;
  border: 2px solid var(--line); background: var(--panel2); color: var(--ink);
  font: inherit; font-size: var(--fs-3); line-height: 1; cursor: pointer; display: grid;
  place-items: center; padding: 0; opacity: .6; }
.fg-root .fg-orb::after { content: ""; position: absolute; inset: -6px; border-radius: 50%; }
.fg-root .fg-orb.on { opacity: 1; border-color: var(--oc, var(--accent));
  box-shadow: 0 0 8px color-mix(in srgb, var(--oc, var(--accent)) 60%, transparent); }
.fg-root .fg-orb-all, .fg-root .fg-orb-w { width: auto; border-radius: var(--r-lg); padding: 0 12px;
  font-size: var(--fs-2); font-weight: 800; }

/* ---- Chiến dịch: pill chương + đường node ------------------------------------------- */
.fg-root .fg-chs { display: flex; gap: 5px; overflow-x: auto; padding: 8px 0 4px;
  -webkit-overflow-scrolling: touch; }
.fg-root .fg-chp { flex: 0 0 auto; min-height: 44px; display: inline-grid; place-items: center; border: 2px solid var(--line); background: var(--panel);
  color: var(--dim); border-radius: 999px; padding: 5px 12px; font: inherit; font-size: var(--fs-2);
  font-weight: 800; cursor: pointer; }
.fg-root .fg-chp.on { color: var(--on-accent); background: var(--accent); border-color: var(--accent); }
.fg-root .fg-chp.locked { opacity: var(--dimmed); }

/* Nút TO NHẤT màn hình = hành động quan trọng nhất. Bản trước 10 thẻ màn cùng cỡ, và thẻ
   cần bấm nằm lẫn trong đó. */
.fg-root .fg-cta { display: flex; align-items: center; gap: 10px; border-color: var(--accent); }
.fg-root .fg-cta-i { flex: 1; min-width: 0; display: grid; gap: 1px; }
.fg-root .fg-cta-i b { font-size: var(--fs-3); font-weight: 800; }
.fg-root .fg-cta-i span { font-size: var(--fs-1); color: var(--dim); }
.fg-root .fg-big { font-size: var(--fs-3); padding: 12px 18px; flex: 0 0 auto; }

/* Đường node: cùng mười thẻ ấy, xếp thành một hàng có đường nối thì đọc ra là "đi từ đây
   tới kia"; một lưới 3x4 thì đọc ra là bảng chọn và không nói được mình đang ở đâu. */
.fg-root .fg-path { display: flex; gap: 0; overflow-x: auto; padding: 4px 0 8px;
  -webkit-overflow-scrolling: touch; align-items: stretch; }
.fg-root .fg-path .fg-stage { flex: 0 0 auto; width: 84px; margin: 0; border-radius: var(--r-md);
  position: relative; }
/* Đường nối giữa hai node. Vẽ bằng ::before của node SAU, nên không có phần tử thừa nào
   trong DOM và node đầu tự nhiên không có đuôi thừa. */
.fg-root .fg-path .fg-stage + .fg-stage { margin-left: 14px; }
.fg-root .fg-path .fg-stage + .fg-stage::before { content: ""; position: absolute;
  left: -16px; top: 50%; width: 14px; height: 3px; background: var(--line); border-radius: var(--r-sm); }
.fg-root .fg-path .fg-stage.done + .fg-stage::before { background: var(--accent); }

/* ---- Màn chi tiết hero -------------------------------------------------------------- */
.fg-root .fg-backrow { margin: 8px 0 0; }
.fg-root .fg-hero-head { display: flex; gap: 12px; align-items: flex-start; }
.fg-root .fg-hero-head .fg-card { flex: 0 0 132px; width: 132px; }
.fg-root .fg-hero-id { flex: 1; min-width: 0; }
.fg-root .fg-hero-id h3 { margin: 0 0 2px; font-size: var(--fs-4); }
.fg-root .fg-rankline { margin: 0 0 4px; font-size: var(--fs-2); font-weight: 800; color: var(--rc, var(--dim)); }
.fg-root .fg-hero-pow { margin: 6px 0 0; font-size: var(--fs-3); font-weight: 800; color: var(--gold); }

/* Khối chỉ số: con số HIỆN TẠI và phần CHÊNH của nấc kế tiếp, cùng một hàng. Hai thứ ấy
   chỉ có nghĩa khi đứng cạnh nhau — bản trước chỉ có giá, nên "600 Tinh Thạch" là một con
   số không so được với cái gì. */
.fg-root .fg-stats { display: grid; gap: 6px; grid-template-columns: repeat(auto-fill, minmax(88px, 1fr)); }
.fg-root .fg-stat { display: grid; gap: 0; background: var(--panel2); border: 2px solid var(--line);
  border-radius: var(--r-md); padding: 6px 8px; }
.fg-root .fg-stat i { font-style: normal; font-size: var(--fs-1); color: var(--dim); }
.fg-root .fg-stat b { font-size: var(--fs-3); font-weight: 800; font-variant-numeric: tabular-nums; }
.fg-root .fg-stat em { font-style: normal; font-size: var(--fs-1); font-weight: 800; color: var(--accent); }

.fg-root .fg-skill { display: flex; gap: 10px; align-items: flex-start; }
.fg-root .fg-skill-ic { flex: 0 0 auto; font-style: normal; font-size: 20px; width: 40px; height: 40px;
  display: grid; place-items: center; border-radius: var(--r-md); background: var(--panel2);
  border: 2px solid var(--line); color: var(--accent); }
.fg-root .fg-skill b { font-size: var(--fs-3); }
.fg-root .fg-skill p { margin: 2px 0 0; }

.fg-root .fg-eqs { display: grid; gap: 6px; grid-template-columns: 1fr 1fr; margin-top: 8px; }
.fg-root .fg-eq { background: var(--panel2); border: 2px solid var(--line); border-radius: var(--r-md); padding: 6px; }
.fg-root .fg-eq-h { display: flex; justify-content: space-between; align-items: baseline; gap: 4px; }
.fg-root .fg-eq-h b { font-size: var(--fs-2); }
.fg-root .fg-eq-h i { font-style: normal; font-size: var(--fs-1); color: var(--dim); }
.fg-root .fg-eq .fg-up { margin-top: 4px; background: var(--panel); }
.fg-root .fg-pips { display: flex; gap: 3px; margin: 4px 0 0; }
.fg-root .fg-pips i { width: 100%; height: 5px; border-radius: var(--r-sm); background: var(--line); }
.fg-root .fg-pips i.on { background: var(--gold); }
.fg-root .fg-gain { font-style: normal; font-size: var(--fs-1); font-weight: 800; color: var(--accent); }

/* ---- Màn triệu hồi ------------------------------------------------------------------ */
.fg-root .fg-summon { text-align: center; }
.fg-root .fg-summon .fg-mrow { justify-content: center; }
.fg-root .fg-odds { display: grid; gap: 5px; }
.fg-root .fg-odd { display: flex; justify-content: space-between; align-items: center;
  border-left: 4px solid var(--rc, var(--line)); background: var(--panel2);
  border-radius: var(--r-sm); padding: 5px 9px; }
.fg-root .fg-odd i { font-style: normal; font-size: var(--fs-2); font-weight: 800; color: var(--rc, var(--ink)); }
.fg-root .fg-odd b { font-size: var(--fs-2); font-variant-numeric: tabular-nums; }

/* Nghi lễ mở gói giờ bọc một THẺ BÀI thật thay vì một hộp chữ. Khổ lá bài phải khớp thẻ
   cỡ md, nếu không mặt sau và mặt trước lệch nhau lúc lật. */
/* Khổ lá bài phải khớp khổ THẬT của thẻ md (art 3:4 + dải chỉ số), nếu không mặt trước
   tràn ra ngoài khung lật và dải sao chồng lên tấm cấp. 116 rộng ⇒ 112 art ⇒ 149 cao,
   cộng dải chỉ số ~19 và hai viền. */
.fg-root .fg-reveal .fg-rvcard { width: 116px; height: 192px; }
.fg-root .fg-reveal .fg-rvface { padding: 0; border: 0; background: none; }
.fg-root .fg-reveal .fg-rvface .fg-card { width: 100%; }
.fg-root .fg-reveal .fg-rvback { border-color: var(--rc, var(--accent)); }

/* ---- 072: Mở 10, thanh bảo hiểm, Mảnh Hồn --------------------------------------------
   Mười lá lật cùng lúc trong một lưới cuộn được. KHÔNG lật lệch pha nhau: mười hoạt ảnh
   trễ dần là bốn giây ngồi nhìn, và ở lượt mở thứ năm thì đó là bốn giây bị lấy mất. */
.fg-root .fg-rv10 { display: grid; gap: 6px; grid-template-columns: repeat(5, 1fr);
  margin: 10px 0 2px; }
.fg-root .fg-rv10 .fg-reveal { margin: 0; }
.fg-root .fg-rv10 .fg-rvcard { width: 100%; height: 104px; }
/* Lá TRÙNG là một kết quả khác về chất, nên nó phải trông khác: thẻ mờ đi một nấc và
   mang một tấm ✦ đếm số mảnh đang có. Trộn nó vào hình dạng "hero mới" là cách chắc chắn
   để người chơi tưởng mình vừa mở ra một con chưa có. */
.fg-root .fg-rv-frag .fg-rvface .fg-card { opacity: .78; }
.fg-root .fg-frag-tag { position: absolute; left: 50%; bottom: 6px; transform: translateX(-50%);
  background: var(--rc, var(--accent)); color: #16140f; font-size: var(--fs-card); font-weight: 800;
  border-radius: 999px; padding: 1px 8px; white-space: nowrap; }

/* Thanh bảo hiểm: hai thanh tiến trình, không đếm ngược, không hạn chót. Người chơi thấy
   chính xác mình đang ở đâu — đó là toàn bộ khác biệt giữa pity tử tế và pity giấu mặt. */
.fg-root .fg-pity { display: grid; gap: 3px; margin-bottom: 8px; text-align: left; }
.fg-root .fg-pity i { font-style: normal; font-size: var(--fs-1); color: var(--dim); font-weight: 800; }
.fg-root .fg-pity-track { display: block; height: 8px; border-radius: 999px;
  background: var(--line); overflow: hidden; }
.fg-root .fg-pity-track b { display: block; height: 100%; width: var(--w, 0%);
  border-radius: 999px; background: var(--gold); }

/* ---- 072: khối Thăng Hoa ở màn chi tiết hero ------------------------------------------
   `fg-keep` là dòng "không mất gì cả". Nó phải NỔI chứ không nằm lẫn trong đám fg-muted:
   người chơi thể loại này đã quen bị lấy mất thứ gì đó khi "tiến hoá", nên một dòng xám
   nhạt sẽ bị đọc lướt qua đúng lúc nó cần được đọc.
   `fg-ascend`, không phải `fg-asc`: `.fg-asc` ở dòng 307 là RUY BĂNG góc thẻ bài và nó
   mang `position: absolute`. Trùng tên là bốc cả panel ra khỏi dòng chảy. */
.fg-root .fg-ascend .fg-mrow { justify-content: flex-start; }
.fg-root .fg-ascend-gain { margin: 0 0 4px; font-size: var(--fs-2); font-weight: 800;
  color: var(--rc, var(--accent)); text-shadow: var(--glow, none); }
.fg-root .fg-keep { margin: 6px 0; font-size: var(--fs-1); line-height: 1.45; color: var(--ink);
  background: var(--panel2); border-left: 4px solid var(--accent); border-radius: var(--r-sm);
  padding: 6px 9px; }
/* VÍ TẠI ĐIỂM TIÊU. Mảnh Sao và Mảnh Vạn Năng rời header (screens/shell.js) vì nhịp của
   chúng chênh ba bậc độ lớn so với xu/Tinh Thạch/vé; đổi lại, chỗ chúng đứng bây giờ là
   chỗ DUY NHẤT nói ra con số ấy, nên nó không được mang màu `fg-muted`. Khuôn pill của
   header đi theo luôn — cùng một thứ thì phải trông giống nhau dù đứng ở hai màn. */
.fg-root .fg-wallet { display: inline-block; margin: 0 0 6px; padding: 3px 9px;
  font-size: var(--fs-2); font-weight: 700; color: var(--ink); background: var(--panel2);
  border: 2px solid var(--line); border-radius: var(--r-md);
  font-variant-numeric: tabular-nums; }
.fg-root .fg-skrank { display: inline-block; margin-left: 6px; font-style: normal;
  font-size: var(--fs-1); font-weight: 800; color: var(--gold); border: 1px solid var(--gold);
  border-radius: 999px; padding: 0 6px; vertical-align: middle; }

/* ---- 073: hạng đối thủ ở đấu trường --------------------------------------------------
   Ba nhãn, không phải một con số: người chơi cần biết "trận này có đáng đánh không".
   Màu nói trước chữ — xanh là ngang cơ (đáng đánh), đỏ là trên cơ mình. */
/* TÊN `fg-atier`, KHÔNG PHẢI `fg-tier` — và cái tên ấy là cả bản vá.
   Bản trước đặt tên `.fg-tier`, trùng đúng tên mà thẻ bài dùng cho icon bậc ✨/🌈
   (dòng 329, `card.js:153`). Hai luật cùng specificity nên cascade GỘP chứ không thay:
     • nhãn hạng thừa hưởng `position:absolute; top:26px; right:4px` của luật kia. `.fg-hcard`
       không có `position` ⇒ containing block leo lên tận `#fgMap` ⇒ CẢ danh sách đối thủ dồn
       nhãn về một điểm góc trên-phải vùng cuộn, chồng lên nhau. Toàn bộ tín hiệu chia hạng
       của 073 biến mất, và cái đống chữ ấy trông như lỗi sản phẩm.
     • ngược lại, icon ✨/🌈 trên thẻ bài bị luật này ép xuống 9px + viền + padding, thành một
       pill tí hon thay vì icon 14px.
   Đúng cái bẫy mà chú thích ở khối `fg-ascend` phía trên đã cảnh báo, mắc lần thứ hai. */
.fg-root .fg-atier { display: inline-block; font-style: normal; font-size: var(--fs-card);
  font-weight: 800; border-radius: 999px; padding: 0 6px; margin: 1px 0 0;
  border: 1px solid currentColor; }
.fg-root .fg-atier-even { color: #7cbf6a; }
.fg-root .fg-atier-up   { color: #e0655f; }
.fg-root .fg-atier-down { color: #8a8175; }

/* ---- Nhãn trận trên thanh điều khiển ------------------------------------------------ */
.fg-root .fg-blabel { align-self: center; font-size: var(--fs-2); font-weight: 800; color: var(--dim);
  margin-right: auto; padding-left: 4px; }

/* ---- body.s8-play: đang chơi ⇒ thanh tab dưới bị ẩn (xem css/ispeak.css) -------------
   Thanh tab là 56px + env(safe-area-inset-bottom). Luật mobile ở trên trừ nó khỏi chiều
   cao sân; khi nó không còn thì 56px ấy phải trả lại, nếu không sân hụt đúng một dải
   trống. Nằm ở FILE NÀY chứ không phải ispeak.css: có test canh không cho luật .fg-root
   rò ngược về đó. */
@media (max-width: 979px) {
  body.s8-play .fg-root { margin-bottom: 0; }
}
@media (max-width: 719px) {
  body.s8-play .fg-root #fgApp {
    height: calc(100vh - 60px);
    height: calc(100dvh - 60px - env(safe-area-inset-top) - env(safe-area-inset-bottom));
  }
}
