/* [Claude Code 2026-06-24] wolves_slot_rush client 樣式（霓虹深色主題；通用渲染器共用） */
/* [claude code] 2026-09-24 v4.97 大廳卡片一列 3 款(檔尾「大廳小卡」一段) */
/* [claude code] 2026-09-24 v4.96 整站固定手機直式 480(body 直欄 + vw 換成欄寬單位 --vw)· 符號圖 ≤ 格子 90% · 外框九宮格 · 圖示調整 */
/* [claude code] 2026-09-24 v4.94 美術外框款整頁等比縮放:body[data-fit] 規則 + 11 組 max-height 媒體查詢對外框款停用 */
/* [claude code] 2026-07-10 梨園變臉：新增觀眾喝采加倍的樣式（fo-cheer / fo-mult-big / #winMeter.fo-ramp） */
:root {
  --bg: #0d0f1a;
  --surface: #171a2b;
  --surface-2: #1f2336;
  --border: #2c3150;
  --text: #e8eaf6;
  --text-soft: #9aa0c0;
  --neon: #ff3df0;
  --neon-2: #36e0ff;
  --gold: #ffd24a;
  --win: #ffe169;
}
/* ---- theme 驅動配色：改 config 的 theme 即換整套風格（新增主題在這加一組）----
   覆寫 --neon/--neon-2 這對主色 → hero/卡片/按鈕/外框整體換色，無需改 code。 */
body[data-theme="neon"]   { --neon: #ff3df0; --neon-2: #36e0ff; }
body[data-theme="lucky777"] { --neon: #ffb31a; --neon-2: #ff4d6d; --gold: #ffd24a; }
body[data-theme="egypt"]  { --neon: #e8b14a; --neon-2: #ffd24a; --gold: #ffe08a; }
body[data-theme="ocean"]  { --neon: #34d3ff; --neon-2: #5ad1ff; }
body[data-theme="fruit"]  { --neon: #ff5f6d; --neon-2: #ffb84a; }
body[data-theme="oriental"] { --neon: #ff3838; --neon-2: #ffcf4a; }
body[data-theme="candy"] { --neon: #ff5fa2; --neon-2: #a06bff; --gold: #ffd24a; }
body[data-theme="pirate"] { --neon: #d4a017; --neon-2: #1f8a70; --gold: #ffd24a; }
body[data-theme="prism"] { --neon: #36e0ff; --neon-2: #b06bff; --gold: #ffe08a; }
body[data-theme="galaxy"] { --neon: #7b6bff; --neon-2: #36e0ff; --gold: #ffe08a; }
body[data-theme="frost"] { --neon: #5ad1ff; --neon-2: #aef0ff; --gold: #d6f3ff; }
body[data-theme="arcane"] { --neon: #a06bff; --neon-2: #d7b3ff; --gold: #ffe08a; }
body[data-theme="honey"] { --neon: #e8920c; --neon-2: #ffc94d; --gold: #ffd766; }
body[data-theme="meadow"] { --neon: #8bc34a; --neon-2: #ffd54a; --gold: #ffe08a; }
/* [Claude Code 2026-07-06] 賓果主題（藍紫 + 金球）*/
body[data-theme="bingo"] { --neon: #5b8bff; --neon-2: #b06bff; --gold: #ffd24a; }
/* [claude code] 2026-07-11 夜市麻將主題（麻將綠 + 金牌）*/
body[data-theme="mahjong"] { --neon: #2fa46a; --neon-2: #46c98a; --gold: #ffcf3a; }
/* [claude code] 2026-07-11 招財彈珠：金 + 桃紅賭場感 */
body[data-theme="plinko"] { --neon: #ffb31a; --neon-2: #ff5d8f; --gold: #ffd24a; }
/* [claude code] 2026-07-11 狼群狩獵（wolf_hunt / 移動百搭）：狩獵夜色（冷藍月光 + 血月金） */
body[data-theme="wolf"] { --neon: #6ea0d8; --neon-2: #9fc2e8; --gold: #ffcf6a; }
/* [claude code] 2026-07-14 尋寶掃雷（treasure_mines / mines）：寶石翠綠 + 金 */
body[data-theme="mines"] { --neon: #2bd4a8; --neon-2: #36e0ff; --gold: #ffd24a; }
/* [claude code] 2026-07-29 闖關奪寶（gem_quest / gemquest）：地城打怪（血橙 + 魔晶紫） */
body[data-theme="gemquest"] { --neon: #ff6a4d; --neon-2: #b06bff; --gold: #ffd24a; }
/* [claude code] 2026-07-14 神秘面具（mystery_mask / mystery）：神秘紫 + 面具金 */
body[data-theme="mask"] { --neon: #a06bff; --neon-2: #ff6bd0; --gold: #ffd24a; }
/* [claude code] 2026-07-18 招財貓（lucky_cat / holdwin）：日式招財朱紅 + 小判金 */
body[data-theme="cat"] { --neon: #e23b3b; --neon-2: #ffcf4a; --gold: #ffd24a; }
/* [claude code] 2026-07-19 能量核心（energy_core / charge）：科技電光藍青 + 能量金 */
body[data-theme="energy"] { --neon: #36e0ff; --neon-2: #7b6bff; --gold: #ffe08a; }
/* 蓄能槽進度條：蓄能中電光藍，放電中（.dis）轉電光黃橙 */
.pm-fill.charge { background: linear-gradient(90deg, #2bd4ff, #7b6bff); }
.pm-fill.charge.dis { background: linear-gradient(90deg, #ffd24a, #ff8a3b); }
#chargeTray.discharging .pm-num { color: #ffcf4a; }
/* 放電：JQK 被電掉的閃電效果 + 掉落補位 */
@keyframes cgZap { 0%{filter:brightness(3) drop-shadow(0 0 8px #7be0ff);transform:scale(1.15)} 50%{filter:brightness(2) drop-shadow(0 0 12px #ffd24a)} 100%{filter:brightness(1);transform:scale(.4);opacity:.15} }
.cell.cg-zap .glyph { animation: cgZap .34s ease-in forwards; }
@keyframes cgDrop { 0%{transform:translateY(-46px);opacity:.2} 100%{transform:translateY(0);opacity:1} }
/* [claude code] 2026-08-15 v2.94 掉落逐排錯開：延遲由 JS 寫進 `--cg-d`（上面先落、下面後落）。
   `both` 是必要的 —— 沒有它，延遲那段時間格子會先用最終樣子顯示出來，等於還是「直接冒出來」。 */
.cell.cg-drop .glyph { animation: cgDrop .46s cubic-bezier(.3,.7,.4,1) var(--cg-d, 0ms) both; }
/* [claude code] 2026-07-19 蓄能收集特效：⚡ 從盤面飛進蓄能槽 + ⚡ 格收集脈動 */
.cg-fly { position: fixed; z-index: 60; font-size: 26px; transform: translate(-50%,-50%); pointer-events: none;
  filter: drop-shadow(0 0 8px #7be0ff) drop-shadow(0 0 4px #ffd24a); }
@keyframes cgChargePop { 0%{filter:brightness(1)} 40%{filter:brightness(2.6) drop-shadow(0 0 12px #7be0ff);transform:scale(1.22)} 100%{filter:brightness(1);transform:scale(1)} }
.cell.cg-charge-pop .glyph { animation: cgChargePop .5s ease; }
/* [claude code] 2026-07-19 放電閃電：從蓄能槽方向拉虛線電擊 JQK */
.cg-dash { position: fixed; height: 0; border-top: 2px dashed #ffd24a; transform-origin: 0 0;
  box-shadow: 0 0 7px #ffd24a, 0 0 3px #7be0ff; z-index: 58; pointer-events: none; animation: cgDash .38s ease-out; }
@keyframes cgDash { 0%{opacity:0;filter:brightness(2.4)} 25%{opacity:1} 100%{opacity:0} }
/* [claude code] 2026-08-17 v3.52 🔴 **盤面上「值錢的」與「廢料」要一眼分得出來**。
   使用者:「**JQK 是比較不值錢的, 能讓他們灰灰或是看起來破爛的嗎, 目前感受不出來其他是值錢的**」。

   🔴 病根是**視覺階層完全顛倒**:平台把 J/Q/K 上成飽和亮色(金 / 青 / 綠,見 `.cell.sym-Q` 那三條),
      而這款的 J/Q/K **完全不計分**(`charge.payouts` 只有 id 4~7)、放電時還會被電掉
      —— 盤面上最搶眼的,正好是唯一沒有價值的東西。

   🔴 用的是**明度 / 彩度 / 大小**這三個「人眼天生有次序」的量,**不是換色相**
      （色相只分類別、不分高低）。平台已經有同一個問題的同一個解法:
      遠古巨獸的 `.col-low`（不賠付的叢林雜物 → 去彩度 + 壓暗）。

   💡 **細單（下面那條 `.dt-scell.k-low`）早就把廢料調暗了** —— 也就是說平台的細單一直講對,
      只有 live 盤面沒講。這次是把同一套語言帶回盤面。

   ⚠️ **用 `font-size` 縮小、不要用 `transform: scale()`** —— 這款的掉落 / 電擊動畫
      (`cgDrop` / `cgZap`) 會整個接管 `transform`,寫 scale 會在動畫播放時被蓋掉、
      播完又跳回來（看起來像「掉下來之後縮一下」）。 */
body[data-theme="energy"] .cell.sym-J,
body[data-theme="energy"] .cell.sym-Q,
body[data-theme="energy"] .cell.sym-K { background: linear-gradient(160deg, #0d1018, #080a12); }
body[data-theme="energy"] .cell.sym-J .glyph,
body[data-theme="energy"] .cell.sym-Q .glyph,
body[data-theme="energy"] .cell.sym-K .glyph {
  color: #69718a;                 /* 蓋掉平台的金 / 青 / 綠 → 一律鐵灰 */
  text-shadow: none;
  opacity: .52;
  font-size: .74em;               /* 比高階符小一圈（大小也是有次序的量）*/
  filter: grayscale(1) brightness(.85);
}
/* 高階能量符（會賠的那四種）：留住彩度 + 一圈冷光 + 略大 → 「這些才是值錢的」 */
body[data-theme="energy"] .cell.sym-H1 .glyph,
body[data-theme="energy"] .cell.sym-H2 .glyph,
body[data-theme="energy"] .cell.sym-H3 .glyph,
body[data-theme="energy"] .cell.sym-H4 .glyph {
  font-size: 1.04em;
  filter: drop-shadow(0 0 7px rgba(54,224,255,.5));
}
/* ⚡ 蓄能符：全盤最亮（它是要被收集的那個） */
body[data-theme="energy"] .cell.sym-CHARGE .glyph {
  filter: drop-shadow(0 0 9px #7be0ff) drop-shadow(0 0 5px #ffd24a);
}
/* 細單：能量核心盤面著色（廢料 JQK 變暗、⚡ 電光） */
.dt-scell.k-low { opacity: .45; }
.dt-scell.k-charge { background: rgba(54,224,255,.20); border-color: rgba(120,224,255,.6); box-shadow: inset 0 0 0 1px rgba(120,224,255,.5); }
/* [claude code] 2026-08-15 星宮聚合細單：⛎ 蛇夫座（base 的觸發來源 / 免費期的萬能宮）在細單上要一眼認得出 */
.dt-scell.k-zscat { background: rgba(185,140,255,.22); border-color: rgba(185,140,255,.65); box-shadow: inset 0 0 0 1px rgba(185,140,255,.55); }
/* [claude code] 2026-08-17 細單盤面：**被算進去的格**（每組一個顏色 + 左上角掛該組圖示）。
   使用者：「細單並沒有標注是中了什麼」—— 看得到「集滿 1 組」卻對不出是盤上哪幾格。 */
/* [claude code] 2026-08-17 免費里程條（只有 `zodiac.miles.need > 0` 的款會畫；星宮聚合沒有） */
.zod-miles { display: flex; align-items: center; gap: 8px; padding: 3px 10px; font-size: 12px; }
.zod-miles .zm-bar { flex: 1; height: 6px; border-radius: 999px; background: rgba(255,255,255,.12); overflow: hidden; }
.zod-miles .zm-bar i { display: block; height: 100%; border-radius: 999px;
  background: linear-gradient(90deg, #7ad2ff, #34e0ff); transition: width .35s ease; }
.zod-miles.full .zm-bar i { background: linear-gradient(90deg, #ffe9a6, var(--gold)); }
.zod-miles.full .zs-total { color: var(--gold); font-weight: 900; }
.dt-scell.zd-hit { position: relative; }
.dt-scell.zd-g0 { background: rgba(255,90,95,.20); box-shadow: inset 0 0 0 2px rgba(255,120,120,.85); }
.dt-scell.zd-g1 { background: rgba(60,190,255,.20); box-shadow: inset 0 0 0 2px rgba(90,205,255,.85); }
.dt-scell.zd-g2 { background: rgba(90,225,140,.20); box-shadow: inset 0 0 0 2px rgba(120,235,165,.85); }
.dt-scell.zd-g3 { background: rgba(255,205,80,.20); box-shadow: inset 0 0 0 2px rgba(255,215,110,.85); }
.dt-scell .zd-tag { position: absolute; top: 1px; left: 2px; font-size: 9px; line-height: 1; pointer-events: none; }
.dt-slot.dt-charge .dt-scell { font-size: 16px; }
.dt-fs-head { font-size: 12px; color: var(--text-mute); text-align: center; margin: 6px 0 2px; }
* { box-sizing: border-box; }
/* [claude code] 2026-09-24 v4.96 🔴 **整站固定手機直式**(使用者:「固定成手機面版格式, 不用有網頁版和 WEB 版」)。
   ① body 就是那條手機欄:最寬 480、置中;電腦上兩側露 html 的背景。
   ② `--vw` = 欄寬的 1%(`min(1vw, 4.8px)`)—— 全檔原本的 `Nvw` 都換成 `calc(N * var(--vw))`,
      手機上跟以前一模一樣,桌機上不會因為螢幕寬而把字 / 間距放大一號。
      🔴 **新寫的 CSS 不要再用裸的 vw**(`fitstage_test.js` 會擋)。
   ③ 全螢幕彈窗的遮罩照樣蓋滿視窗(那是 fixed inset:0),卡片寬度因為 ② 自動不超過欄寬。 */
:root { --vw: min(1vw, 4.8px); --app-w: 480px; }
html { background: #06070d; }
body {
  max-width: var(--app-w); margin: 0 auto; box-shadow: 0 0 48px rgba(0,0,0,.55);
  background: radial-gradient(circle at 50% -10%, #1a1d36 0%, var(--bg) 60%);
  color: var(--text); font-family: -apple-system, "Segoe UI", "Microsoft JhengHei", sans-serif;
  min-height: 100vh;
}
.loading { position: fixed; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 18px; background: var(--bg); z-index: 50; color: var(--text-soft); font-size: 18px;
  transition: opacity .25s ease; }
/* [claude code] 2026-09-24 loading 改「圖 + 進度條」(取代 777 拉霸機):開站 = 平台 LOGO,進遊戲 = 該款大廳卡圖。
   進度條照實際下載量走(app.js setLoadingProgress);文字列只在連線失敗時才有字。 */
.ld-art { width: 128px; height: 128px; border-radius: 26px; object-fit: cover;
  box-shadow: 0 0 26px rgba(255,210,74,.28), 0 6px 18px rgba(0,0,0,.45);
  animation: ldBreath 1.6s ease-in-out infinite; }
@keyframes ldBreath { 0%,100% { transform: scale(1); } 50% { transform: scale(1.04); } }
.ld-bar { width: min(220px, calc(60 * var(--vw))); height: 6px; border-radius: 3px; overflow: hidden;
  background: rgba(255,255,255,.1); box-shadow: inset 0 1px 2px rgba(0,0,0,.5); }
.ld-bar > i { display: block; height: 100%; width: 0; border-radius: inherit;
  background: linear-gradient(90deg, #ffb13b, var(--gold, #ffd24a));
  box-shadow: 0 0 8px rgba(255,210,74,.6); transition: width .2s ease-out; }
.loading-text { font-size: 15px; letter-spacing: 1px; color: var(--text-mute, #8b91a3); text-align: center; padding: 0 16px; }
.loading-text:empty { display: none; }

.topbar { display: flex; justify-content: space-between; align-items: center; padding: 12px 20px;
  background: rgba(23,26,43,.9); border-bottom: 1px solid var(--border); position: sticky; top: 0; z-index: 10; }
.brand { font-size: 20px; font-weight: 800; letter-spacing: .5px;
  text-shadow: 0 0 12px var(--neon); }
.ver { font-size: 11px; color: var(--text-soft); text-shadow: none; }
.top-right { display: flex; flex-wrap: wrap; justify-content: flex-end; align-items: center; gap: 10px; }
.coins-box { background: var(--surface-2); padding: 6px 14px; border-radius: 999px; font-weight: 700; color: var(--gold); }
/* [Claude Code 2026-07-08] 遊戲中把頂列（右上試玩區）的餘額收起 —— 盤面正上方 .wm-balance 已置中顯示餘額，不再擠在右上角試玩標旁 */
body[data-view="game"] .coins-box { display: none; }
.game-tools { display: inline-flex; align-items: center; gap: 6px; }

.btn-ghost { background: transparent; color: var(--text); border: 1px solid var(--border);
  padding: 6px 14px; border-radius: 8px; cursor: pointer; font-size: 14px; }
.btn-ghost:hover { border-color: var(--neon-2); color: var(--neon-2); }

.view { max-width: none; margin: 0 auto; padding: 24px 20px 60px; }   /* v4.96 原本 980(桌機寬版),整站鎖手機直欄後由 body 控寬 */
.section-title { text-align: center; color: var(--text-soft); font-weight: 600; }

/* ---- 大廳 hero + section head ---- */
.lobby-hero { text-align: center; padding: 28px 16px 18px;
  background: radial-gradient(circle at 50% 0%, rgba(255,61,240,.18), transparent 70%); border-radius: 18px; margin-bottom: 18px; }
.hero-title { font-size: clamp(28px, calc(6 * var(--vw)), 44px); font-weight: 900; letter-spacing: 2px;
  display: inline-flex; align-items: center; gap: 12px; color: #fff;
  text-shadow: 0 0 20px rgba(255,61,240,.6), 0 0 8px rgba(54,224,255,.55), 0 2px 4px rgba(0,0,0,.5); }
.hero-ico { font-size: .95em; filter: drop-shadow(0 0 10px rgba(255,210,74,.5)); }
.hero-sub { color: var(--text-soft); margin-top: 6px; font-size: 14px; }
/* [Claude Code 2026-06-25] 平台啟動日期徽章 */
.hero-since { display: inline-block; margin-top: 10px; padding: 3px 12px; border-radius: 999px;
  font-size: 12px; font-weight: 700; letter-spacing: .5px; color: var(--gold);
  background: rgba(255,210,74,.1); border: 1px solid rgba(255,210,74,.3); }
/* [Claude Code 2026-07-08] 串接 API 文件入口（大廳 LOGO 和遊戲中間，置中）
   [Claude Code 2026-07-08] 置中 + 連結改亮色（原本 var(--text) 在深底偏暗、看不出是連結） */
.lobby-apilink { display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
  text-align: center; gap: 6px 14px; margin: 0 0 14px; }
.lobby-apilink a { display: inline-flex; align-items: center; gap: 6px; font-weight: 800; font-size: 14px;
  color: #a9ccff; text-shadow: 0 0 10px rgba(91,139,255,.55); text-decoration: none;
  padding: 8px 18px; border-radius: 999px;
  background: linear-gradient(135deg, rgba(91,139,255,.32), rgba(176,107,255,.26));
  border: 1px solid var(--neon); transition: transform .1s, box-shadow .15s, border-color .15s, color .15s; }
.lobby-apilink a:hover { transform: translateY(-1px); color: #dce8ff; border-color: var(--neon-2);
  box-shadow: 0 4px 18px rgba(91,139,255,.45); }

/* [Claude Code 2026-07-08] 大廳登入列（固定帳號登入 / 已登入狀態）
   [claude code] 2026-07-09 移到右上 topbar：改精簡 inline chip（不再置中大盒）；空 / 遊戲中不顯示 */
.lobby-auth { display: flex; align-items: center; }
.lobby-auth:empty { display: none; }
body[data-view="game"] #lobbyAuth { display: none; }
.la-form { display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  background: linear-gradient(160deg, var(--surface-2), var(--surface));
  border: 1px solid var(--border); border-radius: 999px; padding: 4px 6px 4px 12px; }
.la-title { font-weight: 800; color: var(--text-soft); letter-spacing: .5px; }
.la-inp { background: #10132a; border: 1px solid var(--border); border-radius: 999px;
  color: var(--text); padding: 6px 12px; font-size: 13px; min-width: 100px; flex: 0 1 150px; }
.la-inp:focus { outline: none; border-color: var(--neon-2); box-shadow: 0 0 0 2px rgba(176,107,255,.25); }
.la-btn { background: linear-gradient(135deg, var(--neon-2), var(--neon)); color: #fff; font-weight: 800;
  border: none; border-radius: 999px; padding: 6px 14px; font-size: 13px; cursor: pointer; transition: transform .1s, filter .15s; }
.la-btn:hover { filter: brightness(1.08); }
.la-btn:active { transform: scale(.97); }
.la-btn.ghost { background: var(--surface-2); color: var(--text-soft); border: 1px solid var(--border); }
.la-msg { font-size: 12px; color: var(--text-soft); }
.la-msg.err { color: #ff6b8a; font-weight: 700; }
.la-hint { color: var(--text-soft); font-size: 12px; margin: 8px 4px 0; }
.la-in { display: flex; align-items: center; gap: 10px;
  background: linear-gradient(135deg, rgba(176,107,255,.16), rgba(91,139,255,.12));
  border: 1px solid var(--border); border-radius: 999px; padding: 5px 6px 5px 14px; }
.la-who { font-weight: 700; color: var(--text); font-size: 14px; }
.la-who b { color: var(--neon-2); }
.la-bal { font-weight: 800; color: var(--gold, #ffd24a); }

/* [claude code] 2026-07-09 大廳文件 / 報告：可展開（<details>），預設關閉；文件變多也不佔版面 */
.lobby-docs { max-width: 100%; margin: 0 auto 16px; border: 1px solid var(--border); border-radius: 14px;
  background: linear-gradient(160deg, var(--surface-2), var(--surface)); overflow: hidden; }
.lobby-docs > summary { list-style: none; cursor: pointer; user-select: none;
  display: flex; align-items: center; justify-content: center; gap: 8px;
  padding: 11px 16px; font-weight: 800; color: var(--text); letter-spacing: .5px; }
.lobby-docs > summary::-webkit-details-marker { display: none; }
.lobby-docs > summary:hover { color: var(--neon-2); }
.lobby-docs .ld-ico { filter: drop-shadow(0 0 6px rgba(255,210,74,.4)); }
.lobby-docs .ld-chev { color: var(--text-soft); font-size: 12px; transition: transform .15s; }
.lobby-docs[open] > summary .ld-chev { transform: rotate(180deg); }
.lobby-docs-body { padding: 4px 14px 14px; }
/* [claude code] 2026-07-14 文件 / 報告：改縱向排版統一 → 標題一行、描述固定在下一行（原本 flex-wrap 橫排會因標題長短不一，有的描述並排、有的折到下行，看起來不整齊） */
.lobby-docs-body .lobby-apilink { margin: 0 0 10px; flex-direction: column; gap: 5px; }
.lobby-docs-body .lobby-apilink:last-child { margin-bottom: 0; }

/* [claude code] 2026-07-09 頂列 meta 條（等級 + 每日流水任務；大廳 + 遊戲中都顯示，一次一階） */
/* [claude code] 2026-07-18 v2.4 預留「領取」鈕的高度：領取鈕（.mb-claim ~26px）比旁邊文字/進度條高，
   一顯示就把整條 bar 撐高 → 把下面的介面往下壓。用 min-height 預留鈕出現時的高度（box-sizing:border-box 含 padding）
   → 有沒有領取鈕，bar 高度都固定、不再位移。單行放得下鈕（桌面）就完全不跳；窄螢幕若換行是另一回事。 */
.meta-bar { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 8px 22px;
  padding: 8px 16px; min-height: 44px; background: rgba(23,26,43,.72); border-bottom: 1px solid var(--border); }
.mb-level, .mb-mission { display: flex; align-items: center; gap: 9px; min-width: 0; }
.mb-lv { font-weight: 800; font-size: 13px; color: var(--text); white-space: nowrap; }
.mb-lv b { color: var(--neon-2); }
.mb-xpwrap { display: flex; align-items: center; gap: 7px; }
.mb-xpbar { width: 120px; max-width: calc(32 * var(--vw)); height: 7px; background: #10132a; border: 1px solid var(--border);
  border-radius: 999px; overflow: hidden; }
.mb-xpfill { height: 100%; border-radius: 999px; background: linear-gradient(90deg, var(--neon-2), var(--neon)); transition: width .4s ease; }
.mb-xptext { font-size: 11px; color: var(--text-soft); font-variant-numeric: tabular-nums; white-space: nowrap; }
.mb-mtitle { font-weight: 800; font-size: 12.5px; color: var(--text); white-space: nowrap; }
.mb-minfo { font-size: 12px; color: var(--text-soft); font-variant-numeric: tabular-nums; white-space: nowrap; }
.mb-minfo b { color: var(--gold); }
.mb-mbar { width: 130px; max-width: calc(32 * var(--vw)); height: 7px; background: #10132a; border: 1px solid var(--border);
  border-radius: 999px; overflow: hidden; }
.mb-mfill { height: 100%; border-radius: 999px; background: linear-gradient(90deg, #ffcf4a, #ff9f2e); transition: width .4s ease; }
.mb-claim { border: none; border-radius: 999px; font-weight: 800; cursor: pointer; padding: 5px 13px; font-size: 12.5px;
  white-space: nowrap; animation: mbClaimPulse 1.4s ease-in-out infinite; }
.mb-claim-lv { background: linear-gradient(135deg, #ffcf4a, #ff9f2e); color: #3a2600; box-shadow: 0 0 12px rgba(255,200,60,.5); }
.mb-claim-m { background: linear-gradient(135deg, #ff5b6e, #ff2e5b); color: #fff; box-shadow: 0 0 12px rgba(255,60,90,.45); }
.mb-claim:hover { filter: brightness(1.08); }
@keyframes mbClaimPulse { 0%,100% { transform: scale(1); } 50% { transform: scale(1.06); } }
/* 桌面：等級 / 任務之間加分隔線 */
/* v4.96 原本這裡有一條 `@media (min-width: 640px)`(桌機才出現的分隔線)—— 整站鎖手機直式後不再有桌機版,移除。 */

/* [claude code] 2026-07-09 紅包 pick-em overlay */
.redpack-overlay { position: fixed; inset: 0; z-index: 60; display: none; align-items: center; justify-content: center;
  background: rgba(6,8,18,.82); backdrop-filter: blur(3px); }
.redpack-overlay.show { display: flex; }
.rp-box { text-align: center; padding: 24px 20px; max-width: calc(92 * var(--vw)); }
.rp-title { font-size: 24px; font-weight: 900; color: #ffd24a; text-shadow: 0 0 16px rgba(255,90,90,.6); }
.rp-sub { color: var(--text-soft); margin: 6px 0 10px; font-size: 14px; }
/* [claude code] 2026-07-10 開獎前先列出「這次可抽到的金額」(只講金額,不講機率);開獎後把抽中那顆點亮 */
.rp-amts { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; margin: 0 0 18px; }
.rp-amt { font-size: 13px; font-weight: 800; color: #ffd88a; padding: 3px 11px; border-radius: 999px;
  background: rgba(255,207,74,.10); border: 1px solid rgba(255,207,74,.35); transition: all .3s; }
.rp-amt.hit { color: #3a2600; background: linear-gradient(160deg, #ffe08a, #ffcf4a); border-color: #fff;
  box-shadow: 0 0 14px rgba(255,200,60,.7); }
.rp-amt.miss { opacity: .4; }
.rp-cards { display: flex; gap: 16px; justify-content: center; perspective: 900px; }
.rp-card { width: 92px; height: 130px; cursor: default; }
.rp-card.pickable { cursor: pointer; }
.rp-card.pickable:hover { transform: translateY(-8px); transition: transform .15s; }
.rp-inner { position: relative; width: 100%; height: 100%; transform-style: preserve-3d; transition: transform .5s; }
.rp-card.flip .rp-inner { transform: rotateY(180deg); }
.rp-face { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  border-radius: 14px; backface-visibility: hidden; font-weight: 900; }
.rp-back { font-size: 40px; background: linear-gradient(160deg, #d4283c, #8a1020); border: 2px solid #ffcf4a;
  box-shadow: 0 6px 20px rgba(0,0,0,.4), inset 0 0 18px rgba(255,207,74,.25); }
.rp-front { font-size: 17px; color: #3a2600; background: linear-gradient(160deg, #ffe08a, #ffcf4a);
  transform: rotateY(180deg); border: 2px solid #ff9f2e; line-height: 1.2; }
.rp-card.shuffling { animation: rpShuffle .5s ease-in-out infinite; }
@keyframes rpShuffle { 0%,100% { transform: translateY(0) rotate(-2deg); } 50% { transform: translateY(-6px) rotate(2deg); } }
.rp-card.win .rp-front { box-shadow: 0 0 20px rgba(255,200,60,.85); border-color: #fff; }
.rp-card.win { animation: rpWin .5s ease; }
@keyframes rpWin { 0% { transform: scale(1); } 40% { transform: scale(1.12); } 100% { transform: scale(1); } }
.rp-card.dim { opacity: .55; }
.rp-result { margin-top: 20px; font-size: 18px; color: var(--text); opacity: 0; transform: translateY(6px);
  transition: opacity .3s, transform .3s; }
.rp-result.show { opacity: 1; transform: none; }
.rp-result b { color: var(--gold); font-size: 22px; }
.rp-close { margin-top: 18px; background: linear-gradient(135deg, var(--neon-2), var(--neon)); color: #fff;
  font-weight: 800; border: none; border-radius: 999px; padding: 8px 24px; font-size: 14px; cursor: pointer; }

/* [claude code] 2026-07-09 大廳 toast */
.lobby-toast { position: fixed; left: 50%; bottom: 40px; transform: translateX(-50%) translateY(20px); z-index: 70;
  background: rgba(23,26,43,.96); border: 1px solid var(--neon-2); color: var(--text); font-weight: 700;
  padding: 10px 20px; border-radius: 999px; box-shadow: 0 6px 24px rgba(0,0,0,.5); opacity: 0; pointer-events: none;
  transition: opacity .25s, transform .25s; }
.lobby-toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }

.lobby-section-head { display: flex; align-items: center; gap: 8px; font-weight: 700; margin: 6px 4px 12px; color: var(--text); }
.lobby-section-head .dot { width: 9px; height: 9px; border-radius: 50%; background: var(--neon-2); box-shadow: 0 0 8px var(--neon-2); }
.lobby-section-head .count { background: var(--surface-2); color: var(--text-soft); font-size: 12px; padding: 1px 9px; border-radius: 999px; }

.lobby-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 16px; }

/* [claude code] 2026-08-02 大廳「🚧 未完成（開發中）」區：config 標 wip:true 的款排到最下面自成一區。
   刻意做成低調（橘色區隔 + 卡片整體降透明度），一眼看得出「這排跟上面那批不是同一個成熟度」，
   但仍可點進去玩（hover 會回到全彩）。沒有未完成款時整區由 JS 隱藏。 */
/* [claude code] 2026-08-13 v2.79 已上 DEMO 站：大廳**最上面**自成一區（與最下面的「🚧 未完成」對稱）。
   顏色用青色系（--neon-2）跟未完成的橘色分開 —— 一個是「已經給人看了」、一個是「還沒做完」。 */
/* ⭐ [claude code] 2026-09-08 v3.91 我的最愛區（大廳最上面）。
   配色用金色 —— 與 DEMO 區的青、未完成區的橘各自分開，一眼認得出是哪一區。 */
.lobby-fav { margin-bottom: 26px; padding-bottom: 18px; border-bottom: 1px dashed var(--border); }
.lobby-section-head.fav { color: var(--gold); }
.lobby-section-head.fav .dot { background: var(--gold); box-shadow: 0 0 8px rgba(255,207,58,.75); }
.lobby-section-head.fav .count { background: rgba(255,207,58,.16); color: var(--gold); }

/* 收藏鈕：右下角，與左下的機率模型圖示對稱。
   🔴 **點擊區要夠大**（手機上星星本體只有 15px）→ 用 padding 撐出 ~34px 的熱區，
      但 `line-height: 1` 讓它不撐開卡片。 */
.card-fav { position: absolute; right: 6px; bottom: 4px; z-index: 4; cursor: pointer;
  font-size: 15px; line-height: 1; padding: 8px 9px; border-radius: 999px;
  color: var(--text-soft); opacity: .55; user-select: none;
  transition: opacity .15s ease, transform .12s ease, background .15s ease; }
.card-fav:hover { opacity: 1; background: rgba(255,255,255,.08); transform: scale(1.12); }
.card-fav.on { opacity: 1; filter: drop-shadow(0 0 6px rgba(255,207,58,.55)); }
.card-fav:focus-visible { outline: 2px solid var(--gold); outline-offset: 1px; opacity: 1; }
/* 收藏的卡片整張帶一點金邊 —— 🔴 星星只有一個角落，掃過去容易漏掉 */
.lobby-fav .game-card { border-color: rgba(255,207,58,.34); }
.lobby-fav .game-card:hover { border-color: var(--gold); box-shadow: 0 10px 34px rgba(255,207,58,.22); }

/* 大廳提示（遊戲內是訊息帶，大廳沒有）—— 固定在底部中央，不擋任何按鈕 */
.lobby-toast { position: fixed; left: 50%; bottom: 26px; transform: translate(-50%, 14px);
  z-index: 90; max-width: min(calc(88 * var(--vw)), 420px); padding: 10px 16px; border-radius: 12px;
  background: rgba(20,22,32,.96); border: 1px solid var(--border); color: var(--text);
  font-size: 13px; line-height: 1.5; text-align: center; pointer-events: none;
  opacity: 0; transition: opacity .18s ease, transform .18s ease; }
.lobby-toast.show { opacity: 1; transform: translate(-50%, 0); }

.lobby-demo { margin-bottom: 26px; padding-bottom: 18px; border-bottom: 1px dashed var(--border); }
.lobby-section-head.demo { color: var(--neon-2); }
.lobby-section-head.demo .dot { background: var(--neon-2); box-shadow: 0 0 8px rgba(54,224,255,.75); }
.lobby-section-head.demo .count { background: rgba(54,224,255,.16); color: var(--neon-2); }
.lobby-demo-hint { margin: -6px 4px 14px; font-size: 12px; line-height: 1.6; color: var(--text-soft); }
.game-card.demo { border-color: rgba(54,224,255,.34); }
.game-card.demo:hover { border-color: var(--neon-2); box-shadow: 0 10px 34px rgba(54,224,255,.24); }
/* 徽章位置與 .card-dev 同一格（demo 款不會同時是 wip，不會疊在一起）*/
.card-demo { position: absolute; top: 12px; left: 12px; z-index: 3; font-size: 11px; font-weight: 800;
  background: rgba(54,224,255,.16); color: var(--neon-2); border: 1px solid rgba(54,224,255,.5);
  padding: 3px 10px; border-radius: 999px; letter-spacing: .03em; }
/* 同 wip：右上的「進入 / 試玩」鈕往下讓一排，免得在窄卡上跟左上的徽章撞在一起 */
.game-card.demo .card-emoji-row { margin-top: 18px; }

.lobby-wip { margin-top: 30px; padding-top: 20px; border-top: 1px dashed var(--border); }
.lobby-section-head.wip { color: #ffb454; }
.lobby-section-head.wip .dot { background: #ff9900; box-shadow: 0 0 8px rgba(255,153,0,.7); }
.lobby-section-head.wip .count { background: rgba(255,153,0,.16); color: #ffb454; }
.lobby-wip-hint { margin: -6px 4px 14px; font-size: 12px; line-height: 1.6; color: var(--text-soft); }
.game-card.wip { opacity: .78; border-color: rgba(255,153,0,.35); }
.game-card.wip::before { background: repeating-linear-gradient(135deg, #ff9900 0 10px, #6b4a12 10px 20px); opacity: .9; }
.game-card.wip:hover { opacity: 1; border-color: #ffb454; box-shadow: 0 10px 34px rgba(255,153,0,.26); }
/* 未完成卡的右上「進入 / 試玩」鈕往下讓一排，避免跟左上的 🚧 開發中 徽章在窄卡上撞在一起 */
.game-card.wip .card-emoji-row { margin-top: 18px; }
/* [claude code] 2026-07-30 v2.31 卡片改 flex column —— 才有辦法用 margin-top:auto
   把 .card-meta(RTP / 波動 / 最大倍數)釘在卡底,讓一整排卡片的那一列對齊。 */
.game-card { position: relative; background: linear-gradient(160deg, var(--surface-2), var(--surface));
  border: 1px solid var(--border); border-radius: 16px; padding: 18px 16px 16px; cursor: pointer;
  color: var(--text); text-align: left; overflow: hidden;
  display: flex; flex-direction: column;
  transition: transform .15s, box-shadow .15s, border-color .15s; }
.game-card::before { content: ""; position: absolute; inset: 0 0 auto 0; height: 4px;
  background: linear-gradient(90deg, var(--neon), var(--neon-2)); opacity: .85; }
.game-card:hover { transform: translateY(-4px); border-color: var(--neon); box-shadow: 0 10px 34px rgba(255,61,240,.28); }
.card-badge { position: absolute; top: 12px; right: 12px; font-size: 11px; font-weight: 700;
  background: rgba(54,224,255,.15); color: var(--neon-2); border: 1px solid rgba(54,224,255,.4); padding: 3px 10px; border-radius: 999px; }
/* [Claude Code 2026-06-28] 大廳「開發中」徽章（沒填 completedAt 的款；放左上、橘色，與右上「▶ 開玩」不重疊）*/
.card-dev { position: absolute; top: 12px; left: 12px; z-index: 3; font-size: 11px; font-weight: 800;
  background: rgba(255,153,0,.18); color: #ffb454; border: 1px solid rgba(255,153,0,.5);
  padding: 3px 10px; border-radius: 999px; letter-spacing: .03em; }
/* [claude code] 2026-07-11 圖示 + 星等同一列（星等放圖示右邊）*/
.card-emoji-row { display: flex; align-items: center; gap: 10px; margin: 6px 0 8px; }
.card-emoji { position: relative; width: 64px; height: 64px; flex: 0 0 64px;
  font-size: 46px; line-height: 1; display: grid; place-items: center; transform-origin: 50% 50%; }
/* [codex] 256px WebP 以 64px 顯示；圖片失敗時下面的 emoji 自動露出。 */
.card-art { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain;
  border-radius: 14px; background: #101125; }
/* 大廳權重星等（放圖示旁）：滿星金色 + 發光、半星左半金、灰星暗 */
.card-stars { display: inline-flex; gap: 1px; font-size: 15px; line-height: 1; letter-spacing: 0; }
.card-stars .st { color: #3b405c; }
.card-stars .st.f { color: #ffcf4a; text-shadow: 0 0 6px rgba(255,200,60,.55); }
.card-stars .st.h { position: relative; color: #3b405c; }
.card-stars .st.h::before { content: "★"; position: absolute; left: 0; top: 0; width: 50%; overflow: hidden;
  color: #ffcf4a; text-shadow: 0 0 6px rgba(255,200,60,.55); }
/* [claude code] 2026-08-14 v2.88 換版進度指示（使用者要的）：**還沒換到遊戲畫面版型 v2 的款 → 星星變紅**。
   class 由 app.js 的 buildGameCard 依 `NEWUI_MECHS` 掛上（唯一資料來源）→ 換完一款就自動變回黃星。
   ⚠️ 只換顏色，星數（＝ lobbyWeight）與版面完全不動 —— 這是暫時的施工告示，全部換完就整段拿掉。 */
/* [claude code] 2026-08-18 v3.54 `.card-stars.ui-todo`（換版進度的紅星）已移除 —— 全 26 款換完，施工告示收掉。 */
/* [Claude Code 2026-06-28] 大廳圖示動畫「一次只動一張」：JS 輪流給某張卡的圖示掛 fx-pulse。
   [Claude Code 2026-07-10] 效果改成「呼吸光暈」，只作用在圖示（.card-emoji）本身、不碰整張卡的框：
   - 平時 idle：JS 每隔 LOBBY_PULSE_MS 隨機挑一款，那款圖示呼吸一輪（fx-pulse，一次性）
   - 滑鼠移到卡上：該款圖示持續呼吸（infinite）+ 常駐金光，滑開即停
   [claude code] 2026-07-11 hover 加「常駐光暈」保底：就算 reduced-motion 關掉動畫，移上去也看得到亮一下。 */
.card-emoji.fx-pulse { animation: cardBreathe 1.7s ease-in-out; }
.game-card:hover .card-emoji {
  animation: cardBreathe 1.5s ease-in-out infinite;
  filter: brightness(1.25) drop-shadow(0 0 12px var(--neon, #5b6cf6));
}
@keyframes cardBreathe {
  0%, 100% { transform: scale(1);    filter: brightness(1.1) drop-shadow(0 0 4px var(--neon, #5b6cf6)); }
  50%      { transform: scale(1.18); filter: brightness(1.65) drop-shadow(0 0 16px var(--neon, #5b6cf6)); }
}
/* reduced-motion：不做縮放動畫，但 hover 仍給常駐金光（上面的 filter 不是 animation，保留）*/
@media (prefers-reduced-motion: reduce) {
  .card-emoji.fx-pulse, .game-card:hover .card-emoji { animation: none !important; }
}

/* 擴展百搭（黃金法老）：整軸展開成 WILD 時，每格金光放大一下 */
.cell.expand-fill { box-shadow: inset 0 0 0 2px var(--gold, #ffd24a), 0 0 16px rgba(255,210,74,.6); z-index: 4; }
.cell.expand-fill .glyph { animation: expandFill .42s ease; }
@keyframes expandFill { 0% { transform: scale(.4); opacity: .2; filter: brightness(2); } 60% { transform: scale(1.18); } 100% { transform: scale(1); opacity: 1; } }
/* [claude code] 2026-07-11 移動百搭（walking / 狼群狩獵）：頭狼 🐺 奔襲——狼格藍白發光、從右滑入；其餘格重抽時淡入 */
.cell.walk-wolf { box-shadow: inset 0 0 0 2px #bcd8f6, 0 0 16px rgba(140,180,230,.75); z-index: 4; }
.cell.walk-wolf .glyph { animation: walkWolfPulse 1s ease-in-out infinite; }
@keyframes walkWolfPulse { 0%,100% { transform: scale(1); filter: drop-shadow(0 0 4px #8fb6e6); } 50% { transform: scale(1.12); filter: brightness(1.4) drop-shadow(0 0 10px #bcd8f6); } }
.cell.walk-arrive .glyph { animation: walkArrive .28s cubic-bezier(.2,.9,.25,1); }
@keyframes walkArrive { 0% { transform: translateX(60%) scale(.7); opacity: .2; filter: brightness(2); } 60% { transform: translateX(-6%) scale(1.15); } 100% { transform: translateX(0) scale(1); opacity: 1; } }
.cell.walk-respin .glyph { animation: walkRespin .24s ease; }
@keyframes walkRespin { 0% { transform: translateY(-22%) scale(.9); opacity: .25; } 100% { transform: translateY(0) scale(1); opacity: 1; } }
/* 🐺 [claude code] 2026-09-08 v3.92 狼王走位的四拍表演（使用者要「再放慢一點」）。
   ① 吼 ② 其他格抖 ③ 真的撲過去 ④ 落定 —— 見 app.js 的 playWalk。 */

/* ① 吼：狼王放大 + 白光收束，其餘不動（讓視線先被牠抓住） */
.cell.wolf-roar { z-index: 6; }
.cell.wolf-roar .glyph { animation: wolfRoar .62s cubic-bezier(.25,.8,.3,1) both; }
@keyframes wolfRoar {
  0%   { transform: scale(1); filter: drop-shadow(0 0 4px #8fb6e6); }
  35%  { transform: scale(1.42) rotate(-4deg); filter: brightness(1.8) drop-shadow(0 0 18px #dceaff); }
  55%  { transform: scale(1.30) rotate(3deg); }
  100% { transform: scale(1.34); filter: brightness(1.35) drop-shadow(0 0 12px #bcd8f6); }
}

/* ② 抖：其他格「呼吸抖動」—— 🔴 幅度刻意很小（2~3px / 3%），
   大了會變成整盤都在動，反而看不出狼王是主角。 */
.cell.walk-shiver .glyph { animation: walkShiver .34s ease-in-out 2; }
@keyframes walkShiver {
  0%,100% { transform: translateX(0) scale(1); }
  25%     { transform: translateX(-2px) scale(.97); }
  75%     { transform: translateX(2px) scale(.97); }
}

/* ③ 撲：跨軸飛行用的浮動狼王（格子被關在 `.reel` 的 overflow:hidden 裡，飛不出去）。
   🔴 `.board` 只有在走位期間才 `position: relative` —— 常駐的話會改變其他款
      絕對定位元素的定位基準（`.mw-multbar` 就靠祖先鏈）。 */
/* 🔴 [claude code] 2026-09-22 v4.55 走位期間**加裁切** —— 走出最左軸的狼沒有目標格，
   程式讓牠往左飛一整格；沒有裁切的話整隻會畫在盤面外面
   （使用者 2026-09-22 截圖回報「比較左邊那隻會跑出框」）。
   ⚠️ `overflow` 與 `position` 一樣**只掛在 `.walk-stage` 上** —— 常駐會影響其他款
      （`.mw-multbar` / `.tw-multbar` 都是絕對定位、而且刻意畫在盤面外緣）。 */
.board.walk-stage { position: relative; overflow: hidden; }
.walk-ghost { position: absolute; z-index: 20; display: flex; align-items: center; justify-content: center;
  pointer-events: none; will-change: transform;
  filter: drop-shadow(0 0 14px rgba(188,216,246,.85)) brightness(1.3); }
.cell.wolf-gone .glyph { opacity: 0; }   /* 原格先空出來，不然畫面上會有兩隻 */

/* [Claude Code 2026-06-28] 神秘符（mystery）：🔮 揭曉前脈動蓄勢、揭曉時翻牌 */
.cell.myst-orb { box-shadow: inset 0 0 0 2px #c08bff, 0 0 18px rgba(160,107,255,.7); z-index: 4; }
.cell.myst-orb .glyph { animation: mystPulse .54s ease infinite; }
@keyframes mystPulse { 0%,100% { transform: scale(1); filter: brightness(1); } 50% { transform: scale(1.15); filter: brightness(1.6) drop-shadow(0 0 8px #c08bff); } }
.cell.myst-flip { box-shadow: inset 0 0 0 2px var(--neon-2, #d7b3ff), 0 0 16px rgba(160,107,255,.6); z-index: 4; }
.cell.myst-flip .glyph { animation: mystFlip .56s ease; }
@keyframes mystFlip { 0% { transform: rotateY(90deg) scale(.6); opacity: .2; filter: brightness(2); } 55% { transform: rotateY(0deg) scale(1.2); } 100% { transform: rotateY(0deg) scale(1); opacity: 1; } }
/* [Claude Code 2026-06-28] 黏性百搭（sticky）：免費期黏住的 🐝 百搭金色光暈 + 輕微脈動（表示「黏住、持續生效」）*/
.cell.sticky-wild { box-shadow: inset 0 0 0 2px #ffcf4a, 0 0 14px rgba(255,180,40,.7); z-index: 4; }
.cell.sticky-wild .glyph { animation: stickyPulse 1.1s ease-in-out infinite; }
@keyframes stickyPulse { 0%,100% { transform: scale(1); } 50% { transform: scale(1.09); filter: drop-shadow(0 0 6px #ffb400); } }
/* [Claude Code 2026-07-08] 黏性百搭免費期：已黏住的 WILD 用「靜態覆蓋層」釘在原位（旋轉時不跟著轉）。
   放在 reel 內、strip 之外 → 不透明蓋住底層滾動格；比 win(z4) 更上層；左下角 📌 提示「釘住」。 */
.cell.sticky-hold { z-index: 7; background: var(--surface-2);
  box-shadow: inset 0 0 0 2px #ffcf4a, 0 0 16px rgba(255,180,40,.85); }
/* [claude code] 2026-08-18 v3.53 🎬 開場展示盤也會掛同一顆 📌（`.showcase-pin`）——
   甜蜜蜂巢的賣點「免費期百搭會黏住」原本**只在免費期看得到**，沒玩到的人永遠不知道。
   🔴 **刻意共用同一個 class 與同一顆 📌**：玩家在進場畫面看到的記號，跟他之後在免費期看到的
      是同一個東西 —— 展示盤在教的是**真的規則**，不是另外發明一套符號。 */
.cell.sticky-hold .hold-pin, .cell.showcase-pin .hold-pin { position: absolute; bottom: 2px; right: 3px; z-index: 8;
  font-size: clamp(.5rem, calc(2.4 * var(--vw)), .72rem); pointer-events: none; filter: drop-shadow(0 1px 2px rgba(0,0,0,.6)); }
/* [Claude Code 2026-06-29] 蜜蜂採蜜（cashcollect）：空格變暗、花蜜面額徽章、採集動畫 */
.cell.sym-EMPTY .glyph { opacity: .28; font-size: .7em; }   /* 空格：⬡ 淡化、縮小，看起來「空」 */
/* [claude code] 2026-08-14 v2.83 🌱 花苞 → 🌸 開花（依使用者：「出現是還沒開花的那種，然後再一格一格開花顯示金額」）。
   落盤時盤面上全是花苞（symbols 的 glyph 就是 🌱）→ 小一點、淡一點、微微搖，一看就是「還沒開」；
   開花那一下才放大成該面額的花，金額同時從底下彈出來。 */
.cell.sym-NECTAR .glyph { font-size: .74em; opacity: .8; filter: saturate(.8); transition: none; }
.cell.sym-NECTAR .glyph.nectar-open { font-size: 1em; opacity: 1; filter: none;
  animation: nectarBloom .42s cubic-bezier(.2, 1.5, .4, 1); }
@keyframes nectarBloom {
  0%   { transform: scale(.5) rotate(-14deg); opacity: .45; }
  55%  { transform: scale(1.24) rotate(5deg); opacity: 1; filter: drop-shadow(0 0 9px rgba(255,210,90,.8)); }
  100% { transform: scale(1) rotate(0); }
}
.cell .nectar-val { position: absolute; bottom: 4px; left: 50%; transform: translateX(-50%); z-index: 6; pointer-events: none;
  font-family: "Arial Black", system-ui, sans-serif; font-weight: 900; font-size: 11px; line-height: 1;
  padding: 2px 6px; border-radius: 8px; white-space: nowrap; animation: nectarValIn .3s ease;
  background: linear-gradient(135deg, #fff1c2, #ffcf4a); color: #5a3a00; box-shadow: 0 0 7px rgba(255,180,40,.7), 0 1px 2px rgba(0,0,0,.5); }
@keyframes nectarValIn {
  0%   { transform: translateX(-50%) translateY(7px) scale(.5); opacity: 0; }
  100% { transform: translateX(-50%) translateY(0) scale(1); opacity: 1; }
}
.cell.cash-bee { box-shadow: inset 0 0 0 2px #ffd54a, 0 0 16px rgba(255,200,60,.85); z-index: 4; }
.cell.cash-bee .glyph { animation: stickyPulse .7s ease-in-out infinite; }
.cell.cash-grab .glyph { animation: cashGrab .6s ease; }
@keyframes cashGrab { 0% { transform: scale(1); } 45% { transform: scale(1.25); filter: brightness(1.6) drop-shadow(0 0 8px #ffd54a); } 100% { transform: scale(1); } }
/* 採蜜賠付表：花蜜面額列 */
.nectar-list { display: flex; flex-wrap: wrap; gap: 6px; margin: 6px 0; }
.nectar-chip { background: rgba(255,200,60,.14); border: 1px solid rgba(255,200,60,.4); color: var(--neon-2, #ffd54a);
  padding: 3px 9px; border-radius: 999px; font-size: 12.5px; font-weight: 700; }
/* [claude code] 2026-07-30 v2.31 大廳卡片統一版型（規範見 CLAUDE.md「大廳遊戲卡片規範」）。
   🔴 問題:grid 的一列會被「最高的那張卡」撐開 —— 環遊世界的 desc 寫了 356 字,
   整排卡片跟著變成三倍高、RTP 那列各自散在不同高度,大廳看起來就亂了。
   🔴 修法分兩層,缺一不可:
     ① 內容面:文案長度寫進規範 + `tools/lintcards` 可執行檢查(見該工具)
     ② 版型面:【就算文案超標,版型也不能爛】—— desc 固定夾 3 行、tags 固定一行、
        meta 用 margin-top:auto 推到卡底 → 不管文案多長,每張卡等高、RTP 那列對齊。
   只做①不做②,下次有人多打幾個字就又跑版;只做②不做①,卡片會出現沒頭沒尾的截斷句。 */
.card-name { font-size: 19px; font-weight: 800; }
.card-sub { font-size: 12px; color: var(--text-soft); letter-spacing: .5px; margin-top: 1px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.card-desc { font-size: 12.5px; color: #c8cce8; line-height: 1.5; margin: 10px 0 0; min-height: 3.6em;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; line-clamp: 3;
  overflow: hidden; }
/* tags 固定一行(超出就截掉)—— 讓每張卡的 tags 佔一樣高度,不會有人用 4 個長標籤把卡撐高 */
.card-tags { display: flex; flex-wrap: nowrap; gap: 5px; margin-top: 10px; overflow: hidden; }
.card-tags .tag { font-size: 11px; background: rgba(255,255,255,.05); border: 1px solid var(--border);
  color: var(--text-soft); padding: 2px 9px; border-radius: 999px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: 0 1 auto; }
/* margin-top:auto → 不管上面內容多高,RTP / 波動 / 最大倍數這一列一律貼在卡底對齊 */
.card-meta { display: flex; flex-wrap: wrap; gap: 6px; margin-top: auto; padding-top: 10px; }
.card-meta span { font-size: 10.5px; color: var(--text-soft); background: var(--bg); border: 1px solid var(--border);
  padding: 2px 8px; border-radius: 8px; }
/* [Claude Code 2026-07-09] 大廳權重（lobbyWeight）金色小徽章 */
.card-meta span.cm-weight { color: #ffcf4a; border-color: rgba(255,200,60,.5);
  background: rgba(255,200,60,.08); font-weight: 700; text-shadow: 0 0 5px rgba(255,200,60,.35); }

/* ---- 直版 / 手機優先：整個遊戲區置中、限寬 ---- */
.game-stage { max-width: 480px; margin: 0 auto; padding: 8px 4px 24px; }
.game-head { display: grid; grid-template-columns: 48px 1fr auto; align-items: center; gap: 8px; margin-bottom: 12px; }
/* [claude code] 2026-07-29 v2.27 抬頭右側工具（ⓘ 展開 / 📋 賠付）*/
.head-tools { display: flex; gap: 6px; }
/* 可展開的抬頭區（標語 / 注單號 / 資訊 chips）：**預設關閉**，把高度讓給盤面；點 ⓘ 才展開。
   依使用者 2026-07-29：「只要留遊戲名那排就好了，有需要再呈現，不用一直占位置」。*/
.game-meta { display: none; }
.game-meta.open { display: block; animation: gmIn .18s ease; }
@keyframes gmIn { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }
.meta-toggle.on { color: var(--neon-2); border-color: var(--neon-2); }
/* v4.96 展開鈕改成 ▾(原本 ⓘ,使用者:「讓人感覺是可以展開的」;ⓘ 讓給賠付表)—— 展開時轉成 ▴ */
.meta-toggle { transition: transform .2s ease; }
.meta-toggle.on { transform: rotate(180deg); }
/* [claude code] 2026-08-13 v2.72 版型兜底：遊戲名一律**單行**（最長 6 字，正常寬度綽綽有餘）。
   min-width:0 讓它在 grid 內收得起來，真的塞不下就 ellipsis —— 就算哪天版面又塌，
   也只會截字，不會像 v2.71 那樣被擠成直排、把整排抬頭撐高三倍。*/
.game-head h2 { margin: 0; text-align: center; font-size: 19px;
  min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.game-head .btn-ghost { padding: 6px 10px; }
.head-spacer { display: block; }
.icon-btn { font-size: 17px; padding: 6px 11px; line-height: 1; }

.machine { position: relative; background: var(--surface); border: 1px solid var(--border);
  border-radius: 18px; padding: 14px; box-shadow: 0 8px 30px rgba(0,0,0,.4); }

/* ---- 盤面（treadmill 掉落式）---- */
.board { display: grid; gap: 6px; background: #070a14; border-radius: 12px; padding: 6px; }
.reel { position: relative; overflow: hidden; border-radius: 10px; background: #0a0c16; }
.strip { position: absolute; inset: 0; }
.cell { position: absolute; left: 0; right: 0; top: 0; display: flex; align-items: center; justify-content: center;
  font-size: var(--cell-font, clamp(26px, calc(9 * var(--vw)), 46px)); background: var(--surface-2);   /* v4.96 --cell-font 由 measureCellH 依格子大小寫入 */
  border: 2px solid #070a14; box-sizing: border-box; user-select: none; will-change: transform; }
.cell .glyph { position: relative; z-index: 2; line-height: 1; display: flex; align-items: center; justify-content: center; transition: transform .2s; }
/* 字牌類（A/K/Q/J/7/BAR）純文字 → 與 emoji 基線一致、置中不歪；各符號給色易辨 */
.cell .glyph.txt { font-family: "Arial Black", "Segoe UI", system-ui, sans-serif; font-weight: 900;
  letter-spacing: .5px; color: #e8eaf6; text-shadow: 0 2px 5px rgba(0,0,0,.55); }
.cell .glyph.txt-multi { font-size: .5em; letter-spacing: 1.5px; }
.cell.sym-SEVEN .glyph { color: #ff4d6d; text-shadow: 0 0 10px rgba(255,77,109,.45); }
.cell.sym-BAR  .glyph { color: #c77dff; text-shadow: 0 0 10px rgba(199,125,255,.45); }
/* [claude code] 2026-09-01 v3.66 🔴 **皇家符（A/K/Q/J）改成「廢料感」—— 平台預設**。
   使用者 2026-08-17:「**JQK 是比較不值錢的, 能讓他們灰灰或是看起來破爛的嗎,
   目前感受不出來其他是值錢的**」→ 2026-09-01:「**要**」（推到其他款）。

   🔴 **病根是這四行自己**：舊值把 A/K/Q/J 上成**粉 / 青 / 金 / 綠**四個飽和亮色，
      而它們在**每一款**都是最低階 —— 盤面上最搶眼的正好是最不值錢的東西。
      v3.52 只在 `body[data-theme="energy"]` 範圍內壓過（那款的 JQK 完全不計分），
      這次把**預設**改對，剩下的用例外處理。💡 **讓預設是對的，比逐款加規則好。**

   🔴 用的是**明度 / 彩度 / 大小**這三個「人眼天生有次序」的量，不是換色相。
      而且**四張之間也用明度排序**（A 最亮 → J 最暗），因為它們彼此之間也有高低：
      顏色不再負責「這是哪一張」（字母本來就講完了），改負責「這張值多少」。

   ⚠️ **比 energy 那組溫和** —— 那一款的 JQK **完全不賠**（灰到底是誠實的）；
      其他款的皇家符**是會賠的**，壓成幽靈會變成另一種騙人。
      實測 9 款有皇家符（`A/K/Q/J`）：其中 8 款它們確實是最低階。

   🔴 **`opera` 梨園變臉是唯一的例外，見下面那段** —— 量過才發現的。 */
.cell.sym-A .glyph, .cell.sym-K .glyph,
.cell.sym-Q .glyph, .cell.sym-J .glyph {
  text-shadow: none;
  font-size: .84em;                 /* 比高階符小一圈 —— 大小也是有次序的量 */
  filter: saturate(.35);            /* 留一點點彩度，全灰會跟「被禁用」混淆 */
}
/* [claude code] 2026-09-06 v3.75 **值錢 / 廢料的視覺階層 —— 從賠付表算出來的版本**
   （使用者：「把低價位或是低倍的, 能不要那麼鮮亮嗎, 我不知道會他是值錢還是不值錢」）。
   上面那組 `.sym-A/K/Q/J` 是**認名字**的（所以梨園變臉要手動開例外）；
   這一組 `.val-low1..4` 由 `buildSymLowTier()` **讀那一款自己的賠付表排名**掛上去 → 不可能認錯。
   🔴 這些款的符號是**彩色 emoji**，`color` 對它們完全無效 —— 只動彩度 / 明度 / 大小
      （跟上面那組刻意用同一組梯度值，兩邊看起來才是同一套語言）。
   🔴 **不要壓成幽靈**：它們是會賠的，只是賠得少；壓太狠會變成另一種騙人（同 v3.66 的分寸）。 */
/* 🔴 **兩個地方要一起套**：盤面的格子 `.cell .glyph`、賠付表的符號 `.ef-pt-sym`。
      只套盤面的話，賠付表裡那幾種還是鮮亮的 —— 兩邊會像在講不同的事。 */
.cell.val-low1 .glyph, .cell.val-low2 .glyph,
.cell.val-low3 .glyph, .cell.val-low4 .glyph,
.ef-pt-sym.val-low1, .ef-pt-sym.val-low2,
.ef-pt-sym.val-low3, .ef-pt-sym.val-low4 { text-shadow: none; font-size: .88em; }
.cell.val-low4 .glyph, .ef-pt-sym.val-low4 { filter: saturate(.62) brightness(.94); opacity: .90; }
.cell.val-low3 .glyph, .ef-pt-sym.val-low3 { filter: saturate(.54) brightness(.90); opacity: .86; }
.cell.val-low2 .glyph, .ef-pt-sym.val-low2 { filter: saturate(.46) brightness(.86); opacity: .82; }
.cell.val-low1 .glyph, .ef-pt-sym.val-low1 { filter: saturate(.38) brightness(.82); opacity: .78; }
/* 🔴 中獎 / 差一軸的那一刻要**還原**成原本的樣子 —— 壓暗是「平常誰比較值錢」，
      不是「這一格現在怎麼樣」；兩個語意疊在一起會讓中獎的低階符看起來像沒中。 */
.cell.cs-win .glyph, .cell.ef-help .glyph, .cell.ef-near .glyph {
  filter: none !important; opacity: 1 !important; }

/* [claude code] 2026-09-08 v3.92 盤面**底框分層**（使用者：「貴和便宜的底框目前都還是一樣的」）。
   v3.92 第一版只壓暗了**符號**（`.val-low* .glyph` 的 saturate/opacity），
   但使用者要的是**格子本身**看得出貴賤 —— 符號的飽和度差異在小螢幕上幾乎看不出來。

   🔴 **不可以用 `::after`** —— 那個偽元素被「WILD」/「SCATTER」角標占著（見上面 .is-wild::after）；
      第一版在那裡畫框，結果把角標整個蓋掉（使用者：「框壓住狼了」）。
      → 改用 `box-shadow` 的 inset 描邊，不碰任何偽元素。
   🔴 **百搭不套** —— 它本來就有自己的金框（`.is-wild::before`），再疊一層只是更花。
      使用者說的「狼王也是用值錢的框」＝ 它已經是值錢的那一種，不要把它降級成普通格。 */
.cell.val-high { background: linear-gradient(160deg, #1b1a12, #12131c);
  box-shadow: inset 0 0 0 1.5px rgba(255,207,58,.34); }
.cell.val-low1, .cell.val-low2, .cell.val-low3, .cell.val-low4 {
  background: linear-gradient(160deg, #0d0f16, #0a0c12);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.05); }
/* 🔴 中獎 / 走位那一刻要讓位 —— 底框是「平常誰比較值錢」，不是「這一格現在怎麼樣」 */
.cell.val-high.win, .cell.val-low1.win, .cell.val-low2.win,
.cell.val-low3.win, .cell.val-low4.win { box-shadow: none; }

.cell.sym-A .glyph { color: #aab1c9; opacity: .82; }
.cell.sym-K .glyph { color: #9aa1ba; opacity: .78; }
.cell.sym-Q .glyph { color: #8b92ac; opacity: .74; }
.cell.sym-J .glyph { color: #7d849e; opacity: .70; }
/* 🔴 **梨園變臉例外：它的皇家符不是最低階** —— 量出來的，不是憑印象。
      `face.payouts` 湊 4 張時：**A 1.43 / K 1.12 比任何一種臉譜（0.62 / 0.52 / 0.52）都高**。
      （臉譜要靠 👏 觀眾合併衝到 7~10 張才反超，最高階 39.0 遠勝 A 的 10.3。）
      → 在這一款把 A/K/Q/J 灰掉，等於告訴玩家「湊這個沒用」，而那在入門階是**錯的**。
      💡 **通則:推廣一條「這些是廢料」的視覺規則之前，要逐款量過它在那一款真的是廢料。** */
body[data-theme="opera"] .cell.sym-A .glyph,
body[data-theme="opera"] .cell.sym-K .glyph,
body[data-theme="opera"] .cell.sym-Q .glyph,
body[data-theme="opera"] .cell.sym-J .glyph {
  text-shadow: 0 2px 5px rgba(0,0,0,.55); font-size: 1em; filter: none; opacity: 1; }
body[data-theme="opera"] .cell.sym-A .glyph { color: #ff7aa8; }
body[data-theme="opera"] .cell.sym-K .glyph { color: #5ad1ff; }
body[data-theme="opera"] .cell.sym-Q .glyph { color: #ffd24a; }
body[data-theme="opera"] .cell.sym-J .glyph { color: #7ee787; }
.strip.spinning .glyph { filter: blur(2.5px); }
.cell.win { background: rgba(255,225,105,.12); box-shadow: inset 0 0 0 2px var(--win), 0 0 16px var(--win); z-index: 4; }
.cell.win .glyph { animation: pop .45s ease; }
@keyframes pop { 0%{transform:scale(1)} 45%{transform:scale(1.18)} 100%{transform:scale(1)} }

/* ---- WILD / SCATTER 辨識（比照 slot_town：金/青外框 + 角標）----
   [claude code] 2026-08-14 v2.83 `.is-scatter` = **依 scatterId 掛的**（app.js 的 setCell），
   與靠符號 key 命中的 `.sym-SCATTER` 共用同一組外觀 → 符號 key 叫什麼都有框
   （花蜜採集的 👑 蜂王 key 是 QUEEN，之前就是這樣漏掉框的）。
   [claude code] 2026-09-06 v3.75 🔴 **`.is-wild` = 依 wildId 掛的** —— v2.83 只做了 scatter 那一半，
   wild 這一半還在認 key（不熄之火的 🔥 key 是 `fire` → 明明是百搭卻沒有框）。現在兩邊一致。
   ⚠️ 下面各主題（arcane / frost / candy）針對 `.sym-WILD` 的覆寫**不用跟著加 `.is-wild`** ——
   那些款的 key 本來就是 `WILD`（兩個 class 會同時掛上），而 `body[data-theme=…]` 的
   特異性比 `.cell.is-wild` 高，覆寫照樣贏。 */
.cell.sym-WILD::before, .cell.is-wild::before,
.cell.sym-SCATTER::before, .cell.is-scatter::before {
  content: ""; position: absolute; inset: 3px; border-radius: 8px; pointer-events: none; z-index: 1; }
.cell.sym-WILD::before, .cell.is-wild::before { border: 2px solid rgba(255,210,74,.65);
  box-shadow: 0 0 10px rgba(255,210,74,.45), inset 0 0 8px rgba(255,210,74,.3); }
.cell.sym-SCATTER::before, .cell.is-scatter::before { border: 2px solid rgba(52,224,255,.6);
  box-shadow: 0 0 10px rgba(52,224,255,.4), inset 0 0 8px rgba(52,224,255,.25); }
.cell.sym-WILD::after, .cell.is-wild::after,
.cell.sym-SCATTER::after, .cell.is-scatter::after {
  position: absolute; top: 3px; left: 3px; z-index: 3; padding: 1px 5px; border-radius: 6px;
  font-size: clamp(.4rem, calc(2.6 * var(--vw)), .58rem); font-weight: 900; letter-spacing: .04em; line-height: 1.25;
  pointer-events: none; box-shadow: 0 1px 3px rgba(0,0,0,.5); }
.cell.sym-WILD::after, .cell.is-wild::after { content: "WILD"; background: linear-gradient(#ffe9a6, var(--gold)); color: #2a1d00; }
.cell.sym-SCATTER::after, .cell.is-scatter::after { content: "SCATTER"; background: linear-gradient(#bff4ff, #34e0ff); color: #042530; }
.cell.sym-WILD .glyph, .cell.is-wild .glyph { filter: drop-shadow(0 0 6px rgba(255,210,74,.6)); }
.cell.sym-SCATTER .glyph, .cell.is-scatter .glyph { filter: drop-shadow(0 0 6px rgba(52,224,255,.6)); }

/* [Claude Code 2026-06-28] 倍率百搭（frost_wilds）：❄️ 百搭格右上角的 ×N 倍率徽章。
   放右上、避開既有「WILD」字樣（在左上 ::after）；藍冰漸層 + 發光。 */
.cell .wild-mult {
  position: absolute; top: 3px; right: 3px; z-index: 6; pointer-events: none;
  font-family: "Arial Black", system-ui, sans-serif; font-weight: 900;
  font-size: clamp(.5rem, calc(2.8 * var(--vw)), .72rem); line-height: 1; letter-spacing: .02em;
  padding: 2px 5px; border-radius: 7px;
  background: linear-gradient(135deg, #e8f9ff, #5ad1ff); color: #042a3a;
  box-shadow: 0 0 9px rgba(90,209,255,.85), 0 1px 3px rgba(0,0,0,.5);
  animation: wmPop .4s ease; }
@keyframes wmPop { 0%{transform:scale(.4);opacity:0} 60%{transform:scale(1.2)} 100%{transform:scale(1);opacity:1} }
/* [claude code] 2026-09-01 v3.64 🎩 細單盤面上的帽子角標（`+N`）。
   使用者:「細單上面沒有標注 +5」—— 抬頭寫著「本轉倍率 ×8（底 1 ＋ 2 ＋ 5）」，
   盤面卻看不出那 2 和 5 是哪兩頂帽子，玩家對不起來。
   🔴 用**紫金**（跟遊戲畫面 arcane 主題的 `.wild-mult` 同一組色）——
      細單是拿來對照盤面的，兩邊顏色不同會讓人以為是兩種東西。
   ⚠️ 這裡**不吃 `body[data-theme]`**（細單 modal 在大廳 / 紀錄頁也開得起來，
      那時 body 的主題不是 arcane）→ 顏色寫死。 */
.dt-scell .dt-wm {
  position: absolute; top: 1px; right: 1px; z-index: 3; pointer-events: none;
  font-family: "Arial Black", system-ui, sans-serif; font-weight: 900;
  font-size: 9px; line-height: 1; letter-spacing: .02em;
  padding: 1px 3px; border-radius: 5px;
  background: linear-gradient(135deg, #f6ecff, #a06bff); color: #2a0f4a;
  box-shadow: 0 0 6px rgba(160,107,255,.7), 0 1px 2px rgba(0,0,0,.5); }

/* [claude code] 2026-08-31 v3.59 🎩 細單裡的「相乘算式」那一行（賠付表 × 帽子 = 實付）。
   縮排一格掛在該線下面 —— 它是那條線的**算式**,不是另一條線。 */
.dt-wmrow { margin: 2px 0 6px 26px; padding: 3px 8px; border-radius: 8px;
  font-size: .78rem; line-height: 1.5; color: #e8d9ff;
  background: rgba(160,107,255,.14); border-left: 3px solid rgba(160,107,255,.7); }
.dt-wmrow b { color: #ffe08a; }
/* [claude code] 2026-08-31 v3.59 🎩 魔術師（arcane 主題）：×N 徽章換成紫金。
   🔴 frost 那組是**藍冰色** —— 直接套在紫色主題上會像另一款遊戲的零件掉進來。 */
body[data-theme="arcane"] .cell .wild-mult {
  background: linear-gradient(135deg, #f6ecff, #a06bff); color: #2a0f4a;
  box-shadow: 0 0 9px rgba(160,107,255,.85), 0 1px 3px rgba(0,0,0,.5); }
body[data-theme="arcane"] .cell.sym-WILD::after { display: none; }
body[data-theme="arcane"] .cell.sym-WILD::before { border-color: rgba(215,179,255,.75);
  box-shadow: 0 0 10px rgba(160,107,255,.5), inset 0 0 8px rgba(160,107,255,.3); }
/* 相乘演出第一拍：沿線逐頂彈起。🔴 用不同的 keyframes（不是 wmPop）——
   wmPop 是「落盤出現」的動畫，這裡要的是「被點到」的那一下，兩者混用會分不出來。 */
.cell .wild-mult.pop { animation: wmHop .3s cubic-bezier(.2,1.6,.4,1); }
@keyframes wmHop { 0%{transform:scale(1)} 45%{transform:scale(1.45) translateY(-3px)} 100%{transform:scale(1)} }
/* frost 主題：百搭已用 ×N 徽章標示，隱藏左上「WILD」字樣避免兩標籤擠在一起（保留外框光暈）。 */
body[data-theme="frost"] .cell.sym-WILD::after { display: none; }
body[data-theme="frost"] .cell.sym-WILD::before { border-color: rgba(90,209,255,.7);
  box-shadow: 0 0 10px rgba(90,209,255,.5), inset 0 0 8px rgba(90,209,255,.3); }
/* [Claude Code 2026-06-25] candy 款：取消「框+角標」這種疊在格子上的辨識（消除掉落時會跟 glyph 分離），
   改成把光暈做在 glyph 上 → drop-shadow 隨 glyph 一起掉落/消除，棒棒糖🍭/轉盤🎡 與光暈永遠同進退。 */
/* candy 款：標示框做在 .glyph 上（不是 .cell）→ inset 環 + 光暈會隨 glyph 一起掉落/消除，永不分離。 */
body[data-theme="candy"] .cell.sym-WILD::before,
body[data-theme="candy"] .cell.sym-WILD::after,
body[data-theme="candy"] .cell.sym-SCATTER::before,
body[data-theme="candy"] .cell.sym-SCATTER::after { display: none; }
/* 框做小一點、留邊（emoji 縮 .82em + 內距），外光暈也收斂 → 不會被 reel 的 overflow:hidden 裁掉。 */
body[data-theme="candy"] .cell.sym-SCATTER .glyph,
body[data-theme="candy"] .cell.sym-BONUS .glyph { box-sizing: border-box; font-size: .82em; padding: 5px; border-radius: 12px; }
body[data-theme="candy"] .cell.sym-SCATTER .glyph { box-shadow: inset 0 0 0 2.5px #34e0ff, 0 0 7px rgba(52,224,255,.55); }
body[data-theme="candy"] .cell.sym-BONUS .glyph { box-shadow: inset 0 0 0 2.5px var(--gold), 0 0 7px rgba(255,95,162,.5); }
/* 小角標（跟著 glyph 走）標明是哪種特殊符 */
body[data-theme="candy"] .cell.sym-SCATTER .glyph::after,
body[data-theme="candy"] .cell.sym-BONUS .glyph::after {
  position: absolute; top: -6px; left: 50%; transform: translateX(-50%); z-index: 3; pointer-events: none;
  font-size: 8px; font-weight: 900; letter-spacing: .03em; line-height: 1.3; padding: 1px 5px; border-radius: 6px;
  white-space: nowrap; box-shadow: 0 1px 3px rgba(0,0,0,.55); }
body[data-theme="candy"] .cell.sym-SCATTER .glyph::after { content: "SCATTER"; background: linear-gradient(#bff4ff, #34e0ff); color: #042530; }
body[data-theme="candy"] .cell.sym-BONUS .glyph::after { content: "BONUS"; background: linear-gradient(#ffe9a6, var(--gold)); color: #5a1d00; }
/* [claude code] 2026-07-17 v1.95 icecream 款（烈日冰舖 serve）：同 candy 的修法 —— 消除掉落款的 SCATTER
   「框+角標」不能疊在 .cell 上（掉落動畫只動 .glyph → 外框先在原地出現、跟符號分離），
   改做在 .glyph 上（暖橘陽光色配 ☀️），框/角標隨符號一起掉落、永不分離。 */
body[data-theme="icecream"] .cell.sym-SCATTER::before,
body[data-theme="icecream"] .cell.sym-SCATTER::after { display: none; }
body[data-theme="icecream"] .cell.sym-SCATTER .glyph { box-sizing: border-box; font-size: .82em; padding: 5px; border-radius: 12px;
  box-shadow: inset 0 0 0 2.5px #ffb340, 0 0 7px rgba(255,179,64,.55); }
body[data-theme="icecream"] .cell.sym-SCATTER .glyph::after {
  content: "SCATTER"; position: absolute; top: -6px; left: 50%; transform: translateX(-50%); z-index: 3; pointer-events: none;
  font-size: 8px; font-weight: 900; letter-spacing: .03em; line-height: 1.3; padding: 1px 5px; border-radius: 6px;
  white-space: nowrap; box-shadow: 0 1px 3px rgba(0,0,0,.55);
  background: linear-gradient(#ffe9a6, #ffb340); color: #5a2d00; }
/* [claude code] 2026-07-18 v2.2 顧客符加框（依使用者：顧客變多了，要像 scatter 一眼看出是「會觸發成交」的特別符）。
   ⚠️ 框+「顧客」角標做在 .glyph 上（沿用 icecream SCATTER 寫法）→ 掉落補位時跟符號一起動、不分離。
   ⚠️ v2.2 修：**.glyph 不能掛 animation** —— 掉落動畫 csDrop 也在 .glyph 上，而本選擇器優先級較高，
       一掛 animation 就把 csDrop 蓋掉 → 顧客符不落下、框跟圖看起來分離。故框做「靜態」（同 scatter，無 pulse）。
       想要「動」的注意力就放在 ::after 角標（另一個元素、不影響 .glyph 的 csDrop transform）。 */
body[data-theme="icecream"] .cell.serve-cust .glyph {
  box-sizing: border-box; font-size: .82em; padding: 5px; border-radius: 12px;
  box-shadow: inset 0 0 0 2.5px #ffd24a, 0 0 8px rgba(255,205,70,.6); }
/* 🔴 [claude code] 2026-09-22 v4.53 **「顧客」那個文字角標拿掉了**（寫死中文、沒走 i18n；
   而且平台通則「畫面上能不寫字就不寫」）→ 當時換成「他點的那款冰」的圖示角標。
   [claude code] 2026-09-22 v4.57 **那顆圖示角標也拿掉了**（使用者：「人物右上的圖示可以拿掉了,
   目前新圖人物都有標示了」）—— 新畫的四張顧客圖**手上就拿著那款冰**，角標變成同一件事講兩次。
   🔴 **這條規則留著、而且改成 `display: none`** —— 玩家的瀏覽器可能還快取著會產生角標的舊 `app.js`；
      留著它，換版當下那顆角標就直接不顯示（整條刪掉的話它會變成一個沒有定位的 inline 元素
      排在符號旁邊 ＝ v4.55 修過的「一格塞兩個半格」又會回來一次）。 */
.cell .serve-want { display: none; }

/* 固定高度動作區：撐住「翻倍鈕 / 免費旋轉文字」其一的空間（兩者不同時出現）→ 高度固定、SPIN 不跳動。
   拿掉「贏得 N！」後只需一排高度，縮小與盤面的間距。 */
.action-zone { min-height: 44px; margin-top: 8px; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 6px; }
.win-banner { text-align: center; margin: 0; font-size: 17px; font-weight: 700;
  color: var(--win); text-shadow: 0 0 10px rgba(255,225,105,.5); }

/* [claude code] 2026-07-10 免費期遞增倍率:banner 上的「×N」要醒目(原本 ×2 固定又沒顯示,玩家無感) */
.win-banner .fs-mult { color: #ffd24a; font-weight: 900; text-shadow: 0 0 10px rgba(255,210,74,.55);
  display: inline-block; animation: fsMultPop .35s ease; }
@keyframes fsMultPop { 0% { transform: scale(.7); opacity: .3; } 60% { transform: scale(1.25); } 100% { transform: scale(1); } }
.win-banner .fs-win { color: var(--gold, #ffd24a); font-weight: 800; }
.win-banner:empty { display: none; }   /* 空時不佔行，避免把翻倍鈕往下推 */

/* ---- 大獎全螢幕特效 overlay（BIG / MEGA / EPIC WIN）---- */
.win-overlay { position: fixed; inset: 0; z-index: 40; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 10px; pointer-events: none;
  opacity: 0; visibility: hidden; transition: opacity .25s; background: radial-gradient(circle at 50% 45%, rgba(0,0,0,.55), rgba(0,0,0,.82)); }
.win-overlay.show { opacity: 1; visibility: visible; }
.wo-tier { font-size: clamp(40px, calc(13 * var(--vw)), 90px); font-weight: 900; letter-spacing: 2px;
  background: linear-gradient(90deg, var(--gold), #fff, var(--gold)); -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; filter: drop-shadow(0 0 24px var(--gold)); animation: woPop .5s ease; }
.wo-amt { font-size: clamp(26px, calc(8 * var(--vw)), 52px); font-weight: 900; color: #fff; text-shadow: 0 0 18px var(--win); animation: woRise .6s ease;
  font-variant-numeric: tabular-nums; }   /* 等寬數字：跳的時候寬度不會忽大忽小 */
/* [claude code] 2026-08-13 跳錢中：微微抖 + 更亮；停住時「咚」一下放大再收 */
.wo-amt.rolling { animation: woRise .6s ease, woRoll .12s ease-in-out infinite alternate;
  text-shadow: 0 0 26px var(--win), 0 0 46px rgba(255,232,150,.75); }
@keyframes woRoll { from { transform: translateY(-1px) scale(1); } to { transform: translateY(1px) scale(1.012); } }
.wo-amt.landed { animation: woLand .42s cubic-bezier(.2,1.5,.4,1); }
/* [claude code] 2026-08-14 v2.93 「領取」鈕 —— 中大獎特效改成按了才收（不再自動關）。
   跳錢跑完（`.ready`）才長出來，免得數字還在跳就被按掉。 */
.wo-collect { margin-top: 18px; padding: 12px 40px; border: 0; border-radius: 999px; cursor: pointer;
  font-size: clamp(15px, calc(4.4 * var(--vw)), 19px); font-weight: 900; letter-spacing: .06em; color: #2a1d00;
  background: linear-gradient(#fff3c8, var(--gold));
  box-shadow: 0 6px 18px rgba(0,0,0,.45), 0 0 22px rgba(255,207,58,.6), inset 0 1px 0 rgba(255,255,255,.7);
  opacity: 0; transform: translateY(10px) scale(.94); pointer-events: none; transition: .28s ease; }
.win-overlay.ready .wo-collect { opacity: 1; transform: none; pointer-events: auto;
  animation: woCollectPulse 1.6s ease-in-out .4s infinite; }
.wo-collect:active { transform: scale(.96); }
@keyframes woCollectPulse { 0%, 100% { box-shadow: 0 6px 18px rgba(0,0,0,.45), 0 0 22px rgba(255,207,58,.6), inset 0 1px 0 rgba(255,255,255,.7); }
  50% { box-shadow: 0 6px 22px rgba(0,0,0,.5), 0 0 34px rgba(255,207,58,.95), inset 0 1px 0 rgba(255,255,255,.8); } }
@keyframes woLand { 0% { transform: scale(1.24); } 100% { transform: scale(1); } }
.win-overlay.tier-mega .wo-tier { background: linear-gradient(90deg, #ff3df0, #36e0ff, #ffd24a); -webkit-background-clip: text; background-clip: text; filter: drop-shadow(0 0 26px #ff3df0); }
.win-overlay.tier-epic .wo-tier { background: linear-gradient(90deg, #ff3df0, #7a5cff, #36e0ff, #ffd24a); -webkit-background-clip: text; background-clip: text; filter: drop-shadow(0 0 30px #7a5cff); animation: woPop .5s ease, woShake .6s ease .5s; }
@keyframes woPop { 0%{transform:scale(.3);opacity:0} 60%{transform:scale(1.15)} 100%{transform:scale(1);opacity:1} }
@keyframes woRise { 0%{transform:translateY(20px);opacity:0} 100%{transform:translateY(0);opacity:1} }
@keyframes woShake { 0%,100%{transform:translateX(0)} 25%{transform:translateX(-8px)} 75%{transform:translateX(8px)} }

/* ---- 控制列（直版置底一排）---- */
.control-bar { display: flex; align-items: center; justify-content: center; gap: 14px; margin-top: 16px; flex-wrap: wrap; }
/* ---- 單注 +/- stepper ---- */
.bet-stepper { display: flex; align-items: center; gap: 10px; background: var(--surface-2);
  border: 1px solid var(--border); border-radius: 999px; padding: 5px 8px; }
.bet-label { color: var(--text-soft); font-size: 13px; padding-left: 6px; }
.bet-btn { width: 34px; height: 34px; border-radius: 50%; border: none; cursor: pointer;
  background: var(--surface); color: var(--text); font-size: 20px; font-weight: 700; line-height: 1;
  display: flex; align-items: center; justify-content: center; transition: background .15s, color .15s; }
.bet-btn:hover:not(:disabled) { background: var(--neon-2); color: #08101a; }
.bet-btn:disabled { opacity: .35; cursor: not-allowed; }
.bet-value { min-width: 64px; text-align: center; font-size: 17px; font-weight: 800; color: var(--gold); }
.btn-spin { background: linear-gradient(135deg, var(--neon), var(--neon-2)); color: #0a0c16;
  border: none; padding: 14px 40px; border-radius: 999px; font-size: 18px; font-weight: 800;
  cursor: pointer; letter-spacing: 1px; box-shadow: 0 6px 20px rgba(54,224,255,.35);
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  transition: transform .14s ease, box-shadow .18s ease, filter .14s ease; }
.btn-spin:disabled { opacity: .5; cursor: not-allowed; }
/* [claude code] 2026-08-13 ④ 圖示持續慢轉。純 CSS 畫的環形箭頭：一圈粗邊缺一角 + 一個小三角。
   2026-08-13 二版（依使用者：「那個 SPIN 左邊在轉的，能是**繞著 SPIN 字轉**的」）：
   從「按鈕左邊自轉」改成**沿著按鈕的橢圓軌道公轉**（CSS Motion Path）。 */
/* 2026-08-13 二版（使用者：「那個在轉的怪怪的，**就算是小亮點轉都好**」）：
   從「缺一角的環形箭頭」改成**一顆發光小亮點**。環形箭頭同時自轉又公轉，兩個旋轉疊在一起看起來雜；
   亮點沒有方向性，繞著跑就只是純粹的光，乾淨得多。 */
.spin-ico { width: 8px; height: 8px; flex: 0 0 auto; border-radius: 50%; border: none;
  background: radial-gradient(circle, #fff 0%, #fff3c8 40%, rgba(255,207,58,.85) 66%, rgba(255,207,58,0) 100%);
  box-shadow: 0 0 10px 3px rgba(255,232,150,.9), 0 0 20px 6px rgba(255,200,80,.45);
  animation: spinIcoPulse 1.6s ease-in-out infinite; }
@keyframes spinIcoPulse { 0%, 100% { opacity: .8; transform: scale(1); }
  50% { opacity: 1; transform: scale(1.28); } }

/* 🔴 公轉：`offset-path: ellipse(...)` 用**百分比**貼著按鈕自己的大小 → 按鈕多寬多高都跟得上，
   不必寫死像素（寫死的話手機或字型不同就會跑到框外）。
   `offset-rotate: 0deg` = 沿路徑走但**自己不跟著轉向**，這樣它才能同時用 transform 做自轉。
   ⚠️ 包 @supports：不支援 Motion Path 的瀏覽器自動退回「左邊自轉」那版（上面那段），不會壞掉。 */
@supports (offset-path: ellipse(40% 30% at 50% 50%)) {
  .btn-spin { position: relative; }
  .spin-ico { position: absolute; left: 0; top: 0; margin: 0;
    offset-path: ellipse(44% 31% at 50% 50%);
    offset-rotate: 0deg;
    animation: spinOrbit 3.6s linear infinite, spinIcoPulse 1.6s ease-in-out infinite; }
  .btn-spin:disabled .spin-ico { animation-duration: 1.2s, 0.7s; }   /* 表演中：繞得快、閃得也快 */
  /* 圖示改成絕對定位後就不佔寬度了 → 左右各留一點，免得它壓到 SPIN 字 */
  .btn-spin .spin-txt { padding: 0 4px; }
}
@keyframes spinOrbit { to { offset-distance: 100%; } }

/* [claude code] 2026-08-13 ⑤ hover 的黃光。
   二版（依使用者：「能變成放大，再縮小放大的黃框嗎」）：從**靜態**黃框改成**脈動** ——
   一路 放大 → 收 → 再放大，光暈跟著一起呼吸。1.15s 一次，比心跳稍慢，看久不煩。 */
/* 三版（使用者：「黃框到最大時，**SPIN 字會往下動一下**」）：
   🔴 病根是脈動動畫在改 `transform: scale()` —— 按鈕一放大，裡面的字當然跟著長大位移。
   改成 **transform 固定在 :hover 上放大一次就不動**，動畫**只改 box-shadow**（光暈自己呼吸）。
   → 黃框照樣放大縮小，但按鈕與 SPIN 字**完全不動**。 */
.btn-spin:hover:not(:disabled) { filter: brightness(1.06); transform: scale(1.045);
  animation: spinGlow 1.15s ease-in-out infinite; }
@keyframes spinGlow {
  0%, 100% { box-shadow: 0 8px 24px rgba(54,224,255,.38), 0 0 12px 1px rgba(255,232,150,.4); }
  50%      { box-shadow: 0 10px 30px rgba(54,224,255,.46), 0 0 36px 10px rgba(255,232,150,.85); }
}
/* 🔴 按下去要壓得住 hover 的 animation（animation 的優先級高於一般宣告）→ 明確關掉它 */
.btn-spin:active:not(:disabled) { animation: none; transform: scale(.97);
  box-shadow: 0 4px 14px rgba(54,224,255,.35), 0 0 16px 3px rgba(255,232,150,.5); }

/* [claude code] 2026-07-29 v2.22 賠付表過寬修正（使用者回報「太寬下面會出現醜醜的 scroll bar」）：
   ① card 加寬 360→min(420, calc(100 * var(--vw))−24) ② 表格內距壓縮 + **數字欄不換行**（原本「相連數」被逐字拆成直排）
   ③ 欄多的表自動縮字級（.pt-compact）④ 真的塞不下才捲，且捲軸改細版主題色（.pt-wrap，由 openPaytable 統一包）。*/
/* [claude code] 2026-08-17 v3.45 🔴 這裡的 width 一直沒生效 —— `.modal-card { width: 320px }`
   寫在本檔**後面**(同為單一 class,權重一樣 → 後者勝),所以 v2.22「加寬到 420」等於沒做,
   賠付表一直是 320px。改用 `.modal-card.paytable-card`(權重 0,2,0)明確蓋過去。
   ⚠️ 順序性的覆蓋很難用肉眼看出來:兩條規則隔了 25 行,而且「320」看起來像是誰刻意設的。 */
.modal-card.paytable-card { width: min(420px, calc(calc(100 * var(--vw)) - 24px)); }
.paytable-card { max-height: 80vh; overflow-y: auto; overflow-x: hidden; }
.paytable h4 { margin: 0 0 10px; color: var(--text-soft); }
table.pt { width: 100%; border-collapse: collapse; font-size: 13px; }
table.pt th, table.pt td { padding: 4px 6px; text-align: left; border-bottom: 1px solid var(--border); white-space: nowrap; }
table.pt th { color: var(--text-soft); font-weight: 600; }
/* 首欄（符號 / 名稱）才允許換行，其餘（數字）一律不換行 */
table.pt th:first-child, table.pt td:first-child { white-space: normal; }
/* 欄多的表（闖關奪寶 6 欄等）自動縮字級 → 免捲軸 */
table.pt.pt-compact { font-size: 11.5px; }
table.pt.pt-compact th, table.pt.pt-compact td { padding: 3px 4px; }
/* 仍塞不下才捲：細捲軸 + 主題色，不再是系統預設那條粗白條 */
.pt-wrap { overflow-x: auto; scrollbar-width: thin; scrollbar-color: var(--border) transparent; }
.pt-wrap::-webkit-scrollbar { height: 6px; }
.pt-wrap::-webkit-scrollbar-track { background: transparent; }
.pt-wrap::-webkit-scrollbar-thumb { background: var(--border); border-radius: 999px; }
.pt-wrap::-webkit-scrollbar-thumb:hover { background: var(--text-soft); }
/* modal 自己的垂直捲軸也改細版（原本系統預設粗條跟畫面不搭）*/
.paytable-card { scrollbar-width: thin; scrollbar-color: var(--border) transparent; }
.paytable-card::-webkit-scrollbar { width: 7px; }
.paytable-card::-webkit-scrollbar-track { background: transparent; }
.paytable-card::-webkit-scrollbar-thumb { background: var(--border); border-radius: 999px; }
.fs-note { font-size: 12px; color: var(--neon-2); margin-top: 10px; }

.modal { position: fixed; inset: 0; background: rgba(0,0,0,.6); display: flex; align-items: center;
  justify-content: center; z-index: 30; }
.modal-card { background: var(--surface); border: 1px solid var(--border); border-radius: 16px;
  padding: 24px; width: 320px; position: relative; }
.modal-card h3 { margin: 0 0 8px; }
.modal-card .hint { font-size: 12px; color: var(--text-soft); }
.modal-card input { width: 100%; margin: 8px 0; padding: 10px; border-radius: 8px;
  border: 1px solid var(--border); background: var(--surface-2); color: var(--text); }
.modal-actions { display: flex; gap: 10px; margin-top: 6px; }
.modal-close { position: absolute; top: 10px; right: 12px; background: none; border: none;
  color: var(--text-soft); font-size: 22px; cursor: pointer; }
.acc-msg { font-size: 13px; color: var(--neon-2); min-height: 18px; margin: 10px 0 0; }
.newguest-btn { width: 100%; margin-top: 10px; border-color: var(--neon-2); color: var(--neon-2); }
.newguest-btn:hover { background: var(--neon-2); color: #08101a; }

/* ---- 遊戲內小圖示（標題前）---- */
/* 🖼 [claude code] 2026-09-21 v4.50 標題列的圖示盒：插畫疊在 emoji 上面（圖失敗 → emoji 露出來）。
   🔴 **固定成一個方盒 + `vertical-align: middle`** —— `.game-head h2` 是
      `nowrap + ellipsis` 的 grid 欄；圖沒有明確寬高的話，載入前後整排抬頭會跳一下，
      而且盒子比文字行高還高的話會把抬頭撐高（手機是一屏可見，那幾 px 是從盤面借的）。 */
.title-emoji { position: relative; display: inline-block; width: 24px; height: 24px;
  font-size: 21px; line-height: 24px; text-align: center; vertical-align: middle; }
.title-art { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain;
  border-radius: 7px; background: #101125; }

/* ---- 該款完成日期（SPIN 下方）---- */
.game-completed { text-align: center; color: var(--text-mute, #8b91a3); font-size: 12px; letter-spacing: .3px; margin: 14px 0 4px; }
/* [claude code] 2026-07-19 該款身世（🗓️ 開始做的日期 + 平台版本）：放遊戲畫面最下面、置中 */
.game-born { display: flex; justify-content: center; margin: 6px 0 4px; }
/* 遊戲內資訊列：波動 / 最大賠付 / 核心玩法 */
.game-info { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px; margin: 0 0 10px; }
.game-info:empty { display: none; }
.gi-chip { font-size: 11.5px; font-weight: 600; color: var(--text-soft, #c7ccda);
  background: rgba(255,255,255,.06); border: 1px solid rgba(255,255,255,.1);
  padding: 3px 9px; border-radius: 999px; white-space: nowrap; }
.gi-vol { color: #ffcf7a; border-color: rgba(255,207,122,.3); }
.gi-max { color: var(--gold, #ffd24a); border-color: rgba(255,210,74,.3); }
.gi-core { color: #8fd3ff; border-color: rgba(143,211,255,.28); }
/* [claude code] 2026-07-16 每款「開始做的日期 + 當時平台版本」身世 chip */
.gi-born { color: #b6a7e8; border-color: rgba(182,167,232,.3); }
/* [claude code] 2026-09-09 v3.98 🔧 優化時間 —— 與建立日同一排、顏色分開(那是兩件事:
   一個是「什麼時候做的」、一個是「最近一次動它」)。刻意比建立日淡一點,它是次要資訊。 */
.gi-upd { color: #8fb6e6; border-color: rgba(143,182,230,.28); }

/* ---- 注單號（名字和盤面中間）---- */
/* 固定寬度 + monospace tabular，單號變動或在「—」之間切換時不會左右跳動 */
/* [claude code] 2026-07-18 各款主題味小標語（遊戲名 ↔ 注單號 之間）：小字、柔和、置中，一行放不下就自動折。 */
.game-tagline { text-align: center; font-size: 12.5px; color: var(--text-soft); line-height: 1.45;
  margin: -4px auto 9px; max-width: 90%; letter-spacing: .3px; }
/* [claude code] 2026-07-19 標語輪換動畫：每次 SPIN 兩段式「由上往下捲動」——
   第一段 tag-out：舊句往下滑出 + 淡出；第二段 tag-in：新句從上方滑入落定（整體往下捲，像翻過一句）。 */
/* [claude code] 2026-07-19 依使用者放慢、位移加大 → 「由上往下捲動」看得清楚（原 .17s/.32s 太快、被 SPIN 盤面動畫蓋過）。 */
.game-tagline.tag-out { animation: tagOut .42s ease-in both; }
.game-tagline.tag-in  { animation: tagIn .72s cubic-bezier(.22,.68,.36,1) both; }
@keyframes tagOut {
  0%   { opacity: 1; transform: translateY(0); }
  100% { opacity: 0; transform: translateY(20px); filter: blur(1.5px); }
}
@keyframes tagIn {
  0%   { opacity: 0; transform: translateY(-22px); filter: blur(2px); }
  55%  { opacity: 1; filter: blur(0); }
  100% { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .game-tagline.tag-out, .game-tagline.tag-in { animation: none; }
}
.spin-ticket { display: flex; align-items: center; justify-content: center; gap: 8px; margin: 4px 0 10px; }
.st-label { font-size: 12px; color: var(--text-soft); letter-spacing: 1px; white-space: nowrap; }
.st-no { font-family: "JetBrains Mono", "SF Mono", Consolas, monospace; font-size: 13px; font-weight: 700;
  color: var(--gold); letter-spacing: .5px; font-variant-numeric: tabular-nums;
  min-width: 210px; text-align: center; padding: 4px 10px; border-radius: 8px;
  background: var(--surface-2); border: 1px solid var(--border);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.st-copy { flex: 0 0 auto; width: 30px; height: 30px; border-radius: 8px; cursor: pointer; line-height: 1;
  font-size: 15px; background: var(--surface); color: var(--text-soft); border: 1px solid var(--border);
  transition: background .15s, color .15s, transform .12s; }
.st-copy:hover:not(:disabled) { background: var(--neon-2); color: #08101a; border-color: var(--neon-2); }
.st-copy:disabled { opacity: .4; cursor: not-allowed; }
.st-copy.copied { background: var(--get, #16a34a); color: #fff; border-color: var(--get, #16a34a); transform: scale(1.08); }

/* ---- 本局贏分計量區 ---- */
.win-meter { display: flex; align-items: center; justify-content: space-around; gap: 10px; margin-bottom: 10px;
  background: linear-gradient(180deg, rgba(255,210,74,.08), transparent); border: 1px solid var(--border);
  border-radius: 10px; padding: 7px 14px; }
/* [Claude Code 2026-06-29] 盤面正上方一排：本局贏分 + 餘額（玩遊戲時餘額好找）*/
.wm-group { display: flex; align-items: center; gap: 8px; }
.wm-balance { border-left: 1px solid var(--border); padding-left: 16px; }
.wm-balance .wm-value { color: var(--gold, #ffd24a); }
.wm-label { font-size: 12px; color: var(--text-soft); letter-spacing: 1px; }
.wm-value { font-size: 24px; font-weight: 900; color: var(--win); text-shadow: 0 0 10px rgba(255,225,105,.4);
  font-variant-numeric: tabular-nums; }
.wm-value.bump { animation: wmBump .3s ease; }
@keyframes wmBump { 0%{transform:scale(1)} 40%{transform:scale(1.25)} 100%{transform:scale(1)} }
/* [Claude Code 2026-06-29] 領獎慶祝彈窗（任務/升級領取）—— 中央金幣 + 標籤 + 金額，彈起放大再淡出 */
.reward-burst { position: fixed; left: 50%; top: 42%; transform: translate(-50%, -50%); z-index: 120;
  text-align: center; pointer-events: none; animation: rbPop 1.6s ease forwards; }
.reward-burst .rb-coins { font-size: 40px; letter-spacing: 6px; animation: rbCoins 1.6s ease forwards; }
.reward-burst .rb-label { font-size: 15px; font-weight: 800; color: #fff; letter-spacing: 1px; margin-top: 4px;
  text-shadow: 0 2px 8px rgba(0,0,0,.6); }
.reward-burst .rb-amt { font-size: 40px; font-weight: 900; color: var(--gold, #ffd24a);
  text-shadow: 0 0 16px rgba(255,210,74,.8), 0 2px 6px rgba(0,0,0,.6); font-variant-numeric: tabular-nums; }
@keyframes rbPop { 0% { opacity: 0; transform: translate(-50%, -40%) scale(.5); } 18% { opacity: 1; transform: translate(-50%, -50%) scale(1.15); }
  30% { transform: translate(-50%, -50%) scale(1); } 78% { opacity: 1; transform: translate(-50%, -54%) scale(1); }
  100% { opacity: 0; transform: translate(-50%, -70%) scale(.95); } }
@keyframes rbCoins { 0%,100% { transform: translateY(0); } 30% { transform: translateY(-8px); } 60% { transform: translateY(2px); } }

/* ---- AUTO 按鈕 ---- */
.auto-btn.auto-on { border-color: var(--neon); color: var(--neon); box-shadow: 0 0 12px rgba(255,61,240,.4); }

/* ---- modal 表單欄位（AUTO 設定）---- */
.field { display: block; color: var(--text-soft); font-size: 14px; margin: 10px 0 4px; }
.field select { margin-left: 8px; background: var(--surface-2); color: var(--text); border: 1px solid var(--border);
  padding: 6px 10px; border-radius: 8px; font-size: 14px; }
.field-title { color: var(--text-soft); font-size: 13px; margin: 14px 0 6px; }
.check { display: flex; align-items: center; gap: 8px; color: var(--text); font-size: 14px; margin: 8px 0; }
.check input[type="number"] { background: var(--surface-2); color: var(--text); border: 1px solid var(--border);
  border-radius: 6px; padding: 4px 6px; margin: 0 4px; }

/* ---- 翻倍按鈕（中獎後亮起，opt-in）---- */
/* [claude code] 2026-07-29 v2.22 翻倍鈕併進控制列第二排（原 .gamble-dock 已移除）：常駐 + 未中獎 disabled */
.gamble-btn { display: block; margin: 0 auto; padding: 9px 22px; border-radius: 999px; cursor: pointer;
  font-size: 15px; font-weight: 800; color: #2a1d00; border: none;
  background: linear-gradient(135deg, #ffe9a6, var(--gold)); box-shadow: 0 0 0 0 rgba(255,210,74,.6); }
.gamble-btn:disabled { opacity: .38; cursor: default; filter: grayscale(.5); }
.gamble-btn.armed { animation: gPulse 1.3s ease-in-out infinite; }
@keyframes gPulse { 0%,100%{ box-shadow: 0 0 10px 0 rgba(255,210,74,.5); } 50%{ box-shadow: 0 0 20px 6px rgba(255,210,74,.35); transform: scale(1.03); } }

/* ---- 翻倍玩法視窗 ---- */
.gamble-card { width: 330px; text-align: center; }
.gamble-stake { font-size: 16px; color: var(--text); margin: 4px 0; }
.gamble-stake span { color: var(--win); font-weight: 900; font-size: 22px; }
.gamble-board { position: relative; margin: 16px 0 4px; }
.gamble-choices { display: flex; gap: 14px; }
.gamble-color { flex: 1; padding: 20px 0; border-radius: 14px; border: 2px solid var(--border); cursor: pointer;
  font-size: 26px; color: #fff; transition: transform .12s, box-shadow .15s; }
.gamble-color span { display: block; font-size: 14px; font-weight: 800; margin-top: 2px; }
.gamble-color.red { background: linear-gradient(160deg, #ff5b6d, #c81e3a); }
.gamble-color.black { background: linear-gradient(160deg, #3a3f52, #14171f); }
.gamble-color:hover:not(:disabled) { transform: translateY(-2px); box-shadow: 0 6px 18px rgba(0,0,0,.5); }
.gamble-color:disabled { opacity: .5; cursor: not-allowed; }
/* 揭曉反饋：大 ✓×2 / ✗ + 綠/紅徑向閃光，蓋在選色上 */
.gamble-reveal { position: absolute; inset: -6px; display: flex; align-items: center; justify-content: center;
  border-radius: 16px; font-size: 46px; font-weight: 900; opacity: 0; visibility: hidden; pointer-events: none; }
.gamble-reveal.show { opacity: 1; visibility: visible; animation: gReveal .4s ease; }
.gamble-reveal.win { color: #aef5c0; background: radial-gradient(circle, rgba(46,230,166,.45), rgba(46,230,166,.05) 70%);
  text-shadow: 0 0 18px #2ee6a6; }
.gamble-reveal.lose { color: #ffb3b3; background: radial-gradient(circle, rgba(255,77,109,.45), rgba(255,77,109,.05) 70%);
  text-shadow: 0 0 18px #ff4d6d; }
@keyframes gReveal { 0%{ transform: scale(.4); opacity: 0; } 60%{ transform: scale(1.15); } 100%{ transform: scale(1); opacity: 1; } }
/* 開牌路單 */
.gamble-trail { display: flex; align-items: center; justify-content: center; gap: 8px; margin: 12px 0; flex-wrap: wrap; }
.gt-label { font-size: 12px; color: var(--text-mute, #8b91a3); }
.gt-dots { display: inline-flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.g-dot { width: 11px; height: 11px; border-radius: 50%; display: inline-block; }
.g-dot.red { background: #ff4d6d; } .g-dot.black { background: #6b7280; }
.gt-empty { font-size: 12px; color: var(--text-soft); }
.g-tally { font-size: 12px; color: var(--text-soft); margin-left: 4px; }

/* ---- Hold & Win 鎖幣重轉 ---- */
/* 金幣符號（COIN）：金色光暈，holdwin 款的核心符號 */
.cell.sym-COIN .glyph { filter: drop-shadow(0 0 8px rgba(255,210,74,.85)); }
.cell.sym-COIN { background: radial-gradient(circle at 50% 45%, rgba(255,210,74,.22), transparent 70%); }
/* 鎖定金幣：金框 + 面額徽章 */
.cell.hw-lock { box-shadow: inset 0 0 0 2px var(--gold), 0 0 14px rgba(255,210,74,.5); border-radius: 8px; }
.cell.hw-lock.hw-pop { animation: hwPop .35s ease; }
@keyframes hwPop { 0%{ transform: scale(.4); opacity:.2; } 60%{ transform: scale(1.18); } 100%{ transform: scale(1); opacity:1; } }
.hw-val { position: absolute; left: 50%; bottom: 6px; transform: translateX(-50%);
  background: linear-gradient(135deg, #ffe9a6, var(--gold)); color: #2a1d00;
  font-size: 11px; font-weight: 900; padding: 1px 7px; border-radius: 999px;
  font-variant-numeric: tabular-nums; box-shadow: 0 1px 3px rgba(0,0,0,.4); white-space: nowrap; z-index: 6; }
/* 重轉中：未鎖定（空）格「靜態」變暗 → 讓鎖定金幣明顯突出（不再無意義一直閃）。 */
.cell.hw-dim { opacity: .28; filter: grayscale(.5); transition: opacity .2s; }
/* 落新幣前：該空格一次性快閃一下（不是無限），暗示「這格在轉」。 */
.cell.hw-spin { animation: hwSpin .45s ease; }
@keyframes hwSpin { 0%{ filter: brightness(.5); } 50%{ filter: brightness(1.5); } 100%{ filter: brightness(1); } }
/* HUD（重轉次數 + 收集總額）覆在盤面上方 */
.hw-hud { position: absolute; top: 6px; left: 50%; transform: translateX(-50%); z-index: 7;
  display: flex; align-items: center; gap: 14px; padding: 7px 18px; border-radius: 999px;
  background: rgba(8,16,26,.9); border: 1px solid var(--gold); box-shadow: 0 4px 16px rgba(0,0,0,.6);
  backdrop-filter: blur(3px); white-space: nowrap; }
.hw-title { font-size: 12px; font-weight: 900; color: var(--gold); letter-spacing: 1px; }
.hw-respins { font-size: 13px; color: var(--text); }
.hw-respins span { font-weight: 900; color: var(--neon-2); font-size: 18px; display: inline-block; min-width: 14px; text-align: center; }
/* 落新幣 → 重轉次數重置，數字跳一下（讓玩家看出「重置了」）。 */
.hw-respins span.reset { animation: hwReset .5s ease; color: var(--gold); }
@keyframes hwReset { 0%{ transform: scale(2); text-shadow: 0 0 14px var(--gold); } 100%{ transform: scale(1); } }
.hw-collect { font-size: 15px; font-weight: 900; color: var(--win); font-variant-numeric: tabular-nums; }
.hw-collect.bump { animation: wmBump .3s ease; }

/* ---- Candy 消除掉落（scatter-pays），三段表演：高亮 → 消除露空格 → 掉落補位 ---- */
/* 1) 中獎符「閃爍」（持續一閃一閃，停一下讓玩家看清中了什麼） */
.cell.cs-win { z-index: 4; }
.cell.cs-win .glyph { animation: csWin .34s ease-in-out infinite alternate; }
@keyframes csWin { from{ transform: scale(1); filter: none; } to{ transform: scale(1.2); filter: brightness(1.75) drop-shadow(0 0 11px var(--win)); } }
/* 2) 消除（放大一下再縮成 0 + 淡出，露出空格） */
.cell.cs-clear .glyph { animation: csClear .3s ease forwards; }
@keyframes csClear { 0%{ transform: scale(1.2); opacity: 1; filter: brightness(1.75); } 35%{ transform: scale(1.4); opacity: 1; } 100%{ transform: scale(0); opacity: 0; } }
/* 3) 掉落補位：survivor 從原位往下掉、新符從盤面上方掉入。距離用 --drop-from（px，負=從上方）。 */
.cell.cs-drop .glyph { animation: csDrop var(--drop-ms, 520ms) cubic-bezier(.33,1.06,.5,1) both; }
/* 🔴 WILD / SCATTER 的外框(::before)與角標(::after)**要跟著符號一起掉**（使用者：「scatter 框會在原地,
   等飛機掉下來,理論上應該要在一起」）。成因：掉落 / 中獎 / 消除這三支通用動畫都掛在子元素 `.glyph` 上，
   而框與角標是掛在 `.cell` 上的偽元素 → 符號在動、框卻黏在終點。
   ⚠️ 這兩個偽元素本來就沒有自己的 transform（純 inset / top-left 定位），套上去不會打架。
   **這是全平台通用修正**，不是哪一款專屬的。 */
.cell.cs-drop::before, .cell.cs-drop::after { animation: csDrop var(--drop-ms, 520ms) cubic-bezier(.33,1.06,.5,1) both; }
/* 🔴 [claude code] 2026-09-09 v3.96 **格子的底色也要跟符號一起出現**
   （使用者：「這個感覺底色框會先在原地，上面符號才掉進來」）。
   成因跟上面那條（框與角標）是**同一件事的第三半**：掉落動畫掛在 `.glyph` 與偽元素上，
   而 `background` 是 `.cell` 自己的 → `setCell` 一換 class 底色立刻變，符號才慢慢掉進來。
   ⚠️ **星宮聚合特別明顯** —— 那一款的符號底色就是識別（一個星座一個顏色）；
      多數款的符號是 emoji、底色都一樣，所以以前看不出來。

   🔴 **用 opacity 不用 transform** —— `renderReel` 會設 `cell.style.transform` 當**定位**
      （treadmill 的每一格靠它擺位置），拿 transform 做動畫會在動畫結束時把格子拉跑位。
      opacity 不碰定位，安全。 */
.cell.cs-drop { animation: csDropFade var(--drop-ms, 520ms) ease both; }
@keyframes csDropFade { from { opacity: .001; } to { opacity: 1; } }
.cell.cs-win::before, .cell.cs-win::after { animation: csWin .34s ease-in-out infinite alternate; }
.cell.cs-clear::before, .cell.cs-clear::after { animation: csClear .3s ease forwards; }
@keyframes csDrop { from{ transform: translateY(var(--drop-from, -100%)); opacity: .35; } to{ transform: translateY(0); opacity: 1; } }
/* 倍率糖面值徽章（免費期） */
.cs-bombv { position: absolute; left: 50%; top: 50%; transform: translate(-50%,-50%);
  background: linear-gradient(135deg, #fff0a6, var(--gold)); color: #7a1d6b;
  font-size: 13px; font-weight: 900; padding: 2px 8px; border-radius: 999px;
  border: 2px solid #fff; box-shadow: 0 0 10px rgba(255,210,74,.8); z-index: 6; white-space: nowrap; }
.cell.cs-bombfire { animation: csBombFire .6s ease infinite; }
@keyframes csBombFire { 0%,100%{ filter: brightness(1); } 50%{ filter: brightness(1.8) drop-shadow(0 0 10px var(--gold)); } }

/* [claude code] 2026-08-15 v2.99 原本這裡是 `.serve-heat-badge`（烈日冰舖自製的 🔥×N 徽章）——
   已改用全平台通用的倍率條（`#gameMult` + `.ui-multbar`），整組移除。
   🔥 仍然會從盤面飛過去，只是目標換成倍率條上那顆亮著的 chip（見 app.js 的 serveMultTarget）。 */
/* 盤面 🔥 飄向倍數徽章（fixed，飛行途中放大發光→縮進徽章） */
/* [claude code] 2026-09-01 v3.66 🐝 花蜜採集的飛行表演（三拍：蜜蜂 → 倍率條 / 花 → 贏分 / 倍數 → 贏分）。
   🔴 `position: fixed` + 掛在 `body` 上 —— 飛的路徑會跨過盤面邊界，
      掛在格子裡會被 `overflow` 裁掉（而且是在半路裁掉，看起來像消失了）。 */
.cash-fly { position: fixed; z-index: 24; pointer-events: none;
  will-change: transform, opacity; line-height: 1; }
.cash-fly-bee { font-size: 26px; filter: drop-shadow(0 0 8px #ffd24a); }
.cash-fly-nectar { font-size: 22px; filter: drop-shadow(0 0 7px #ffb14a); }
.cash-fly-mult { font-family: "Arial Black", system-ui, sans-serif; font-weight: 900;
  font-size: 30px; color: #ffe08a; text-shadow: 0 0 14px rgba(255,210,74,.9), 0 2px 6px rgba(0,0,0,.6); }

.serve-heat-fly { position: fixed; z-index: 24; pointer-events: none; font-size: 30px;
  filter: drop-shadow(0 0 10px #ff6a3c); will-change: transform, opacity; }
/* 初始盤 🔥 待飄前的脈動提示 */
.cell.serve-heat-wait .glyph { animation: shWait .7s ease-in-out infinite; }
@keyframes shWait { 0%,100%{ filter: drop-shadow(0 0 3px #ff7a3c); transform: scale(1);} 50%{ filter: drop-shadow(0 0 12px #ff3d6e); transform: scale(1.18);} }

/* [claude code] 2026-07-18 v2.0 盤面熱度層：有火 → 盤上透出紅光，火愈多（倍數愈高）愈紅愈燙（hot1→hot4）。
   蓋在盤面上、不吃點擊；用漸層 + 混色，高熱度加「熱浪抖動」動畫。*/
.serve-heat-layer { position: absolute; inset: -4px; border-radius: 14px; pointer-events: none; z-index: 8;
  opacity: 0; transition: opacity .5s ease; mix-blend-mode: screen;
  background: radial-gradient(120% 90% at 50% 108%, rgba(255,90,40,.0), rgba(255,60,40,.0)); }
.serve-heat-layer.on { opacity: 1; }
.serve-heat-layer.hot1 { background: radial-gradient(130% 95% at 50% 110%, rgba(255,150,60,.30), rgba(255,110,50,.10) 55%, transparent 78%); }
.serve-heat-layer.hot2 { background: radial-gradient(130% 100% at 50% 110%, rgba(255,130,50,.46), rgba(255,80,40,.20) 58%, transparent 82%); }
.serve-heat-layer.hot3 { background: radial-gradient(135% 105% at 50% 112%, rgba(255,95,40,.60), rgba(255,55,45,.30) 60%, rgba(220,30,60,.10) 85%);
  box-shadow: inset 0 -30px 60px rgba(255,70,40,.35); }
.serve-heat-layer.hot4 { background: radial-gradient(140% 115% at 50% 114%, rgba(255,70,35,.74), rgba(255,40,45,.42) 55%, rgba(200,20,70,.18) 88%);
  box-shadow: inset 0 -40px 80px rgba(255,50,35,.5); animation: shHeatWave 1.1s ease-in-out infinite; }
.serve-heat-layer.hot3 { animation: shHeatWave 1.6s ease-in-out infinite; }
@keyframes shHeatWave { 0%,100%{ filter: brightness(1) saturate(1); transform: translateY(0) scaleY(1); }
  50%{ filter: brightness(1.22) saturate(1.25); transform: translateY(-2px) scaleY(1.03); } }

/* ---- Ways / Megaways 變動高度盤面 ---- */
.board.ways-board { display: flex !important; gap: 5px; align-items: center; justify-content: center; }
/* [claude code] 2026-09-01 v3.64 ⛰️ **空軌道**：每一軸都撐成滿高，空的部分畫成淡格。
   使用者:「不定軸, 每次下來軸數都是很突兀 / 能讓玩家有預期嗎」——
   🔴 沒有參考框的話，2 格的軸看起來是「盤面壞了」而不是「這軸開了 2 格」。
   軌道用 `::before` 的 repeating-linear-gradient 畫 → **零 DOM 變動**，
   `reel.children[row]` 的索引完全不受影響（cascade 的補位掉落直接依賴它）。 */
.ways-reel { position: relative; display: flex; flex-direction: column;
  justify-content: center; gap: 5px; }
.ways-reel::before { content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  border-radius: 9px;
  background: repeating-linear-gradient(to bottom,
    rgba(255,255,255,.045) 0 var(--wc, 64px),
    transparent var(--wc, 64px) calc(var(--wc, 64px) + var(--wg, 5px)));
  -webkit-mask-image: linear-gradient(to bottom, #000, #000);   /* 讓圓角吃得到 */ }
/* 符號要壓在軌道上面 */
.ways-reel > .ways-cell { z-index: 1; }

/* 🔴 **整格一起長出**（不是只有 .glyph）—— `.ways-cell` 的底框畫在 cell 上，
   只動 .glyph 的話「格子」會整排先冒出來、符號才慢慢進來，等於長出的是空盒子。
   ⚠️ 通用的 `.cell.cs-drop .glyph` 仍然會跑（它負責符號本身的位移），
      這裡只是**多加一層 cell 的淡入 + 把兩者的 delay 對齊**。 */
.cell.ways-cell.cs-drop { animation: waysGrow var(--drop-ms, 440ms) cubic-bezier(.33,1.06,.5,1) both;
  animation-delay: var(--drop-delay, 0ms); }
.cell.ways-cell.cs-drop .glyph,
.cell.ways-cell.cs-drop::before,
.cell.ways-cell.cs-drop::after { animation-delay: var(--drop-delay, 0ms); }
@keyframes waysGrow { from { opacity: 0; } 55% { opacity: 1; } to { opacity: 1; } }
/* 🔴 清場要**連格子的底框一起淡掉** —— `cs-clear` 通用版只動 `.glyph`，
   底框是畫在 `.cell` 上的 → 不加這條的話「清場」只會讓符號消失、盤面形狀還留在原地，
   那正好是這次要修掉的東西（玩家看不到空軌道，就沒有參考框）。
   ⚠️ cascade 的消除也走 `cs-clear`，但 `waysDrop` 會用 `setWaysCell` 重設 className 把它清掉，
      補位掉落照常顯示，不受影響。 */
.cell.ways-cell.cs-clear { animation: waysFade .26s ease forwards; }
@keyframes waysFade { to { opacity: 0; } }
.ways-cell { position: relative; flex: 0 0 auto; display: flex; align-items: center; justify-content: center;
  background: var(--surface-2); border-radius: 8px; left: auto; right: auto; top: auto; }
/* 消除掉落款（ways / cluster）：WILD/SCATTER 的框做在 .glyph 上（不是 .cell）→ 掉落時框跟符號一起動、不分離、不被裁。 */
.ways-cell.sym-WILD::before, .ways-cell.sym-WILD::after,
.ways-cell.sym-SCATTER::before, .ways-cell.sym-SCATTER::after,
.clus-cell.sym-WILD::before, .clus-cell.sym-WILD::after,
.clus-cell.sym-SCATTER::before, .clus-cell.sym-SCATTER::after { display: none; }
.ways-cell.sym-WILD .glyph, .ways-cell.sym-SCATTER .glyph,
.clus-cell.sym-WILD .glyph, .clus-cell.sym-SCATTER .glyph { box-sizing: border-box; font-size: .78em; padding: 6px; border-radius: 11px; }
.ways-cell.sym-WILD .glyph, .clus-cell.sym-WILD .glyph { box-shadow: inset 0 0 0 2.5px var(--gold), 0 0 7px rgba(255,210,74,.55); }
.ways-cell.sym-SCATTER .glyph, .clus-cell.sym-SCATTER .glyph { box-shadow: inset 0 0 0 2.5px #34e0ff, 0 0 7px rgba(52,224,255,.55); }
.ways-cell.sym-WILD .glyph::after, .ways-cell.sym-SCATTER .glyph::after,
.clus-cell.sym-WILD .glyph::after, .clus-cell.sym-SCATTER .glyph::after {
  position: absolute; top: -6px; left: 50%; transform: translateX(-50%); z-index: 3; pointer-events: none;
  font-size: 8px; font-weight: 900; letter-spacing: .03em; line-height: 1.3; padding: 1px 5px; border-radius: 6px;
  white-space: nowrap; box-shadow: 0 1px 3px rgba(0,0,0,.55); }
.ways-cell.sym-WILD .glyph::after, .clus-cell.sym-WILD .glyph::after { content: "WILD"; background: linear-gradient(#ffe9a6, var(--gold)); color: #2a1d00; }
.ways-cell.sym-SCATTER .glyph::after, .clus-cell.sym-SCATTER .glyph::after { content: "SCATTER"; background: linear-gradient(#bff4ff, #34e0ff); color: #042530; }

/* ---- Cluster 群落消除（N×N CSS grid）---- */
.board.clus-board { display: grid !important; gap: 4px; justify-content: center; }
.clus-cell { position: relative; display: flex; align-items: center; justify-content: center;
  background: var(--surface-2); border-radius: 8px; left: auto; right: auto; top: auto; }

/* ---- 遠古巨獸（colossal 巨型符號 6×4 CSS grid + k×k 方塊 overlay）---- */
.board.colossal-board { display: grid !important; gap: 5px; justify-content: center; align-content: center; }
.col-cell { position: relative; display: flex; align-items: center; justify-content: center;
  left: auto; right: auto; top: auto; border-radius: 10px;
  background: linear-gradient(160deg, #141d33, #0d1424); box-shadow: inset 0 0 0 1px rgba(255,255,255,.05); }
.col-cell .glyph { line-height: 1; }
/* [claude code] 2026-07-12 不賠付的叢林雜物 → 去彩度 + 壓暗，讓「會賠的巨獸」在盤面一眼跳出來 */
.col-low { background: linear-gradient(160deg, #10131c, #0a0d15); opacity: .62; }
.col-low .glyph { filter: grayscale(.85) brightness(.75); }
/* 會賠的 4 隻巨獸 → 醒目：彩色 tier 邊框（下方 col-t0..3）+ 微微放大字，跟雜物拉開對比 */
.col-beast .glyph { transform: scale(1.06); filter: drop-shadow(0 0 4px rgba(255,255,255,.15)); }
.col-beast.col-t0 { background: linear-gradient(160deg, #3a1620, #1a0d12); box-shadow: inset 0 0 0 2px rgba(255,110,90,.55), 0 0 10px rgba(255,90,70,.22); }
.col-beast.col-t1 { background: linear-gradient(160deg, #2a1838, #150c1e); box-shadow: inset 0 0 0 2px rgba(190,120,255,.5), 0 0 9px rgba(170,107,255,.2); }
.col-beast.col-t2 { background: linear-gradient(160deg, #10283a, #0a1622); box-shadow: inset 0 0 0 2px rgba(90,200,255,.5), 0 0 9px rgba(70,180,255,.2); }
.col-beast.col-t3 { background: linear-gradient(160deg, #12321f, #0a1c12); box-shadow: inset 0 0 0 2px rgba(110,230,140,.5), 0 0 9px rgba(90,220,120,.2); }
.col-wild { background: linear-gradient(160deg, #3a2a0a, #241803); box-shadow: inset 0 0 0 2px var(--gold, #ffd24a), 0 0 12px rgba(255,180,40,.4); }
.col-wild .glyph { filter: drop-shadow(0 0 6px rgba(255,210,74,.7)); }
.col-scatter { background: linear-gradient(160deg, #06303c, #04202a); box-shadow: inset 0 0 0 2px #34e0ff, 0 0 12px rgba(52,224,255,.5); }
.col-scatter .glyph { filter: drop-shadow(0 0 7px rgba(52,224,255,.7)); animation: colScatPulse 1s ease-in-out infinite; }
@keyframes colScatPulse { 0%,100% { transform: scale(1); } 50% { transform: scale(1.12); } }
/* k×k 巨型方塊 overlay（靠左踏入；預設暴龍金框 = t0，其餘 tier 換框色）*/
.col-colossal { position: relative; display: flex; align-items: center; justify-content: center; border-radius: 12px; z-index: 5;
  background: radial-gradient(circle at 40% 30%, rgba(255,220,120,.26), rgba(0,0,0,.15));
  box-shadow: inset 0 0 0 3px var(--gold, #ffd24a), 0 0 24px rgba(255,190,60,.5); }
.col-colossal.col-t1 { box-shadow: inset 0 0 0 3px #c58bff, 0 0 24px rgba(170,107,255,.5); }
.col-colossal.col-t2 { box-shadow: inset 0 0 0 3px #5ac8ff, 0 0 24px rgba(70,180,255,.5); }
.col-colossal.col-t3 { box-shadow: inset 0 0 0 3px #6ee68c, 0 0 24px rgba(90,220,120,.5); }
.col-colossal .glyph { filter: drop-shadow(0 0 10px rgba(255,255,255,.35)); }
.col-cell.cs-win, .col-colossal.cs-win { box-shadow: inset 0 0 0 3px var(--win, #ffe169), 0 0 20px var(--win, #ffe169); z-index: 6; }
.col-cell.cs-win .glyph { animation: csWin .34s ease-in-out infinite alternate; }
.col-cell.mb-drop { animation: colDrop .42s cubic-bezier(.33,1.06,.5,1) both; animation-delay: var(--mb-delay, 0ms); }
@keyframes colDrop { from { transform: translateY(-38px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }
.col-colossal.mb-stomp { animation: colStomp .5s cubic-bezier(.2,.9,.25,1.2) both; }
@keyframes colStomp { 0% { transform: scale(.25); opacity: 0; } 60% { transform: scale(1.08); opacity: 1; } 100% { transform: scale(1); } }
/* 遠古巨獸賠付表：會賠 / 不賠 分區 + 符號 chip + 算分說明 */
.col-pay-head { margin: 12px 0 6px; font-size: 13px; font-weight: 800; }
.col-pay-head.yes { color: #6ee68c; }
.col-pay-head.no { color: #ff7a90; }
.col-pay-head.sp { color: var(--gold, #ffd24a); }
.col-symrow { display: flex; flex-wrap: wrap; gap: 6px; margin: 4px 0 2px; }
.col-symchip { display: inline-flex; align-items: center; gap: 3px; padding: 4px 9px; border-radius: 999px;
  font-size: 13px; font-weight: 700; border: 1.5px solid transparent; }
.col-symchip.pay { background: rgba(110,230,140,.14); border-color: rgba(110,230,140,.55); color: #d7ffe4; }
.col-symchip.nopay { background: rgba(255,122,144,.1); border-color: rgba(255,122,144,.4); color: #ffd6dd;
  filter: grayscale(.5); text-decoration: line-through; text-decoration-color: rgba(255,122,144,.7); }
.col-symchip.wild { background: rgba(255,210,74,.13); border-color: rgba(255,210,74,.5); color: #ffe9a6; }
.col-symchip.scat { background: rgba(52,224,255,.12); border-color: rgba(52,224,255,.5); color: #bff4ff; }
.col-howto { font-size: 12.5px; line-height: 1.85; color: var(--mut, #b9c2d6); background: rgba(255,255,255,.03);
  border-left: 3px solid var(--gold, #ffd24a); border-radius: 6px; padding: 9px 11px; margin: 4px 0 2px; }
.col-howto b { color: var(--text, #eef); }

/* ---- 轉盤 Bonus overlay ---- */
.wheel-overlay { position: absolute; inset: 0; z-index: 20; display: none;
  flex-direction: column; align-items: center; justify-content: center; gap: 14px;
  background: radial-gradient(circle at 50% 40%, rgba(40,10,50,.92), rgba(8,8,20,.96));
  border-radius: 14px; padding: 16px; }
.wheel-overlay.show { display: flex; animation: lineIn .3s ease; }
.wheel-title { font-size: 20px; font-weight: 900; color: var(--gold); letter-spacing: 1px;
  text-shadow: 0 0 16px rgba(255,210,74,.7); }
/* 圓形轉盤：旋轉圓盤（conic 分段）+ 固定指針 + 中心軸 */
.wheel-circle { position: relative; width: 248px; height: 248px; max-width: calc(80 * var(--vw)); max-height: calc(80 * var(--vw)); }
.wheel-disc { position: absolute; inset: 0; border-radius: 50%;
  border: 5px solid var(--gold); box-shadow: 0 0 26px rgba(255,210,74,.5), inset 0 0 22px rgba(0,0,0,.45);
  transform: rotate(0deg); will-change: transform; }
.wheel-label { position: absolute; top: 50%; left: 50%; font-size: 12px; font-weight: 900;
  color: #fff; text-shadow: 0 1px 3px rgba(0,0,0,.85); white-space: nowrap; pointer-events: none;
  transition: filter .2s ease; }
.wheel-label.win { filter: drop-shadow(0 0 7px var(--win)) brightness(1.25); font-size: 13px; }
.wheel-hub { position: absolute; top: 50%; left: 50%; width: 36px; height: 36px;
  transform: translate(-50%, -50%); border-radius: 50%; z-index: 3;
  background: radial-gradient(circle at 40% 35%, #ffe9a6, var(--gold) 55%, #8a5a00);
  border: 3px solid #fff; box-shadow: 0 2px 6px rgba(0,0,0,.5); }
.wheel-pointer { position: absolute; top: -8px; left: 50%; transform: translateX(-50%);
  width: 0; height: 0; border-left: 14px solid transparent; border-right: 14px solid transparent;
  border-top: 24px solid var(--win); z-index: 4; filter: drop-shadow(0 2px 3px rgba(0,0,0,.55)); }
.wheel-result { font-size: 22px; font-weight: 900; color: var(--win); min-height: 28px;
  text-shadow: 0 0 14px rgba(255,225,105,.6); }

/* ---- 開寶箱 Pick-em overlay（bothways 款）---- */
.pickme-overlay { position: absolute; inset: 0; z-index: 20; display: none;
  flex-direction: column; align-items: center; justify-content: center; gap: 12px;
  background: radial-gradient(circle at 50% 35%, rgba(16,46,40,.94), rgba(6,10,18,.97));
  border-radius: 14px; padding: 16px; }
.pickme-overlay.show { display: flex; animation: lineIn .3s ease; }
.pickme-title { font-size: 20px; font-weight: 900; color: var(--gold); letter-spacing: 1px;
  text-shadow: 0 0 16px rgba(255,210,74,.7); }
.pickme-sub { font-size: 13px; color: var(--text-soft); }
.pickme-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 8px; width: 100%; max-width: 320px; }
.pickme-chest { aspect-ratio: 1; border-radius: 10px; display: flex; align-items: center; justify-content: center;
  font-size: 26px; background: var(--surface-2); border: 2px solid var(--border); cursor: default;
  transition: transform .12s ease; }
.pickme-chest.opening { transform: scale(1.14); box-shadow: 0 0 16px var(--gold); border-color: var(--gold); }
.pickme-chest.prize { background: linear-gradient(135deg, rgba(212,160,23,.28), rgba(31,138,112,.2));
  border-color: var(--gold); }
.pickme-chest .pc-val { font-size: 12px; font-weight: 900; color: var(--gold); }
.pickme-chest.end { background: linear-gradient(135deg, rgba(220,40,60,.4), rgba(40,8,14,.6));
  border-color: #ff5d6d; box-shadow: 0 0 18px rgba(255,93,109,.7); }
.pickme-collect { font-size: 22px; font-weight: 900; color: var(--win); min-height: 28px;
  text-shadow: 0 0 14px rgba(255,225,105,.6); }
.pickme-collect.bump { animation: wmBump .3s ease; }

/* ---- 淨化光稜：光稜發光 / 雜符被射閃光（mechanic=laser，重用 cs-* 掉落視覺）---- */
.cell.lp-laser { box-shadow: inset 0 0 16px rgba(54,224,255,.85), 0 0 14px rgba(54,224,255,.6); border-radius: 8px; z-index: 4; }
.cell.lp-laser .glyph { animation: lpLaser .42s ease infinite alternate; filter: drop-shadow(0 0 12px #36e0ff); }
.cell.lp-hit { animation: lpHit .32s ease; box-shadow: inset 0 0 14px rgba(255,95,120,.9); border-radius: 8px; }
@keyframes lpLaser { from { transform: scale(1); } to { transform: scale(1.22); } }
@keyframes lpHit { 0% { filter: brightness(1); } 45% { filter: brightness(2.3) drop-shadow(0 0 9px #fff); } 100% { filter: brightness(1); } }
/* 光稜連線（SVG polyline，畫在 #lineLayer）：虛線 —— 青色光暈 + 白色芯，柔和淡入 */
/* [Claude Code 2026-06-28] 閃電由實線改虛線（stroke-dasharray）*/
.bolt { fill: none; stroke: #36e0ff; stroke-width: 3; stroke-linecap: round;
  stroke-dasharray: 7 6; filter: drop-shadow(0 0 5px #36e0ff); opacity: .85; animation: boltFade .3s ease both; }
.bolt-core { fill: none; stroke: #ffffff; stroke-width: 1.3; stroke-linecap: round;
  stroke-dasharray: 7 6; opacity: .9; animation: boltFade .3s ease both; }
@keyframes boltFade { from { opacity: 0; } to { opacity: .88; } }

/* ---- [claude code] 2026-07-11 爆裂礦坑 Boom mine：炸彈落盤幾何爆炸 ---- */
/* 炸彈格點亮（依型別上色：0 直炸=橙 / 1 橫炸=金 / 2 圈炸=紅）*/
.cell.bm-bomb { border-radius: 8px; z-index: 4; box-shadow: inset 0 0 16px rgba(255,150,60,.85), 0 0 14px rgba(255,120,40,.6); }
.cell.bm-bomb .glyph { animation: bmArm .38s ease infinite alternate; filter: drop-shadow(0 0 12px #ff8a3c); }
@keyframes bmArm { from { transform: scale(1); } to { transform: scale(1.2); } }
/* 爆炸範圍逐格閃（--bm-bd 由 JS 設每格延遲 → 由炸彈往外 sweep）*/
.cell.bm-blast { border-radius: 8px; z-index: 3; animation: bmBlast .34s ease both; animation-delay: var(--bm-bd, 0ms); }
@keyframes bmBlast {
  0% { filter: brightness(1); box-shadow: none; }
  40% { filter: brightness(2.4) drop-shadow(0 0 10px #fff); box-shadow: inset 0 0 18px rgba(255,190,90,.95), 0 0 16px rgba(255,120,40,.8); }
  100% { filter: brightness(1); box-shadow: none; }
}
/* 炸彈型別配色（點亮 + 爆炸共用）*/
.cell.bm-bt0 { box-shadow: inset 0 0 16px rgba(255,150,60,.85), 0 0 14px rgba(255,120,40,.6); }   /* 直炸：橙 */
.cell.bm-bt1 { box-shadow: inset 0 0 16px rgba(255,214,90,.85), 0 0 14px rgba(255,190,60,.6); }   /* 橫炸：金 */
.cell.bm-bt2 { box-shadow: inset 0 0 16px rgba(255,90,90,.9), 0 0 15px rgba(255,60,60,.7); }       /* 圈炸：紅 */

/* [claude code] 2026-07-11 🛒 礦車 crash bonus 表演 overlay（蓋在 .board-wrap 上，動態建）——
   礦車沿軌道經過檢查點 ×1/2/3/5/10/30，停在 server 預定倍數處、🪨 石頭擋住。移植 slot_town lp-crash 系統 */
.bm-cart-ov { position: absolute; inset: 0; z-index: 30; display: grid; place-items: center; border-radius: 12px;
  background: rgba(20,10,4,.82); opacity: 0; transition: opacity .26s ease; pointer-events: none; }
.bm-cart-ov.show { opacity: 1; }
.bm-cart-box { text-align: center; width: 100%; }
.bm-cart-title { font-size: 1.05rem; font-weight: 900; color: #ffd24a; margin-bottom: 6px; text-shadow: 0 0 10px rgba(255,150,50,.6); }
.bm-cart-track { position: relative; width: min(86%, 360px); height: 60px; margin: 12px auto 8px; }
.bm-rail { position: absolute; left: 4%; right: 4%; top: 40px; height: 4px; border-radius: 3px;
  background: linear-gradient(90deg, rgba(255,157,60,.25), rgba(255,200,90,.6)); }
.bm-cp { position: absolute; top: 30px; transform: translateX(-50%); text-align: center; }
.bm-cp-dot { display: block; width: 9px; height: 9px; margin: 0 auto; border-radius: 50%;
  background: #4a2f14; border: 1px solid rgba(255,157,60,.5); transition: all .2s; }
.bm-cp-lab { display: block; font-size: .6rem; color: #b88a5a; margin-top: 4px; transition: color .2s; white-space: nowrap; }
.bm-cp.passed .bm-cp-dot { background: #ffce6a; border-color: #fff; box-shadow: 0 0 8px 2px rgba(255,206,106,.85); }
.bm-cp.passed .bm-cp-lab { color: #ffce6a; font-weight: 800; }
.bm-cart { position: absolute; top: 4px; font-size: 1.7rem; transform: translateX(-50%); z-index: 3;
  transition: left .42s cubic-bezier(.4,.1,.5,1); filter: drop-shadow(0 3px 4px rgba(0,0,0,.6)); }
.bm-cart.bm-cart-bump { animation: bmCartBump .4s ease; }
@keyframes bmCartBump { 0% { transform: translateX(-50%); } 28% { transform: translateX(-22%) rotate(6deg); } 100% { transform: translateX(-50%); } }
.bm-rock { position: absolute; top: 10px; font-size: 1.5rem; transform: translateX(-50%) scale(0); opacity: 0; z-index: 2;
  transition: transform .22s cubic-bezier(.34,1.5,.64,1), opacity .22s ease; }
.bm-rock.show { transform: translateX(-50%) scale(1); opacity: 1; }
.bm-cart-val { font-size: clamp(1.5rem, calc(8 * var(--vw)), 2.6rem); font-weight: 900; color: #ff9d3c; text-shadow: 0 0 18px rgba(255,150,50,.8); }
.bm-cart-val.bm-val-pop { animation: bmValPop .45s cubic-bezier(.2,1.4,.4,1), bmValPulse 1s ease-in-out .45s 2; }
@keyframes bmValPop { 0% { transform: scale(.4); opacity: 0; } 60% { transform: scale(1.25); opacity: 1; } 100% { transform: scale(1); } }
@keyframes bmValPulse { 0%,100% { transform: scale(1); } 50% { transform: scale(1.08); } }

/* [claude code] 2026-08-14 v2.93 原本這裡是 `.bm-multbar`（爆裂礦坑專屬的倍率條定位）——
   已合併進通用的 `.game-multbar.pos-row`（見上面）。keyframes `bmChipPop` / `bmChipPopOn` 移到那裡。 */

/* ---- 無盡星河 Infinity：橫向可變軸數盤面 ---- */
/* [claude code] 2026-07-14 修「頁面冒上下捲軸 / 視窗先拉長才表演」：
   ① 高度由 JS 固定（infBoardHeight，以最大格 64 算）→ 不再隨軸數 / 格子縮放而變動，下面的控制列不會被推動。
   ② padding 10px + overflow:hidden → 接上定格的放大(inf-lock scale 1.12)與期待光暈都收在盤面內，
      不會撐出 body 的 scrollHeight（原本 overflow 只擋 x，垂直方向溢出就冒出捲軸）。
   ③ align-items:center → 格子變小時垂直置中留白，不會黏在頂端。 */
.board.inf-board { display: flex; flex-direction: row; align-items: center; justify-content: center;
  gap: 5px; overflow: hidden; padding: 10px 6px; }
.inf-reel { display: flex; flex-direction: column; gap: 4px; flex: 0 0 auto; }
/* ⚠️ 必須覆寫基礎 .cell 的 position:absolute（否則格子全疊在 top:0、reel 高度塌掉只剩一格）—— 比照 .ways-cell/.clus-cell */
.cell.inf-cell { position: relative; display: flex; align-items: center; justify-content: center; border-radius: 8px; }
.inf-reel.inf-grow { animation: infGrow .34s cubic-bezier(.2,.8,.25,1) both; }
@keyframes infGrow { 0% { opacity: 0; transform: translateX(22px) scale(.7); } 100% { opacity: 1; transform: none; } }
/* [claude code] 2026-07-12 星河生長期待表演：慢停翻滾（inf-antic，越長越亮）→ 接上定格 pop（inf-lock）；斷點軸灰掉（inf-breaker） */
.inf-reel.inf-antic { z-index: 3; animation: infAntic .42s ease-in-out infinite;
  box-shadow: 0 0 calc(5px + var(--inf-lvl, 0) * 2.5px) rgba(124,192,255,.6); border-radius: 8px; }
.inf-reel.inf-antic .glyph { animation: infRoll .13s linear infinite; }
@keyframes infAntic { 0%,100% { filter: brightness(1); } 50% { filter: brightness(1.55) drop-shadow(0 0 9px #8fd0ff); } }
@keyframes infRoll { 0% { opacity: .45; transform: translateY(-3px); } 100% { opacity: 1; transform: translateY(0); } }
.inf-reel.inf-lock { animation: infLock .32s cubic-bezier(.2,.9,.25,1.35) both; }
@keyframes infLock { 0% { transform: scale(.7); } 60% { transform: scale(1.12); } 100% { transform: scale(1); } }
.inf-reel.inf-breaker { opacity: .5; filter: grayscale(.65); }

/* ---- 中獎連線高亮（SVG 蓋層）---- */
.board-wrap { position: relative; }
.line-layer { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 5; overflow: visible; }
/* [claude code] 2026-09-01 v3.62 🔴 中獎線的**斷點延伸**(虛線淡色):把「線為什麼停在這裡」畫出來。
   使用者回報:盤上有一顆 ×5 的百搭、中獎線卻停在前一軸 —— 引擎沒算錯(百搭不在那條線經過的格),
   但畫面上線憑空斷掉,玩家沒有任何線索。🔍 本注明細早就這樣畫了,盤面補上同一套語言。 */
.win-line.win-line-stop { stroke-dasharray: 6 6; opacity: .42; stroke-width: 3; }
.win-line { fill: none; stroke: var(--win); stroke-width: 4; stroke-linejoin: round; stroke-linecap: round;
  filter: drop-shadow(0 0 6px var(--win)); opacity: .92; animation: lineIn .4s ease; }
@keyframes lineIn { from { opacity: 0; } to { opacity: .92; } }

/* ---- near-miss 期待停軸（差一個 scatter 就觸發）---- */
.reel.anticipate { animation: anticPulse .5s ease-in-out infinite; z-index: 3; }
@keyframes anticPulse { 0%,100%{ box-shadow: 0 0 0 0 rgba(52,224,255,.5); } 50%{ box-shadow: 0 0 22px 4px rgba(52,224,255,.55); } }
.board-wrap.anticipating .reel:not(.anticipate) { filter: brightness(.5); transition: filter .25s; }

/* ══════ [claude code] 2026-09-10 v4.2 🔥 免費期 / bonus 段：盤面整個換底框 ══════
   使用者：「如果是 FREE SPIN, 能不能換個底框之類的做特別的強化,
            這樣子在領 MEGA WIN 之類也能知道是不是有變色」
         →（v4.3）「**bonus 型的也一起套橘框**」。

   🔴 class 叫 `bonus-mode` 不叫 `free-mode` —— 它涵蓋的不只免費轉：
      HOLD & WIN 重轉 / 礦車 / 轉盤 / 開寶箱 / 深淵之門 / 藏寶圖 / 收集罐 BONUS /
      加碼球雨 / 能量核心放電 / 淨化光稜 crash / 闖關奪寶過關 BONUS / 無盡星河星河彩金。
      共 **20 處**接線（9 免費 + 11 bonus）—— **有 bonus 的款一個都沒有漏**。

   🔴 畫在**盤面**上（不是再加一顆徽章）—— 免費期是整段期間都成立的狀態，
      而畫面上會蓋住小徽章的東西很多（贏分帶佔住訊息帶、中大獎覆蓋層蓋住半個畫面）。
      盤面是「一定看得到的那塊」，而 `.win-overlay` 是半透明的 → 領 MEGA WIN 時橘框照樣透得出來。
   🔴 顏色沿用平台既有的視覺語彙：**免費期 = 橘**（同 `.ui-multbar.fs`），
      不要為這個功能發明第四種顏色（base 金 / 星宮雪球冰藍 / 免費橘）。
   ⚠️ 只動 `.board` 與 `.board-wrap` 的**外框與底色**，不碰格子（`.cell`）——
      碰格子會跟各款自己的中獎高亮 / 黏住 / 清除動畫打架。
   ⚠️ 這裡刻意**不做會動的動畫**（只有很慢的呼吸光暈）：免費期一次十幾轉，
      會跳的東西看十幾次就變吵。 */
body.bonus-mode .board {
  background: linear-gradient(180deg, #2a1405 0%, #1a0c05 60%, #12080a 100%);
  box-shadow: 0 0 0 2px rgba(255, 150, 60, .75), 0 0 22px rgba(255, 122, 60, .45),
    inset 0 0 26px rgba(255, 122, 60, .18);
  animation: fmGlow 2.6s ease-in-out infinite;
}
body.bonus-mode .board-wrap::before {
  content: ""; position: absolute; inset: -8px; border-radius: 16px; pointer-events: none; z-index: 0;
  background: radial-gradient(120% 90% at 50% 0%, rgba(255, 138, 60, .22), rgba(255, 138, 60, 0) 70%);
}
/* 自己畫盤面的款（賓果 / 麻將賓果 / 彈珠 / 闖關奪寶…）沒有 `.board`，
   靠 `.board-wrap::before` 那層光暈一樣看得出來 —— 所以那一條不掛在 `.board` 上。 */
@keyframes fmGlow {
  0%, 100% { box-shadow: 0 0 0 2px rgba(255,150,60,.75), 0 0 22px rgba(255,122,60,.45), inset 0 0 26px rgba(255,122,60,.18); }
  50%      { box-shadow: 0 0 0 2px rgba(255,178,90,.95), 0 0 34px rgba(255,140,70,.70), inset 0 0 30px rgba(255,122,60,.26); }
}
/* ⚠️ 會暈車 / 省電的裝置：只留靜態的橘框，不呼吸 */
@media (prefers-reduced-motion: reduce) {
  body.bonus-mode .board { animation: none; }
}

/* ---- TURBO 加速鈕 ---- */
.turbo-btn.on { border-color: var(--gold); color: var(--gold); box-shadow: 0 0 12px rgba(255,210,74,.5); }

/* ---- 按下 SPIN 立即回饋 ---- */
.btn-spin.pressed { transform: scale(.95); filter: brightness(1.12); }

/* ---- [claude code] 2026-07-29 v2.22 控制列第二排（依使用者：改 slot_town 的做法）----
   SPIN 下面固定一排：[停止條件下拉][🔁 自動][🎲 翻倍]。取代原本的 AUTO 下接浮窗 + 翻倍獨立底座 —— 
   三個都常駐（翻倍未中獎時 disabled）→ 高度固定、不會忽有忽無把版面推來推去。*/
.control-row2 { display: flex; align-items: stretch; justify-content: center; gap: 8px;
  max-width: 420px; margin: 10px auto 0; }
.control-row2 .auto-stop-sel { flex: 1.15 1 0; min-width: 0; background: var(--surface-2); color: var(--text);
  border: 1px solid var(--border); border-radius: 999px; padding: 0 10px; font-size: 13px; height: 42px; cursor: pointer; }
.control-row2 .auto-btn { flex: 1 1 0; height: 42px; padding: 0 10px; white-space: nowrap; }
.control-row2 .gamble-btn { flex: 1.2 1 0; height: 42px; padding: 0 10px; white-space: nowrap; }

/* ---- 任務 / 等級 ---- */
.meta-btn { position: relative; }
.meta-dot { position: absolute; top: 2px; right: 2px; width: 9px; height: 9px; border-radius: 50%;
  background: #ff4d6d; box-shadow: 0 0 6px #ff4d6d; }
.meta-card { width: 360px; max-width: calc(calc(100 * var(--vw)) - 32px); }
.meta-sec { margin-bottom: 18px; }
.meta-sec-head { font-weight: 800; color: var(--text); margin-bottom: 10px; display: flex; align-items: center; gap: 8px; }
.meta-sub { font-size: 12px; color: var(--text-soft); font-weight: 400; margin-left: auto; }
.lvl-badge { background: linear-gradient(135deg, var(--neon), var(--neon-2)); color: #0a0c16; font-weight: 900;
  padding: 2px 10px; border-radius: 999px; font-size: 13px; }
.lvl-bar { height: 12px; background: var(--surface-2); border-radius: 999px; overflow: hidden; border: 1px solid var(--border); }
.lvl-fill { height: 100%; background: linear-gradient(90deg, var(--neon), var(--neon-2)); transition: width .4s ease; }
.lvl-exp { font-size: 12px; color: var(--text-soft); text-align: right; margin: 4px 0 8px; }
.meta-claim { width: 100%; padding: 9px 0; border: none; border-radius: 10px; cursor: pointer; font-weight: 800;
  color: #2a1d00; background: linear-gradient(135deg, #ffe9a6, var(--gold)); }
.meta-claim:disabled { background: var(--surface-2); color: var(--text-mute, #8b91a3); cursor: not-allowed; }
.miss-list { display: flex; flex-direction: column; gap: 8px; }
.miss-row { display: flex; align-items: center; gap: 10px; }
.miss-info { flex: 1; }
.miss-need { font-size: 12px; color: var(--text-soft); margin-bottom: 3px; }
.miss-bar { height: 8px; background: var(--surface-2); border-radius: 999px; overflow: hidden; border: 1px solid var(--border); }
.miss-fill { height: 100%; background: linear-gradient(90deg, var(--neon-2), var(--neon)); }
.miss-claim { min-width: 62px; padding: 7px 10px; border: none; border-radius: 8px; cursor: pointer; font-weight: 800; font-size: 13px;
  color: #2a1d00; background: linear-gradient(135deg, #ffe9a6, var(--gold)); }
.miss-claim:disabled { background: var(--surface-2); color: var(--text-soft); cursor: not-allowed; }
.miss-claim.done { background: transparent; border: 1px solid var(--border); color: var(--get, #16a34a); }
.miss-step { color: var(--text-mute, #8b91a3); font-size: 11px; }
.miss-done-all { text-align: center; color: var(--get, #16a34a); font-weight: 700; padding: 10px 0; }

/* ---- 升級獎勵逐筆列（每筆標明等級、可個別領）---- */
.lvl-claims { display: flex; flex-direction: column; gap: 8px; }
.lvl-claim-none { color: var(--text-mute, #8b91a3); font-size: 13px; padding: 6px 2px; }
.lvl-claim-row { display: flex; align-items: center; gap: 10px; background: var(--surface-2);
  border: 1px solid var(--border); border-radius: 10px; padding: 8px 12px; }
.lcr-label { flex: 1; font-weight: 700; color: var(--text); font-size: 13.5px; }
.lcr-btn { min-width: 92px; padding: 8px 12px; border: none; border-radius: 8px; cursor: pointer; font-weight: 800; font-size: 13px;
  color: #2a1d00; background: linear-gradient(135deg, #ffe9a6, var(--gold)); }
.lcr-btn:hover { filter: brightness(1.05); }


/* ---- [claude code] 2026-09-01 v3.62 賠付表 / 玩法：**一區一張卡**（手機版）----
   使用者:「賠付表, 玩法能像 wolves_pg 做手機版, 放大一點, 每個區域隔開一點」。
   舊版所有段落擠在同一張底上、字級 12~13.5px —— 手機上一片糊、段與段之間沒有界線。
   數值對齊 `wolves_pg/client/src/games/helpPanel.ts` + `panelKit.ts`:
     卡片 padding 14 / gap 12 / 圓角 14 / 1px 邊；內文 16、次階 14.5、註記 13.5；行高 1.68。
   🔴 卡片是 JS 後處理生的(`ptCardify`)——29 款各自的 build 分支一個都不用改。 */
.modal-card.paytable-card { width: min(460px, calc(calc(100 * var(--vw)) - 16px)); }
.paytable-card { padding: 16px 14px; }
#paytable, #rules { display: flex; flex-direction: column; gap: 12px; }
.pt-card { padding: 14px; border-radius: 14px;
  background: var(--surface-2); border: 1px solid var(--border); }
/* 🔴 卡片內第一個 / 最後一個元素不要再帶自己的外距 —— 不然卡片上下會浮出一截空白，
   看起來像「卡片高度不一致」（每張卡的留白會隨裡面放什麼而變）。 */
.pt-card > :first-child { margin-top: 0; }
.pt-card > :last-child { margin-bottom: 0; }
#paytable h4, #rules h4 { margin: 0 0 10px; color: var(--text-soft);
  font-size: 15.5px; line-height: 1.5; font-weight: 700; }
table.pt { font-size: 14.5px; }
table.pt th, table.pt td { padding: 7px 6px; }
table.pt.pt-compact { font-size: 13px; }
table.pt.pt-compact th, table.pt.pt-compact td { padding: 5px 4px; }

/* [claude code] 2026-09-08 v3.92 賠付表**高賠 / 低賠分層**（使用者：「讓人知道下面比較不值錢」）。
   🔴 **顏色不是唯一線索** —— 高賠那幾列另外加左邊框與字重，色弱玩家 / 印出來也分得出來
      （同「顏色是類別不是次序」那條）。 */
table.pt tr.pt-hi td { background: linear-gradient(90deg, rgba(255,207,58,.10), rgba(255,207,58,.03));
  border-left: 2px solid rgba(255,207,58,.55); }
table.pt tr.pt-hi td:first-child { font-weight: 700; color: var(--text); }
table.pt tr.pt-lo td { background: rgba(255,255,255,.015); opacity: .82; }
table.pt tr.pt-lo td:first-child { border-left: 2px solid rgba(255,255,255,.10); }
/* ✕ ＝ 這一檔不算數（不是「賠 0」）—— 壓暗，不要跟真的數字搶注意力 */
table.pt td.pt-x { color: var(--text-soft); opacity: .6; font-weight: 700; }
.pt-card .fs-note { margin: 0; font-size: 14px; line-height: 1.7; }
/* 🔴 玩法那一列改成**上下堆疊**（標題一行、內文一行）——
   舊版是 `92px 1fr` 兩欄，手機上內文只剩一半寬度，中文一行擠不下幾個字。
   wolves_pg 也是堆疊的（標題在上、內文在下）。 */
.rule-row { display: block; padding: 0; border-bottom: none; }
.rule-t { font-size: 15.5px; margin-bottom: 5px; }
.rule-d { font-size: 14.5px; line-height: 1.7; }
.pt-tab { font-size: 15px; padding: 10px 0; }
/* 賠付線圖 / 符號圖這類寬元素在卡片裡要能自己捲，不要把卡片撐出去 */
.pt-card .pt-wrap { overflow-x: auto; }
@media (max-width: 380px) {
  .paytable-card { padding: 12px 10px; }
  .pt-card { padding: 11px; }
  #paytable, #rules { gap: 10px; }
  table.pt { font-size: 13.5px; }
  .rule-d, .pt-card .fs-note { font-size: 13.5px; }
}
/* [claude code] 2026-09-01 v3.66 🐝 花蜜採集：六種花的賠付表（圖示 + 名稱 + 面額）。
   🔴 **一行一種花，圖示放最左邊** —— 玩家是拿盤面上那顆圖示來對照的，
   圖示排在名字後面就要多找一次。面額靠右對齊，六個數字可以直接比大小。 */
.flower-tab { display: flex; flex-direction: column; gap: 6px; margin: 6px 0 10px; }
.flower-cell { display: grid; grid-template-columns: 30px 1fr auto; align-items: center;
  gap: 10px; padding: 7px 10px; border-radius: 10px;
  background: var(--surface-2); border: 1px solid var(--border); }
.flower-cell .fl-glyph { font-size: 22px; line-height: 1; text-align: center; }
.flower-cell .fl-name { font-size: 14px; color: var(--text-soft); }
.flower-cell .fl-val { font-size: 15px; font-weight: 800; color: var(--gold);
  font-variant-numeric: tabular-nums; }

/* ---- 賠付 / 玩法 分頁 ---- */
/* [claude code] 2026-08-17 v3.45 右上角的 `×`(.modal-close, top:10 right:12)是絕對定位,
   會**蓋在分頁鈕上面** —— 中文「賠付表 / 玩法」字短看不出來,切英文 "Paytable / How to play"
   就明顯壓到(使用者截圖回報)。留出 × 的寬度,順便讓那顆按鈕真的按得到。 */
.pt-tabs { display: flex; gap: 8px; margin-bottom: 12px; padding-right: 28px; }
.pt-tab { flex: 1; padding: 8px 0; border: 1px solid var(--border); background: var(--surface-2);
  color: var(--text-soft); border-radius: 8px; cursor: pointer; font-size: 14px; font-weight: 600; }
.pt-tab.active { background: var(--neon-2); color: #08101a; border-color: var(--neon-2); }
.rule-row { display: grid; grid-template-columns: 92px 1fr; gap: 10px; padding: 8px 0; border-bottom: 1px solid var(--border); }
.rule-t { font-weight: 700; color: var(--text); font-size: 13.5px; }
.rule-d { color: var(--text-soft); font-size: 13px; line-height: 1.55; }

/* ==== 賓果（lucky_bingo）：波動檔選擇 + 5×5 卡 + 開球托盤 ==== */
/* [Claude Code 2026-07-06] 底座是輪盤機器，賓果自成一路渲染，這整段是賓果專屬。 */

/* 波動檔選擇（保守 / 標準 / 衝刺）
   [claude code] 2026-09-22 v4.55 🔴 位置從**盤面上方**搬到**金額列底下**（使用者指定）——
   賓果卡是 aspect-ratio 1/1，盤面上方每多一列就把卡往下推一次，手機一屏就看不完。
   搬下來之後要自己對齊金額列那一排（`max-width:480px` + 置中 + 同樣的左右內距）。 */
.bingo-tiers { display: flex; gap: 8px; margin: 0 auto 9px; max-width: 480px; padding: 0 4px; }
.bingo-tier { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 3px;
  padding: 8px 4px; border: 1.5px solid var(--border); border-radius: 12px; cursor: pointer;
  background: var(--surface-2); color: var(--text-soft); transition: transform .1s, box-shadow .15s, border-color .15s; }
.bingo-tier:hover:not(:disabled) { transform: translateY(-1px); border-color: var(--neon-2); }
.bingo-tier:disabled { opacity: .55; cursor: default; }
.bingo-tier.sel { border-color: var(--neon-2); color: var(--text);
  background: linear-gradient(135deg, rgba(91,139,255,.28), rgba(176,107,255,.22));
  box-shadow: 0 0 0 1px var(--neon-2), 0 4px 16px rgba(91,139,255,.35); }
.bingo-tier .bt-name { font-weight: 800; font-size: 14px; }
.bingo-tier .bt-draw { font-size: 11px; opacity: .85; }
/* v4.55 實測值兩行：命中率（這一檔多久中一次）+ RTP（三檔幾乎一樣 = 挑哪顆不影響期望值）*/
/* 🔴 class 叫 .bt-meas 不叫 .bt-stat —— `.bt-stat` 已經是開球托盤的狀態列（本檔 1758 行，沒有層級限定）。 */
.bingo-tier .bt-meas { display: flex; flex-direction: column; align-items: center; gap: 1px; margin-top: 2px; }
.bingo-tier .bt-hit { font-size: 10px; color: var(--neon-2); font-variant-numeric: tabular-nums; }
.bingo-tier .bt-rtp { font-size: 10px; opacity: .62; font-variant-numeric: tabular-nums; }

/* 5×5 賓果卡 */
.board.bingo-board { position: relative; display: grid; gap: 6px; padding: 8px; aspect-ratio: 1 / 1;
  background: linear-gradient(160deg, #1a1f3a, #141830); border-radius: 14px;
  box-shadow: inset 0 0 0 1px var(--border); }
.bingo-cell { position: relative; display: flex; align-items: center; justify-content: center;
  border-radius: 10px; background: #10132a; box-shadow: inset 0 0 0 1px #262c4c;
  font-weight: 800; font-size: clamp(14px, calc(5 * var(--vw)), 26px); color: var(--text);
  transition: transform .12s, background .18s, box-shadow .18s; user-select: none; }
.bingo-cell .bc-num { transition: color .18s; }
.bingo-cell.free { color: var(--gold); background: linear-gradient(160deg, #2a2340, #1c1832);
  box-shadow: inset 0 0 0 1.5px var(--gold), 0 0 10px rgba(255,210,74,.3); }
.bingo-cell.free .bc-free { font-size: 1.1em; text-shadow: 0 0 8px rgba(255,210,74,.7); }
/* 標記態：開球命中（[Claude Code 2026-07-08] 拿掉常駐 animation → 只有剛命中那格 .just-marked 才彈跳，
   否則每開一顆球整張卡的 marked 格都會重播一次彈跳，整個盤面跟著晃） */
.bingo-cell.marked { background: linear-gradient(160deg, #24407a, #1c3060);
  box-shadow: inset 0 0 0 1.5px var(--neon), 0 0 10px rgba(91,139,255,.4); color: #eaf1ff; }
.bingo-cell.just-marked { animation: bingoMark .3s ease; }
@keyframes bingoMark { 0% { transform: scale(.7); } 60% { transform: scale(1.12); } 100% { transform: scale(1); } }
/* 命中金球 */
.bingo-cell.gold { background: linear-gradient(160deg, #4a3a12, #6a4e14);
  box-shadow: inset 0 0 0 2px var(--gold), 0 0 14px rgba(255,210,74,.6); color: #fff3c8; }
.bingo-cell.gold::after { content: "🟡"; position: absolute; top: 2px; right: 3px; font-size: .5em; }
/* 完成線內的格：外光暈脈動（[Claude Code 2026-07-08] 放慢 1s→2s、收斂光暈範圍，減少「一直閃」的晃感） */
.bingo-cell.in-line { box-shadow: inset 0 0 0 2px var(--win), 0 0 12px rgba(255,225,105,.45);
  animation: bingoLine 2s ease-in-out infinite alternate; z-index: 2; }
@keyframes bingoLine { from { box-shadow: inset 0 0 0 2px var(--win), 0 0 8px rgba(255,225,105,.32); }
  to { box-shadow: inset 0 0 0 2px var(--win), 0 0 15px rgba(255,225,105,.6); } }

/* [Claude Code 2026-07-10] 做法 B — 差一格：這格再被開到就完成一條線。慢速脈動描邊，把期待感留在缺口上。
   [claude code] 2026-07-16 🔴 修「誤亮」（同 mjbingo v1.73 鐵則：提示樣式不可把未中格弄得像已亮）：
   原本 to 段帶外光暈 0 0 14px —— 未標記格是全亮底，掛上金框+外光暈看起來就跟 .in-line（已完成線）幾乎一樣
   → 玩家誤判它已中，結算拿掉時又「暗一下」。改成**只有內描邊脈動、無外光暈**，一眼就是「提示」不是「已中」。
   （.near 現在只在開球途中由 renderBingoCard(revealing=true) 套；結算 render 不套，收尾無跳動。） */
.bingo-cell.near { animation: bingoNear 1.1s ease-in-out infinite alternate; z-index: 3; }
@keyframes bingoNear {
  from { box-shadow: inset 0 0 0 2px rgba(255,225,105,.3); }
  to   { box-shadow: inset 0 0 0 2.5px rgba(255,225,105,.75); }
}

/* [Claude Code 2026-07-10] 做法 A — 連線掃光：完成線疊一條光束，看得出「這 5 格是一條線」。
   .bline 的 top/left/width/transform 由 JS（bingoLineStyle）算好塞進 style；
   .sweep = 這一球剛完成的線 → clip-path 由左掃到右現形一次，之後常駐。 */
.bingo-lines { position: absolute; inset: 8px; pointer-events: none; z-index: 4; }
.bline { position: absolute; height: 5px; border-radius: 999px; transform-origin: 50% 50%;
  background: linear-gradient(90deg, rgba(255,225,105,0), var(--win) 18%, #fff 50%, var(--win) 82%, rgba(255,225,105,0));
  box-shadow: 0 0 10px rgba(255,225,105,.75), 0 0 22px rgba(255,225,105,.35); opacity: .75; }
.bline.sweep { animation: bingoSweep .5s ease-out; }
@keyframes bingoSweep {
  0%   { clip-path: inset(0 100% 0 0); opacity: 1; filter: brightness(1.7); }
  70%  { clip-path: inset(0 0 0 0);    opacity: 1; filter: brightness(1.7); }
  100% { clip-path: inset(0 0 0 0);    opacity: .75; filter: none; }
}
@media (prefers-reduced-motion: reduce) {
  .bingo-cell.near, .bline.sweep { animation: none !important; }
}

/* 開球托盤 */
.bingo-tray { margin-top: 10px; padding: 10px; border-radius: 12px;
  background: var(--surface); box-shadow: inset 0 0 0 1px var(--border); }
.bt-current-wrap { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
.bt-current-label { font-size: 12px; color: var(--text-soft); font-weight: 700; }
.bt-current { min-width: 46px; height: 46px; padding: 0 6px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center; font-weight: 900; font-size: 22px;
  color: #08101a; background: radial-gradient(circle at 35% 30%, #cfe0ff, #7ea3ff);
  box-shadow: 0 3px 10px rgba(91,139,255,.5); }
.bt-current .bball.gold { color: #4a2f00; }
.bt-current .bball { position: relative; display: inline-flex; align-items: center; }
.bt-stat { flex: 1; text-align: right; font-size: 13px; color: var(--text-soft); }
.bt-stat b { color: var(--win); font-size: 15px; }
/* 已開球列 */
.bt-drawn { display: flex; flex-wrap: wrap; gap: 4px; max-height: 74px; overflow-y: auto; }
.bd-chip { min-width: 22px; height: 22px; padding: 0 4px; border-radius: 999px;
  display: inline-flex; align-items: center; justify-content: center; font-size: 11px; font-weight: 700;
  background: #10132a; color: var(--text-soft); box-shadow: inset 0 0 0 1px #2a3050; }
.bd-chip.hit { background: #24407a; color: #eaf1ff; box-shadow: inset 0 0 0 1px var(--neon); }
.bd-chip.gold { background: #6a4e14; color: #fff3c8; box-shadow: inset 0 0 0 1px var(--gold); }

/* 賓果賠付表小標 */
.bingo-pt-head { margin-top: 12px !important; color: var(--neon-2); }

/* ===== [claude code] 2026-07-11 夜市麻將賓果（mjbingo）：5×5/6×6 洗牌翻牌 + 金牌 ===== */
/* 控制列：盤面 + 賠付檔 */
.mj-controls { display: flex; flex-direction: column; gap: 8px; margin: 4px 0 10px; }
.mj-row { display: flex; align-items: stretch; gap: 8px; }
.mj-row-label { align-self: center; min-width: 34px; font-size: 12px; font-weight: 800; color: var(--text-soft); }
.mj-opt { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
  padding: 8px 4px; border: 1.5px solid var(--border); border-radius: 12px; cursor: pointer;
  background: var(--surface-2); color: var(--text-soft); font-weight: 800; font-size: 14px;
  transition: transform .1s, box-shadow .15s, border-color .15s; }
.mj-opt:hover:not(:disabled) { transform: translateY(-1px); border-color: var(--neon-2); }
.mj-opt:disabled { opacity: .55; cursor: default; }
.mj-opt.sel { border-color: var(--neon-2); color: var(--text);
  background: linear-gradient(135deg, rgba(47,164,106,.30), rgba(70,201,138,.22));
  box-shadow: 0 0 0 1px var(--neon-2), 0 4px 16px rgba(47,164,106,.35); }
.mj-opt .mo-name { font-weight: 800; font-size: 14px; }
.mj-opt .mo-sub { font-size: 11px; opacity: .85; font-weight: 700; }

/* 盤面（麻將桌氈綠底）*/
.board.mj-board { position: relative; display: grid; gap: 6px; padding: 8px; aspect-ratio: 1 / 1;
  background: radial-gradient(circle at 50% 20%, #16603f, #0d3b28 70%), #0d3b28;
  border-radius: 14px; box-shadow: inset 0 0 0 1px rgba(255,255,255,.06), inset 0 0 30px rgba(0,0,0,.35); }
.board.mj-board.mj-shuffling { animation: mjShuffle .34s ease-in-out; }
@keyframes mjShuffle { 0%,100% { transform: none; } 25% { transform: translateX(-3px) rotate(-.4deg); }
  50% { transform: translateX(3px) rotate(.4deg); } 75% { transform: translateX(-2px); } }

/* [claude code] 2026-07-11 麻將牌永遠亮牌面（象牙白 + 立體邊）；抽到才「亮起來」(.lit)，未抽到開牌中變暗 (.dim)。 */
.mj-cell { position: relative; display: flex; align-items: center; justify-content: center;
  border-radius: 9px; user-select: none; transition: transform .12s, box-shadow .18s, opacity .18s, filter .18s;
  color: #1b2330; font-weight: 800; overflow: hidden;
  background: linear-gradient(158deg, #fbf6e9 0%, #efe6d0 62%, #e2d4b6 100%);
  box-shadow: inset 0 2px 0 rgba(255,255,255,.8), inset 0 -5px 7px rgba(140,120,80,.35), 0 2px 5px rgba(0,0,0,.35); }
.mj-cell.sm { border-radius: 7px; }
/* [claude code] 2026-07-14 v1.71 未抽到 = 暗（基準狀態：桌面翻正後一開始就是暗的，抽中才 .lit 亮起來）。
   調得比原本更暗一點讓「亮起來」有感，但牌面仍看得清（是翻正的牌、不是蓋牌）。 */
.mj-cell.dim { opacity: .55; filter: saturate(.62) brightness(.8); }
.mj-cell.lit { opacity: 1; filter: none; z-index: 2;
  box-shadow: inset 0 2px 0 rgba(255,255,255,.9), inset 0 0 0 2px var(--gold), 0 0 12px rgba(255,207,58,.55), 0 2px 5px rgba(0,0,0,.35); }
.mj-cell.just-lit { animation: mjLit .32s ease; z-index: 3; }
@keyframes mjLit { 0% { transform: scale(.82); } 55% { transform: scale(1.12); } 100% { transform: scale(1); } }

/* 牌面內容：字牌 / 萬 / 花牌 = 字；筒 / 條 / 白板 = SVG（.mj-pip） */
.mj-honor { font-size: clamp(17px, calc(6.2 * var(--vw)), 32px); line-height: 1; font-weight: 900; text-shadow: 0 1px 0 rgba(255,255,255,.5); }
.mj-cell.sm .mj-honor { font-size: clamp(12px, calc(4 * var(--vw)), 22px); }
.mj-man { display: flex; flex-direction: column; align-items: center; line-height: .96; }
.mj-man .mm-n { font-size: clamp(13px, calc(4.6 * var(--vw)), 23px); font-weight: 900; color: #1b2330; }
.mj-man .mm-s { font-size: clamp(9px, calc(3.2 * var(--vw)), 15px); font-weight: 900; color: #c0392b; letter-spacing: -.04em; }
.mj-cell.sm .mj-man .mm-n { font-size: clamp(10px, calc(3.2 * var(--vw)), 17px); }
.mj-cell.sm .mj-man .mm-s { font-size: clamp(7px, calc(2.2 * var(--vw)), 11px); }
.mj-pip { width: 74%; height: 74%; display: block; }
.mj-cell.mj-red .mj-honor { color: #c62828; }
.mj-cell.mj-green .mj-honor { color: #1f8f4e; }
.mj-cell.mj-flower .mj-honor { color: #d9720c; }

/* 差一格：這格再被開到就完成一條線 → 金色脈動描邊（只在開牌中）。
   [claude code] 2026-07-14 v1.72 🔴 修「錯誤亮起」：原本 .near 是 opacity:1; filter:none;（＝把「未抽到」的格弄成全亮），
   看起來就像被抽中了（畫面上亮的格數 > 已開張數）；結算後 remove("near") 又讓它們掉回 .dim → 「最後暗一下把錯的暗回去」。
   [claude code] 2026-07-14 v1.73 再修殘留亮度差：v1.72 讓 .near「亮一點點」（.68）仍比一般暗格（.55）亮 → 結算不套 near 時
   會掉回 .55，就是使用者看到的「暗格再回到一致暗度」的亮度差。**改成完全不動亮度**（不覆寫 opacity/filter，
   一律沿用 .dim 的暗度），差一格只用「金色脈動描邊」表示 → 結算前後暗格亮度完全一致，不再有那一下。
   ⚠️ 鐵則：任何「提示 / 期待」樣式都**不可以改未抽到格的亮度**，只能加描邊 / 光暈，否則玩家會誤判已開張數、且結算會跳。 */
.mj-cell.near { animation: mjNear 1.1s ease-in-out infinite alternate; z-index: 3; }
@keyframes mjNear { from { box-shadow: inset 0 0 0 2px rgba(255,207,58,.55), 0 2px 5px rgba(0,0,0,.35); }
  to { box-shadow: inset 0 0 0 3px var(--gold), 0 0 16px rgba(255,207,58,.9), 0 2px 5px rgba(0,0,0,.35); } }

/* 金牌：金色牌面 + ×N 角標 */
.mj-cell.mj-gold { background: linear-gradient(158deg, #fff3c8 0%, #ffd868 55%, #e9b62e 100%);
  box-shadow: inset 0 2px 0 rgba(255,255,255,.9), inset 0 0 0 2px #e9a72e, 0 0 16px rgba(255,207,58,.85), 0 2px 5px rgba(0,0,0,.35); }
.mj-cell .mj-goldbadge { position: absolute; top: 1px; right: 3px; font-size: clamp(8px,calc(2.4 * var(--vw)),12px); font-weight: 900; color: #7a4f00; z-index: 2; }
/* 完成線內的格：金色外光暈脈動 */
.mj-cell.in-line { z-index: 2; animation: bingoLine 2s ease-in-out infinite alternate; }

/* 開牌托盤走賓果托盤樣式（.bingo-tray）；補目前牌/記錄 chip 的麻將牌縮圖 */
.mj-current.bt-current { border-radius: 8px; background: linear-gradient(158deg, #fbf6e9, #e2d4b6); color: #1b2330;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.7), 0 2px 6px rgba(0,0,0,.4); }
.mj-current .mj-cur-face { display: inline-flex; align-items: center; justify-content: center; width: 100%; height: 100%; position: relative; }
.mj-current .mj-cur-face.gold { filter: drop-shadow(0 0 3px rgba(255,207,58,.9)); }
.mj-current .mj-pip { width: 76%; height: 76%; }
.mj-current .mj-honor { font-size: 22px; }
.mj-current .mj-man .mm-n { font-size: 16px; } .mj-current .mj-man .mm-s { font-size: 10px; }
.mj-current .mj-goldbadge { font-size: 9px; top: 0; right: 1px; }
/* [claude code] 2026-08-17 v3.51 v3.49 曾把手牌列改成固定高 74px（為了讓「夾盤面」量到穩定的托盤高度）——
   夾盤面已移除 → 這裡也還原成原本的「有幾張就多高」（上限仍是 `.bt-drawn` 的 max-height: 74px + 捲動）。 */
.mj-record .mj-chip { position: relative; width: 26px; height: 30px; min-width: 26px; padding: 0; border-radius: 5px;
  display: inline-flex; align-items: center; justify-content: center; overflow: hidden;
  background: linear-gradient(158deg, #fbf6e9, #e6d8bd); color: #1b2330;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.7), 0 1px 2px rgba(0,0,0,.35); }
/* [claude code] 2026-07-14 v1.69 手牌金牌 +N 角標改「絕對定位小角標」塞進 chip 角落（原本 inline 會把 中+1 撐出格外）。 */
.mj-record .mj-chip .mj-goldbadge { position: absolute; top: 0; right: 0; font-size: 8px; line-height: 1;
  padding: 0 1px; font-weight: 900; color: #7a4f00; z-index: 2; }
.mj-record .mj-chip.gold { background: linear-gradient(158deg, #fff3c8, #ffd868); box-shadow: inset 0 0 0 1px #e9a72e, 0 0 6px rgba(255,207,58,.6); }
.mj-record .mj-chip .mj-pip { width: 82%; height: 82%; }
.mj-record .mj-chip .mj-honor { font-size: 15px; }
.mj-record .mj-chip .mj-man .mm-n { font-size: 11px; } .mj-record .mj-chip .mj-man .mm-s { font-size: 7px; }

/* [claude code] 2026-07-14 蓋牌（背面）：竹紋玉綠牌背，跟牌桌氈綠區隔（比桌面亮、帶織紋 + 內框）。 */
.mj-cell.mj-back {
  background: linear-gradient(158deg, #1f7d58 0%, #135c3f 60%, #0f4c35 100%);
  box-shadow: inset 0 2px 0 rgba(255,255,255,.18), inset 0 -4px 6px rgba(0,0,0,.3),
    inset 0 0 0 1.5px rgba(255,255,255,.13), 0 2px 5px rgba(0,0,0,.4);
}
.mj-back-art { width: 58%; height: 58%; border-radius: 4px;
  background: repeating-linear-gradient(45deg, rgba(255,255,255,.11) 0 3px, transparent 3px 6px),
    repeating-linear-gradient(-45deg, rgba(0,0,0,.10) 0 3px, transparent 3px 6px);
  box-shadow: inset 0 0 0 1.5px rgba(255,255,255,.24); }
/* [claude code] 2026-07-14 翻牌動畫：蓋牌 → 翻面亮起（rotateY 翻過來）。 */
.mj-cell.just-flip { animation: mjFlip .36s ease; z-index: 3; }
@keyframes mjFlip {
  0%   { transform: perspective(320px) rotateY(-86deg); filter: brightness(1.5); }
  55%  { transform: perspective(320px) rotateY(9deg); }
  100% { transform: perspective(320px) rotateY(0); filter: none; }
}
/* [claude code] 2026-07-14 換桌：整盤淡出再淡入（重發一桌）。 */
.board.mj-board.mj-dealout { animation: mjDealOut .24s ease forwards; }
.board.mj-board.mj-dealin { animation: mjDealIn .3s ease; }
@keyframes mjDealOut { to { opacity: .15; transform: scale(.96); } }
@keyframes mjDealIn { from { opacity: .15; transform: scale(.96); } to { opacity: 1; transform: none; } }

/* [claude code] 2026-07-14 開局儀式列（洗牌 / 換桌）：對蓋牌盤面播表演 */
.mj-ritual { justify-content: center; gap: 10px; }
.mj-ritual-btn { flex: 1; max-width: 160px; padding: 8px 6px; border-radius: 10px; cursor: pointer;
  font-weight: 800; font-size: 13px; background: var(--surface-2); color: var(--text-soft); border: 1.5px solid var(--border);
  transition: transform .1s, border-color .15s, color .15s; }
.mj-ritual-btn:hover:not(:disabled) { transform: translateY(-1px); border-color: var(--neon-2); color: var(--text); }
.mj-ritual-btn:disabled { opacity: .5; cursor: default; }

/* [claude code] 2026-07-14 麻將盤完成線：紅線（比黃線在象牙牌面上清楚），v1.68 依回饋「再淡一點」→ 降透明度/細一點/柔光。 */
.mj-board .bline { height: 5px; opacity: .72;
  background: linear-gradient(90deg, rgba(255,90,110,0), #ff5c74 16%, #ff8a9c 50%, #ff5c74 84%, rgba(255,90,110,0));
  box-shadow: 0 0 0 1px rgba(70,0,12,.4), 0 0 7px rgba(255,80,100,.55); }

/* [claude code] 2026-07-14 v1.68 下面的「手牌」：先發蓋著的牌（玉綠背），開牌時逐張翻面。 */
.mj-record .mj-chip.mj-chip-back { background: linear-gradient(158deg, #1f7d58, #0f4c35);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 2px rgba(0,0,0,.4); }
.mj-record .mj-chip.mj-chip-back .mj-back-art { width: 62%; height: 62%; }
.mj-record .mj-chip.mj-chip-flip { animation: mjChipFlip .34s ease; }
@keyframes mjChipFlip {
  0%   { transform: perspective(220px) rotateY(-82deg); filter: brightness(1.5); }
  55%  { transform: perspective(220px) rotateY(8deg); }
  100% { transform: perspective(220px) rotateY(0); filter: none; }
}
/* [claude code] 2026-07-14 v1.69 發牌：蓋牌一張一張「放上去」（由上滑入 + 放大到定位）。 */
.mj-record .mj-chip.mj-chip-deal { animation: mjChipDeal .2s ease; }
@keyframes mjChipDeal {
  0%   { transform: translateY(-14px) scale(.7); opacity: 0; }
  100% { transform: translateY(0) scale(1); opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .mj-cell.near, .mj-cell.just-lit, .mj-cell.just-flip, .board.mj-board.mj-shuffling,
  .board.mj-board.mj-dealout, .board.mj-board.mj-dealin, .mj-cell.in-line,
  .mj-record .mj-chip.mj-chip-flip, .mj-record .mj-chip.mj-chip-deal { animation: none !important; }
}

/* [claude code] 2026-07-11 「現在幾倍」倍率徽章（賓果 + 麻將賓果共用）：累計金球 / 金牌 → 目前總倍率。 */
.bt-multi-wrap { display: inline-flex; align-items: baseline; gap: 3px;
  padding: 3px 9px; border-radius: 999px; background: rgba(255,207,58,.10); box-shadow: inset 0 0 0 1px rgba(255,207,58,.28); }
.bt-multi-label { font-size: 11px; font-weight: 700; color: var(--text-soft); }
.bt-multi { font-size: 17px; font-weight: 900; color: var(--text-soft); transition: color .18s; }
.bt-multi.hot { color: var(--gold); text-shadow: 0 0 8px rgba(255,207,58,.6); }
.bt-multi-suffix { font-size: 11px; font-weight: 700; color: var(--text-soft); }
.bt-multi.bump { animation: mbBump .28s ease; }
@keyframes mbBump { 0% { transform: scale(1); } 45% { transform: scale(1.35); } 100% { transform: scale(1); } }
/* 賓果 stat 靠右時保留一點空間給倍率徽章 */
.bingo-tray .bt-current-wrap { flex-wrap: wrap; }

/* [claude code] 2026-07-10 梨園變臉（faceoff）
   👏 觀眾：金光脈動（他是觸發者，要最醒目）
   🎭 變臉：被翻的格子沿 Y 軸翻牌，翻到背面時 JS 換掉 glyph → 看起來就是「一瞬間換了張臉」 */
.cell.fo-aud { z-index: 5; }
.cell.fo-aud .glyph { animation: foAud .45s ease-in-out infinite alternate; }
@keyframes foAud { from { transform: scale(1); filter: drop-shadow(0 0 2px rgba(255,210,74,.5)); }
                   to   { transform: scale(1.22); filter: drop-shadow(0 0 12px rgba(255,210,74,.95)); } }
/* 落定時彈一下 + 金光，強調「這張臉定住了」 */
.cell.fo-landed .glyph { animation: foLand .26s ease-out; }
@keyframes foLand {
  0%   { transform: scale(1.35); filter: drop-shadow(0 0 14px rgba(255,210,74,.9)); }
  100% { transform: scale(1);    filter: none; }
}
.win-banner .fo-mult { color: #ffd24a; font-weight: 900; text-shadow: 0 0 10px rgba(255,210,74,.55); }

/* [claude code] 2026-07-10 觀眾喝采加倍：第 2 位觀眾起逐一點亮，每點亮一位就把臉譜那份再疊一倍。
   fo-cheer 是「這一位剛喊出來」的一次性爆閃，結束後留在 fo-aud 的常態脈動上。 */
.cell.fo-cheer { z-index: 6; }
.cell.fo-cheer .glyph { animation: foCheer .34s ease-out; }
@keyframes foCheer {
  0%   { transform: scale(1);    filter: drop-shadow(0 0 4px rgba(255,210,74,.6)); }
  45%  { transform: scale(1.75); filter: drop-shadow(0 0 20px rgba(255,210,74,1)); }
  100% { transform: scale(1.22); filter: drop-shadow(0 0 12px rgba(255,210,74,.95)); }
}
/* 倍率數字：每跳一檔彈出來一次，比原本的 fo-mult 更大更亮 */
.win-banner .fo-mult-big { display: inline-block; font-size: 1.4em; animation: foMultPop .3s ease-out; }
@keyframes foMultPop {
  0%   { transform: scale(.55); opacity: .25; }
  60%  { transform: scale(1.28); opacity: 1; }
  100% { transform: scale(1); }
}
/* 加倍過程中的贏分數字：轉金 + 發光，跟平常的白字分開 */
#winMeter.fo-ramp { color: #ffd24a; text-shadow: 0 0 16px rgba(255,210,74,.75); }
/* 錢飛進來的那一下：贏分被「撞」一下（比一般 bump 更重），強調錢是從觀眾那邊進來的 */
#winMeter.hit { animation: wmHit .32s ease-out; }
@keyframes wmHit {
  0%   { transform: scale(1); }
  35%  { transform: scale(1.42); filter: drop-shadow(0 0 16px rgba(255,210,74,1)); }
  100% { transform: scale(1); }
}
/* 從觀眾格飛向贏分的「+金額」（fixed；起點由 JS 給，transform 位移到 meter） */
.fo-fly {
  position: fixed; z-index: 60; pointer-events: none; white-space: nowrap;
  font-size: 21px; font-weight: 900; color: #ffd24a; font-variant-numeric: tabular-nums;
  text-shadow: 0 0 14px rgba(255,210,74,.95), 0 2px 5px rgba(0,0,0,.7);
  transform: translate(-50%,-50%);
  transition-property: transform, opacity;
  transition-timing-function: cubic-bezier(.34,.85,.3,1), ease-in;
  animation: foFlyFade .1s ease-out;   /* 冒出來時彈一下 */
}
@keyframes foFlyFade { from { opacity: 0; } to { opacity: 1; } }

/* =====================================================================
   [claude code] 2026-07-11 招財彈珠（plinko）：釘板落球獨立盤面 + 球數選鈕 + 碎片/收集罐托盤
   ===================================================================== */
/* 球數選鈕列（取代單注 stepper） */
.plink-controls { display: flex; flex-direction: column; gap: 8px; margin: 4px 0 10px; }
.plink-row { display: flex; align-items: stretch; gap: 8px; }
.plink-row-label { align-self: center; min-width: 34px; font-size: 12px; font-weight: 800; color: var(--text-soft); }
.plink-opt { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px;
  padding: 8px 4px; border: 1.5px solid var(--border); border-radius: 12px; cursor: pointer;
  background: var(--surface-2); color: var(--text-soft); transition: transform .1s, box-shadow .15s, border-color .15s; }
.plink-opt:hover:not(:disabled) { transform: translateY(-1px); border-color: var(--neon-2); }
.plink-opt:disabled { opacity: .55; cursor: default; }
.plink-opt.sel { border-color: var(--neon-2); color: var(--text);
  background: linear-gradient(135deg, rgba(255,93,143,.28), rgba(255,179,26,.18));
  box-shadow: 0 0 0 1px var(--neon-2), 0 4px 16px rgba(255,93,143,.32); }
.plink-opt .po-n { font-weight: 900; font-size: 18px; }
.plink-opt .po-sub { font-size: 10px; opacity: .8; font-weight: 700; }
.plink-cost { text-align: center; font-size: 12px; color: var(--text-soft); }
.plink-cost b { color: var(--text); } .plink-cost .pc-cost { color: var(--gold); font-size: 14px; }

/* 盤面：#board 覆寫成 block + 絕對定位子層 */
.board.plink-board { display: block; position: relative; width: 100%; aspect-ratio: 13 / 15;
  background: radial-gradient(circle at 50% 10%, #1b2440, #0a0e1c 78%); border-radius: 14px; padding: 0;
  overflow: hidden; box-shadow: inset 0 0 0 1px rgba(255,255,255,.05), 0 8px 26px rgba(0,0,0,.4); }
/* 釘板（裝飾） */
.plink-pegs { position: absolute; left: 4%; right: 4%; top: 9%; height: 58%;
  display: flex; flex-direction: column; justify-content: space-between; pointer-events: none; }
.plink-peg-row { display: flex; justify-content: space-between; }
.plink-peg-row.odd { padding: 0 3.8%; }
.plink-peg { width: 6px; height: 6px; border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #fff, #8a93b5); box-shadow: 0 0 4px rgba(255,255,255,.3); }
/* 中間碎片收集器（移到左側，球會被導過來撞它） */
.plink-collector { position: absolute; left: 22%; top: 41%; transform: translateX(-50%); z-index: 5;
  display: flex; align-items: center; gap: 5px; padding: 4px 13px; border-radius: 999px; pointer-events: none;
  background: rgba(255,93,143,.18); box-shadow: inset 0 0 0 1.5px rgba(255,93,143,.6), 0 0 12px rgba(255,93,143,.3);
  font-size: 12px; font-weight: 800; color: #ffdbe6; transition: box-shadow .15s; }
.plink-collector .pc-ico { font-size: 16px; }
.plink-collector.hit { animation: pcHit .5s cubic-bezier(.3,1.6,.5,1); }
@keyframes pcHit {
  0%   { transform: translateX(-50%) scale(1); }
  30%  { box-shadow: inset 0 0 0 2.5px #fff, 0 0 30px rgba(255,93,143,1); transform: translateX(-50%) scale(1.42) rotate(-7deg); }
  55%  { transform: translateX(-50%) scale(.9) rotate(4deg); }
  100% { transform: translateX(-50%) scale(1); } }
.plink-collector.hit-big { box-shadow: inset 0 0 0 2.5px var(--gold), 0 0 30px rgba(255,210,74,.95); color: #fff3c8;
  animation: pcHitBig .55s ease infinite alternate; }
@keyframes pcHitBig { from { transform: translateX(-50%) scale(1); } to { transform: translateX(-50%) scale(1.16); } }
/* 撞擊迸出的碎片粒子 */
.plink-particle { position: absolute; width: 9px; height: 9px; border-radius: 50%; z-index: 6; pointer-events: none;
  transform: translate(-50%, -50%);
  background: radial-gradient(circle at 35% 30%, #fff, #ff5d8f 70%); box-shadow: 0 0 7px rgba(255,93,143,.9); }
/* 球落格 → 飛一顆「🍬+N」到收集罐（fixed，起點終點由 JS 算） */
.plink-fly { position: fixed; z-index: 60; pointer-events: none; white-space: nowrap;
  transform: translate(-50%, -50%); font-size: 15px; font-weight: 900; color: #4a2f00;
  padding: 2px 9px; border-radius: 999px; background: linear-gradient(135deg, #ffe08a, var(--gold));
  box-shadow: 0 0 10px rgba(255,210,74,.85), 0 2px 6px rgba(0,0,0,.5); animation: plinkFlyIn .12s ease-out; }
@keyframes plinkFlyIn { from { opacity: 0; } to { opacity: 1; } }
/* 球層 */
.plink-balls { position: absolute; inset: 0; z-index: 4; pointer-events: none; }
.plink-ball { position: absolute; width: 6.6%; aspect-ratio: 1; border-radius: 50%; transform: translate(-50%, -50%);
  background: radial-gradient(circle at 32% 26%, #ffffff 7%, #ffd9ea 26%, #ff5ea0 60%, #e21e72 100%);
  box-shadow: 0 0 4px #fff, 0 0 13px rgba(255,90,160,.9), inset 0 -2px 5px rgba(150,0,60,.4);
  display: flex; align-items: center; justify-content: center; font-size: 10px; font-weight: 900; color: #4a0d22;
  will-change: left, top; }
.plink-ball.gold { background: radial-gradient(circle at 32% 26%, #ffffff 7%, #fff0b8 26%, #ffcf3a 58%, #e09a10 100%);
  box-shadow: 0 0 5px #fff, 0 0 19px rgba(255,207,58,1), inset 0 -2px 5px rgba(130,85,0,.45); color: #5e4200; }
.plink-ball.free { background: radial-gradient(circle at 32% 26%, #ffffff 7%, #d6f7ff 26%, #5cd6ff 58%, #158fd0 100%);
  box-shadow: 0 0 5px #fff, 0 0 17px rgba(90,215,255,1); color: #05303f; }
.plink-ball .pb-mult { font-size: 8px; }
.plink-ball.gone { opacity: 0; transform: translate(-50%, -50%) scale(.4); transition: opacity .3s, transform .3s; }
/* 底部 13 金額格 */
.plink-slots { position: absolute; left: 0; right: 0; bottom: 0; height: 17%; z-index: 2;
  display: flex; gap: 2px; padding: 0 3px 3px; align-items: stretch; }
.plink-slot { flex: 1; min-width: 0; position: relative; display: flex; align-items: center; justify-content: center;
  border-radius: 0 0 7px 7px; font-size: clamp(7px, calc(2 * var(--vw)), 12px); font-weight: 800; color: #fff; padding: 2px 0;
  box-shadow: inset 0 2px 0 rgba(255,255,255,.14); }
.plink-t0 { background: linear-gradient(#3b4668, #2b3350); }
.plink-t1 { background: linear-gradient(#3f5a72, #2c4051); }
.plink-t2 { background: linear-gradient(#3f6f5f, #2c4f43); }
.plink-t3 { background: linear-gradient(#6f6a3a, #4f4b28); }
.plink-t4 { background: linear-gradient(#8a5a2c, #5f3d1c); }
.plink-t5 { background: linear-gradient(#a8432c, #6f2c1c); }
.plink-t6 { background: linear-gradient(#c62a5a, #8a1d3f); box-shadow: inset 0 0 0 1px rgba(255,210,74,.5); }
.plink-slot.plink-landed { animation: psLand .5s ease; z-index: 3; }
@keyframes psLand { 0% { transform: translateY(0); } 30% { transform: translateY(5px); filter: brightness(1.8); } 100% { transform: translateY(0); } }
.plink-slot .ps-hits { position: absolute; top: -13px; left: 50%; transform: translateX(-50%);
  font-size: 10px; font-weight: 900; color: var(--gold); background: rgba(0,0,0,.6);
  padding: 0 5px; border-radius: 999px; white-space: nowrap; }
/* 托盤：碎片 / 收集罐進度條 */
.plink-tray .plink-meters { display: flex; gap: 12px; margin-bottom: 8px; }
.plink-meter { flex: 1; }
.pm-head { display: flex; align-items: baseline; gap: 5px; font-size: 12px; font-weight: 700; color: var(--text-soft); }
.pm-head .pm-ico { font-size: 14px; }
.pm-head .pm-name { font-weight: 800; color: var(--text); }
.pm-head .pm-num { margin-left: auto; font-weight: 900; color: var(--gold); font-variant-numeric: tabular-nums; }
.pm-bar { height: 9px; border-radius: 999px; background: rgba(255,255,255,.08); overflow: hidden; margin: 4px 0 3px; }
.pm-fill { height: 100%; border-radius: 999px; width: 0; transition: width .4s ease; }
.pm-fill.frag { background: linear-gradient(90deg, #ff8fb6, #ff5d8f); }
.pm-fill.jar { background: linear-gradient(90deg, #ffe08a, var(--gold)); }
.pm-fill.pulse { animation: pmPulse .42s ease; }
@keyframes pmPulse { 0% { filter: brightness(1); } 40% { filter: brightness(2.1); } 100% { filter: brightness(1); } }
.pm-num.bump { animation: mbBump .28s ease; }
.pm-hint { font-size: 10px; color: var(--text-soft); opacity: .85; line-height: 1.35; }
.plink-stat { text-align: center; font-size: 13px; color: var(--text-soft); }
.plink-stat b { color: var(--win); }
/* 賠付表金額格條 */
.plink-pt-row { display: flex; flex-wrap: wrap; gap: 4px; margin: 6px 0 4px; }
.plink-pt-cell { padding: 4px 8px; border-radius: 7px; font-size: 12px; font-weight: 800; color: #fff; }
/* pickme overlay 收集罐格 */
.pickme-chest.jar.prize { }
@media (prefers-reduced-motion: reduce) {
  .plink-collector.hit, .plink-collector.hit-big, .plink-slot.plink-landed { animation: none !important; }
}

/* ============================================================================
   [claude code] 2026-07-14 尋寶掃雷（treasure_mines / mines）—— 獨立 view 樣式
   5×5 挖寶格 + 風險檔（地雷數）選擇 + 目前/下一格倍率；沿用 .machine / .win-meter /
   .control-bar / .bet-stepper / .btn-spin 既有元件。
   ============================================================================ */
.mn-machine { gap: 12px; }

.mn-riskbar { display: flex; align-items: center; justify-content: center; gap: 10px; flex-wrap: wrap; margin: 2px 0 4px; }
.mn-risk-label { font-size: .82rem; color: var(--text-soft); letter-spacing: .5px; }
.mn-risk { display: flex; gap: 6px; }
.mn-risk button {
  min-width: 44px; padding: 7px 10px; border-radius: 10px; cursor: pointer;
  background: var(--surface-2); color: var(--text); border: 1.5px solid var(--border);
  font-weight: 700; font-size: .95rem; transition: transform .1s, border-color .15s, background .15s, box-shadow .15s;
}
.mn-risk button:hover:not(:disabled) { border-color: var(--neon); transform: translateY(-1px); }
.mn-risk button.on {
  background: linear-gradient(135deg, var(--neon), var(--neon-2)); color: #08121a;
  border-color: transparent; box-shadow: 0 0 12px rgba(43, 212, 168, .5);
}
.mn-risk button:disabled { opacity: .55; cursor: default; }

.mn-head { text-align: center; font-size: .9rem; color: var(--text); min-height: 1.3em; padding: 2px 6px; }
.mn-multrow { display: flex; align-items: center; justify-content: center; gap: 10px; flex-wrap: wrap; font-size: .86rem; color: var(--text-soft); min-height: 1.4em; }
.mn-cur-label { opacity: .8; }
.mn-cur { font-weight: 900; font-size: 1.35rem; color: var(--gold); text-shadow: 0 0 10px rgba(255, 210, 74, .5); transition: color .2s, text-shadow .2s; }
.mn-cur.mn-boom-text { color: #ff5468 !important; text-shadow: 0 0 12px rgba(255, 84, 104, .6); }
.mn-next b { color: var(--neon-2); }
.mn-next .mn-cash { color: #7CFC9E; }
/* [claude code] 2026-08-31 v3.58 倍率已封頂 —— 用琥珀色而不是綠色:它不是好消息,是「別再翻了」。 */
.mn-next .mn-cap { color: #FFC65C; }
.mn-next .mn-boom { color: #ff8a9a; }
.mn-next .mn-full { color: #2bd4a8; }

.mn-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 8px; max-width: min(calc(92 * var(--vw)), 420px); width: 100%; margin: 6px auto 2px; }
.mn-cell {
  aspect-ratio: 1 / 1; border-radius: 12px; display: flex; align-items: center; justify-content: center;
  font-size: clamp(20px, calc(6.5 * var(--vw)), 34px); user-select: none;
  background: linear-gradient(160deg, #232842, #1a1e30);
  border: 1.5px solid var(--border); box-shadow: inset 0 1px 0 rgba(255, 255, 255, .05);
  transition: transform .08s, box-shadow .15s, background .2s, border-color .15s; cursor: pointer;
}
.mn-cell:not(.revealed):not(.locked):hover { border-color: var(--neon); transform: translateY(-2px); box-shadow: 0 4px 14px rgba(43, 212, 168, .28); }
.mn-cell.locked { cursor: default; }
.mn-cell.dim { opacity: .3; }
.mn-cell.revealed { cursor: default; animation: mnPop .28s ease; }
.mn-cell.safe { background: radial-gradient(circle at 50% 40%, rgba(43, 212, 168, .3), #17233a); border-color: #2bd4a8; box-shadow: 0 0 12px rgba(43, 212, 168, .35); }
.mn-cell.mine { background: radial-gradient(circle at 50% 40%, rgba(255, 84, 104, .32), #2a1622); border-color: #ff5468; }
.mn-cell.mine.hit { box-shadow: 0 0 18px rgba(255, 84, 104, .7); animation: mnBoom .4s ease; }
@keyframes mnPop { 0% { transform: scale(.6); } 60% { transform: scale(1.12); } 100% { transform: scale(1); } }
@keyframes mnBoom { 0% { transform: scale(1); } 30% { transform: scale(1.25); } 100% { transform: scale(1); } }

.mn-mainbtn.mn-cashmode { background: linear-gradient(135deg, #ffcf4a, #ff9d2e); color: #3a2400; box-shadow: 0 0 16px rgba(255, 180, 60, .5); }
.mn-rules { padding-left: 1.2em; line-height: 1.7; font-size: .88rem; }
.mn-rules li { margin-bottom: 6px; }

@media (prefers-reduced-motion: reduce) {
  .mn-cell.revealed, .mn-cell.mine.hit { animation: none !important; }
}

/* ============================================================================
   [claude code] 2026-07-14 登入 / 建帳號 —— topbar 帳號區鈕 + 帳號來源徽章 + authModal
   ============================================================================ */
.la-open { white-space: nowrap; }
.la-origin {
  display: inline-block; margin-left: 6px; padding: 1px 6px; border-radius: 999px;
  font-size: .64rem; font-weight: 700; vertical-align: middle; letter-spacing: .5px;
}
.la-origin.plt { background: rgba(160, 107, 255, .22); color: #d7b3ff; border: 1px solid rgba(160, 107, 255, .5); }
.la-origin.api { background: rgba(54, 224, 255, .18); color: #8fe6ff; border: 1px solid rgba(54, 224, 255, .45); }

.auth-card { max-width: 340px; width: 92%; text-align: center; }
.auth-tabs { display: flex; gap: 6px; margin: 4px 0 16px; }
.auth-tab {
  flex: 1; padding: 9px 0; border-radius: 10px; cursor: pointer; font-weight: 700; font-size: .95rem;
  background: var(--surface-2); color: var(--text-soft); border: 1.5px solid var(--border);
  transition: background .15s, color .15s, border-color .15s;
}
.auth-tab.active { background: linear-gradient(135deg, var(--neon), var(--neon-2)); color: #08121a; border-color: transparent; }
.auth-form { display: flex; flex-direction: column; gap: 10px; }
.auth-inp {
  width: 100%; padding: 11px 13px; border-radius: 10px; font-size: 1rem;
  background: var(--surface-2); color: var(--text); border: 1.5px solid var(--border);
}
.auth-inp:focus { outline: none; border-color: var(--neon); box-shadow: 0 0 0 3px rgba(160, 107, 255, .18); }
.auth-submit { width: 100%; margin-top: 2px; }
.auth-msg { min-height: 1.2em; font-size: .82rem; color: var(--neon-2); }
.auth-msg.err { color: #ff6b81; }
.auth-hint { margin-top: 12px; font-size: .76rem; line-height: 1.5; color: var(--text-soft); }

/* ---- [claude code] 2026-07-14 本注明細（玩家版細單）：注單號旁「🔍 明細」+ 明細 modal ---- */
.st-view { flex: 0 0 auto; height: 30px; padding: 0 10px; border-radius: 8px; cursor: pointer; line-height: 1;
  font-size: 12px; font-weight: 700; white-space: nowrap;
  background: var(--surface); color: var(--text-soft); border: 1px solid var(--border);
  transition: background .15s, color .15s, transform .12s; }
.st-view:hover:not(:disabled) { background: var(--gold); color: #1b2330; border-color: var(--gold); }
.st-view:disabled { opacity: .4; cursor: not-allowed; }

.detail-card { width: min(560px, calc(94 * var(--vw))); max-height: 88vh; overflow-y: auto; padding: 20px; }
.dt-title { font-size: 16px; font-weight: 800; margin-bottom: 6px; }
.dt-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 12px;
  font-size: 12px; color: var(--text-soft); }
.dt-meta .dt-game { color: var(--text); font-weight: 700; }
.dt-meta .dt-no { font-size: 11px; letter-spacing: .3px; word-break: break-all; }
.dt-loading, .dt-empty { padding: 22px 4px; text-align: center; font-size: 13px; color: var(--text-soft); line-height: 1.6; }
.dt-board { max-width: 360px; margin: 0 auto 12px; }
.dt-board .mj-cell { animation: none !important; }   /* 明細是靜態存證：不跑完成線脈動 */
.dt-sum { font-size: 13px; line-height: 1.7; color: var(--text-soft); text-align: center; }
.dt-sum b { color: var(--text); }
.dt-sum .dt-gold { color: var(--gold); }
.dt-sum .dt-win { color: var(--gold); font-size: 15px; }
.dt-formula { margin-top: 8px; padding: 8px 10px; border-radius: 8px; font-size: 12.5px; line-height: 1.6;
  background: var(--surface-2); border: 1px solid var(--border); color: var(--text); text-align: center; }
.dt-legend { margin-top: 8px; font-size: 11px; color: var(--text-soft); text-align: center; }
.dt-subtitle { margin: 14px 0 6px; font-size: 12px; font-weight: 700; color: var(--text-soft); }
.dt-chips { display: flex; flex-wrap: wrap; gap: 4px; max-height: 132px; overflow-y: auto; }
/* ✖️ [claude code] 2026-09-21 v4.45 細單裡的倍數軸：那一轉五格長什麼樣，生效的那格標起來。
   🔴 細單是「回看」不是「重算」—— 看的人要能指著它說「就是這一格乘上去的」。 */
.dt-zmr { display: flex; flex-wrap: wrap; gap: 4px; justify-content: center; margin: 0 auto 8px; }
.dt-zmrc { font-size: 11px; font-weight: 800; padding: 2px 8px; border-radius: 999px;
  background: var(--surface-2); border: 1px solid var(--border); color: var(--text-soft); }
.dt-zmrc.on { background: linear-gradient(#fff3c8, var(--gold)); color: #2a1d00; border-color: var(--gold); }

/* ---- [claude code] 2026-07-15 拉霸類明細盤面（狼王夜襲 walking / 花蜜採集 cashcollect）----
   靜態存證盤面：每格 glyph（花蜜格再帶面額籌碼）；中獎線上的格高亮。 */
.dt-slot { display: grid; gap: 4px; max-width: 360px; margin: 0 auto 8px; position: relative; }
/* [claude code] 2026-07-18 中獎線畫在盤面上：SVG 覆蓋整個盤、折線連過中獎格中心（不擋點擊） */
.dt-lineoverlay { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 3; overflow: visible; }
.dt-lineoverlay polyline { filter: drop-shadow(0 0 2px rgba(0,0,0,.55)); }
.dt-scell { position: relative; aspect-ratio: 1 / 1; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 2px; border-radius: 8px; font-size: 20px;
  background: var(--surface-2); border: 1px solid var(--border); }
.dt-scell .dt-glyph { line-height: 1; }
.dt-scell .dt-cell-amt { font-size: 10px; font-weight: 700; color: var(--gold); line-height: 1; }
.dt-scell.hit { border-color: var(--gold); box-shadow: inset 0 0 0 1px var(--gold); }
/* [claude code] 2026-09-01 v3.69 🪞 雙生鏡界細單：在「複製後」那一盤上標出鏡像。
   使用者：「細單沒有標注之鏡是那一個（前一版有）」—— 盤面畫的是複製後的，☯️ 已經被抄掉了。
   🔴 **用底色 + 角標，不搶 `.hit` 的金框** —— 被抄的軸常常同時是中獎軸，
      兩個都改 border 的話會互相蓋掉，玩家就看不出「這一格有沒有參與中獎」。
   🔴 顏色沿用盤面表演的分工：**紫 = 鏡符（因）**（見 `.cell.sy-cue`）。 */
.dt-scell.dt-symir { background: rgba(176,120,255,.15); }                 /* 被抄的整軸 */
/* ☯️ 原本落在這一格：**只加深底色 + 角標，一個框都不畫**。
   ⚠️ 第一版畫了 `inset 0 0 0 2px` 的紫框，實測撞到「這一格同時是中獎格」的情況 ——
      紫框把 `.hit` 的金框壓掉，玩家就看不出它有參與中獎（截圖才發現，看 CSS 看不出來）。
   💡 **兩種標記搶同一個視覺通道時，讓後來的那個換通道**（框 → 底色 + 角標）。 */
.dt-scell.dt-symirsrc { background: rgba(176,120,255,.34); }
.dt-symark { position: absolute; top: 1px; right: 1px; z-index: 3; font-size: 11px; line-height: 1;
  padding: 1px 3px; border-radius: 999px; background: #2a1b45;
  box-shadow: 0 0 0 1px rgba(199,139,255,.9), 0 1px 3px rgba(0,0,0,.6); }
.dt-scell.k-wolf { background: rgba(120, 90, 200, .22); border-color: rgba(150, 120, 235, .55); }
.dt-scell.k-bee { background: rgba(240, 190, 60, .20); border-color: rgba(240, 190, 60, .55); }
.dt-scell.k-nectar { background: rgba(240, 140, 40, .14); border-color: rgba(240, 160, 60, .40); }
.dt-scell.k-empty { opacity: .55; }
/* [claude code] 2026-07-15 甜蜜蜂巢（sticky）：黏住的百搭 / 本轉新落地的百搭 / expanding 展開出來的百搭 */
.dt-scell.k-stuck { background: rgba(150, 110, 235, .24); border-color: rgba(170, 130, 245, .60); }
.dt-scell.k-newwild { background: rgba(90, 200, 140, .20); border-color: rgba(110, 220, 160, .55); }
.dt-scell.k-expanded { background: rgba(90, 160, 235, .20); border-color: rgba(110, 180, 245, .55); }
/* [claude code] 2026-07-15 無盡星河（infinity）：軸數可變（最多可長很多軸）→ 格縮小、超寬時橫向捲動 */
.dt-slot.dt-inf { max-width: 100%; }
.dt-slot.dt-inf .dt-scell { font-size: 15px; border-radius: 6px; }
/* [claude code] 2026-07-15 剩餘 9 款細單盤面著色 */
.dt-scell.k-bomb { background: rgba(240, 120, 200, .20); border-color: rgba(240, 120, 200, .55); }
.dt-scell.k-scatter { background: rgba(120, 200, 240, .20); border-color: rgba(120, 200, 240, .55); }
.dt-scell.k-bonus { background: rgba(240, 200, 60, .22); border-color: rgba(240, 200, 60, .60); }
.dt-scell.k-laser, .dt-scell.k-win { border-color: var(--gold); box-shadow: inset 0 0 0 1px var(--gold); }
.dt-scell.k-target, .dt-scell.k-cleared, .dt-scell.k-bomb2 { opacity: .5; }
.dt-scell.k-colossal { background: rgba(200, 120, 90, .22); border-color: rgba(220, 140, 100, .60); }
/* [claude code] 2026-07-18 招財貓（holdwin）：最終鎖定盤的金幣格（金框 + 面額籌碼） */
.dt-scell.k-coin { background: rgba(255, 200, 60, .22); border-color: rgba(255, 210, 74, .6); box-shadow: inset 0 0 0 1px rgba(255, 210, 74, .5); }
/* [claude code] 2026-07-17 烈日冰舖（serve）細單：顧客 / 🔥 熱浪格 */
.dt-scell.k-cust { background: rgba(240, 200, 60, .22); border-color: rgba(240, 200, 60, .60); }
.dt-scell.k-heat { background: rgba(240, 90, 60, .20); border-color: rgba(240, 110, 70, .55); }
.dt-scell.k-audience { background: rgba(120, 200, 240, .18); }
.dt-slot.dt-plinko-slots { max-width: 100%; }
.dt-slot.dt-plinko-slots .dt-scell { aspect-ratio: auto; padding: 6px 2px; font-size: 11px; }
.dt-slot.dt-mines { max-width: 240px; }
.dt-scell.m-mine { background: rgba(230, 70, 70, .22); border-color: rgba(230, 70, 70, .55); }
.dt-scell.m-safe { background: rgba(90, 200, 140, .20); border-color: rgba(110, 220, 160, .55); }
.dt-scell.m-hidden { opacity: .45; }
.dt-lines { display: flex; flex-direction: column; gap: 3px; margin: 0 auto 4px; max-width: 360px; }
.dt-line { display: flex; align-items: center; gap: 6px; padding: 4px 8px; border-radius: 7px;
  background: var(--surface-2); border: 1px solid var(--border); font-size: 12px; color: var(--text-soft); }
.dt-line .dt-lsym { font-size: 15px; }
.dt-line .dt-llabel { color: var(--text); font-weight: 600; }
.dt-line .dt-lmatch { margin-left: auto; }
.dt-line .dt-lpay { color: var(--gold); font-weight: 700; }
.dt-line .dt-lnum { font-size: 10px; font-weight: 800; color: var(--text-mute);
  background: rgba(255,255,255,.06); border-radius: 5px; padding: 1px 5px; }
/* [claude code] 2026-07-18 線號色點（與盤面上該條線同色 → 清單 ↔ 盤面對得起來） */
.dt-line .dt-lswatch { width: 11px; height: 11px; border-radius: 50%; flex: none;
  box-shadow: 0 0 0 1px rgba(0,0,0,.35), 0 0 4px rgba(255,255,255,.25); }
/* [claude code] 2026-07-18 中獎線的「整線路徑」符號帶（前 match 軸中獎、第 match 軸斷點、之後暗） */
.dt-linewrap { display: flex; flex-direction: column; gap: 2px; }
.dt-lines { gap: 6px; }
.dt-path { display: flex; gap: 3px; padding: 0 6px 2px; }
.dt-pcell { flex: 1; text-align: center; font-size: 14px; line-height: 1.7; border-radius: 5px;
  background: var(--surface-2); border: 1px solid var(--border); }
.dt-pcell.hit { border-color: var(--gold); background: rgba(255,210,74,.18); box-shadow: inset 0 0 0 1px var(--gold); }
.dt-pcell.stop { border-color: rgba(255,90,90,.65); background: rgba(255,90,90,.14); }
.dt-pcell.off { opacity: .4; }
.dt-pathnote { font-size: 11px; color: var(--text-mute); text-align: center; margin: 4px auto 0; max-width: 360px; line-height: 1.5; }
/* [claude code] 2026-07-18 賠付表「所有賠付線」迷你盤面圖 */
.pl-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); gap: 8px; margin: 4px 0 8px; }
.pl-item { display: flex; flex-direction: column; align-items: center; gap: 3px; }
.pl-num { font-size: 10px; font-weight: 800; color: var(--text-mute); }
.pl-mini { display: grid; gap: 2px; width: 100%; }
.pl-cell { aspect-ratio: 1 / 1; border-radius: 3px; background: var(--surface-2); border: 1px solid var(--border); }
.pl-cell.on { background: rgba(255,210,74,.85); border-color: var(--gold); box-shadow: 0 0 4px rgba(255,210,74,.45); }

/* ---- [claude code] 2026-07-14 我的紀錄（頂列 📜）：注單記錄（可翻頁 → 本注明細）+ 轉帳記錄 ---- */
.records-card { width: min(560px, calc(94 * var(--vw))); max-height: 88vh; display: flex; flex-direction: column; padding: 20px; }
.rc-days { font-size: 11px; font-weight: 400; color: var(--text-soft); margin-left: 6px; }
.rc-tabs { display: flex; gap: 6px; margin: 10px 0 8px; }
.rc-tab { flex: 1; padding: 7px 0; border-radius: 8px; cursor: pointer; font-size: 13px; font-weight: 700;
  background: var(--surface-2); color: var(--text-soft); border: 1px solid var(--border); }
.rc-tab.active { background: var(--gold); color: #1b2330; border-color: var(--gold); }
/* [claude code] 2026-07-16 注單記錄「依遊戲」下拉篩選列 */
.rc-filter { display: flex; align-items: center; gap: 8px; margin: 0 0 8px; }
.rc-filter label { font-size: 12px; color: var(--text-soft); font-weight: 700; }
.rc-filter select { flex: 1; padding: 7px 10px; border-radius: 8px; font-size: 13px; font-weight: 700;
  background: var(--surface-2); color: var(--text); border: 1px solid var(--border); cursor: pointer; }
/* [claude code] 2026-08-17 v3.48 第一列看起來「被切到」的修正(使用者回報:「my history 第一個被選中時會被切到」)。
   🔴 病根有兩層,少做一層都還是會切:
   ① 這是捲動容器(`overflow-y: auto`)而**內距是 0** → 第一列的邊框緊貼容器上緣,選中(金框)時看起來就是被切齊的;
   ② `.rc-row.clickable:hover` 會 `translateY(-1px)` **往上抬** → 抬出去的那 1px 真的會被 overflow 裁掉。
   → 上下左右都留一點:上面 6px(讓第一列明顯離開邊緣)、左右 2px(金框與 hover 陰影不貼邊)。
   ⚠️ 捲到底時下面也要有空間,不然最後一列一樣貼邊 → 底部同樣給 6px。 */
.rc-body { flex: 1; overflow-y: auto; min-height: 180px; padding: 6px 2px; }
.rc-list { display: flex; flex-direction: column; gap: 6px; }
.rc-row { display: flex; align-items: center; gap: 10px; padding: 9px 10px; border-radius: 9px;
  background: var(--surface-2); border: 1px solid var(--border); }
.rc-row.clickable { cursor: pointer; transition: border-color .15s, transform .08s; }
.rc-row.clickable:hover { border-color: var(--gold); transform: translateY(-1px); }
.rc-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.rc-game { font-size: 13px; font-weight: 700; color: var(--text); }
.rc-time { font-size: 11px; color: var(--text-soft); }
.rc-txn { font-size: 10px; color: var(--text-soft); word-break: break-all; }
.rc-nums { flex: 0 0 auto; display: flex; flex-direction: column; align-items: flex-end; gap: 2px; font-size: 12px; }
.rc-bet, .rc-bal { color: var(--text-soft); }
.rc-win { color: var(--text-soft); font-weight: 700; }
.rc-win.pos { color: var(--gain, #e5484d); }        /* 台灣慣例：紅 = 贏 / 進帳 */
.rc-amt { font-weight: 800; }
.rc-amt.in { color: var(--gain, #e5484d); }
.rc-amt.out { color: var(--loss, #16a34a); }        /* 綠 = 出帳 */
.rc-tail { flex: 0 0 auto; font-size: 11px; }
.rc-more { color: var(--gold); font-weight: 700; }
.rc-nomore { color: var(--text-soft); opacity: .7; }

/* ---- [claude code] 2026-08-14 v2.83 場次記錄（一次坐下來玩的那一段，展開才看逐筆）---- */
.rc-views { flex: 0 0 auto; display: flex; gap: 4px; }
.rc-view { padding: 6px 12px; border-radius: 8px; cursor: pointer; font-size: 12px; font-weight: 700;
  background: var(--surface-2); color: var(--text-soft); border: 1px solid var(--border); }
.rc-view.active { background: var(--gold); color: #1b2330; border-color: var(--gold); }
.rc-sess { display: flex; flex-direction: column; }
.rc-sessrow.open { border-color: var(--gold); border-bottom-left-radius: 0; border-bottom-right-radius: 0; }
.rc-rounds { margin-left: 6px; font-size: 11px; font-weight: 700; color: var(--text-soft); }
.rc-net { font-weight: 900; font-size: 13px; font-variant-numeric: tabular-nums; color: var(--text-soft); }
.rc-net.pos { color: var(--gain, #e5484d); }        /* 台灣慣例：紅 = 賺 */
.rc-net.neg { color: var(--loss, #16a34a); }        /* 綠 = 賠 */
.rc-caret { display: inline-block; color: var(--gold); font-size: 13px; transition: transform .15s ease; }
.rc-sessrow.open .rc-caret { transform: rotate(180deg); }
/* 展開區：縮排 + 左側金線，一眼看出「這幾筆屬於上面那一場」 */
.rc-sub { display: flex; flex-direction: column; gap: 5px; margin: 0 0 2px 10px; padding: 6px 0 6px 10px;
  border-left: 2px solid rgba(255,210,74,.35); }
.rc-sub .rc-row { padding: 7px 9px; background: rgba(255,255,255,.03); }
.rc-sub .rc-game { font-size: 12px; }
.rc-more-btn { align-self: center; margin-top: 2px; padding: 6px 14px; border-radius: 8px; cursor: pointer;
  font-size: 12px; font-weight: 700; background: var(--surface-2); color: var(--gold); border: 1px solid var(--border); }
.rc-more-btn:disabled { opacity: .5; cursor: default; }
.rc-note { margin-top: 10px; padding: 8px 10px; border-radius: 8px; font-size: 11.5px; line-height: 1.55;
  color: var(--text-soft); background: rgba(255,180,60,.08); border: 1px solid rgba(255,180,60,.25); }
.rc-pager { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: 10px; }
.rc-pgbtn { padding: 6px 12px; border-radius: 8px; cursor: pointer; font-size: 12px;
  background: var(--surface-2); color: var(--text); border: 1px solid var(--border); }
.rc-pgbtn:hover:not(:disabled) { border-color: var(--gold); }
.rc-pgbtn:disabled { opacity: .35; cursor: not-allowed; }
.rc-pginfo { font-size: 12px; color: var(--text-soft); }
/* [claude code] 2026-07-14 明細 modal 的開球記錄托盤（沿用 .bd-chip，只放寬高度限制）*/
.dt-balls { max-height: 120px; }

/* [claude code] 2026-07-14 大廳卡片「細單未開放」標記（server games.spinDetail=false 才掛；
   已支援的款不掛徽章 —— 依使用者：只標還沒做的）。灰底虛線、低調不搶版面。 */
.card-detail { margin-top: 6px; align-self: flex-start; padding: 2px 8px; border-radius: 999px;
  font-size: 10.5px; font-weight: 700; letter-spacing: .3px; }
.card-detail.off { color: var(--text-soft); background: transparent; border: 1px dashed var(--border); opacity: .75; }

/* [claude code] 2026-07-14 花蜜採集：每隻蜜蜂的「×1」角標（多隻時才掛）→ 「幾隻＝幾倍」一眼看懂。
   配色沿用蜜蜂金；角標絕對定位在格子右上，不撐開格子。 */
.cell .bee-mult { position: absolute; top: 2px; right: 3px; z-index: 3;
  font-size: 11px; font-weight: 900; line-height: 1; padding: 1px 3px; border-radius: 5px;
  color: #4a3400; background: var(--gold); box-shadow: 0 0 6px rgba(255,207,58,.7); }

/* ===== [claude code] 2026-07-16 招財海盜寶藏（treasure）：鑰匙發光 / 開箱內容徽章 / 藏寶圖 HUD / 寶藏開箱 ===== */
/* 鑰匙發光 + ×N 角標 */
.cell.key-glow { box-shadow: inset 0 0 0 2px #ffd54a, 0 0 16px rgba(255,205,74,.9); z-index: 4; }
.cell.key-glow .glyph { animation: stickyPulse .7s ease-in-out infinite; }
.cell .key-mult { position: absolute; top: 2px; right: 3px; z-index: 3; font-size: 11px; font-weight: 900; line-height: 1;
  padding: 1px 3px; border-radius: 5px; color: #4a3400; background: var(--gold, #ffcf3a); box-shadow: 0 0 6px rgba(255,207,58,.7); }
/* 寶箱開啟 + 內容徽章（💰 金幣面額 / 🗺️ 碎片編號） */
.cell.chest-sealed .glyph { filter: brightness(.82); animation: chestSeal 1.1s ease-in-out infinite; }
@keyframes chestSeal { 0%,100% { transform: translateY(0) scale(1); } 50% { transform: translateY(-2px) scale(1.04); } }
.cell.chest-open .glyph { animation: chestPop .45s ease; }
@keyframes chestPop { 0% { transform: scale(1); } 40% { transform: scale(1.22) rotate(-6deg); filter: brightness(1.4); } 100% { transform: scale(1); } }
.cell.chest-grab .glyph { animation: cashGrab .6s ease; }
.cell .chest-cash { position: absolute; bottom: 4px; left: 50%; transform: translateX(-50%); z-index: 6; pointer-events: none;
  font-family: "Arial Black", system-ui, sans-serif; font-weight: 900; font-size: 11px; line-height: 1; padding: 2px 6px; border-radius: 8px; white-space: nowrap;
  background: linear-gradient(135deg, #fff1c2, #ffcf4a); color: #5a3a00; box-shadow: 0 0 7px rgba(255,180,40,.7), 0 1px 2px rgba(0,0,0,.5); }
.cell .chest-piece { position: absolute; bottom: 4px; left: 50%; transform: translateX(-50%); z-index: 6; pointer-events: none;
  font-weight: 900; font-size: 11px; line-height: 1; padding: 2px 6px; border-radius: 8px; white-space: nowrap;
  background: linear-gradient(135deg, #cdeafd, #6db8e6); color: #123a55; box-shadow: 0 0 8px rgba(90,170,235,.75), 0 1px 2px rgba(0,0,0,.5); animation: chestPop .5s ease; }
/* 藏寶圖進度 HUD（8 格） */
.treasure-map { display: none; flex-direction: column; align-items: center; gap: 4px; margin: 6px auto 2px; }
.treasure-map .tm-cap { font-size: 12px; font-weight: 800; color: #ffe08a; letter-spacing: 1px; text-shadow: 0 1px 3px rgba(0,0,0,.6); }
.treasure-map .tm-row { display: flex; gap: 5px; }
.treasure-map .tm-slot { position: relative; width: 26px; height: 26px; border-radius: 6px; display: flex; align-items: center; justify-content: center;
  background: rgba(20,30,45,.7); border: 1px solid rgba(120,150,190,.35); box-shadow: inset 0 0 6px rgba(0,0,0,.5); transition: all .25s ease; }
.treasure-map .tm-slot .tm-num { font-size: 13px; font-weight: 900; color: #5a6a80; }
.treasure-map .tm-slot.got { background: linear-gradient(135deg, #ffe9a8, #f5b13a); border-color: #ffd45a; box-shadow: 0 0 10px rgba(255,190,60,.8); }
.treasure-map .tm-slot.got .tm-num { color: #5a3a00; }
.treasure-map .tm-slot.just { animation: tmJust .55s ease; }
@keyframes tmJust { 0% { transform: scale(1); } 45% { transform: scale(1.35); box-shadow: 0 0 16px rgba(255,220,90,1); } 100% { transform: scale(1); } }
/* 寶藏開箱 overlay */
.treasure-bonus-ov { position: fixed; inset: 0; z-index: 120; display: flex; align-items: center; justify-content: center;
  background: radial-gradient(circle at 50% 40%, rgba(30,20,60,.82), rgba(8,6,18,.94)); backdrop-filter: blur(2px); }
.treasure-bonus-ov .tb-card { width: min(calc(92 * var(--vw)), 560px); padding: 20px 18px; border-radius: 16px; text-align: center;
  background: linear-gradient(160deg, #2a1f4a, #17122e); border: 1px solid rgba(255,210,120,.4); box-shadow: 0 12px 48px rgba(0,0,0,.6); }
.treasure-bonus-ov .tb-title { font-size: 22px; font-weight: 900; color: #ffe08a; text-shadow: 0 0 12px rgba(255,190,60,.7); }
.treasure-bonus-ov .tb-total { font-size: 30px; font-weight: 900; color: #fff; margin: 6px 0 12px; transition: transform .2s ease; }
.treasure-bonus-ov .tb-total.done { transform: scale(1.12); color: #ffd45a; text-shadow: 0 0 16px rgba(255,200,60,.9); }
.treasure-bonus-ov .tb-boxes { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; max-height: 40vh; overflow-y: auto; padding: 4px; }
.treasure-bonus-ov .tb-box { position: relative; width: 52px; height: 52px; border-radius: 10px; display: flex; align-items: center; justify-content: center;
  font-size: 24px; background: rgba(10,10,24,.6); border: 1px solid rgba(150,150,190,.3); opacity: 0; transform: scale(.6); }
.treasure-bonus-ov .tb-box.open { opacity: 1; transform: scale(1); transition: all .25s cubic-bezier(.2,1.4,.5,1); }
.treasure-bonus-ov .tb-box.prize { background: linear-gradient(135deg, #4a3a10, #806014); border-color: #ffd45a; box-shadow: 0 0 12px rgba(255,190,60,.6); }
.treasure-bonus-ov .tb-box.skull { background: linear-gradient(135deg, #3a1015, #601020); border-color: #ff6a7a; box-shadow: 0 0 16px rgba(255,80,110,.7); }
.treasure-bonus-ov .tb-box .tb-amt { position: absolute; bottom: 2px; left: 50%; transform: translateX(-50%); font-size: 10px; font-weight: 900; color: #ffe08a; white-space: nowrap; }
.treasure-bonus-ov .tb-hint { margin-top: 12px; font-size: 12px; color: #b8b0d0; }
/* [claude code] 2026-07-16 招財海盜寶藏細單：藏寶圖碎片編號徽章（沿用 .dt-cell-amt 位置，藍色系區分金幣） */
.dt-slot .dt-scell .dt-piece-amt { position: absolute; bottom: 2px; left: 50%; transform: translateX(-50%);
  font-size: 10px; font-weight: 900; line-height: 1; padding: 1px 4px; border-radius: 6px; white-space: nowrap;
  background: linear-gradient(135deg, #cdeafd, #6db8e6); color: #123a55; box-shadow: 0 0 5px rgba(90,170,235,.6); }

/* [claude code] 2026-07-29 v2.20 闖關奪寶（gemquest）：三關 BOSS 群落消除闖關 --------------------- */
/* BOSS 面板（盤面上方）：關卡指示燈 + 頭像 + 頭上血條（MMORPG 樣式） */
.gq-boss { position: relative; margin: 0 auto 8px; width: min(100%, 470px); padding: 8px 12px 10px;
  border-radius: 14px; background: linear-gradient(160deg, rgba(45,25,60,.92), rgba(16,12,28,.94));
  border: 1px solid rgba(255,140,90,.30); box-shadow: 0 6px 20px rgba(0,0,0,.45); overflow: hidden; }
.gq-boss.cleared { animation: gqCleared .9s ease; }
@keyframes gqCleared { 0%{ box-shadow: 0 0 0 rgba(255,210,74,0); } 40%{ box-shadow: 0 0 28px rgba(255,210,74,.85); } 100%{ box-shadow: 0 6px 20px rgba(0,0,0,.45); } }
.gq-levels { display: flex; gap: 6px; justify-content: center; margin-bottom: 8px; }
.gq-lv { display: flex; flex-direction: column; align-items: center; gap: 1px; min-width: 62px; padding: 3px 6px;
  border-radius: 8px; font-size: 11px; font-weight: 800; color: var(--text-soft);
  background: rgba(255,255,255,.05); border: 1px solid transparent; }
.gq-lv small { font-size: 9px; font-weight: 700; opacity: .75; }
.gq-lv.on { color: #fff; background: linear-gradient(135deg, rgba(255,120,80,.35), rgba(255,60,110,.28)); border-color: rgba(255,150,110,.65); }
.gq-lv.done { color: var(--gold); background: rgba(255,210,74,.12); border-color: rgba(255,210,74,.35); }
.gq-boss-body { display: flex; align-items: center; gap: 12px; }
.gq-boss-info { flex: 1 1 auto; min-width: 0; }
.gq-boss-name { font-size: 12px; font-weight: 900; color: #ffd9c2; letter-spacing: .02em; margin-bottom: 4px; }
.gq-hpbar { position: relative; height: 13px; border-radius: 999px; overflow: hidden;
  background: rgba(0,0,0,.55); box-shadow: inset 0 0 0 1px rgba(255,255,255,.10); }
.gq-hpfill { height: 100%; width: 100%; border-radius: 999px;
  background: linear-gradient(90deg, #ff5d5d, #ff9a3c); box-shadow: 0 0 10px rgba(255,90,70,.55);
  transition: width .35s cubic-bezier(.3,1,.5,1); }
.gq-hpbar.hit { animation: gqBarHit .45s ease; }
@keyframes gqBarHit { 0%{ filter: brightness(2.2); } 100%{ filter: brightness(1); } }
/* near-miss：只差 1 滴血 → 血條青光脈動 */
.gq-hpbar.near { animation: gqBarNear 1s ease-in-out infinite; }
@keyframes gqBarNear { 0%,100%{ box-shadow: inset 0 0 0 1px rgba(255,255,255,.10); } 50%{ box-shadow: inset 0 0 0 1px #36e0ff, 0 0 12px rgba(54,224,255,.8); } }
.gq-hptxt { margin-top: 3px; font-size: 11px; font-weight: 800; color: #ffb9a0; font-variant-numeric: tabular-nums; }
.gq-boss-glyph { flex: 0 0 auto; font-size: 44px; line-height: 1; filter: drop-shadow(0 3px 8px rgba(0,0,0,.6)); }
.gq-boss-glyph.hit { animation: gqBossHit .5s cubic-bezier(.36,.07,.19,.97); }
@keyframes gqBossHit {
  0%   { transform: translateX(0) scale(1); filter: none; }
  18%  { transform: translateX(14px) scale(1.12) rotate(7deg); filter: brightness(3) sepia(1) hue-rotate(-35deg) saturate(6); }
  45%  { transform: translateX(-8px) scale(1.04) rotate(-4deg); filter: brightness(2) sepia(.7) hue-rotate(-35deg) saturate(4); }
  100% { transform: translateX(0) scale(1); filter: none; }
}
.gq-boss-hint { margin-top: 6px; font-size: 10.5px; color: var(--text-mute, #9aa0c0); text-align: center; }
/* 受擊特效（絕對定位在 BOSS 面板上，播完自己移除） */
.gq-slash, .gq-spark, .gq-dmg { position: absolute; pointer-events: none; z-index: 5; }
.gq-slash { right: 26px; top: 42%; font-size: 40px; animation: gqSlash .55s ease-out forwards; }
@keyframes gqSlash { 0%{ opacity: 0; transform: translate(-26px,-26px) rotate(-45deg) scale(.6);} 30%{ opacity: 1; }
  100%{ opacity: 0; transform: translate(22px,22px) rotate(35deg) scale(1.5); } }
.gq-spark { right: 30px; top: 34%; font-size: 34px; animation: gqSpark .55s ease-out forwards; }
@keyframes gqSpark { 0%{ opacity: 0; transform: scale(.3);} 35%{ opacity: 1; transform: scale(1.5);} 100%{ opacity: 0; transform: scale(2); } }
.gq-dmg { right: 18px; top: 8px; font-size: 26px; font-weight: 900; color: #ff5a5a;
  text-shadow: 0 0 10px rgba(255,60,60,.9), 0 2px 3px rgba(0,0,0,.8); animation: gqDmg .95s ease-out forwards; }
@keyframes gqDmg { 0%{ opacity: 0; transform: translateY(10px) scale(.6);} 25%{ opacity: 1; transform: translateY(-6px) scale(1.35);}
  100%{ opacity: 0; transform: translateY(-34px) scale(1); } }
/* 盤面：沿用 cluster 的 N×N grid（.clus-board / .clus-cell）；⚔️ 攻擊符石格加辨識度。
   [claude code] 2026-07-29 v2.22 修「紅框先在原地、等符號才掉進去」（使用者回報）——
   消除掉落款的掉落動畫**只動 .glyph**，框若做在 .cell 上就會先出現在目的地、跟符號分離。
   比照 candy(v1.95) / icecream 的修法：框改做在 .glyph 上 → 框跟著符號一起掉，永不分離。 */
.gq-cell .glyph { box-sizing: border-box; display: flex; align-items: center; justify-content: center;
  width: 100%; height: 100%; border-radius: 9px; }
/* [claude code] 2026-09-17 v4.24 盤面比照 amonovo 連環奪寶:上方預掉落區(.gq-pv,絕對定位在 padding 區)+ 空白 + 盤面貼底。
   上緣永遠裁切 → 推出來的寶石是從邊緣外冒出來的(左右下留 40px 給中獎放大)。 */
.board.gq-board { position: relative; clip-path: inset(0 -40px -40px -40px); }
.gq-pv { position: absolute; top: 0; display: flex; align-items: center; justify-content: center; pointer-events: none; }
.gq-board .glyph { will-change: transform; }
.gq-cell.gq-drill .glyph { background: linear-gradient(160deg, #3a2140, #241426); box-shadow: inset 0 0 0 1.5px rgba(255,140,90,.55); }
.gq-cell.gq-hit { z-index: 5; }
/* 被砍的 ⚔️：純光暈脈動、**零幾何位移**（避免像 slot_town 早期那樣「框壓來壓去」）*/
.gq-cell.gq-hit .glyph { animation: gqHitPulse .32s ease-in-out infinite alternate; }
@keyframes gqHitPulse {
  from { box-shadow: inset 0 0 0 2px #ff6a5a; filter: none; }
  to   { box-shadow: inset 0 0 0 3px #ff8a6a, 0 0 18px rgba(255,90,70,.9); filter: brightness(1.7); }
}
/* 細單：⚔️ 攻擊符石格 / 一起清掉的 ⚔️（紅框） */
.dt-scell.k-drill { background: rgba(255,120,80,.16); border-color: rgba(255,150,110,.5); }
.dt-scell.drillhit { border-color: #ff6a5a; box-shadow: inset 0 0 0 1px #ff6a5a; }
.dt-slot.dt-gq .dt-scell { font-size: 15px; }

/* [claude code] 2026-07-29 v2.23 闖關奪寶 BONUS 表演（依使用者：怪要飛到中間死、紅包改成真寶箱且要有開啟動作、
   破第三關要變成「一直開箱到 💀」的 BONUS GAME）。以下是共用 overlay + 寶箱元件 + BOSS 陣亡飛行。*/
.gq-ov { position: fixed; inset: 0; z-index: 70; display: none; align-items: center; justify-content: center;
  background: radial-gradient(circle at 50% 42%, rgba(60,26,18,.86), rgba(8,6,14,.95)); backdrop-filter: blur(2px); }
.gq-ov.show { display: flex; animation: gqOvIn .28s ease; }
@keyframes gqOvIn { from { opacity: 0; } to { opacity: 1; } }
.gq-ov-box { width: min(calc(94 * var(--vw)), 520px); max-height: 92vh; overflow-y: auto; padding: 18px 16px 20px; text-align: center;
  border-radius: 18px; background: linear-gradient(165deg, #35201a, #17111d);
  border: 1px solid rgba(255,190,110,.4); box-shadow: 0 16px 50px rgba(0,0,0,.62); }
.gq-ov-title { font-size: 23px; font-weight: 900; color: #ffd88a; text-shadow: 0 0 18px rgba(255,140,60,.7); }
.gq-ov-sub { margin-top: 6px; font-size: 12.5px; color: var(--text-soft); }
.gq-ov-result { margin-top: 12px; font-size: 17px; font-weight: 900; color: #fff; opacity: 0; transform: translateY(6px); transition: .3s; }
.gq-ov-result.show { opacity: 1; transform: none; }
.gq-ov-result b { color: var(--win); text-shadow: 0 0 14px rgba(255,225,105,.8); }
.gq-ov-close { margin-top: 14px; padding: 10px 26px; border: none; border-radius: 999px; cursor: pointer;
  font-weight: 800; color: #2a1d00; background: linear-gradient(135deg, #ffe9a6, var(--gold)); }


/* ---- BOSS 陣亡：從血條那隻怪飛到畫面中央 → 放大 → 中彈紅閃 → 旋轉墜落淡出 ---- */
.gq-boss-glyph.gone { opacity: 0; }
.gq-death { position: fixed; z-index: 75; pointer-events: none; font-size: 46px; line-height: 1;
  transform: translate(-50%,-50%); filter: drop-shadow(0 6px 14px rgba(0,0,0,.7));
  animation: gqDeathFly 1.25s cubic-bezier(.25,.9,.3,1) forwards; }
@keyframes gqDeathFly {
  0%   { transform: translate(-50%,-50%) scale(1) rotate(0); filter: none; }
  38%  { transform: translate(calc(-50% + var(--fly-x)), calc(-50% + var(--fly-y))) scale(3.1) rotate(-12deg); }
  52%  { transform: translate(calc(-50% + var(--fly-x)), calc(-50% + var(--fly-y))) scale(3.4) rotate(8deg);
         filter: brightness(3) sepia(1) hue-rotate(-40deg) saturate(7); }
  100% { transform: translate(calc(-50% + var(--fly-x)), calc(-50% + var(--fly-y) + 90px)) scale(2.2) rotate(96deg);
         filter: grayscale(1) brightness(.5); opacity: 0; }
}
.gq-death-boom { position: fixed; z-index: 76; pointer-events: none; font-size: 60px; transform: translate(-50%,-50%);
  animation: gqDeathBoom .7s ease-out forwards; }
@keyframes gqDeathBoom { 0% { opacity: 0; transform: translate(-50%,-50%) scale(.3); }
  30% { opacity: 1; transform: translate(-50%,-50%) scale(1.9); } 100% { opacity: 0; transform: translate(-50%,-50%) scale(2.8); } }

/* ---- [claude code] 2026-07-29 v2.22 手機一屏可見（依使用者規則）----
   規則：**手機不捲動就要看得到 SPIN / 🔁 自動 / 🎲 翻倍**；「完成日 / 🗓️ 身世（日期＋平台版本）」可以被切掉。
   螢幕越矮，版面越緊：先縮邊距與字級，再把日期 / 身世 / 資訊列 / 標語收起來。
   [claude code] 2026-07-29 v2.26 門檻放寬（840→900 / 700→780）：筆電視窗高度常在 740~800，
   原本吃不到收合、盤面上方的裝飾把可用高度壓到放不下 6×6 → 盤面被迫夾到很小或溢出。
   盤面本身另由 JS 的 boardHeightBudget() 依「剩餘高度」夾格子大小（見 app.js）。*/
/* [claude code] 2026-09-24 v4.94 🔴 全部 11 組 `@media (max-height)` 的選擇器都包了
   `:where(body:not([data-fit="1"]))`(0 權重,不改原本的優先順序)—— 美術外框款改成整頁等比縮放,
   矮螢幕要的是「整張一起縮」,不是「先把某幾塊壓扁」;不排除的話兩台電腦看到的比例又會不一樣。
   新增 max-height 規則時照樣包這一層。 */
@media (max-height: 900px) {
  :where(body:not([data-fit="1"])) .game-stage { padding: 4px 4px 10px; }
  :where(body:not([data-fit="1"])) .game-head { margin-bottom: 6px; }
  :where(body:not([data-fit="1"])) .game-head h2 { font-size: 17px; }
  :where(body:not([data-fit="1"])) .title-emoji { width: 22px; height: 22px; font-size: 19px; line-height: 22px; }
  :where(body:not([data-fit="1"])) .game-info { margin-bottom: 6px; gap: 4px; }
  :where(body:not([data-fit="1"])) .machine { padding: 9px; border-radius: 14px; }
  :where(body:not([data-fit="1"])) .win-meter { margin-bottom: 6px; }
  :where(body:not([data-fit="1"])) .control-bar { margin-top: 9px; gap: 10px; }
  :where(body:not([data-fit="1"])) .control-row2 { margin-top: 6px; }
  :where(body:not([data-fit="1"])) .btn-spin { padding: 12px 32px; font-size: 17px; }
  :where(body:not([data-fit="1"])) .game-completed, :where(body:not([data-fit="1"])) .game-born { display: none !important; }   /* 使用者：日期 / 版本可以看不到 */
  /* [claude code] 2026-07-29 v2.26 闖關奪寶 BOSS 面板在矮螢幕壓扁（原本約 150px，是盤面上方最肥的一塊）*/
  :where(body:not([data-fit="1"])) .gq-boss { padding: 6px 10px 7px; margin-bottom: 6px; }
  :where(body:not([data-fit="1"])) .gq-boss-hint { display: none; }
  :where(body:not([data-fit="1"])) .gq-levels { margin-bottom: 5px; gap: 4px; }
  :where(body:not([data-fit="1"])) .gq-lv { min-width: 52px; font-size: 10px; padding: 2px 5px; }
  :where(body:not([data-fit="1"])) .gq-lv small { font-size: 8px; }
  :where(body:not([data-fit="1"])) .gq-boss-glyph { font-size: 34px; }
  :where(body:not([data-fit="1"])) .gq-boss-name { font-size: 11px; margin-bottom: 3px; }
  :where(body:not([data-fit="1"])) .gq-hpbar { height: 11px; }
  :where(body:not([data-fit="1"])) .gq-hptxt { font-size: 10px; margin-top: 2px; }
  /* [claude code] 2026-08-17 v3.51 🔴 **這裡原本有兩組「為了塞下一屏」的硬壓縮，已整組移除**：
       ① v3.50 的「遊戲中收起 meta 條」（`body[data-view="game"] #metaBar:not(.mb-claimable)`）
       ② v3.49 的「夜市麻將賓果控制列 / 開牌托盤壓扁」
     使用者 2026-08-17:「**我想取消 C 的那個修改, 各版本來就有長有短, 硬限制很怪**」
     + 「（夜市麻將賓果）這個版本不好看」。
     🔴 **判斷改了**:各款版面本來就有長有短,**捲一下是正常的**;為了硬塞進一屏而把盤面夾小、
        把控制列壓扁,換來的是「小小一塊盤面浮在寬版面中間」——那比捲動難看得多。
     ⚠️ 所以本檔的 `.gq-boss`（闖關奪寶 BOSS 面板）那組壓縮**保留** —— 那是把「一塊過肥的 HUD」
        調到合理大小,不是為了硬塞一屏而犧牲主體。差別在**有沒有動到玩家在看的那塊**。 */
}
@media (max-height: 780px) {
  :where(body:not([data-fit="1"])) .spin-ticket { margin-bottom: 4px; font-size: 11px; }
  :where(body:not([data-fit="1"])) .machine { padding: 7px; }
  :where(body:not([data-fit="1"])) .btn-spin { padding: 10px 26px; font-size: 16px; }
  :where(body:not([data-fit="1"])) .control-row2 .auto-stop-sel, :where(body:not([data-fit="1"])) .control-row2 .auto-btn, :where(body:not([data-fit="1"])) .control-row2 .gamble-btn { height: 38px; font-size: 12.5px; }
}

/* ============================================================
   [claude code] 2026-07-29 v2.29 環遊世界（travel）：旅程列 / 行李箱 / 盤面符號分類 / 出國選單
   盤面沿用 cluster 的 N×N grid（.clus-board / .clus-cell）與 cs-win / cs-clear / cs-drop 三段表演；
   這裡只加「哪些符號會被收集」的視覺分類（本國綠框 / 🛂 金框 / ✈️ 藍框 / 外國淡出）與旅程 HUD。
   ============================================================ */
.tv-trip { width: min(100%, 470px); margin: 0 auto 8px; padding: 7px 12px 8px; border-radius: 14px;
  background: linear-gradient(160deg, rgba(38,58,92,.9), rgba(18,20,34,.92));
  border: 1px solid rgba(120,190,255,.28); box-shadow: 0 6px 20px rgba(0,0,0,.35); }
.tv-head { display: flex; align-items: center; gap: 8px; }
.tv-flag { font-size: 20px; }
.tv-name { font-size: 14.5px; font-weight: 900; color: #eaf4ff; }
.tv-rule { font-size: 11.5px; color: #9fd0ff; padding: 1px 8px; border-radius: 999px;
  border: 1px solid rgba(120,190,255,.4); background: rgba(80,160,255,.12); }
.tv-day { margin-left: auto; font-size: 12.5px; font-weight: 800; color: var(--gold); }
.tv-daybar { margin-top: 5px; height: 7px; border-radius: 999px; overflow: hidden; background: rgba(255,255,255,.09); }
.tv-dayfill { height: 100%; width: 0; border-radius: 999px; transition: width .45s cubic-bezier(.2,.9,.3,1);
  background: linear-gradient(90deg, #4ea8ff, #9be0ff); box-shadow: 0 0 12px rgba(90,180,255,.6); }
.tv-stats { display: flex; gap: 14px; margin-top: 5px; font-size: 12px; color: var(--text-soft); flex-wrap: wrap; }
.tv-stat b { color: #fff; font-size: 13px; margin: 0 2px; }
.tv-ico { margin-right: 3px; }
.tv-tier { margin-left: 6px; font-size: 11px; padding: 1px 7px; border-radius: 999px; font-weight: 800;
  color: #6a4a12; background: linear-gradient(135deg, #e7c07a, #c99a4e); }
.tv-tier.t1 { color: #3d4450; background: linear-gradient(135deg, #eef3f8, #b9c6d4); }
.tv-tier.t2 { color: #4a3400; background: linear-gradient(135deg, #ffe9a6, var(--gold)); box-shadow: 0 0 12px rgba(255,205,90,.6); }
.tv-pot-pop { animation: tvPotPop .4s ease; }
@keyframes tvPotPop { 0% { transform: scale(1); } 45% { transform: scale(1.28); color: var(--win); } 100% { transform: scale(1); } }

/* 盤面符號分類（框做在 .glyph 上 → 掉落時框跟著符號走，不分離；對齊 v2.22 鐵則） */
.tv-cell .glyph { box-sizing: border-box; display: flex; align-items: center; justify-content: center;
  width: 100%; height: 100%; border-radius: 9px; transition: opacity .2s; }
.tv-cell.tv-home .glyph { box-shadow: inset 0 0 0 1.5px rgba(90,225,160,.5); background: rgba(70,210,150,.1); }
.tv-cell.tv-stamp .glyph { box-shadow: inset 0 0 0 1.5px rgba(255,205,90,.7); background: rgba(255,200,80,.14); }
.tv-cell.tv-board .glyph { box-shadow: inset 0 0 0 1.5px rgba(120,190,255,.7); background: rgba(90,170,255,.14); }
.tv-cell.tv-foreign .glyph { opacity: .38; filter: grayscale(.55); }

/* 行李箱：本國 6 種紀念品各一格，裝滿即時給獎 */
.tv-bags { display: grid; grid-template-columns: repeat(6, 1fr); gap: 5px; width: min(100%, 470px); margin: 6px auto 0; }
.tv-bag { position: relative; padding: 4px 2px 5px; border-radius: 10px; text-align: center; overflow: hidden;
  background: rgba(255,255,255,.05); border: 1px solid rgba(255,255,255,.1); }
.tv-bag-glyph { font-size: 17px; line-height: 1.1; }
.tv-bag-num { font-size: 10px; color: var(--text-soft); }
.tv-bag-bar { margin-top: 3px; height: 4px; border-radius: 999px; background: rgba(255,255,255,.1); overflow: hidden; }
.tv-bag-fill { height: 100%; width: 0; border-radius: 999px; transition: width .35s ease;
  background: linear-gradient(90deg, #5ae1a0, #9bffcf); }
.tv-bag.full { animation: tvBagFull .6s ease; border-color: var(--win); }
@keyframes tvBagFull {
  0% { transform: none; box-shadow: none; }
  35% { transform: translateY(-5px) scale(1.09); box-shadow: 0 0 20px rgba(255,225,105,.85); }
  100% { transform: none; box-shadow: none; }
}
/* 收集到的符號飛向行李箱 / 旅費 */
.tv-fly { position: fixed; z-index: 65; font-size: 22px; pointer-events: none;
  animation: tvFly var(--fly-ms, 520ms) cubic-bezier(.3,.1,.4,1) forwards; }
@keyframes tvFly {
  from { transform: translate(-50%,-50%) scale(1); opacity: 1; }
  to { transform: translate(calc(-50% + var(--fly-x)), calc(-50% + var(--fly-y))) scale(.45); opacity: .1; }
}

/* 出國選單 overlay（沿用 .gq-ov 骨架，改成旅遊藍） */
.tv-ov { background: radial-gradient(circle at 50% 40%, rgba(22,48,86,.9), rgba(8,8,16,.95)); }
.tv-ov-box { background: linear-gradient(165deg, #1d3350, #131425); border-color: rgba(120,190,255,.45); }
.tv-ov .gq-ov-title { color: #cfe8ff; text-shadow: 0 0 18px rgba(80,170,255,.7); }
.tv-pick-countries { display: grid; grid-template-columns: repeat(2, 1fr); gap: 9px; margin: 13px 0 4px; }
.tv-pick-country { padding: 9px 8px; border-radius: 13px; cursor: pointer; text-align: left; transition: .18s;
  background: rgba(255,255,255,.05); border: 1.5px solid rgba(255,255,255,.12); }
.tv-pick-country:hover { background: rgba(120,190,255,.12); }
.tv-pick-country.on { border-color: #6fc0ff; background: rgba(90,170,255,.2); box-shadow: 0 0 16px rgba(90,170,255,.4); }
.tv-pc-head { font-size: 14px; font-weight: 900; color: #fff; }
.tv-pc-sub { margin-top: 2px; font-size: 11px; color: var(--text-soft); line-height: 1.45; }
.tv-pc-syms { margin-top: 4px; font-size: 15px; letter-spacing: 1px; }
.tv-pick-label { margin-top: 12px; font-size: 12px; color: var(--text-soft); }
.tv-pick-days { display: flex; gap: 8px; justify-content: center; margin-top: 6px; flex-wrap: wrap; }
.tv-pick-day { padding: 7px 16px; border-radius: 999px; cursor: pointer; font-weight: 800; font-size: 13px;
  color: #cfe8ff; background: rgba(255,255,255,.06); border: 1.5px solid rgba(255,255,255,.14); transition: .18s; }
.tv-pick-day.on { color: #10233a; background: linear-gradient(135deg, #bfe4ff, #6fc0ff); border-color: #fff; }
.tv-pick-info { margin-top: 11px; font-size: 12px; line-height: 1.7; color: var(--text-soft);
  background: rgba(255,255,255,.04); border-radius: 10px; padding: 8px 10px; text-align: left; }
.tv-pick-info b { color: #fff; }
.tv-pick-btns { display: flex; gap: 10px; justify-content: center; }
.tv-ov .gq-ov-close { background: linear-gradient(135deg, #bfe4ff, #6fc0ff); color: #10233a; }
.tv-ov .gq-ov-close.tv-cancel { background: rgba(255,255,255,.1); color: var(--text-soft); }
/* 細單：travel 盤面格分類 */
.dt-scell.k-home { background: rgba(70,210,150,.14); border-color: rgba(90,225,160,.5); }
.dt-scell.k-stamp { background: rgba(255,200,80,.16); border-color: rgba(255,205,90,.6); }
.dt-scell.k-board { background: rgba(90,170,255,.16); border-color: rgba(120,190,255,.6); }
.dt-scell.k-foreign { opacity: .42; }
.dt-scell.tvpick { box-shadow: inset 0 0 0 2px var(--win); }

@media (max-height: 780px) {
  :where(body:not([data-fit="1"])) .tv-trip { padding: 5px 10px 6px; margin-bottom: 5px; }
  :where(body:not([data-fit="1"])) .tv-bags { gap: 4px; }
  :where(body:not([data-fit="1"])) .tv-bag-glyph { font-size: 15px; }
}

/* [claude code] 2026-07-29 v2.30 環遊世界收集規則改「湊數量」後的三種格子狀態（依使用者回饋）:
   ① .cs-win  = 有湊夠、被收走計分（沿用平台通用高亮）
   ② .tv-stay = 沒湊夠、**留在盤上**累積 → 藍框呼吸 + 右上角「差 N」角標
   ③ .tv-sweep= 沒收集到的外國符號 / 用掉的 ✈️ → 淡出離場 */
.tv-cell { position: relative; }
.tv-cell.tv-stay { z-index: 4; }
.tv-cell.tv-stay .glyph { animation: tvStayPulse .9s ease-in-out infinite alternate; }
@keyframes tvStayPulse {
  from { box-shadow: inset 0 0 0 1.5px rgba(120,190,255,.5); }
  to   { box-shadow: inset 0 0 0 2.5px #6fc0ff, 0 0 14px rgba(90,170,255,.55); }
}
.tv-cell.tv-stay::after {
  content: attr(data-short); position: absolute; right: 2px; top: 1px; z-index: 5;
  font-size: 10px; font-weight: 800; line-height: 1.5; padding: 0 4px; border-radius: 999px;
  color: #10233a; background: linear-gradient(135deg, #bfe4ff, #6fc0ff); box-shadow: 0 1px 4px rgba(0,0,0,.4);
}
.tv-cell.tv-sweep .glyph { animation: tvSweep .32s ease forwards; }
@keyframes tvSweep { to { opacity: .12; transform: scale(.82); filter: grayscale(1); } }
/* 行李箱格上的「湊 N 顆」門檻角標 */
.tv-bag-glyph { position: relative; }
.tv-bag-min { position: absolute; right: -2px; top: -3px; font-size: 9px; font-weight: 800;
  padding: 0 3px; border-radius: 999px; color: #10233a; background: linear-gradient(135deg, #bfe4ff, #6fc0ff); }
.tv-need { color: var(--text-mute); font-size: 11px; margin-left: 1px; }

.dt-scell.tvstay { box-shadow: inset 0 0 0 2px #6fc0ff; }
.dt-line.dt-line-dim { opacity: .6; }

/* ===== [claude code] 2026-07-31 v2.33 深海潛行（dive）=====
   航道是「往深處捲動的視窗」：.dv-view 固定高度 + overflow hidden，.dv-lane 整片 translateY
   → 鏡頭跟著潛水員下沉。未揭露的排一律深黑（server 也沒給內容，見 engine/dive.go 的裁切）。 */
.dv-hud { width: min(100%, 470px); margin: 0 auto 8px; padding: 7px 12px 8px; border-radius: 14px;
  background: linear-gradient(135deg, rgba(20,60,95,.72), rgba(8,26,48,.72)); border: 1px solid rgba(110,190,255,.28); }
/* [claude code] 2026-08-14 v2.92 「換潛點」鈕（選完潛點就留在潛水畫面，要換點才點這裡）。
   [claude code] 2026-08-14 v2.93 🔴 可點的只有左邊那顆 `.dv-pick`，不是整排 ——
   v2.93 把 🪣 漁獲袋也收進這一排了，整排可點的話「看一下賺多少」會誤觸換潛點。 */
.dv-head { display: flex; align-items: center; gap: 7px; }
.dv-pick { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; border-radius: 8px;
  padding: 2px 6px; margin: -2px -2px; transition: background .15s; }
.dv-pick:hover { background: rgba(120,190,255,.12); }
.dv-pick:focus-visible { outline: 2px solid #6fc0ff; outline-offset: 1px; }
.dv-switch { font-size: 10.5px; font-weight: 800; color: #9fd0ff; padding: 1px 6px; border-radius: 999px;
  border: 1px solid rgba(120,190,255,.4); background: rgba(90,170,255,.12); white-space: nowrap; }
.dv-emoji { font-size: 19px; }
.dv-name { font-weight: 900; font-size: 14px; color: #cfe8ff; }
/* [claude code] 2026-08-05 v2.42 .dv-spot-btn（換潛點鈕）已移除 —— 潛點改成每趟在盤面四個區直接選 */
.dv-depth { margin-left: auto; font-size: 11.5px; color: var(--text-soft); }
/* [claude code] 2026-08-14 v2.93 原本這裡有 `.dv-oxy` / `.dv-oxybar` / `.dv-oxyfill`（HUD 的氧氣條）——
   氧氣改掛在潛水員身上（`.dv-d-oxy`，見下）後整組移除，HUD 也從兩排收成一排。 */
.dv-catch { font-size: 12px; color: var(--text-soft); }
.dv-catch b { color: var(--win); font-size: 14px; }
/* [claude code] 2026-08-14 v2.93 🫧 氧氣徽章：掛在潛水員右下角（取代 HUD 那條氧氣條）。
   剩幾排就寫幾 —— 貼在潛水員身上，往下潛時數字跟著他一起動，比抬頭去看一條進度條直覺得多。 */
.dv-d-oxy { position: absolute; right: -2px; bottom: -2px; z-index: 3; pointer-events: none;
  font-weight: 900; line-height: 1; padding: 2px 4px; border-radius: 999px;
  color: #06202e; background: linear-gradient(#bfeaff, #6fc0ff);
  box-shadow: 0 0 8px rgba(110,200,255,.75), inset 0 1px 0 rgba(255,255,255,.6); }
.dv-d-oxy.low { background: linear-gradient(#ffd8a8, #ff9a4a); color: #2e1605;
  box-shadow: 0 0 10px rgba(255,150,70,.85); animation: dvOxyLow .9s ease-in-out infinite; }
.dv-d-oxy.out { background: linear-gradient(#ffb3b3, #ff6a6a); color: #2e0a0a; animation: none; }
@keyframes dvOxyLow { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.14); } }
.dv-diver { display: flex; align-items: center; justify-content: center; }
.dv-d-g { line-height: 1; }

/* 盤面就是「選潛點」的畫面（[claude code] 2026-08-05 v2.42）：四個區由上而下＝越潛越深，
   點一區就直接出發。取代原本的彈窗選單 + 「換潛點」鈕。 */
/* [claude code] 2026-08-14 v2.91 換到版型 v2 + 簡化：高度由 JS 夾成「可用高度」（見 renderDVChooser），
   四個區用 flex 均分 → 不管螢幕多矮，SPIN 都還在畫面上（手機一屏可見鐵則）。 */
.board.dv-choose { display: flex; flex-direction: column; gap: 6px; width: min(100%, 470px); margin: 0 auto;
  padding: 8px; border-radius: 14px; background: linear-gradient(180deg, rgba(20,70,110,.5), rgba(2,10,24,.92)); }
.dv-ch-head { font-size: 12.5px; font-weight: 800; color: #cfe8ff; text-align: center; flex: 0 0 auto; }
.dv-zone { padding: 7px 10px; border-radius: 12px; cursor: pointer; text-align: left; transition: .18s;
  flex: 1 1 0; min-height: 0; display: flex; flex-direction: column; justify-content: center;
  border: 1px solid rgba(120,190,255,.3); background: linear-gradient(180deg, rgba(90,170,255,.14), rgba(90,170,255,.05)); }
/* 越下面的區＝越深：底色越暗、藍越沉 */
.dv-zone.z1 { background: linear-gradient(180deg, rgba(70,150,240,.13), rgba(40,100,190,.06)); }
.dv-zone.z2 { background: linear-gradient(180deg, rgba(50,110,200,.13), rgba(20,60,140,.06)); border-color: rgba(120,190,255,.24); }
.dv-zone.z3 { background: linear-gradient(180deg, rgba(24,60,130,.16), rgba(2,10,30,.5)); border-color: rgba(120,190,255,.2); }
.dv-zone:hover { border-color: #6fc0ff; box-shadow: 0 0 14px rgba(90,170,255,.35); transform: translateY(-1px); }
.dv-zone.go { border-color: #6fc0ff; box-shadow: 0 0 20px rgba(90,170,255,.6); }
.dv-z-main { display: flex; align-items: baseline; flex-wrap: wrap; gap: 6px; }
.dv-z-emoji { font-size: 17px; }
.dv-z-name { font-size: 14px; font-weight: 900; color: #eaf4ff; }
/* [claude code] 2026-08-14 v2.91 波動檔徽章 —— SLOT 玩家的母語，四個潛點真正的差別就是這個。
   低→極高：綠 → 黃 → 橘 → 紅（跟平台其他地方的「越燙越紅」一致；⚠️ 這是風險刻度不是損益，
   所以不套「台灣紅賺綠賠」那條 —— 那條管的是賺賠配色）。 */
.dv-z-vol { font-size: 10.5px; font-weight: 900; padding: 1px 7px; border-radius: 999px; letter-spacing: .03em; }
.dv-z-vol.v0 { color: #0e2a18; background: linear-gradient(#b9f0cd, #6bd898); }
.dv-z-vol.v1 { color: #2a2206; background: linear-gradient(#ffe9a8, #ffcf4a); }
.dv-z-vol.v2 { color: #2e1605; background: linear-gradient(#ffcb9a, #ff9a4a); }
.dv-z-vol.v3 { color: #2e0a0a; background: linear-gradient(#ffb3b3, #ff6a6a); }
.dv-z-gate { font-size: 10.5px; font-weight: 800; color: #ffd76a; }
/* 「最貴的那隻」貼右：🔴 顯示的是 ×總注（賠率 ÷ divisor），不是設定檔裡的原始賠率 */
.dv-z-top { margin-left: auto; font-size: 11px; color: #9fd0ff; white-space: nowrap; }
.dv-z-top b { color: #ffd76a; font-size: 12.5px; }
.dv-z-sub { margin-top: 3px; font-size: 11px; color: var(--text-soft); line-height: 1.45;
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 8px; }
/* 內部參數（氧氣 / 光圈）降成小 meta：留著（不給看等於逼玩家瞎選），但不再是主角 */
.dv-z-meta { font-size: 10px; color: #7fb4e0; opacity: .9; }
.dv-ch-info { font-size: 10.5px; color: var(--text-soft); line-height: 1.4; text-align: center; flex: 0 0 auto; }
/* 按了 SPIN 但還沒選 → 整片閃一下提醒「要先點一個區」 */
.board.dv-choose.hint { animation: dvHint .7s ease; }
@keyframes dvHint { 0%,100% { box-shadow: none; } 40% { box-shadow: 0 0 0 2px #6fc0ff, 0 0 22px rgba(90,170,255,.55); } }
@media (max-height: 780px) {
  :where(body:not([data-fit="1"])) .dv-zone { padding: 5px 9px; }
  /* [claude code] 2026-08-14 v2.91 矮螢幕先收「氧氣 / 光圈」那顆小 meta（次要資訊），
     再收底下那句回報率說明 —— 波動檔與最貴倍數是選擇依據，最後才會被犧牲。 */
  :where(body:not([data-fit="1"])) .dv-z-meta { display: none; }
  :where(body:not([data-fit="1"])) .dv-ch-info { display: none; }
}

/* 航道視窗 */
.board.dv-view { display: block; overflow: hidden; position: relative; margin: 0 auto;
  border-radius: 14px; background: linear-gradient(180deg, rgba(20,70,110,.5), rgba(2,10,24,.92)); }
.dv-lane { display: grid; gap: 4px; transition: transform .42s cubic-bezier(.4,.1,.2,1); will-change: transform; }
.dv-cell { position: relative; border-radius: 9px; display: flex; align-items: center; justify-content: center;
  background: rgba(255,255,255,.03); box-shadow: inset 0 0 0 1px rgba(255,255,255,.05); }
.dv-cell .glyph { display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; }
.dv-cell.dv-hidden { background: rgba(0,0,0,.42); box-shadow: none; }
.dv-cell.dv-sea .glyph { opacity: .3; }
/* [claude code] 2026-08-14 v2.92 **前方還沒潛到的排**：看得到、但明顯「還在遠處」——
   壓暗 + 輕微模糊 + 縮一點。要一眼分得出「已經收到的」跟「只是先看到的」，
   不然玩家會以為那些已經進袋了。潛到那排時 dvRevealRow 重畫，這個 class 自動消失。 */
.dv-cell.dv-peek { opacity: .42; filter: blur(.7px) saturate(.75); transform: scale(.9); }
.dv-cell.dv-peek .glyph { text-shadow: none; }
/* [claude code] 2026-08-14 v2.93 格子上的金額徽章：撿到的（金）/ 錯過的（紅，帶刪除線＝沒進袋）。
   使用者：「撿到的東西, 可以顯示金額嗎, 這樣子才知道自己少撿了多少錢的」。 */
.dv-cell { position: relative; }
.dv-val { position: absolute; left: 50%; bottom: 1px; transform: translateX(-50%); z-index: 5;
  font-size: 10px; font-weight: 900; line-height: 1; padding: 1px 4px; border-radius: 6px;
  white-space: nowrap; pointer-events: none; }
.dv-val.take { color: #2a1d00; background: linear-gradient(#fff3c8, var(--gold));
  box-shadow: 0 0 7px rgba(255,207,58,.7); }
.dv-val.miss { color: #ffd8d8; background: rgba(120,20,20,.75); text-decoration: line-through;
  border: 1px solid rgba(255,120,120,.5); }
.dv-cell.dv-oxy2 .glyph { filter: drop-shadow(0 0 6px rgba(140,220,255,.9)); }
.dv-cell.dv-gate2 .glyph { animation: dvGateGlow 1.1s ease-in-out infinite alternate; }
@keyframes dvGateGlow { from { filter: drop-shadow(0 0 3px rgba(255,190,90,.6)); }
  to { filter: drop-shadow(0 0 14px rgba(255,170,60,1)); transform: scale(1.08); } }
/* 光圈照到（可收） */
.dv-cell.lit { box-shadow: inset 0 0 0 2px rgba(255,240,170,.75), 0 0 16px rgba(255,225,120,.4);
  background: rgba(255,230,140,.12); }
/* 收進漁獲袋 */
.dv-cell.took .glyph { animation: dvTook .34s ease forwards; }
@keyframes dvTook { to { opacity: 0; transform: scale(.5) translateY(-10px); } }
/* 錯過的：擦身而過（側邊）/ 差一點就到（前方） */
.dv-cell.miss-side { box-shadow: inset 0 0 0 2px rgba(150,175,205,.55); }
.dv-cell.miss-ahead { box-shadow: inset 0 0 0 2px rgba(255,140,140,.7); background: rgba(255,90,90,.1); }
.dv-cell.miss-big .glyph { animation: dvMissBig 1s ease-in-out infinite alternate; }
@keyframes dvMissBig { from { transform: scale(1); } to { transform: scale(1.14); filter: drop-shadow(0 0 12px rgba(255,120,120,.95)); } }
/* 潛水員 */
.dv-diver { position: absolute; z-index: 6; pointer-events: none; display: flex; align-items: center; justify-content: center;
  transition: transform .42s cubic-bezier(.4,.1,.2,1); filter: drop-shadow(0 0 10px rgba(140,220,255,.85)); }
.board.dv-view.shake { animation: dvShake .45s ease; }
@keyframes dvShake { 0%,100% { transform: translateX(0); } 20% { transform: translateX(-7px); }
  45% { transform: translateX(6px); } 70% { transform: translateX(-4px); } }
/* 飛進漁獲袋 */
.dv-fly { position: fixed; z-index: 65; font-size: 22px; pointer-events: none;
  transform: translate(-50%, -50%); animation: dvFly var(--fly-ms, 460ms) cubic-bezier(.3,.1,.2,1) forwards; }
@keyframes dvFly { to { transform: translate(calc(-50% + var(--fly-x)), calc(-50% + var(--fly-y))) scale(.42); opacity: .1; } }

/* 「這趟錯過了什麼」面板 */
.dv-missed { width: min(100%, 470px); margin: 6px auto 0; padding: 6px 10px 7px; border-radius: 12px;
  font-size: 11.5px; color: var(--text-soft); text-align: left;
  background: rgba(255,255,255,.04); border: 1px solid rgba(255,255,255,.08); }
.dv-missed .dv-m-title { font-weight: 800; color: #ffb0b0; }
.dv-missed .dv-m-list { margin-top: 3px; display: flex; flex-wrap: wrap; gap: 4px 8px; }
.dv-missed .dv-m-item.big { color: #ffd0d0; font-weight: 800; }

/* [claude code] 2026-08-05 v2.42 潛點選單彈窗（.dv-ov / .dv-pick-* / .dv-ps-*）已移除 ——
   潛點改成每趟在盤面上的四個區直接選（見上面 .board.dv-choose / .dv-zone）。
   🔱 深淵之門的 BONUS 彈窗仍在，用的是 .dv-gate-ov（下面那組，琥珀色，不受影響）。 */

/* 深淵之門 BONUS overlay（續潛階梯） */
.dv-gate-ov .gq-ov-box { background: linear-gradient(160deg, rgba(52,26,8,.97), rgba(10,6,20,.98)); border-color: rgba(255,180,80,.45); }
.dv-gate-ov .gq-ov-title { color: #ffd88a; text-shadow: 0 0 18px rgba(255,150,60,.8); }
.dv-rungs { display: grid; gap: 4px; margin-top: 12px; max-height: 46vh; overflow-y: auto; }
.dv-rung { display: flex; align-items: center; gap: 8px; padding: 5px 10px; border-radius: 10px;
  background: rgba(255,255,255,.05); opacity: 0; transform: translateY(6px); transition: .22s; }
.dv-rung.show { opacity: 1; transform: none; }
.dv-rung .dv-r-lv { font-size: 11.5px; color: var(--text-soft); min-width: 54px; text-align: left; }
.dv-rung .dv-r-mult { font-size: 12px; color: #ffd88a; }
.dv-rung .dv-r-pay { margin-left: auto; font-weight: 900; color: var(--win); }
.dv-rung.end { background: rgba(255,90,90,.16); }
.dv-rung.end .dv-r-lv { color: #ffc9c9; }
.dv-gate-total { margin-top: 10px; font-size: 17px; font-weight: 900; color: #fff; }
.dv-gate-total b { color: var(--win); text-shadow: 0 0 14px rgba(255,225,105,.8); }

/* 細單：航道盤面 */
.dt-dive { gap: 3px; }
.dt-scell.dvlit { box-shadow: inset 0 0 0 2px rgba(255,240,170,.8); background: rgba(255,230,140,.13); }
.dt-scell.dvtook { box-shadow: inset 0 0 0 2px var(--win); background: rgba(255,225,105,.16); }
.dt-scell.dvmiss { box-shadow: inset 0 0 0 2px rgba(255,140,140,.7); }
.dt-scell.dvhidden { background: rgba(0,0,0,.4); }
.dt-scell.dvdiver { box-shadow: inset 0 0 0 2px #6fc0ff, 0 0 12px rgba(90,170,255,.6); }

@media (max-height: 840px) {
  :where(body:not([data-fit="1"])) .dv-hud { padding: 5px 10px 6px; margin-bottom: 5px; }
  :where(body:not([data-fit="1"])) .dv-missed { display: none !important; }
}

/* ===== [claude code] 2026-08-05 v2.44 蟻巢遠征（ants：地面覓食）=====
   🔴 舊版是「往地下捲動的視窗 + 迷霧」，整組砍掉：這款盤面**一屏全可見、無捲動、無迷霧**
   （食物本來就該全部看得到 —— 那才是螞蟻覓食的畫面）。 */
.ant-hud { width: min(100%, 470px); margin: 0 auto 8px; padding: 7px 12px 8px; border-radius: 14px;
  background: linear-gradient(135deg, rgba(74,52,30,.75), rgba(32,22,12,.78)); border: 1px solid rgba(210,160,90,.3); }
.an-head { display: flex; align-items: center; gap: 10px; }
.an-squad { font-weight: 900; font-size: 13px; color: #d8b57e; }
/* [claude code] 2026-08-09 v2.51 出動池是這款唯一要盯的數字 → 字最大、顏色最亮 */
.an-squad b { font-size: 19px; color: #ffe6b0; margin-left: 2px; }
/* 這趟倍數：×1 時低調，>×1 就發亮（「愈後面愈值錢」要看得到） */
.an-mult { font-size: 13px; font-weight: 900; color: #9aa4b2; }
.an-mult.an-mult-hot { color: #ffd45e; text-shadow: 0 0 10px rgba(255,200,70,.6); }
.an-trip { font-size: 12.5px; color: #d8b57e; }
.an-catch { margin-left: auto; font-size: 12.5px; color: var(--text-soft); }
.an-catch b { color: var(--win); font-weight: 900; }
.an-legend { margin-top: 5px; font-size: 10.5px; line-height: 1.6; color: var(--text-soft); }
.an-lg { display: inline-block; padding: 0 4px; border-radius: 999px; font-size: 9.5px; font-weight: 800;
  color: #2a1a08; background: rgba(240,200,130,.92); }

/* 地面（一屏全可見） */
.board.ant-view { display: flex; align-items: center; justify-content: center; margin: 0 auto; overflow: visible;
  border-radius: 14px; background: linear-gradient(180deg, rgba(96,120,60,.35), rgba(30,26,14,.9)); }
.ant-ground { display: grid; }
.ant-cell { position: relative; border-radius: 8px; display: flex; align-items: center; justify-content: center;
  background: rgba(120,140,70,.18); box-shadow: inset 0 0 0 1px rgba(255,255,255,.05); }
.ant-cell .glyph { display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; }
.ant-cell.an-empty { background: rgba(120,140,70,.14); }
/* [claude code] 2026-08-05 v2.49 空地畫 🌿 但壓淡 —— 有草地才像一片地面（細單本來就有，主畫面補回來），
   壓淡是為了讓「有食物的格」仍然一眼跳出來。 */
.ant-cell.an-empty .glyph { opacity: .3; }
.ant-cell.an-food { background: rgba(255,210,120,.12); box-shadow: inset 0 0 0 1.5px rgba(255,200,110,.4); }
.ant-cell.an-nest { background: rgba(150,110,60,.5); box-shadow: inset 0 0 0 2px rgba(230,180,110,.7); }
.ant-cell.an-hill { background: rgba(120,120,130,.3); }
.ant-cell.an-water { background: rgba(90,160,220,.22); }
.ant-cell.an-hole { background: rgba(20,16,10,.75); }
.ant-cell.an-blocked { opacity: .5; }
/* 🔴 [claude code] 2026-08-09 v2.53 **燃料框**（使用者：「希望能加入 scatter 或是不用標注字的框，
   用來讓別人明白很特別」）：回巢補的隻數 ≥ 派出去的 —— 這是「還能不能再出一趟」的關鍵，
   但它在賠付表上是最便宜的那幾樣，玩家不會注意。**用框講，不寫字**：
     · 淨不虧 → 綠色呼吸框
     · 大幅增兵（🍯）→ 金色脈動框 + 外光暈（這款的 FREE SPIN，要跟 SCATTER 一樣搶眼） */
.ant-cell.an-fuel { box-shadow: inset 0 0 0 2px rgba(120,235,150,.7); animation: anFuel 2.1s ease-in-out infinite; }
@keyframes anFuel { 50% { box-shadow: inset 0 0 0 2.5px rgba(150,255,180,1), 0 0 10px rgba(110,230,150,.45); } }
.ant-cell.an-fuel-big { background: rgba(255,205,90,.14);
  box-shadow: inset 0 0 0 2.5px rgba(255,205,90,.9), 0 0 12px rgba(255,190,70,.5);
  animation: anFuelBig 1.5s ease-in-out infinite; }
@keyframes anFuelBig { 50% { box-shadow: inset 0 0 0 3px rgba(255,235,150,1), 0 0 22px rgba(255,200,80,.95); } }
.ant-cell.an-fuel-big .glyph { animation: anFuelPop 1.5s ease-in-out infinite; }
@keyframes anFuelPop { 50% { transform: scale(1.12); } }
/* 已搬走 / 湊不到的格不要再閃（框只用來標「還在地上、而且是燃料」） */
.ant-cell.an-took.an-fuel, .ant-cell.an-took.an-fuel-big,
.ant-cell.an-cant.an-fuel, .ant-cell.an-cant.an-fuel-big { animation: none; }
.ant-cell.an-cant.an-fuel, .ant-cell.an-cant.an-fuel-big { box-shadow: inset 0 0 0 1.5px rgba(255,140,140,.35); }
/* 🔴 [claude code] 2026-08-09 v2.52 **搬走的格要看得出結果**（使用者：「只是拿掉數字，看不出來結果」）：
   圖示留著壓淡 + 左下 ✅ + 右上「+實拿多少」→ 整盤掃完就是一張「這局在哪幾格賺了多少」的收據。 */
.ant-cell.an-took { background: rgba(120,200,120,.10); box-shadow: inset 0 0 0 1.5px rgba(140,220,140,.42); }
.ant-cell.an-took .glyph { opacity: .34; filter: grayscale(.5); }
.an-need.an-need-took { color: #06301a; background: linear-gradient(135deg, #b6f5c9, #6fdd92); }
.ant-cell.an-took .an-pay { color: #8ef0a8; text-shadow: 0 1px 3px rgba(0,0,0,.85); }
/* 食物角落：要幾隻（左下）+ 搬回來值多少（右上） */
.an-need { position: absolute; left: 1px; bottom: 0; font-size: 9.5px; font-weight: 800; line-height: 1.4;
  padding: 0 3px; border-radius: 999px; color: #2a1a08; background: rgba(240,200,130,.92); }
/* 🔴 [claude code] 2026-08-09 v2.51 當下出動池湊不到的格：標籤翻紅寫「差 N」+ 整格壓暗。
   使用者要的「畫面上顯示還能出動幾隻」不只是 HUD 一個數字 ——
   盤面當場分成「搬得動 / 搬不動」兩種顏色，才看得出這趟會發生什麼。 */
.an-need.an-need-short { color: #3a0d0d; background: linear-gradient(135deg, #ffc9c9, #ff8a8a); }
.ant-cell.an-cant { opacity: .62; box-shadow: inset 0 0 0 1.5px rgba(255,140,140,.35); }
.ant-cell.an-cant .an-pay { opacity: .55; }
.an-pay { position: absolute; right: 2px; top: 0; font-size: 9px; font-weight: 900; color: var(--win);
  text-shadow: 0 1px 3px rgba(0,0,0,.8); }
/* 🔴 [claude code] 2026-08-09 v2.53 **換一片地** 取代原本的「由上往下掉」。
   使用者：「畫面上不用由上下往掉，能讓人換場景的動作，感覺好像換個地方」——
   逐格掉看起來像**洗牌 / 重發同一副牌**，跟「螞蟻走到另一塊地覓食」對不上。
   A. 整片滑出 / 滑入（鏡頭跟著螞蟻走到下一塊地）　B. 進場後由近而遠逐圈浮現（原地淡入，不位移） */
.ant-ground.an-scene-in { animation: anSceneIn .52s cubic-bezier(.22,.9,.28,1); }
@keyframes anSceneIn { from { transform: translateX(46%) scale(.94); opacity: 0; } to { transform: none; opacity: 1; } }
.ant-ground.an-scene-out { animation: anSceneOut .3s ease-in forwards; }
@keyframes anSceneOut { to { transform: translateX(-42%) scale(.94); opacity: 0; } }
.ant-cell.an-hide { opacity: 0; }
.ant-cell.an-rise { animation: anRise .34s cubic-bezier(.34,1.4,.64,1); }
@keyframes anRise { from { opacity: 0; transform: scale(.62); } to { opacity: 1; transform: none; } }
/* 每一局換一種草地色調 —— 「這次是走到另一片地」最直接的訊號（色調由盤面 hash 決定，可重播） */
.board.ant-view.an-scene-0 { background: linear-gradient(180deg, rgba(96,120,60,.35), rgba(30,26,14,.9)); }
.board.ant-view.an-scene-1 { background: linear-gradient(180deg, rgba(72,124,86,.35), rgba(18,30,20,.9)); }
.board.ant-view.an-scene-2 { background: linear-gradient(180deg, rgba(130,116,54,.35), rgba(34,28,12,.9)); }
.board.ant-view.an-scene-3 { background: linear-gradient(180deg, rgba(78,110,124,.32), rgba(16,24,30,.9)); }
.board.ant-view.an-scene-4 { background: linear-gradient(180deg, rgba(124,92,60,.34), rgba(32,22,12,.9)); }
.board.ant-view.an-scene-5 { background: linear-gradient(180deg, rgba(96,84,128,.30), rgba(22,18,32,.9)); }

/* 扛走 / 差一點 */
.ant-cell.an-carry .glyph { animation: anCarry .45s ease forwards; }
@keyframes anCarry { to { opacity: 0; transform: scale(.4) translateY(-16px); } }
.ant-cell.an-short { box-shadow: inset 0 0 0 2px rgba(255,130,130,.75); }
.ant-cell.an-short .glyph { animation: anShake .5s ease-in-out infinite alternate; }
@keyframes anShake { from { transform: translateX(-2px) rotate(-5deg); } to { transform: translateX(2px) rotate(5deg); } }
.ant-cell.an-short-big { background: rgba(255,90,90,.16); }
.an-shorttag { position: absolute; left: 50%; top: -8px; transform: translateX(-50%); white-space: nowrap; z-index: 9;
  font-size: 10px; font-weight: 900; padding: 1px 5px; border-radius: 999px;
  color: #3a0d0d; background: linear-gradient(135deg, #ffc9c9, #ff7a7a); }

/* 螞蟻（沿路走；同格散開 + ×N，不疊圖） */
/* 🔴 [claude code] 2026-08-09 v2.52 盤面上的兩顆徽章（出動池 / 倍數）。
   使用者：「能出動的數量和倍數很重要，放在上面看中間表演時完全不會注意，也很難去查看」——
   表演時視線都在盤面上，所以把這兩個數字**搬進盤面裡**：池子貼巢口（兵從那裡出去）、倍數貼右上角。 */
.an-pool-badge { position: absolute; z-index: 12; transform: translate(-50%, -100%);
  display: flex; align-items: center; gap: 3px; padding: 2px 9px 2px 7px; border-radius: 999px;
  background: linear-gradient(135deg, rgba(92,62,28,.97), rgba(48,32,14,.97));
  border: 1.5px solid rgba(255,205,120,.75); box-shadow: 0 3px 10px rgba(0,0,0,.55);
  white-space: nowrap; line-height: 1.15; }
.an-pool-badge .apb-ico { font-size: 13px; }
.an-pool-badge b { font-size: 19px; font-weight: 900; color: #ffe6b0; text-shadow: 0 1px 4px rgba(0,0,0,.7); }
.an-mult-badge { position: absolute; z-index: 12; right: 2px; top: 2px; padding: 2px 8px; border-radius: 999px;
  font-size: 12px; font-weight: 900; color: #9aa4b2; line-height: 1.3;
  background: rgba(18,16,28,.82); border: 1px solid rgba(255,255,255,.12); }
.an-mult-badge b { font-size: 17px; margin-left: 2px; }
.an-mult-badge.an-mult-hot { color: #ffd45e; border-color: rgba(255,200,70,.6);
  box-shadow: 0 0 14px rgba(255,190,60,.45); }
/* 數字有變就放大閃一下 —— 「本錢在動」要用餘光就看得到（漲綠、跌紅） */
.an-pool-badge.an-bump { animation: anBump .42s cubic-bezier(.34,1.56,.64,1); }
@keyframes anBump { 0% { transform: translate(-50%,-100%) scale(1); } 45% { transform: translate(-50%,-100%) scale(1.32); } 100% { transform: translate(-50%,-100%) scale(1); } }
.an-mult-badge.an-bump { animation: anBumpPlain .42s cubic-bezier(.34,1.56,.64,1); }
@keyframes anBumpPlain { 0% { transform: scale(1); } 45% { transform: scale(1.35); } 100% { transform: scale(1); } }
.an-pool-badge.an-bump-up { border-color: rgba(150,240,170,.95); box-shadow: 0 0 16px rgba(120,230,150,.6); }
.an-pool-badge.an-bump-down { border-color: rgba(255,160,140,.9); box-shadow: 0 0 14px rgba(255,130,110,.45); }

.ant-bug { z-index: 6; pointer-events: none; display: flex; align-items: center; justify-content: center;
  transition: transform .22s linear; filter: drop-shadow(0 0 5px rgba(255,220,150,.7)); }
.an-bug-n { position: absolute; left: 50%; bottom: -2px; transform: translateX(-50%); white-space: nowrap;
  font-size: 10px; font-weight: 900; color: #2a1a08; background: rgba(255,225,150,.95);
  border-radius: 999px; padding: 0 4px; line-height: 1.35; }
.an-bug-n:empty { display: none; }
.an-fly { position: fixed; z-index: 65; font-size: 20px; pointer-events: none;
  transform: translate(-50%, -50%); animation: anFly var(--fly-ms, 460ms) cubic-bezier(.3,.1,.2,1) forwards; }
@keyframes anFly { to { transform: translate(calc(-50% + var(--fly-x)), calc(-50% + var(--fly-y))) scale(.42); opacity: .1; } }

/* [claude code] 2026-08-09 v2.51 🔴 偵察兵樣式整段移除（an-scout / an-trail / an-found / an-foundtag）——
   「由近而遠」之後不需要演一個出門的理由，理由就寫在盤面上。 */
/* 扛著食物走 —— 食物掛在領頭那隻身上，整群一起往巢口移動 */
.an-carrying { position: absolute; left: 50%; top: -60%; transform: translateX(-50%);
  font-size: 0.95em; filter: drop-shadow(0 1px 3px rgba(0,0,0,.6)); }
.ant-bug.an-loaded { filter: drop-shadow(0 0 6px rgba(255,225,120,.9)); z-index: 9; }

/* 每一趟發生什麼（搬回什麼 + 最可惜的那一樣） */
.ant-log { width: min(100%, 470px); margin: 6px auto 0; padding: 6px 10px 7px; border-radius: 12px;
  font-size: 11.5px; color: var(--text-soft); text-align: left;
  background: rgba(255,255,255,.04); border: 1px solid rgba(255,255,255,.08); }
.an-lg-row { line-height: 1.75; }
.an-lg-row b { color: #f2d9a8; }
.an-lg-ok { margin-left: 6px; color: var(--win); font-weight: 700; }
.an-lg-non { margin-left: 6px; opacity: .7; }
.an-lg-miss { margin-left: 6px; color: #ffb0b0; }
/* 🍯 回巢增兵那一段（這款的免費遊戲）要在紀錄裡看得到 */
.an-lg-fed { margin-left: 6px; color: #ffd45e; font-weight: 700; }
.an-lg-fin { border-top: 1px dashed rgba(255,255,255,.14); margin-top: 3px; padding-top: 3px; }
/* 賠付表：開局扛不動 / 淨增兵 */
.an-pt-over { color: #ff9a9a; }
.an-pt-plus { color: #ffd45e; }
/* 賠付表上的「框」色塊 —— 跟盤面那圈光是同一套語言，玩家對得起來 */
.an-pt-frame { display: inline-block; width: 14px; height: 14px; border-radius: 4px; vertical-align: -2px;
  box-shadow: inset 0 0 0 2px rgba(120,235,150,.85); }
.an-pt-frame.big { box-shadow: inset 0 0 0 2.5px rgba(255,205,90,.95), 0 0 8px rgba(255,190,70,.55);
  background: rgba(255,205,90,.16); }

/* 細單：地面盤 */
.dt-ants { gap: 3px; }
.dt-ants .dt-scell { position: relative; }
.dt-need { position: absolute; right: 1px; bottom: 0; font-size: 9px; font-weight: 800;
  padding: 0 2px; border-radius: 999px; color: #2a1a08; background: rgba(240,200,130,.9); }
.dt-scell.anfood { box-shadow: inset 0 0 0 1.5px rgba(255,200,110,.4); }
.dt-scell.antook { box-shadow: inset 0 0 0 2px var(--win); background: rgba(255,225,105,.16); }
.dt-scell.anshort { box-shadow: inset 0 0 0 2px rgba(255,130,130,.75); }
.dt-scell.annest { box-shadow: inset 0 0 0 2px rgba(230,180,110,.8); }
.dt-scell.anterrain { opacity: .6; }

@media (max-height: 840px) {
  :where(body:not([data-fit="1"])) .ant-hud { padding: 5px 10px 6px; margin-bottom: 5px; }
  /* [claude code] 2026-08-05 圖例與「搬回什麼」是在回答「這數字什麼意思 / 我拿到什麼」→ 矮螢幕先縮不先砍 */
  :where(body:not([data-fit="1"])) .an-legend { margin-top: 3px; font-size: 10px; }
  :where(body:not([data-fit="1"])) .ant-log { padding: 5px 9px 6px; }
}
@media (max-height: 700px) {
  :where(body:not([data-fit="1"])) .an-legend { display: none !important; }
}

/* ================= 金運麻將（mechanic="mjway"）=================
   [claude code] 2026-08-13 建立。4-5-5-5-4 = 2000 路滾輪 + 消除掉落 + 連鎖升倍 + 金牌翻百搭。
   牌面直接沿用夜市麻將賓果那套 low art（.mj-cell / .mj-honor / .mj-man / .mj-pip），
   這裡只加「滾輪排版 + 金牌 + 百搭/奪寶牌面 + 三段表演 + 倍率條」。
   ⚠️ 通用的 .cell.cs-win/.cs-clear/.cs-drop 是把動畫套在子元素 .glyph 上；
      麻將牌沒有 .glyph（內容是牌面 span）→ 這裡另外寫一組套在格子本身。 */
/* [claude code] 2026-08-13 ① 暖色桌面底（依使用者：「牌的切割感不要那麼重」）。
   在此之前縫隙是深色底板的純黑 → 每張白牌都像被切開的磚。改成暗紅金的牌桌感 +
   中央往外的柔光，縫隙有了顏色，整盤就連成一片。 */
/* [claude code] 2026-08-13 v2.73 `margin-top` 把整塊盤面往下讓 12px，空間留給上緣的倍率條
   （配 `.mw-multbar` 的 top −13 → −25，兩者位移相同 → 條的絕對位置不變）。
   ⚠️ 這 12px 會被 `boardHeightBudget()` 的 offsetTop 鏈自動算進去 → 牌張跟著夾小約 2px，
   不會頂出控制列（手機一屏可見鐵則）。 */
.board.mw-board { display: flex !important; position: relative; gap: 4px; margin-top: 12px;
  align-items: center; justify-content: center; overflow: visible;
  background:
    radial-gradient(ellipse at 50% -10%, rgba(190,60,45,.30), transparent 62%),
    radial-gradient(ellipse at 50% 115%, rgba(140,40,35,.22), transparent 60%),
    linear-gradient(162deg, #2b161a 0%, #1d1014 58%, #170c10 100%);
  box-shadow: inset 0 0 0 1px rgba(255,200,90,.18), inset 0 0 42px rgba(0,0,0,.55); }
/* [claude code] 2026-08-13 角飾改「跨界疊上去」（使用者看參考圖後的補充：
   「他們感覺是使用一些東西，蓋在上面，有連續感，又不會很突兀」）。

   🔴 關鍵是**跨過盤面的邊界**：一半在盤外、一半蓋住牌的邊緣（z-index 疊在牌之上）
   → 那條「盤面到此為止」的直線被打斷，整塊才不像一個被框住的矩形。
   第一版把裝飾規規矩矩放在盤內、opacity .13 當浮水印 —— 邊界完全沒被碰到，等於白做。

   🔴 「不突兀」靠的是 **mask 讓外緣淡出**：實心貼上去會像貼紙，
   用 radial-gradient 遮罩把邊緣化掉，它才會像長在背景裡。
   ⚠️ 溢出量刻意壓在 ~20px 以內 —— 再多會頂到抬頭區與控制列。 */
.mw-deco { position: absolute; inset: 0; pointer-events: none; z-index: 3; overflow: visible; }
.mw-deco-c { position: absolute; line-height: 1; user-select: none;
  font-size: clamp(34px, calc(13 * var(--vw)), 74px); opacity: .42; filter: saturate(.85) drop-shadow(0 3px 6px rgba(0,0,0,.5));
  -webkit-mask-image: radial-gradient(closest-side, #000 52%, transparent 96%);
  mask-image: radial-gradient(closest-side, #000 52%, transparent 96%); }
/* 🔴 只放四角。**左右腰不要放**（2026-08-13 使用者回報「左8萬、右2筒上面，像有蓋到東西」）——
   腰身的位置正好壓在最外側那一軸的牌上，而牌是象牙白、雲也是白的 → 糊成一團，
   看起來不是裝飾、是髒污。四角可以，是因為外軸只有 4 格、上下本來就有空隙，壓到的是背景。 */
.mw-deco-0 { left: -20px;  top: -18px;    transform: rotate(-14deg); }
.mw-deco-1 { right: -20px; top: -18px;    transform: rotate(14deg) scaleX(-1); }
.mw-deco-2 { left: -18px;  bottom: -16px; transform: rotate(10deg); opacity: .36; }
.mw-deco-3 { right: -18px; bottom: -16px; transform: rotate(-10deg) scaleX(-1); opacity: .36; }
@media (max-width: 420px) {
  /* 手機上盤面貼近螢幕邊 → 溢出量收一半，免得被裁掉只剩半隻 */
  .mw-deco-0, .mw-deco-2 { left: -10px; }
  .mw-deco-1, .mw-deco-3 { right: -10px; }
}

/* [claude code] 2026-08-13 ②③ 點牌跳出的賠付小卡 */
.mw-paypop { position: absolute; z-index: 12; transform: translate(-50%, -100%);
  display: flex; align-items: center; gap: 13px; padding: 9px 15px 9px 11px;
  border-radius: 13px; pointer-events: none; white-space: nowrap;
  background: linear-gradient(160deg, #a3160f, #7a0c07);
  box-shadow: inset 0 0 0 2px var(--gold), 0 8px 22px rgba(0,0,0,.55), 0 0 18px rgba(255,180,60,.35);
  animation: mwPopIn .16s ease both; }
.mw-paypop.below { transform: translate(-50%, 0); }
@keyframes mwPopIn { from { opacity: 0; transform: translate(-50%, -92%) scale(.9); } }
.mw-paypop.below { animation-name: mwPopInB; }
@keyframes mwPopInB { from { opacity: 0; transform: translate(-50%, 8%) scale(.9); } }
/* 2026-08-13 二版（使用者：「圖 + 右邊6個數字就可以，但**再放大一點**」）：
   拿掉牌名與底下那行算式，整體尺寸拉大約 1.4 倍 —— 這張卡是「掃一眼」用的，
   完整算式在 📋 賠付表與 🔍 細單裡本來就有。 */
.mw-pp-face { width: 48px; height: 61px; flex: 0 0 auto; border-radius: 8px; overflow: hidden;
  display: inline-flex; align-items: center; justify-content: center;
  background: linear-gradient(158deg, #fbf6e9, #e2d4b6); color: #1b2330;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.7), 0 2px 6px rgba(0,0,0,.45); }
.mw-pp-face .mj-honor { font-size: 29px; }
.mw-pp-face .mj-pip { width: 82%; height: 82%; }
.mw-pp-face .mj-man .mm-n { font-size: 20px; } .mw-pp-face .mj-man .mm-s { font-size: 13px; }
.mw-pp-face .mw-ingot { font-size: 22px; } .mw-pp-face .mw-wtxt { font-size: 11px; }
.mw-pp-face .mw-scat-art { font-size: 27px; animation: none; }
.mw-pp-body { display: flex; flex-direction: column; gap: 2px; }
.mw-pp-row { display: flex; align-items: baseline; gap: 12px; line-height: 1.12; }
.mw-pp-n { font-size: 17px; font-weight: 900; color: #cfe3ff; min-width: 12px; }
.mw-pp-v { font-size: 21px; font-weight: 900; color: var(--gold); text-shadow: 0 1px 2px rgba(0,0,0,.45); }
.mw-pp-note { font-size: 12px; font-weight: 700; color: rgba(255,235,200,.85); }
/* 被點的那張牌：金色描邊（不改亮度 —— 對齊「提示樣式不動亮度」那條） */
.mw-cell.mw-picked { z-index: 6; box-shadow: inset 0 2px 0 rgba(255,255,255,.85),
  inset 0 0 0 2.5px var(--gold), 0 0 15px rgba(255,207,58,.8), 0 2px 5px rgba(0,0,0,.35); }
.mw-reel { display: flex; flex-direction: column; justify-content: center; }
/* 🎰 滾輪落盤：轉的時候整軸裁切（.spinning），裡面那條 .mw-strip 由上往下捲進來。
   ⚠️ 只有轉的那幾百毫秒才裁切 —— 常態不裁，不然金牌 / 百搭的外發光會被切掉。 */
.mw-reel.spinning { overflow: hidden; justify-content: flex-start; }
/* ✨ 黃金軸（免費期的特殊局：那一軸整軸只出金牌）——
   金框 + 呼吸光，其餘軸壓暗（跟 near win 一樣的手法，玩家一眼就看得出是哪一軸）。 */
.mw-reel.mw-rush { position: relative; z-index: 3; border-radius: 10px;
  animation: mwRushPulse .9s ease-in-out infinite; }
@keyframes mwRushPulse {
  0%,100% { box-shadow: 0 0 0 2px rgba(242,193,78,.55), 0 0 0 0 rgba(242,193,78,.35); }
  50%     { box-shadow: 0 0 0 2px rgba(242,193,78,.95), 0 0 24px 6px rgba(242,193,78,.45); }
}
.board.mw-rushing .mw-reel:not(.mw-rush) { filter: brightness(.62); transition: filter .25s; }
/* [claude code] 2026-08-13 v2.76 使用者：「總覺得他轉動停下來後，會往左右再拉開一點」。
   🔴 病根就是上面那個 `overflow: hidden`：它是**四邊都裁**的 ——
      轉的時候牌的**外發光 / 陰影（金牌、百搭那圈光）左右兩側被切掉**，
      一停下來 `.spinning` 拿掉、overflow 恢復 visible，那圈光才整個跑出來
      → 牌沒有真的移動半格，但「亮的範圍」變寬了，看起來就是往左右撐開一點。
   解法：改用 `clip-path` **只裁上下、左右往外放 18px** —— 垂直方向照舊裁乾淨（滾輪不會溢出到別軸），
   水平方向留空間給發光 → **轉動中與停住後一樣寬**，那一下的「拉開」就沒有了。
   🔴 clip-path 不佔版面（不像 padding 會改寬度）→ 軸距完全不動。
   ⚠️ 包 @supports：不支援的瀏覽器自動退回上面那條 overflow: hidden，行為與 v2.75 相同、不會壞。 */
@supports (clip-path: inset(0 -18px)) {
  .mw-reel.spinning { overflow: visible; clip-path: inset(0 -18px); }
}
.mw-strip { display: flex; flex-direction: column; will-change: transform; }
/* [claude code] 2026-08-13 v2.74 按下 SPIN 到結果回來之間的**無限空轉**（見 app.js 的 mwSpinLaunch）。
   strip 裡放兩份內容相同的假牌，捲完一個週期（--mw-loop = 一份的高度）畫面與起點一致 → 無縫。 */
@keyframes mwLoop { from { transform: translateY(var(--mw-loop)); } to { transform: translateY(0); } }
/* 覆寫基礎 .cell 的 absolute 定位（比照 .ways-cell/.clus-cell），不然整軸會塌成一格 */
.mw-cell { position: relative !important; flex: 0 0 auto; overflow: hidden; }
/* 層級：牌(1) < 角飾(3) < 中獎高亮(4~6) < 倍率條(6) < 賠付小卡(12)
   —— 角飾要「蓋在牌上面」才有疊上去的感覺，但不能蓋掉中獎高亮與小卡。 */
.mw-reel { position: relative; z-index: 1; }

/* 🟡 金牌：中獎後不會爆掉，而是原地翻成百搭 → 用金色牌面 + 角標，讓玩家一眼認得 */
.mw-cell.mw-gold { background: linear-gradient(158deg, #fff6d0 0%, #ffd45e 55%, #e6ad24 100%);
  box-shadow: inset 0 2px 0 rgba(255,255,255,.92), inset 0 0 0 2px #e0a11f,
    0 0 14px rgba(255,203,58,.7), 0 2px 5px rgba(0,0,0,.35); }
/* [claude code] 2026-08-17 v3.46 角落那個「金」字拿掉(使用者:「不是用黃金牌底了嗎,再多個金字是不是多餘了」)。
   🔴 對齊「畫面上能不寫字的,就不要用文字呈現」——**金色牌底已經把「這是金牌」講完了**,
   角上再寫一個字是同一件事講兩次;而且它壓在牌面右上角,牌本身的圖案反而被擠。 */

/* 💰 百搭（元寶牌）：金紅漸層 + 元寶 + 直排「百搭」 */
.mw-cell.mw-wild { background: linear-gradient(160deg, #fff2c4 0%, #ffcf4a 46%, #d98b18 100%);
  box-shadow: inset 0 2px 0 rgba(255,255,255,.95), inset 0 0 0 2.5px #b9302a,
    0 0 16px rgba(255,196,60,.85), 0 2px 5px rgba(0,0,0,.4); }
.mw-wild-art { display: flex; flex-direction: column; align-items: center; justify-content: center; line-height: 1; gap: 1px; }
.mw-ingot { font-size: clamp(13px, calc(4.6 * var(--vw)), 24px); filter: drop-shadow(0 1px 1px rgba(0,0,0,.3)); }
.mw-wtxt { font-size: clamp(8px, calc(2.5 * var(--vw)), 12px); font-weight: 900; color: #9c1d14; letter-spacing: .06em; }

/* 🧧 奪寶（胡）：紅底金字 + 呼吸光暈（只觸發免費，不參與連線） */
.mw-cell.mw-scat { background: linear-gradient(158deg, #a3160f 0%, #7d0c07 60%, #5c0704 100%);
  box-shadow: inset 0 2px 0 rgba(255,255,255,.25), inset 0 0 0 2px #ffcf4a,
    0 0 16px rgba(255,120,60,.75), 0 2px 5px rgba(0,0,0,.45); }
.mw-scat-art { font-size: clamp(17px, calc(6 * var(--vw)), 32px); font-weight: 900; line-height: 1;
  color: #ffe28a; text-shadow: 0 0 8px rgba(255,180,60,.95), 0 1px 0 rgba(0,0,0,.5);
  animation: mwScat 1.3s ease-in-out infinite alternate; }
@keyframes mwScat { from { transform: scale(1); filter: none; } to { transform: scale(1.08); filter: brightness(1.3); } }

/* 三段表演（套在格子本身，不是 .glyph） */
/* 🔴 中獎高亮走過兩次極端，這是第三版：
   一版 `brightness(1.45)` → 使用者：「很閃很亮」（象牙白再提亮就是過曝刷白）
   二版 只留金色描邊     → 使用者：「中獎目前不明顯」（白牌上的細金框看不出來）
   三版 **改變對比的方向**：不是把中獎的弄更亮，而是**把沒中的壓暗**（`.mw-board.mw-hl`）。
        中獎的維持原本亮度 + 金框 + 微放大，靠周圍變暗自己跳出來 —— 這是不會過曝的作法。 */
.mw-cell.cs-win { z-index: 4; animation: mwWin .46s ease-in-out infinite alternate; }
@keyframes mwWin {
  from { transform: scale(1.01);
    box-shadow: inset 0 2px 0 rgba(255,255,255,.85), inset 0 0 0 2.5px rgba(255,207,58,.75), 0 0 10px rgba(255,207,58,.45); }
  to { transform: scale(1.06);
    box-shadow: inset 0 2px 0 rgba(255,255,255,.9), inset 0 0 0 3.5px var(--gold), 0 0 20px rgba(255,190,40,.9), 0 3px 8px rgba(0,0,0,.4); } }
/* 沒中的牌壓暗（只在高亮那一小段時間）。⚠️ 這跟「提示樣式不可動亮度」那條不衝突 ——
   那條講的是**未揭曉**的格（會讓玩家誤判已開幾張）；這裡是結果已定、且**變暗的是沒中的**，
   中獎的反而維持原亮度，不會有誤判。 */
.mw-board.mw-hl .mw-cell:not(.cs-win):not(.mw-turn):not(.cs-clear) {
  opacity: .34; filter: saturate(.55) brightness(.8); transition: opacity .18s ease, filter .18s ease; }
.mw-cell.cs-clear { animation: mwClear .3s ease forwards; z-index: 3; }
@keyframes mwClear { 0% { transform: scale(1.045); opacity: 1; }
  35% { transform: scale(1.16); opacity: .95; } 100% { transform: scale(0); opacity: 0; } }
.mw-cell.cs-drop { animation: mwDrop var(--drop-ms, 430ms) cubic-bezier(.33,1.06,.5,1) both; }
@keyframes mwDrop { from { transform: translateY(var(--drop-from, -100%)); opacity: .4; } to { transform: translateY(0); opacity: 1; } }
/* 🟡 這張金牌等一下要翻成百搭：先脈動一下把注意力抓過來（翻牌動畫沿用 .mj-cell.just-flip） */
.mw-cell.mw-turn { z-index: 5; animation: mwTurn .3s ease-in-out infinite alternate; }
@keyframes mwTurn { from { box-shadow: inset 0 0 0 2px #e0a11f, 0 0 10px rgba(255,203,58,.7); }
  to { box-shadow: inset 0 0 0 3px #fff0b0, 0 0 22px rgba(255,225,120,1); } }

/* 倍率條（貼在盤面最上緣）：base 顯示 x1 x2 x3 x5、免費顯示雪球值。
   ⚠️ 它是 #board 的最後一個 child（mwReelEl 靠 children[r] 取軸 → 一定要 append 在所有軸之後）。 */
/* [claude code] 2026-08-13 倍率條改成「壓在盤面上緣的橫幅」（同一個道理：跨過邊界才有連續感）。
   底色用麻將牌背那個玉綠（.mj-cell.mj-back 同一組色）→ 跟這款的牌是同一套視覺語言。 */
/* [claude code] 2026-08-13 v2.73 依使用者「主 SLOT 區再下來一點，目前被倍數蓋的有點多」：
   🔴 條與盤面**一起移、位移量相同**（board `margin-top: 12px` ↔ 這裡 top −13 → −25）
   → 條的**絕對位置不動**（不會往上頂到餘額 / 本局贏分那排），純粹是牌往下讓開。
   結果：條的下緣落在盤面 padding 內 2px（27−25）、牌從 padding 6px 起排
   → **一張牌都沒被蓋到**，但條仍壓在盤面背景的上緣，跨界的連續感保留。 */
/* ⛎ 星宮聚合:盤面上的「風火水土」分組（2026-09-20 使用者:「我覺得風火水土不明顯」）。
   🔴 **邊框 + 底部色條**，不是整格染色 —— 符號圖本身就有顏色，整格染色會把圖洗掉。
   四個顏色跟細單（`.dt-scell.zd-g0..3`）與星盤面板同一組，三個地方看到的是同一件事。 */
.cell.zd-e0 { box-shadow: inset 0 0 0 2px rgba(255,110,105,.85); }   /* 🔥 火象 */
.cell.zd-e1 { box-shadow: inset 0 0 0 2px rgba(178,164,142,.85); }   /* ⛰️ 土象（灰土色）*/
.cell.zd-e2 { box-shadow: inset 0 0 0 2px rgba(105,225,175,.85); }   /* 💨 風象 */
.cell.zd-e3 { box-shadow: inset 0 0 0 2px rgba(61,155,255,.90); }    /* 💧 水象（比風的青綠更藍）*/
.cell.zd-e0::before, .cell.zd-e1::before, .cell.zd-e2::before, .cell.zd-e3::before {
  content: ""; position: absolute; left: 4px; right: 4px; bottom: 2px; height: 3px;
  border-radius: 2px; z-index: 2; pointer-events: none; }
.cell.zd-e0::before { background: rgba(255,110,105,.95); }
.cell.zd-e1::before { background: rgba(178,164,142,.95); }
.cell.zd-e2::before { background: rgba(105,225,175,.95); }
.cell.zd-e3::before { background: rgba(61,155,255,1); }
/* 🔴 [claude code] 2026-09-21 每一格左上角的元素角標（🔥⛰️💨💧）**当天加、当天拿掉**
   （使用者：「每格 星宮聚合左上角標元素圖示 🔥⛰️💨💧 ← 拿掉」）。
   分組線索留下上面那兩種：**邊框顏色 + 底部色條**，再加上盤面下方的星盤面板。
   💡 角標是「多一層資訊」，而不是「多一層辨識」—— 四個元素在盤上本來就有框色跟底條兩個
      維度在講同一件事，再疊一個 emoji 只是把 20 格都變得更撠。 */

/* ✖️ ============ [claude code] 2026-09-21 v4.46 倍數軸（zodiac.multReel） ============
   使用者：「有倍數軸在最後面，一樣是五格，中間那格同樣有標示，有中獎了，倍數也會飛過去」。
   v4.46 改版（使用者看畫面後）：「五格應該也是由上往下滾動」「倍數也不明顯」。

   結構跟盤面的軸一模一樣（對照 wolves_pg 的迦羅戰神：它的倍數軸就是一道普通的軸）：
     .zmr        軸（overflow hidden，跟盤面等高）
       .zmr-strip  會捲的那一層（絕對定位，格子用 translate3d 排）
         .zmr-cell 池化的格子（高度 = 軸高 ÷ 格數，由 JS 設）
       .zmr-frame  🔴 **不動的生效框**（疊在最上面、不吃點擊）

   🔴 **生效框不能跟著捲** —— 跟著捲的話「哪一格算數」每一幀都在換，玩家根本盯不住。
   🔴 **數字要壓得過獎牌圖**：獎牌中心是亮的，淡金色小字會直接消失在上面
      （v4.45 就是這樣，使用者回報「倍數不明顯」）→ 白字 + 八方向深色描邊 + 字級拉大，
      生效格再放大一級。**辨識靠對比與大小，不靠色相。** */
.zmr { position: relative; }
/* 🔴 **會被裁切的只有這一層** —— 生效框比格子大一圈，裝進來會被切掉左右兩根金柱。 */
.zmr-mask { position: absolute; inset: 0; overflow: hidden; border-radius: 10px;
  background: linear-gradient(180deg, #1a1408, #0d0b06);
  box-shadow: inset 0 0 0 1.5px rgba(255,207,58,.35); }
.zmr-strip { position: absolute; inset: 0; }
.zmr-cell { position: absolute; left: 0; right: 0; top: 0; display: flex;
  align-items: center; justify-content: center; box-sizing: border-box;
  border-bottom: 1px solid rgba(255,207,58,.14);
  background: linear-gradient(180deg, rgba(38,30,12,.9), rgba(20,16,8,.9));
  background-repeat: no-repeat; background-position: center; will-change: transform; }
/* 🎨 套上獎牌圖的格子：圖自己就是底，漸層底色要讓位，不然兩層打架。 */
.zmr-cell.art { background-color: transparent; background-size: contain; }
/* 🔴 沒落在生效框裡的格子**降彩降亮** —— 五張獎牌一樣鮮豔時，玩家看不出哪一格才算數。
   轉動中（`.zmr.spinning`）一律降，停好之後只有 `.on` 那一格恢復。 */
.zmr.spinning .zmr-cell, .zmr.settled .zmr-cell:not(.on) { filter: saturate(.62) brightness(.6); }
.zmr-cell.on { filter: none; z-index: 2; }

/* 數字。🔴 八方向描邊（不是 `paint-order`）—— 描邊要在**每一台機器上**都成立，
   而 `paint-order` 在 HTML 文字上是比較新的支援；這一款是 TWA 上 Google Play，
   舊 WebView 也要讀得出來。 */
.zmr-val { position: relative; z-index: 2; font-weight: 900; letter-spacing: -.03em; line-height: 1;
  font-size: clamp(13px, calc(3.9 * var(--vw)), 21px); color: #fff6d8;
  text-shadow:
    1.6px 0 0 #0a0702, -1.6px 0 0 #0a0702, 0 1.6px 0 #0a0702, 0 -1.6px 0 #0a0702,
    1.2px 1.2px 0 #0a0702, -1.2px 1.2px 0 #0a0702, 1.2px -1.2px 0 #0a0702, -1.2px -1.2px 0 #0a0702,
    0 2px 6px rgba(0,0,0,.95); }
/* ×10 以上：燙起來（面額的次序用溫度講，不用色相） */
.zmr-cell.hot .zmr-val { color: #ffd76a; }
/* 生效那一格：字再大一級 + 金色光暈（它是唯一會算進贏分的數字） */
.zmr-cell.on .zmr-val { font-size: clamp(16px, calc(5 * var(--vw)), 27px); color: #fff;
  text-shadow:
    1.8px 0 0 #0a0702, -1.8px 0 0 #0a0702, 0 1.8px 0 #0a0702, 0 -1.8px 0 #0a0702,
    1.4px 1.4px 0 #0a0702, -1.4px 1.4px 0 #0a0702, 1.4px -1.4px 0 #0a0702, -1.4px -1.4px 0 #0a0702,
    0 0 14px rgba(255,207,58,1), 0 2px 6px rgba(0,0,0,.95); }

/* 🔴 生效框：**不動**。金框 + 左邊一個指向盤面的箭頭（「這一格會乘到盤面上」）。 */
.zmr-frame { position: absolute; left: 0; right: 0; z-index: 3; pointer-events: none;
  box-shadow: inset 0 0 0 2px var(--gold), 0 0 14px rgba(255,207,58,.45);
  border-radius: 6px; }
.zmr-frame::before { content: ""; position: absolute; left: -1px; top: 50%; width: 0; height: 0;
  transform: translateY(-50%); border: 5px solid transparent; border-left-color: var(--gold); }
/* 🖼 有金框圖就用圖（`_extra/mr_frame`：比格子大 1.22 × 1.28 倍、中心透明）。
   這時 CSS 畫的金邊與箭頭都讓位 —— 兩套疊起來只會互相打架。
   [claude code] 2026-09-21 v4.49 金框改成自己畫的（`doc/symbol-art/originals/.../mr_frame.png`）。
   🔴 **`100% 100%` 是「拉滿」不是「保比例」** —— 原圖就照 122:128 畫（488 × 512），
   換圖時比例跟著改才不會被拉扁；中心 80% × 78% 全透明 = 拉完剛好圈住格子、不壓到獎牌。 */
.zmr-frame.art { box-shadow: none; }
.zmr-frame.art::before { content: none; }
.zmr-frame.art::after { content: ""; position: absolute; left: 50%; top: 50%;
  width: 122%; height: 128%; transform: translate(-50%,-50%);
  background: var(--zmr-frame) center / 100% 100% no-repeat; }
.zmr-frame.art.fire { animation: zmrFireArt .5s ease-in-out infinite alternate; }
@keyframes zmrFireArt { from { filter: none; } to { filter: brightness(1.7) drop-shadow(0 0 10px rgba(255,225,120,.95)); } }
/* 🪨 期待停軸：整道軸的框跳起來（大面額 / 推動格真的要來了才會出現 —— 不造假訊號）。 */
.zmr.antic .zmr-frame { animation: zmrAntic .42s ease-in-out infinite alternate; }
@keyframes zmrAntic { from { box-shadow: inset 0 0 0 2px var(--gold), 0 0 12px rgba(255,207,58,.4); }
  to { box-shadow: inset 0 0 0 3px #fff6d0, 0 0 26px rgba(255,225,120,.95); } }
.zmr.antic .zmr-frame.art { animation: zmrAnticArt .42s ease-in-out infinite alternate; }
@keyframes zmrAnticArt { from { filter: none; }
  to { filter: brightness(1.6) drop-shadow(0 0 9px rgba(255,225,120,.9)); } }
/* ⏬ Ex NUDGE 推動中：軸底轉暖色，一眼看得出「現在在做另一件事」 */
.zmr.nudging .zmr-mask { background: linear-gradient(180deg, #3a2208, #1a1004);
  box-shadow: inset 0 0 0 1.5px rgba(255,160,60,.8), 0 0 18px rgba(255,150,40,.35); }
#winBanner.zmr-hot { color: #ffcf4a; text-shadow: 0 0 10px rgba(255,180,60,.6); }
/* 轉動中：整道軸糊掉（跟盤面 `.strip.spinning` 同一個語彙） */
.zmr.spinning .zmr-val { filter: blur(1.4px); opacity: .85; }
/* 倍數飛出去的那一刻，生效框亮起來（因果鏈的「頭」） */
.zmr-frame.fire { animation: zmrFire .5s ease-in-out infinite alternate; }
@keyframes zmrFire { from { box-shadow: inset 0 0 0 2px var(--gold), 0 0 14px rgba(255,207,58,.45); }
  to { box-shadow: inset 0 0 0 3px #fff0b0, 0 0 30px rgba(255,225,120,1); } }

/* ✈️ 飛過去的那顆倍數。定位基準是 `.board-wrap`（它 `position: relative`、沒有 padding / border
   → `getBoundingClientRect()` 相減出來的座標可以直接當 left/top 用）。
   ⚠️ 刻意**不用** blaze `.bz-fly` 那套 `position: fixed` —— fixed 只要祖先有 filter / transform
   就會改吃那一層當容器，而盤面這一帶本來就有 `filter` 在跑（期待停軸壓暗、獎牌降彩）。 */
.zmr-fly { position: absolute; z-index: 40; pointer-events: none;
  transform: translate(-50%,-50%); font-weight: 900; letter-spacing: -.02em;
  font-size: clamp(20px, calc(6 * var(--vw)), 32px); color: #fff3c8;
  text-shadow: 0 0 12px rgba(255,207,58,.95), 0 2px 6px rgba(0,0,0,.9); }
.zmr-fly.big { font-size: clamp(26px, calc(8 * var(--vw)), 44px); color: #fff; }
.zmr-fly.land { animation: zmrFlyLand .5s ease-out; }
@keyframes zmrFlyLand { 0% { filter: brightness(2.2); } 100% { filter: brightness(1); opacity: 0; } }

/* 🔴 聚合成立 / 差一宮 / ⛎ 的框要壓過元素框 —— 那三個是「這一轉發生了什麼」，比分組重要 */
.cell.zd-elem, .cell.zd-near, .cell.zd-scat { z-index: 3; }

/* ================= [claude code] 2026-08-15 星宮聚合（zodiac）=================
   三種格子狀態，刻意做成**三種不同強度**，玩家一眼分得出「中了 / 有希望 / 特殊符」：
   - `.zd-elem` 聚合成立（金框 + 脈動）＝ 這局真的算到分的格
   - `.zd-near` 就差一宮（虛線淡框）＝ **純表演**，提示「這組差一個就成立了」
   - `.zd-scat` ⛎ 蛇夫座（紫光）＝ base 的觸發來源、免費期的萬能宮
   🔴 三者靠**框線樣式 + 亮度**分，不是只靠顏色（辨識要靠形狀，色盲也分得出）。 */
/* [claude code] 2026-08-15 v3.5 星宮聚合的**兩條倍率**（雪球在上、組數階梯在下）。
   🔴 高度**永遠佔著兩條** —— `boardHeightBudget` 是 buildBoard 當下量的，
      「進免費期才長出一條」會把盤面往下推、可能把 SPIN 頂出畫面（手機一屏可見鐵則）。
      所以 base 期上面那條是**安靜的待命樣子**（只寫名字），不是空白。 */
.game-multbar.zod-2row { display: flex; flex-direction: column; gap: 4px; }
.zod-snowbar { height: 27px; border-radius: 8px; display: flex; align-items: center; justify-content: center;
  gap: 8px; pointer-events: none; transition: background .25s ease, box-shadow .25s ease;
  background: rgba(255,255,255,.045); box-shadow: inset 0 0 0 1px rgba(255,255,255,.10); }
/* 第 13 宮：整條轉成冰藍（與組數階梯的綠 / 免費期的橘都分得開） */
.zod-snowbar.on { background: linear-gradient(180deg, #3a86e0 0%, #1d4f9e 55%, #10306b 100%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.30), inset 0 0 0 1.5px rgba(170,225,255,.65),
    0 4px 12px rgba(0,0,0,.5); }
/* 🔴 [claude code] 2026-09-10 v4.2 免費期（第 13 宮）整條轉橘 —— 對齊平台「免費期 = 橘」的視覺語彙。
   ⚠️ 覆寫要寫在 `.on` **後面**，不然被前面那條冰藍蓋掉（CSS 兩個靜默坑之一）。 */
.zod-snowbar.on.fs { background: linear-gradient(180deg, #ff9a4d 0%, #d1571a 55%, #7a2f08 100%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.35), inset 0 0 0 1.5px rgba(255,200,150,.75),
    0 4px 14px rgba(0,0,0,.5); }
/* 「還剩幾轉」排在最前面 —— 免費期玩家最想知道的就是這個數字 */
.zs-fs { font-size: clamp(10px, calc(2.9 * var(--vw)), 13px); font-weight: 900; color: #fff2e2; white-space: nowrap;
  padding: 1px 8px; border-radius: 999px; background: rgba(0,0,0,.28); }
.zs-fs b { color: #fff; font-size: 1.08em; }
.zs-lab { font-size: clamp(10px, calc(2.9 * var(--vw)), 13px); font-weight: 900; letter-spacing: .04em; color: rgba(255,255,255,.55); }
.zod-snowbar.on .zs-lab { color: #d9f0ff; }
.zod-snowbar.on.fs .zs-lab { color: #ffe6cd; }
.zs-idle { font-size: clamp(9px, calc(2.6 * var(--vw)), 11.5px); color: rgba(255,255,255,.33); }
.zs-val { font-size: clamp(13px, calc(3.8 * var(--vw)), 18px); font-weight: 900; color: #fff;
  text-shadow: 0 0 10px rgba(180,230,255,.9); }
/* 🔴 「本轉 ×N」＝ 組數倍率 × 雪球，**這才是真正乘進贏分的數** —— 用金色跟兩個因子分開 */
.zs-total { font-size: clamp(11px, calc(3.1 * var(--vw)), 14px); font-weight: 900; padding: 1px 9px; border-radius: 999px;
  color: #2a1d00; background: linear-gradient(#fff3c8, var(--gold));
  box-shadow: 0 0 10px rgba(255,207,58,.75); }

/* 🔴 [claude code] 2026-08-15 v3.3 **四象限配色**（使用者：「那個紫底是必須的嗎，如果不是，
   能否加入四種底色區分四個象限，更直覺」）。
   ⚠️ 先講清楚：**那塊紫底是 emoji 自己的設計** —— Noto / Android 把 ♈–♓ 畫成「白字 + 紫色圓角磚」，
   不是我們畫的，所以沒辦法「拿掉」。但可以做兩件事：
     ① `hue-rotate` 把那塊磚**整個轉色**（白色字沒有色相、不受影響 → 白字保持白字）
     ② 格子本身鋪一層同色系底 → 三宮一組看起來就是一家的
   🔴 **顏色是「分組」用的，不是「辨識」用的** —— 12 個星座本來就靠形狀分得出來（對齊平台
      「辨識靠形狀不靠顏色」那條）；這裡加色是為了讓「同元素三宮」一眼成群。
   🔴 選擇器直接吃 `setCell` 產生的 `sym-<KEY>` class → **不用改任何 JS**。 */
.cell.sym-ARIES, .cell.sym-LEO, .cell.sym-SAGITTARIUS,
.cell.sym-TAURUS, .cell.sym-VIRGO, .cell.sym-CAPRICORN,
.cell.sym-GEMINI, .cell.sym-LIBRA, .cell.sym-AQUARIUS,
.cell.sym-CANCER, .cell.sym-SCORPIO, .cell.sym-PISCES { border-radius: 10px; }
/* 🔥 火象：♈ 牡羊 · ♌ 獅子 · ♐ 射手 */
.cell.sym-ARIES, .cell.sym-LEO, .cell.sym-SAGITTARIUS {
  background: linear-gradient(180deg, rgba(255,110,60,.26), rgba(150,35,15,.16));
  box-shadow: inset 0 0 0 1px rgba(255,150,100,.32); }
/* 🔴 [claude code] 2026-09-21 **這四條 hue-rotate 只給 emoji，不可以套在符號圖上**。
   它是 v3.3（2026-08-15）為了 ♈–♓ emoji 自帶的紫色圓角磚而加的「整塊轉色」——
   那時格子裡是**白字 + 紫磚**，白字沒有色相所以不受影響。
   2026-09-20 換上真的符號圖之後，這四條變成「把畫好的顏色整個轉掉」：
   紅獅子變綠、金牛變青、青天秤變粉 ⇒ ① 盤面看不出風火水土（圖本來就照象分色了）
   ② **盤面與下方星盤的同一個符號長得不一樣**（星盤沒有這層 filter）——
   使用者 2026-09-21 回報「符號⋯⋯目前是亂的」就是這個。
   ⇒ 加 `:not(.has-art)`：沒有圖的款照舊轉色，有圖的用圖本來的顏色。 */
.cell.sym-ARIES .glyph:not(.has-art), .cell.sym-LEO .glyph:not(.has-art), .cell.sym-SAGITTARIUS .glyph:not(.has-art) { filter: hue-rotate(96deg) saturate(1.2); }
/* ⛰️ 土象：♉ 金牛 · ♍ 處女 · ♑ 摩羯 */
/* ⛰️ 土象刻意是**灰土色不是金色**（2026-09-21 使用者：「土可以用灰色一點的嗎, 就是土色」）——
   金色在這個平台是「中獎 / 值錢」的語彙（`--gold`），拿它當分組色會跟中獎框搶訊號。 */
.cell.sym-TAURUS, .cell.sym-VIRGO, .cell.sym-CAPRICORN {
  background: linear-gradient(180deg, rgba(150,132,108,.26), rgba(78,68,55,.18));
  box-shadow: inset 0 0 0 1px rgba(178,164,142,.30); }
.cell.sym-TAURUS .glyph:not(.has-art), .cell.sym-VIRGO .glyph:not(.has-art), .cell.sym-CAPRICORN .glyph:not(.has-art) { filter: hue-rotate(132deg) saturate(1.05); }
/* 💨 風象：♊ 雙子 · ♎ 天秤 · ♒ 水瓶 */
.cell.sym-GEMINI, .cell.sym-LIBRA, .cell.sym-AQUARIUS {
  background: linear-gradient(180deg, rgba(120,230,215,.22), rgba(30,110,110,.14));
  box-shadow: inset 0 0 0 1px rgba(150,240,225,.30); }
.cell.sym-GEMINI .glyph:not(.has-art), .cell.sym-LIBRA .glyph:not(.has-art), .cell.sym-AQUARIUS .glyph:not(.has-art) { filter: hue-rotate(268deg) saturate(1.1); }
/* 💧 水象：♋ 巨蟹 · ♏ 天蠍 · ♓ 雙魚 */
.cell.sym-CANCER, .cell.sym-SCORPIO, .cell.sym-PISCES {
  background: linear-gradient(180deg, rgba(70,140,255,.26), rgba(20,45,140,.16));
  box-shadow: inset 0 0 0 1px rgba(120,175,255,.32); }
.cell.sym-CANCER .glyph:not(.has-art), .cell.sym-SCORPIO .glyph:not(.has-art), .cell.sym-PISCES .glyph:not(.has-art) { filter: hue-rotate(310deg) saturate(1.15); }
/* [claude code] 2026-08-15 v3.8 原本這裡是 v3.7 的「✦ 標稀有宮」（金色角標 + 金框）——
   已改用**盤面下方的星盤面板**表達「這一組到齊了沒」，整組移除（見下面的 .zod-panel）。
   ⛎ 蛇夫座維持原本的紫 —— 它不屬於任何元素，保持原色才看得出「它是外來的第 13 宮」。 */

/* ================= [claude code] 2026-08-15 v3.8 星宮聚合的星盤面板 =================
   使用者定案：「下面有個分四區的 12 星座盤, 盤面掉完後, 有的就會依序亮起來, 沒有就灰著,
   有中獎的象限就會框起來, 上面也會表演亮起來」。
   🔴 它回答的是**「這一組到齊了沒」** —— 三個格子亮兩個灰一個，缺什麼一眼就看到，
      完全不用解釋規則，也不必再為稀有度做特別標記。
   🔴 三種狀態靠**亮度 + 框線**分（不是只靠顏色）：灰（沒有）/ 金（盤上有）/ 紫（⛎ 補的）。 */
.zod-panel { display: grid; grid-template-columns: repeat(4, 1fr); gap: 5px;
  width: min(100%, 470px); margin: 6px auto 0; padding: 6px;
  border-radius: 12px; background: rgba(10,14,30,.55); box-shadow: inset 0 0 0 1px rgba(255,255,255,.06); }
.zq { display: flex; flex-direction: column; align-items: center; gap: 3px;
  padding: 4px 2px; border-radius: 9px; transition: box-shadow .2s ease, background .2s ease;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.07); }
/* 四區底色跟盤面上的四象限配色同一套 → 星盤與盤面一眼對得起來 */
.zq0 { background: linear-gradient(180deg, rgba(255,110,60,.16), rgba(150,35,15,.10)); }
.zq1 { background: linear-gradient(180deg, rgba(150,132,108,.17), rgba(78,68,55,.11)); }
.zq2 { background: linear-gradient(180deg, rgba(120,230,215,.14), rgba(30,110,110,.09)); }
.zq3 { background: linear-gradient(180deg, rgba(70,140,255,.16), rgba(20,45,140,.10)); }
/* 聚合成立 → 整區框起來（跟盤面上的金框同一個語彙）*/
.zq.on { box-shadow: inset 0 0 0 2px var(--gold), 0 0 14px rgba(255,207,58,.5);
  animation: zqOn .9s ease-in-out infinite; }
@keyframes zqOn { 0%, 100% { box-shadow: inset 0 0 0 2px var(--gold), 0 0 10px rgba(255,207,58,.4); }
  50% { box-shadow: inset 0 0 0 2px var(--gold), 0 0 20px rgba(255,207,58,.85); } }
.zq-ico { font-size: clamp(11px, calc(3 * var(--vw)), 14px); line-height: 1; opacity: .85; }
/* 四組各自帶元素色（跟盤面的 `.zd-e0..3` 同一組）→ 面板與盤面看到的是同一件事 */
.zq[data-e="0"] { border-color: rgba(255,110,105,.55); }
.zq[data-e="1"] { border-color: rgba(178,164,142,.55); }
.zq[data-e="2"] { border-color: rgba(105,225,175,.55); }
.zq[data-e="3"] { border-color: rgba(90,180,255,.55); }
.zq-slots { display: flex; gap: 2px; }
/* 沒有 = 灰掉且縮小（一眼看得出「缺一個」）*/
/* 🔴 [claude code] 2026-08-15 v3.9 待命（灰）狀態要**看得清楚**（使用者：「星盤可以預設是灰的,
   永遠都在下面, 固定位置順序, 和藏寶圖一樣」）。
   原本 `opacity: .22` 太淡 —— 那不是「灰著」，那是「幾乎看不見」，
   星盤就淪為一條空白帶，讀不出「這是一張固定的 12 宮表」。
   藏寶圖那種常駐 HUD 的重點是：**沒收集到的格子也要看得出它是什麼**，玩家才知道自己在集什麼。
   → 拉到 .45 + grayscale（灰但認得出圖案），亮起來時才有明顯落差。 */
.zs { font-size: clamp(13px, calc(3.8 * var(--vw)), 18px); line-height: 1; opacity: .45;
  filter: grayscale(1) brightness(.85);
  transform: scale(.9); transition: opacity .18s ease, transform .18s ease, filter .18s ease; }
/* 盤上真的有 = 亮起來 */
.zs.lit { opacity: 1; filter: none; transform: scale(1);
  animation: zsPop .32s cubic-bezier(.2,1.5,.4,1); }
@keyframes zsPop { 0% { transform: scale(.7); } 60% { transform: scale(1.22); } 100% { transform: scale(1); } }
/* ⛎ 補起來的那一宮 = 紫（跟「盤上真的有」分開，不然玩家會以為它真的落下來了）*/
.zs.wild { opacity: 1; filter: none; transform: scale(1);
  text-shadow: 0 0 8px #b98cff, 0 0 3px #fff; }
@media (max-height: 780px) {
  :where(body:not([data-fit="1"])) .zod-panel { gap: 3px; padding: 4px; margin-top: 4px; }
  :where(body:not([data-fit="1"])) .zq { padding: 2px 1px; }
  :where(body:not([data-fit="1"])) .zq-ico { font-size: 10px; opacity: .95; }   /* 🔴 手機**不要整個藏掉** —— 藏了就只剩三顆宮圖，看不出這一格是哪一象 */
}

/* ══ [claude code] 2026-08-18 v3.55 🎚️ 波動檔切換 + 機率模型（星宮聚合）══
   位置：SPIN 下面、平台資訊（🗓️ 身世）上方 —— 使用者指定「切換按鈕放上面, 下面放現型的模型」。

   🔴 **不套 `.game-born` 那條「矮螢幕隱藏」** —— 那條是給「日期 / 版本」這種註記用的，
      而這一區是**功能**（切手感）+ 玩家判斷用的數字。矮螢幕捲一下看得到就好
      （使用者 2026-08-18：「各版本來就有長有短, 硬限制很怪」）。
   🔴 它在 `#uiPad` 之後 → `boardHeightBudget()` 不會量到它，所以加了它**不會**把盤面壓小、
      也不會把 SPIN 頂出畫面。 */
.gm-modewrap { max-width: 480px; margin: 8px auto 4px; }
.gm-modebar { display: flex; align-items: stretch; gap: 6px; }
/* 檔位鈕（一檔一顆）。左邊原本還有一顆「🎚️ 手感 ▾」開合鈕，
   2026-09-08 v3.90 移除 —— 開合改由下面那排數字（`.gmd-mini`）自己負責。 */
.gmb-btn { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 1px; padding: 6px 4px; border-radius: 10px; cursor: pointer;
  background: rgba(255,255,255,.045); border: 1px solid var(--border); color: var(--text-soft);
  font-family: inherit; transition: background .15s ease, border-color .15s ease, color .15s ease; }
.gmb-btn:hover { background: rgba(255,255,255,.08); }
/* 選中的那顆：邊框 + 底色 + 字色三個一起變（只靠顏色的話，色弱玩家看不出選了哪顆）*/
.gmb-btn.on { background: linear-gradient(180deg, rgba(255,207,58,.20), rgba(255,207,58,.07));
  border-color: var(--gold); color: var(--text); box-shadow: 0 0 10px rgba(255,207,58,.22); }
/* 「推薦」徽章：只掛在 defaultMode 那一顆。
   🔴 兩檔 RTP 一樣、沒有哪一檔比較好賺 → 它講的是「先玩這個比較好上手」，不是「這個比較划算」。
   做成鈕右上角的小標，不佔一整行、也不會把兩顆鈕撐成不同高度。 */
.gmb-btn { position: relative; }
.gmb-rec { position: absolute; top: -7px; right: 6px; padding: 1px 6px; border-radius: 999px;
  font-size: 9.5px; font-weight: 700; letter-spacing: .5px; line-height: 1.5;
  background: linear-gradient(180deg, #6ad39a, #35a86e); color: #06210f;
  box-shadow: 0 1px 4px rgba(0,0,0,.35); }
.gmb-name { font-size: 13px; font-weight: 700; }
.gmb-sub { font-size: 10px; opacity: .8; font-variant-numeric: tabular-nums; }

.gm-model { margin-top: 6px; padding: 6px 8px; border-radius: 10px;
  background: rgba(255,255,255,.035); border: 1px solid var(--border); }
/* 收合：一行四個關鍵數字 */
/* [claude code] 2026-09-08 v3.90 那排數字**自己就是開合鈕**（使用者：「點圖一下面那排 RTP 之類的才展開」）
   → 它從 div 變成 button，所以要把瀏覽器預設的按鈕外觀整組清掉，
   🔴 但**不要清 cursor** —— 那是「這裡可以點」唯一的視覺線索。 */
.gmd-mini { display: flex; flex-wrap: wrap; gap: 4px 6px; justify-content: center; align-items: center;
  width: 100%; background: none; border: 0; padding: 0; margin: 0; font: inherit; color: inherit;
  cursor: pointer; -webkit-tap-highlight-color: transparent; }
.gmd-mini:hover .gmd-chip { border-color: rgba(255,255,255,.22); }
.gmd-mini:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; border-radius: 8px; }
.gmd-caret { font-size: 10px; color: var(--text-soft); transition: transform .18s ease; }
.gmd-mini[aria-expanded="true"] .gmd-caret { transform: rotate(180deg); }
/* 展開時那排數字留在原位、下面接表格 → 中間給一點呼吸 */
.gm-model.open .gmd-mini { margin-bottom: 8px; }
.gmd-chip { display: inline-flex; align-items: baseline; gap: 4px;
  padding: 3px 7px; border-radius: 999px; background: rgba(0,0,0,.22);
  border: 1px solid rgba(255,255,255,.07); font-size: 11px; line-height: 1.5; }
.gmd-lab { color: var(--text-soft); letter-spacing: .4px; }
.gmd-val { color: var(--gold); font-weight: 700; font-variant-numeric: tabular-nums; }
/* 展開：兩檔並排的數學模型表。🔴 `RTP` 那一列自己就講完「兩檔一樣」，不用再寫一句話。 */
.gmd-tab { width: 100%; border-collapse: collapse; font-size: 11.5px;
  font-variant-numeric: tabular-nums; }
.gmd-tab th, .gmd-tab td { padding: 3px 6px; text-align: right; white-space: nowrap;
  border-bottom: 1px solid rgba(255,255,255,.06); }
.gmd-tab th { color: var(--text-soft); font-weight: 700; font-size: 11px; }
.gmd-tab th:first-child, .gmd-tab td:first-child { text-align: left; }
.gmd-tab .gmd-k { color: var(--text-soft); letter-spacing: .4px; }
.gmd-tab td { color: var(--text); }
/* 目前這一檔那一欄整欄標起來 —— 玩家一眼知道自己在看的是哪一組數字 */
.gmd-tab th.on, .gmd-tab td.on { background: rgba(255,207,58,.10); color: var(--gold); font-weight: 700; }
.gmd-tab tr:last-child th, .gmd-tab tr:last-child td { border-bottom: 0; }
.gmd-src { margin-top: 4px; text-align: right; font-size: 10px; color: var(--text-soft); opacity: .75; }

@media (max-height: 780px) {
  :where(body:not([data-fit="1"])) .gm-modewrap { margin: 6px auto 3px; }
  :where(body:not([data-fit="1"])) .gmb-btn { padding: 5px 3px; }
  :where(body:not([data-fit="1"])) .gmd-chip { font-size: 10.5px; padding: 2px 6px; }
  :where(body:not([data-fit="1"])) .gmd-tab { font-size: 11px; }
  :where(body:not([data-fit="1"])) .gmd-tab th, :where(body:not([data-fit="1"])) .gmd-tab td { padding: 2px 5px; }
}

.cell.zd-elem { box-shadow: inset 0 0 0 2px var(--gold), 0 0 14px rgba(255,207,58,.55); border-radius: 8px; }
/* 🔴 [claude code] 2026-08-15 v3.4 修「中獎後四象限配色被打回紫底」（使用者截圖抓到）。
   原本 zdPulse 的 keyframes 寫了 `filter: none` / `filter: drop-shadow(...)` ——
   **animation 的優先權高於一般宣告**，所以只要格子中獎掛上 `.zd-elem`，
   象限配色那條 `filter: hue-rotate(...)` 就被整個蓋掉 → 中獎格全部退回 emoji 原本的紫。
   （非中獎格沒被蓋，所以畫面會變成「中的是紫的、沒中的是彩色的」，正好相反。）
   → **脈動只動 `transform`**；發光改掛在格子的 box-shadow 上（那條本來就是金框，不衝突）。
   ⚠️ 通則：**要在會疊加狀態 class 的元素上做動畫，keyframes 裡不要碰 `filter`**
      —— 底下那層的 filter 一定會被吃掉，而且是靜默的。 */
.cell.zd-elem .glyph { animation: zdPulse .9s ease-in-out infinite; }
@keyframes zdPulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.12); } }
.cell.zd-elem { animation: zdCellGlow .9s ease-in-out infinite; }
@keyframes zdCellGlow {
  0%, 100% { box-shadow: inset 0 0 0 2px var(--gold), 0 0 12px rgba(255,207,58,.45); }
  50% { box-shadow: inset 0 0 0 2px var(--gold), 0 0 24px rgba(255,207,58,.9); } }
.cell.zd-near { box-shadow: inset 0 0 0 2px rgba(255,255,255,.28); border-radius: 8px; }
.cell.zd-near .glyph { opacity: .85; }
.cell.zd-scat { box-shadow: inset 0 0 0 2px #b98cff, 0 0 16px rgba(185,140,255,.6); border-radius: 8px; }
.cell.zd-scat .glyph { filter: drop-shadow(0 0 10px #b98cff); }

/* ================= [claude code] 2026-08-14 v2.83 通用倍率條 `.ui-multbar` =================
   規則見 CLAUDE.md「🔴 倍數顯示一律用倍率條」。**全平台的倍數只有這一種長相**：
   綠底金框的一條 + chips，當前值亮起（金）、免費期整條轉橘（`.fs`）。
   長相與 chips 都在這裡；「貼在哪」由 host 的 `.pos-*` class 決定（見下面 .game-multbar / .mw-multbar）。 */
.ui-multbar { display: flex; align-items: center; justify-content: center; gap: 4px;
  height: 27px; border-radius: 8px; pointer-events: none;
  background: linear-gradient(180deg, #2b8f66 0%, #15694a 55%, #0d4633 100%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.28), inset 0 0 0 1.5px rgba(255,207,58,.5),
    0 4px 12px rgba(0,0,0,.5); }
.ui-mchip { font-size: clamp(11px, calc(3.2 * var(--vw)), 15px); font-weight: 900; letter-spacing: .04em;
  padding: 1px 10px; border-radius: 999px; color: rgba(255,255,255,.5); white-space: nowrap; }
/* [claude code] 2026-08-14 v2.93 階梯格數多的款（淨化光稜 7 格）縮一點，免得窄螢幕擠出框 */
.ui-multbar.many .ui-mchip { padding: 1px 6px; font-size: clamp(10px, calc(2.7 * var(--vw)), 13px); letter-spacing: 0; }
.ui-mchip.on { color: #2a1d00; background: linear-gradient(#fff3c8, var(--gold));
  box-shadow: 0 0 12px rgba(255,207,58,.85), inset 0 1px 0 rgba(255,255,255,.7);
  transform: scale(1.16); text-shadow: 0 1px 0 rgba(255,255,255,.5); }
.ui-multbar.fs .ui-mchip.on { background: linear-gradient(#ffd0a0, #ff7a3c); color: #3a1200;
  box-shadow: 0 0 16px rgba(255,122,60,.9); }
/* 🔴 [claude code] 2026-09-21 v4.45 倍率是 **0** 的那一格（星宮聚合「只聚合 1 組」）。
   它畫的是 `—` 不是 `x0`，顏色也壓得比其他格淡 —— 這一格的意思是「這裡沒有值」，
   不是「乘一個很小的數」（使用者 2026-09-21：「能改成不要像是乘法倍數那種，比如換成 -」）。
   落在這一格時仍然會掛 `.on` 把位置指出來，只是換成沒有溫度的灰金色。 */
.ui-mchip.zero { color: rgba(255,255,255,.3); letter-spacing: 0; }
.ui-mchip.zero.on { color: #40382a; background: linear-gradient(#ded4b8, #b3a582);
  box-shadow: 0 0 10px rgba(179,165,130,.65), inset 0 1px 0 rgba(255,255,255,.55); }
/* 🔴 條上不放說明文字（v2.84 使用者定：「不用那些文字」）—— 原本的 `.ui-mhint` 小字已移除。
   規則要講去 ⓘ 說明 / 📋 賠付表 / 跑馬燈；這條只回答「現在幾倍」。 */

/* 麻將胡牌了：條貼在盤面上緣（絕對定位，盤面自己 margin-top 讓出空間） */
.mw-multbar { position: absolute; top: -25px; left: 10px; right: 10px; z-index: 6; }

/* 賠付表的小牌縮圖 */
.mw-pt-tile { display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 33px; border-radius: 5px; vertical-align: middle; overflow: hidden;
  background: linear-gradient(158deg, #fbf6e9, #e2d4b6); color: #1b2330;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.7), 0 1px 2px rgba(0,0,0,.35); }
.mw-pt-tile .mj-honor { font-size: 15px; }
.mw-pt-tile .mj-pip { width: 82%; height: 82%; }
.mw-pt-tile .mj-man .mm-n { font-size: 11px; } .mw-pt-tile .mj-man .mm-s { font-size: 7px; }
.mw-pt-tile .mw-ingot { font-size: 13px; } .mw-pt-tile .mw-wtxt { font-size: 7px; }
.mw-pt-tile .mw-scat-art { font-size: 15px; animation: none; }

/* 細單：逐步盤面（靜態存證 → 不跑任何脈動動畫） */
/* [claude code] 2026-09-01 v3.61 🪞 雙生鏡界:鏡像表演 + 細單的「鏡像前 / 後」並排。
   🔴 兩個動畫要**分得出來**:左鄰軸是「被抄的來源」(金色脈動)、該軸是「正在被換掉」(翻面)。
      用同一個效果的話,玩家看不出方向 —— 而「從哪抄到哪」正是這一款要教的規則。 */
/* [claude code] 2026-09-01 v3.67 🪞 雙生鏡界 —— 招牌表演 v2（五拍：因 → 方向 → 複製 → 落定 → 鏈接）。
   🔴 **格子動畫一律做在 `.glyph` 上，不可以碰 `.cell` 的 transform** ——
      `.cell` 的位置就是靠 `transform: translate3d(0,Ypx,0)` 排出來的（見 app.js `renderReel`），
      v3.61 的 `@keyframes syFlip` 動 `.cell` 的 transform，一播那一格就會跳回軸頂。
      （它當時剛好被 `setCell` 洗掉所以從沒播過 —— 兩個 bug 互相蓋住，畫面上完全看不出來。）
   🔴 四種狀態**一定要分得出來**：來源（金色實框、脈動）/ 目標（藍虛框、壓暗）/ 幽靈（飛行中）/ 完成（金色定框）。
      用同一種效果的話玩家看不出方向，而「從哪抄到哪」正是這一款要教會玩家的規則。 */

/* ⓪ 因：☯️ 陰陽鏡現身 —— 紫色光環 + 呼吸，一直亮到它那一軸被抄掉（setCell 會自然洗掉 class）。
   🔴 **刻意用紫色、不用金色** —— 金色在這一段已經是「複製動線」的顏色（來源軸 .sy-src / 完成 .sy-done）。
      鏡符跟著一起用金色的話，「還沒輪到的那面鏡」與「這一輪的來源軸」在畫面上長得一樣，
      玩家會以為那一軸也在往右抄。三種顏色分工：**紫 = 鏡符本身（因）· 金 = 複製動線 · 藍 = 待被換掉的目標**。 */
.cell.sy-cue { z-index: 6;
  box-shadow: inset 0 0 0 2px #c08bff, 0 0 24px rgba(176,120,255,.9);
  background: radial-gradient(circle at 50% 50%, rgba(176,120,255,.28), var(--surface-2) 72%); }
.cell.sy-cue .glyph { animation: syCue .92s ease-in-out infinite; }
@keyframes syCue { 0%,100% { transform: scale(1); filter: drop-shadow(0 0 4px rgba(199,139,255,.7)); }
  50% { transform: scale(1.2); filter: drop-shadow(0 0 16px rgba(199,139,255,1)); } }
/* ⚠️ 只加在鏡符格上 —— WILD / SCATTER 的 `::after` 是它們的角標，別把 sy-cue 加到那兩種格 */
.cell.sy-cue::after { content: ""; position: absolute; inset: -2px; border-radius: inherit; z-index: 1;
  border: 2px solid rgba(199,139,255,.95); pointer-events: none; animation: syCueRing 1.15s ease-out infinite; }
@keyframes syCueRing { 0% { transform: scale(1); opacity: .9; } 100% { transform: scale(1.55); opacity: 0; } }

/* ① 方向：來源軸「從這裡抄」= 金色實框 + 呼吸 */
.cell.sy-src { z-index: 5; box-shadow: inset 0 0 0 2px var(--gold, #ffd24a), 0 0 18px rgba(255,210,74,.6); }
.cell.sy-src .glyph { animation: sySrc 1s ease-in-out infinite; }
@keyframes sySrc { 0%,100% { transform: scale(1); } 50% { transform: scale(1.09); } }
/* ① 方向：目標軸「這裡要被換掉」= 藍虛框 + 壓暗（`:not(.sy-cue)` → 站在上面的 ☯️ 保持亮著，它是因不是待換的內容） */
.cell.sy-dst { box-shadow: inset 0 0 0 2px rgba(140,190,255,.5); }
.cell.sy-dst:not(.sy-cue) .glyph { opacity: .3; filter: grayscale(.75);
  transition: transform .2s, opacity .3s ease, filter .3s ease; }

/* ② 複製過去：幽靈。`.reel` 是 overflow:hidden → 只能掛 body 上用 fixed 飛（比照 .plink-fly） */
.cell.sy-ghost { position: fixed; right: auto; bottom: auto; z-index: 60; pointer-events: none;
  border-radius: 10px; transform: translate(-50%, -50%); will-change: transform, opacity;
  box-shadow: inset 0 0 0 2px rgba(255,210,74,.95), 0 0 22px rgba(255,210,74,.75); }

/* ③ 落定：翻面（做在 .glyph 上，見檔頭紅字） */
.cell.sy-flip { z-index: 5; }
.cell.sy-flip .glyph { animation: syFlip .34s cubic-bezier(.3,.9,.4,1); }
@keyframes syFlip { 0% { transform: rotateY(90deg) scale(.66); opacity: .2; }
  62% { transform: rotateY(0deg) scale(1.18); opacity: 1; } 100% { transform: rotateY(0deg) scale(1); } }
/* ③ 收尾：「這一軸現在就是左鄰的樣子了」；鏈接傳遞時它會直接接成下一輪的 .sy-src，高亮不斷 */
.cell.sy-done { box-shadow: inset 0 0 0 2px rgba(255,210,74,.85), 0 0 18px rgba(255,210,74,.6); }

/* ① ➜ 方向箭頭（掛在 .board-wrap 上：它是 position:relative，而且不會被 .reel 裁掉）
   🔗 鏈接傳遞用青色 —— 「抄原本的」與「抄剛複製好的」是兩件事，顏色分開才看得出來 */
.sy-arrow { position: absolute; z-index: 7; pointer-events: none; font-size: 24px; font-weight: 900;
  color: #ffd24a; text-shadow: 0 0 12px rgba(255,210,74,.95), 0 2px 4px rgba(0,0,0,.75);
  transform: translate(-50%, -50%); animation: syArrow .72s ease-in-out infinite; }
@keyframes syArrow { 0%,100% { transform: translate(-50%,-50%) translateX(-5px); opacity: .7; }
  50% { transform: translate(-50%,-50%) translateX(5px); opacity: 1; } }
.sy-arrow.sy-arrow-chain { color: #8ad7ff; text-shadow: 0 0 12px rgba(138,215,255,.95), 0 2px 4px rgba(0,0,0,.75); }
.dt-line-list .dt-lways, .dt-lines .dt-lways { opacity: .85; font-variant-numeric: tabular-nums; }
/* [claude code] 2026-09-01 v3.60 Megaways 本注明細的盤面。
   🔴 **各軸高度不一樣**(2~7 每轉重抽,那就是這款的招牌)→ 一軸一欄、各欄自己置中,
      不能用固定 rows × cols 的方陣(那會把高度差抹平,正好把最該看到的東西弄不見)。 */
.dt-board.dt-ways { display: flex; gap: 3px; align-items: center; justify-content: center; padding: 4px 0; max-width: none; }
.dt-ways-reel { display: flex; flex-direction: column; justify-content: center; gap: 3px; }
.dt-ways-cell { width: 26px; height: 26px; border-radius: 5px; display: flex; align-items: center; justify-content: center;
  font-size: 15px; line-height: 1; background: rgba(255,255,255,.06); border: 1px solid rgba(255,255,255,.10); }
.dt-ways-cell.dt-ways-hit { border-color: #ffd24a; box-shadow: 0 0 7px rgba(255,210,74,.7); background: rgba(255,210,74,.16); }
.dt-board.dt-mw { display: flex; gap: 3px; align-items: center; justify-content: center; padding: 4px 0; }
.dt-mw-reel { display: flex; flex-direction: column; justify-content: center; gap: 3px; }
.dt-mw-cell { position: relative; width: 26px; height: 33px; border-radius: 5px; overflow: hidden; animation: none !important; }
.dt-mw-cell .mj-honor { font-size: 15px; }
.dt-mw-cell .mj-pip { width: 82%; height: 82%; }
.dt-mw-cell .mj-man .mm-n { font-size: 11px; } .dt-mw-cell .mj-man .mm-s { font-size: 7px; }
.dt-mw-cell .mw-ingot { font-size: 13px; } .dt-mw-cell .mw-wtxt { font-size: 7px; }
.dt-mw-cell .mw-scat-art { font-size: 15px; animation: none !important; }
.dt-mw-cell.dt-mw-hit { box-shadow: inset 0 0 0 2px var(--win, #ffe169), 0 0 7px rgba(255,225,105,.6); }
.dt-mw-cell.dt-mw-turn { box-shadow: inset 0 0 0 2px #ffb02e, 0 0 9px rgba(255,176,46,.85); }
.dt-step-head { margin: 8px 0 3px; font-size: 12px; font-weight: 800; color: rgba(255,255,255,.8); }



/* ================= [claude code] 2026-08-13 v2.74 新版型（依使用者參考圖：PG 那類直版 SLOT）=================
   盤面 → ① 訊息帶 → ② 金額列（左餘額 · 右單注）→ ③ 五顆一排 → ④ 自動面板（由下往上）。
   🔴 先只在「麻將胡牌了」啟用（app.js 的 NEWUI_MECHS 白名單）；舊版型 .control-bar / .control-row2
      整組留著沒動，其餘 23 款完全不受影響。驗收 OK 再把 mechanic 加進白名單整批換過去。
   🔴 這一整區的高度會被 boardHeightBudget() 實測（量 #uiBelt + #uiMoney + #uiPad）→ 盤面自動夾小，
      不會頂出畫面（手機一屏可見鐵則）。改這裡的高度不必回頭改那支函式。 */

/* ---- ① 訊息帶：待機跑馬燈 ↔ 中獎贏分，同一塊、同樣高度（不會忽有忽無把版面推來推去）---- */
.ui-belt { position: relative; max-width: 480px; margin: 8px auto 8px; height: 46px;
  border-radius: 12px; overflow: hidden;
  background: linear-gradient(180deg, rgba(255,255,255,.055), rgba(255,255,255,.015));
  border: 1px solid var(--border);
  transition: background .2s ease, border-color .2s ease, box-shadow .2s ease; }
/* 中獎態：金色微光。整塊換底色而不是只換文字顏色 → 餘光掃過去就知道「這局有錢」 */
.ui-belt.win { border-color: rgba(255,210,74,.55);
  background: linear-gradient(180deg, rgba(255,210,74,.16), rgba(255,160,40,.06));
  box-shadow: inset 0 0 0 1px rgba(255,210,74,.2), 0 0 18px rgba(255,190,60,.18); }

/* 跑馬燈：句子直接出現 → 停一下 → 往左移出框 → 換下一句（使用者指定的節奏） */
.belt-marquee { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  padding: 0 14px; }
.belt-msg { display: inline-block; white-space: nowrap; font-size: 13.5px; letter-spacing: .02em;
  color: rgba(255,255,255,.68); text-shadow: 0 1px 2px rgba(0,0,0,.5); }
.belt-msg.in { animation: beltIn .34s ease both; }
/* 🔴 出框距離用 `calc(-100% - calc(52 * var(--vw)))`：`-100%` 只移動自己的寬度，短句根本走不出框 —— 再補一個
   比容器還寬的 vw 才保證真的離場。linear = 等速滑出，像真的跑馬燈。 */
.belt-msg.out { animation: beltOut .9s linear both; }
@keyframes beltIn { from { opacity: 0; transform: translateY(5px); } to { opacity: 1; transform: none; } }
@keyframes beltOut { from { opacity: 1; transform: translateX(0); }
  to { opacity: .25; transform: translateX(calc(-100% - calc(52 * var(--vw)))); } }

/* 中獎：本局贏分置中（表演跑完才由 armGamble 長出右邊那顆翻倍鈕）*/
.belt-win { position: absolute; inset: 0; display: none; align-items: center; justify-content: center; gap: 9px;
  padding: 0 12px; }
.ui-belt.win .belt-marquee { display: none; }
.ui-belt.win .belt-win { display: flex; }
.bw-cap { font-size: 12px; color: rgba(255,255,255,.62); }
.bw-amt { font-size: 21px; font-weight: 900; color: var(--win); font-variant-numeric: tabular-nums;
  text-shadow: 0 0 12px rgba(255,225,105,.55); }
/* [claude code] 2026-08-13 v2.76 使用者：「得 N 倍在跳動時，能跳動一下，讓人知道他換了，**但別太搶眼**」
   → 幅度從 1.16 收到 **1.06**、時間 .28s → **.2s**：看得出「數字換了」，但不會每連鎖一次就在那邊彈。
   🔴 只有數字自己 scale，`.belt-win` 是 flex 置中 → 旁邊的「共贏得」與倍數不會被推位移。 */
.bw-amt.bump { animation: bwBump .2s ease; }
@keyframes bwBump { 50% { transform: scale(1.06); } }
/* [claude code] 2026-08-14 v2.86 拿掉贏分旁邊的「×N 倍」（v2.76 加的 `.bw-x`）——
   使用者:「後面那個 ×0.30 不用顯示, 因為多餘了」。玩家要看的是**拿到多少錢**;
   倍數在賠付表與細單裡都查得到,擺在贏分旁邊只是把一行字變兩件事。 */
/* 🔴 絕對定位貼右，不佔 flex 的位置 —— 贏分要**固定置中**（使用者：「他會置中顯示，右邊會多一個按鈕」）。
   若讓它參與置中排版，翻倍鈕一出現整組就會往左挪一截，數字看起來像跳了一下。
   [claude code] 2026-08-13 v2.75 依使用者：「要可以翻倍時，會從右邊移出來；剛進遊戲時他是縮進去右邊的」
   → 🔴 **不用 display 切換**（那只會忽有忽無地閃出來），改成**一直在那裡、平時縮在框外**：
      預設 translateX 推出右邊界 + opacity 0 + 不可點；可以翻倍時加 `.on` 滑回來。
      `.ui-belt` 有 `overflow: hidden` → 縮出去那截自然被裁掉，看不到半顆鈕。 */
.bw-gamble { position: absolute; right: 10px; top: 50%; margin-top: -14px;
  padding: 5px 12px; border-radius: 999px; cursor: pointer;
  font-size: 12.5px; font-weight: 800; color: #2a1d00; border: none;
  background: linear-gradient(#fff3c8, var(--gold));
  box-shadow: 0 2px 10px rgba(255,207,58,.5);
  transform: translateX(calc(100% + 16px)); opacity: 0; pointer-events: none;
  transition: transform .34s cubic-bezier(.22,.75,.3,1.16), opacity .22s ease; }
.bw-gamble.on { transform: translateX(0); opacity: 1; pointer-events: auto; }
.bw-gamble:hover { filter: brightness(1.08); }
/* 🔴 v2.77：這裡刻意**不加** prefers-reduced-motion —— 翻倍鈕「從右邊滑出來」是使用者指定的行為，
   關掉它就變成憑空出現、失去「從哪裡來」的交代。同理 .ps-ring 那條也已移除（見下面的說明）。 */

/* 加速鈕搬到底部第一顆了 → 遊戲畫面的頂列不要再放一顆（回大廳仍在，那裡沒有底部那排）*/
body[data-view="game"] #turboBtn { display: none; }

/* [claude code] 2026-08-18 v3.54 🔴 `#spinBtn` 已經**不是介面、是狀態載體**（見 index.html 那段說明）——
   20+ 款、123 處 spin 流程寫它的 `disabled`，底部 `#padSpin` 用 MutationObserver 鏡射。
   這裡把它徹底藏起來：玩家看不到、點不到、也不佔版面。 */
.legacy-spin-state { display: none !important; }

/* [claude code] 2026-08-13 v2.76 依使用者：盤面下面那行中獎明細（「三條 連4軸 × 2路 倍率×2 +80」）
   **先收起來**、程式碼留著 —— 要再打開只要拿掉這一條規則，`#winBanner` 的內容照樣在寫。
   🔴 它原本是**固定 44px + margin 8px 的保留區**（刻意佔位讓 SPIN 不跳動）→ 收掉就省 52px，
      整組介面自然往上靠；`boardHeightBudget()` 的 reserve 本來就沒算它，收掉之後反而更準。
   ⚠️ 副作用：免費轉的進度提示（「🧧 免費 3/8 本轉從 🔥×4 起跳」）也走這個元素 → 一併看不到。 */
body .action-zone { display: none; }   /* v3.54 舊版型移除後不必再靠 data-newui 區分 */

/* ---- ② 金額列：左餘額 · 右單注（依使用者確認：照參考圖）---- */
.ui-money { max-width: 480px; margin: 0 auto 9px; padding: 0 4px;
  display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.um-cell { display: inline-flex; align-items: center; gap: 7px; padding: 7px 14px; border-radius: 999px;
  background: rgba(255,255,255,.05); border: 1px solid var(--border); line-height: 1; }
.um-ico { font-size: 14px; }
.um-cap { font-size: 11px; color: var(--text-soft); }
.um-val { font-weight: 800; font-variant-numeric: tabular-nums; }
.um-bal .um-val { font-size: 16px; color: var(--gold); }
.um-bal .um-val.bump { animation: bwBump .28s ease; }
.um-bet .um-val { font-size: 15px; color: var(--text); }
/* [claude code] 2026-08-18 v3.54 招財彈珠**沒有「單注」的概念**（注額 = 球數 × 每顆單價，球數在盤面上方選）
   → 金額列的單注格與五顆一排的 ＋/− 一起收起來。
   舊版型時代這件事是靠 `.bet-stepper` 的 display 做的，那組已隨舊介面移除 → 改掛 class（見 syncPadBet）。
   ⚠️ 收掉 ＋/− 之後五顆變三顆，`justify-content: center` 會自然把 SPIN 擺回正中間，不用另外調。 */
/* [claude code] 2026-09-20 🛒 買特色（夾在餘額與單注中間）。
   金色描邊 = 「這顆要花錢」的訊號，跟旁邊兩格純資訊的膠囊分開。
   🔴 `[hidden]` 要自己補 `display:none` —— `.um-cell` 是 `inline-flex`，
      它的權重比瀏覽器對 `[hidden]` 的預設樣式高，不補的話**沒有這個功能的款也會長出一顆鈕**。 */
.um-buy { cursor: pointer; color: var(--text); font-family: inherit;
  background: linear-gradient(180deg, rgba(242,193,78,.20), rgba(184,122,30,.13));
  border-color: rgba(242,193,78,.55); }
.um-buy[hidden] { display: none; }
.um-buy:hover:not(:disabled) { border-color: rgba(242,193,78,.85); }
.um-buy:disabled { opacity: .42; cursor: not-allowed; }
.um-buy .um-cap { color: rgba(242,193,78,.9); }
.um-buy .um-val { font-size: 15px; color: var(--gold); }
/* 買特色確認面板（沿用 .auto-sheet / .as-card） */
.bs-what { font-size: 14px; font-weight: 700; line-height: 1.5; margin-bottom: 6px; }
.bs-costrow { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.bs-cost { font-size: 22px; font-weight: 800; color: var(--gold); font-variant-numeric: tabular-nums; }
/* [claude code] 2026-09-22 v4.55 🎱 開球數（幸運賓果專用，位置同 🛒 買特色：夾在餘額與單注中間）。
   🔴 `[hidden]` 要自己補 `display:none`（`.um-cell` 是 `inline-flex`，權重比瀏覽器預設高）——
      不補的話**每一款都會長出一顆 🎱**。 */
.um-balls { cursor: pointer; color: var(--text); font-family: inherit; }
.um-balls[hidden] { display: none; }
.um-balls:hover:not(:disabled) { border-color: var(--neon-2); }
.um-balls:disabled { opacity: .42; cursor: not-allowed; }
.um-balls .um-val { font-size: 15px; color: var(--neon-2); }
.um-balls.open { border-color: var(--neon-2); box-shadow: 0 0 0 1px var(--neon-2); }
.ui-money.no-bet .um-bet { display: none; }
.ui-pad.no-bet .pad-step { display: none; }

/* ---- ③ 五顆一排：加速 · − · SPIN · ＋ · 自動 ---- */
.ui-pad { max-width: 480px; margin: 0 auto; padding: 2px 4px 4px;
  display: flex; align-items: center; justify-content: center; gap: 14px; }
.pad-btn { flex: 0 0 auto; border-radius: 50%; cursor: pointer; line-height: 1;
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--text); border: 1px solid var(--border); background: rgba(255,255,255,.06);
  transition: transform .12s ease, background .16s ease, color .16s ease, border-color .16s ease; }
.pad-btn:hover { background: rgba(255,255,255,.11); }
.pad-btn:active { transform: scale(.92); }
.pad-side { width: 42px; height: 42px; font-size: 17px; color: var(--text-soft); }
.pad-step { width: 48px; height: 48px; font-size: 25px; font-weight: 700; }
.pad-btn:disabled { opacity: .38; cursor: not-allowed; }
/* TURBO 開著 → 亮起來；關著就是一顆安靜的灰鈕（用 class 切，不用換字） */
#padTurbo.on { color: var(--gold); border-color: rgba(255,210,74,.6); background: rgba(255,210,74,.14);
  box-shadow: 0 0 12px rgba(255,200,70,.3); }
/* 自動進行中 → 同樣亮起來，讓「現在是自動」有存在感 */
#padAuto.on { color: var(--neon-2); border-color: rgba(54,224,255,.6); background: rgba(54,224,255,.14);
  box-shadow: 0 0 12px rgba(54,224,255,.28); }

.pad-spin { position: relative; flex: 0 0 auto; width: 86px; height: 86px; border-radius: 50%;
  border: none; cursor: pointer; color: #0a0c16; font-weight: 900; letter-spacing: 1px;
  display: inline-flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px;
  background: linear-gradient(135deg, var(--neon), var(--neon-2));
  box-shadow: 0 6px 22px rgba(54,224,255,.38);
  transition: transform .14s ease, box-shadow .18s ease, filter .14s ease; }
.pad-spin:hover { filter: brightness(1.06); }
.pad-spin:active { transform: scale(.95); }
/* 🔴 轉動中不要壓太暗 —— 這顆鈕「正在快轉」本身就是重要的回饋，壓成半透明等於把回饋關掉。 */
.pad-spin:disabled { opacity: .82; cursor: not-allowed; }

/* [claude code] 2026-08-13 v2.74 依使用者：「SLOT 的 SPIN 是轉 → 按鈕做成圓的，平時就慢慢轉，
   按下去（轉動中）變快轉」。缺口環 + 一顆箭頭尖，整圈一起轉。
   [claude code] 2026-08-13 v2.76 二版（使用者：「要**圍著字轉**，表演中要**轉更快**」）：
   · `inset` 8px → **15%**：環從貼著鈕的外緣往內收，變成**繞著 SPIN 那幾個字**跑
     （用 % 不用 px：矮螢幕鈕縮到 68px 時，環會跟著等比內縮，不會壓到字）
   · 平時 7s → **5s**：7s 慢到看不出來它在動（使用者看到的就是一個靜止的框）
   · 轉動中 0.5s → **0.26s**、自動中 1.4s → **1.1s**
   · 顏色加深到 .52 —— 疊在霓虹漸層上，.42 太淡，環的形狀讀不出來 */
.ps-ring { position: absolute; inset: 15%; border-radius: 50%; pointer-events: none;
  animation: padRingRot 3.6s linear infinite; }
/* 🔴 [claude code] 2026-08-15 v3.6 環改成「**接近整圈 + 一個順時鐘箭頭**」
   （使用者：「那個 SPIN 轉的那個, 可以變成順時鐘的箭頭嗎, 他目前斷了」）。
   舊寫法用 border 做環，但**兩個邊設成 transparent → 實際只剩半圈**（180°），
   看起來就是「斷掉的框」而不是「一個在轉的箭頭」。
   → 改用 `conic-gradient` 畫 **330° 的弧**（12 點鐘往順時鐘留 30° 缺口），
     箭頭放在弧的**順時鐘前端**（正上方）**指向右邊** —— 右 = 12 點鐘方向的順時鐘切線，
     所以一眼看得出它在往順時鐘跑。
   ⚠️ `mask` 是把「實心扇形」挖成「環」的必要手段（Chrome / Android WebView 都支援；本產品是 PWA+TWA）。 */
/* [claude code] 2026-08-16 v3.11 依使用者：「這個順時鐘的圓圈箭頭，我希望**只有半圓**就好了」。
   330° → **180°**：缺口從 30° 開到 180°，弧從 6 點鐘（180deg）順時鐘走到 12 點鐘（360deg）。
   🔴 **弧的順時鐘終點仍然壓在 12 點鐘** —— 箭頭（::after）是釘在正上方的，
      只改「弧從哪裡開始」就不會動到箭頭那三個對位（半徑 / 起點 / 顏色，見下面）。
      要是改成「從 0deg 開始畫 180deg」，弧會停在 6 點鐘、箭頭孤零零留在 12 點鐘。 */
.ps-ring::before { content: ""; position: absolute; inset: 0; border-radius: 50%;
  background: conic-gradient(from 0deg, transparent 0deg 180deg, rgba(10,12,22,.60) 180deg 360deg);
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 3px));
  mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 3px)); }
/* 箭頭：在弧的順時鐘前端（正上方），**指向右** → 方向感明確（沒有箭頭的話正轉反轉看起來一樣）。
   🔴 [claude code] 2026-08-15 v3.7 對位修正（使用者：「箭頭和線好像沒有對好」）。三個地方都要對：
     ① **半徑**：環的線佔「最外圈 3px」→ 線的中心在距上緣 **1.5px**。
        箭頭高 8px（上下各 4px）→ `top` 要寫 **-2.5px**（1.5 − 4），中心才落在線上。
        原本寫 -5px = 中心在 0，整支浮在線的外面。
     ② **起點**：弧的順時鐘終點正好在 12 點鐘（= left 50%）→ 箭頭底邊要**貼著 50%**，
        原本 `margin-left: -2px` 把它往左推了 2px，看起來就是「接不上」。
     ③ **顏色**：原本箭頭 .72、環 .60 —— 深淺不同會讀成「兩個零件」。改成同值。 */
.ps-ring::after { content: ""; position: absolute; top: -2.5px; left: 50%;
  width: 0; height: 0; border-top: 4px solid transparent; border-bottom: 4px solid transparent;
  border-left: 8px solid rgba(10,12,22,.60); }
@keyframes padRingRot { to { transform: rotate(360deg); } }
/* 🔴 [claude code] 2026-08-13 v2.77 使用者：「文字旁的黑半圓**沒有在轉**，SPIN 表演中時會轉更快」。
   病根是我 v2.74 自己加的那條 `@media (prefers-reduced-motion: reduce) { .ps-ring { animation: none } }`
   —— 系統只要開了「減少動態 / 關閉動畫效果」（Windows 11 協助工具裡預設就有人關），
   整條 animation 直接 **none** → 不但平時不轉，連 `.pad-spin:disabled` 那個「轉更快」也一起失效
   （沒有動畫可言，改 `animation-duration` 當然沒有任何作用）＝ 使用者看到的兩個現象一次到齊。
   → **那條規則已移除**：這個環不是裝飾，是「現在在跑 / 跑完了」的狀態回饋（等同 loading spinner），
     而且是等速平滑旋轉、沒有閃爍或視差，關掉它反而讓人不知道機台在做什麼。
   同時整體再加快一級（平時 5s → 3.6s、轉動中 .26s → **.18s**、自動中 1.1s → .9s）。
   🔴 `.busy` 是雙保險：`:disabled` 由 MutationObserver 鏡射，萬一哪次時序沒跟上，class 這條照樣會快轉。 */
.pad-spin:disabled .ps-ring, .pad-spin.busy .ps-ring { animation-duration: .18s; }
.pad-spin.auto .ps-ring { animation-duration: .9s; }

/* [claude code] 2026-08-13 v2.76 依使用者：「MOUSE 移上去後，要有黃圓光放大、再縮小放大，是動畫，
   **但不要讓 SPIN 字搖動**」。
   🔴 這是 `.btn-spin` 已經踩過的同一顆雷（見上面「三版」那段）：脈動只要改到**按鈕自己**的
      `transform: scale()`，裡面的字必然跟著長大位移。
   🔴 這裡的解法更徹底：脈動做在**偽元素**上 —— 一圈獨立的黃色光環自己放大縮小，
      按鈕與 SPIN 字**完全不參與這個動畫**，一格都不會動。 */
.pad-spin::after { content: ""; position: absolute; inset: -5px; border-radius: 50%;
  border: 2px solid rgba(255,214,90,.9); pointer-events: none; opacity: 0;
  box-shadow: 0 0 18px rgba(255,200,70,.55), inset 0 0 12px rgba(255,200,70,.28); }
.pad-spin:hover:not(:disabled)::after { animation: padHalo 1.15s ease-in-out infinite; }
@keyframes padHalo {
  0%, 100% { opacity: .45; transform: scale(.93); }
  50%      { opacity: 1;   transform: scale(1.15); }
}
/* 自動進行中：鈕變成金色 → 環與箭頭改成深褐（配 .ps-txt 的 #2a1d00），深藍那組在金底上會糊掉。
   🔴 [claude code] 2026-08-16 這兩條原本還是 **border 時代的寫法**（v3.6 把環改成 conic-gradient
      時漏改），造成兩個問題：
        ① `::before` 已經不用 border 了 → 那些 border-color 全是死規則，自動模式下環根本沒變色
        ② `::after` 是**用 border 疊出來的三角形**，`border-color: transparent` 把 `border-left-color`
           一起蓋掉 → **自動模式下箭頭直接消失**（只剩一塊方向相反的小楔形）
      改成各自用對的屬性：環換 background、箭頭只換 border-left-color。 */
.pad-spin.auto .ps-ring::before {
  background: conic-gradient(from 0deg, transparent 0deg 180deg, rgba(42,29,0,.45) 180deg 360deg); }
.pad-spin.auto .ps-ring::after { border-left-color: rgba(42,29,0,.45); }

.ps-txt { font-size: 18px; }
.ps-sub { font-size: 10px; font-weight: 700; opacity: .78; letter-spacing: 0; }
.ps-sub:empty { display: none; }
/* 自動進行中：SPIN 變成「剩餘次數（+ 條件）」，再按一下就中止 */
.pad-spin.auto { background: linear-gradient(135deg, #ffb03a, var(--gold)); color: #2a1d00;
  box-shadow: 0 6px 22px rgba(255,190,60,.42); }
.pad-spin.auto .ps-txt { font-size: 23px; }

/* ---- ④ 自動旋轉面板：由下往上拉出 ---- */
.auto-sheet { position: fixed; inset: 0; z-index: 60; display: none; }
.auto-sheet.show { display: block; }
.as-mask { position: absolute; inset: 0; background: rgba(4,6,14,.62); animation: asFade .2s ease both; }
@keyframes asFade { from { opacity: 0; } }
.as-card { position: absolute; left: 0; right: 0; bottom: 0; max-width: var(--app-w); margin: 0 auto;
  background: var(--surface); border-top: 1px solid var(--border);
  border-radius: 18px 18px 0 0; padding: 14px 18px calc(22px + env(safe-area-inset-bottom, 0px));
  box-shadow: 0 -12px 40px rgba(0,0,0,.55); animation: asUp .26s cubic-bezier(.22,.7,.3,1) both; }
@keyframes asUp { from { transform: translateY(100%); } }
.as-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
.as-title { font-size: 17px; font-weight: 800; }
.as-close { width: 32px; height: 32px; border-radius: 50%; cursor: pointer; font-size: 15px;
  color: var(--text-soft); background: rgba(255,255,255,.06); border: 1px solid var(--border); }
.as-close:hover { color: var(--text); }
.as-sec { margin-bottom: 14px; }
.as-label { font-size: 12px; color: var(--text-soft); margin-bottom: 7px; }
.as-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.as-chip { padding: 9px 0; min-width: 62px; flex: 1 1 62px; text-align: center; cursor: pointer;
  border-radius: 11px; font-size: 14px; font-weight: 800; color: var(--text-soft);
  background: rgba(255,255,255,.05); border: 1px solid var(--border);
  transition: background .14s ease, color .14s ease, border-color .14s ease; }
.as-chips-stop .as-chip { flex: 1 1 96px; min-width: 96px; font-size: 13px; font-weight: 700; }
.as-chip:hover { background: rgba(255,255,255,.1); color: var(--text); }
.as-chip.on { color: #2a1d00; border-color: transparent; background: linear-gradient(#fff3c8, var(--gold));
  box-shadow: 0 2px 12px rgba(255,207,58,.4); }
.as-start { width: 100%; margin-top: 4px; padding: 14px 0; border: none; border-radius: 13px;
  cursor: pointer; font-size: 16px; font-weight: 900; letter-spacing: 1px; color: #0a0c16;
  background: linear-gradient(135deg, var(--neon), var(--neon-2));
  box-shadow: 0 6px 20px rgba(54,224,255,.35); }
.as-start:hover { filter: brightness(1.06); }

/* 矮螢幕：新版型也要能一屏放得下（對齊「手機一屏可見鐵則」的逐級收合）*/
@media (max-height: 780px) {
  :where(body:not([data-fit="1"])) .ui-belt { height: 42px; margin: 6px auto 6px; }
  :where(body:not([data-fit="1"])) .ui-money { margin-bottom: 7px; }
  :where(body:not([data-fit="1"])) .pad-spin { width: 76px; height: 76px; }
  :where(body:not([data-fit="1"])) .ps-txt { font-size: 16px; }
  :where(body:not([data-fit="1"])) .pad-step { width: 44px; height: 44px; font-size: 23px; }
  :where(body:not([data-fit="1"])) .pad-side { width: 38px; height: 38px; font-size: 15px; }
  :where(body:not([data-fit="1"])) .ui-pad { gap: 11px; }
}
@media (max-height: 690px) {
  :where(body:not([data-fit="1"])) .ui-belt { height: 38px; margin: 5px auto 5px; }
  :where(body:not([data-fit="1"])) .belt-msg { font-size: 12.5px; }
  :where(body:not([data-fit="1"])) .bw-amt { font-size: 18px; }
  :where(body:not([data-fit="1"])) .um-cell { padding: 5px 11px; }
  :where(body:not([data-fit="1"])) .pad-spin { width: 68px; height: 68px; }
  :where(body:not([data-fit="1"])) .ps-txt { font-size: 15px; }
}


/* ================= 花蜜採集的 🐝 倍率條 =================
   [claude code] 2026-08-14 v2.83 依使用者「倍數的那種，我想統一使用麻將胡牌了的方式」——
   原本這裡是一顆獨立的琥珀色 pill（`.cm-ico` / `.cm-val` / `.cm-hint`，v2.82），
   現在整條改用通用的 `.ui-multbar`（見上面），這裡只負責「貼在盤面上緣」。
   🔴 −7px 只壓進盤面自己的 padding（6px），**不會蓋到第一列格子**。 */
/* [claude code] 2026-08-14 v2.84 拿掉 max-width：條改成**貼齊盤面兩端**（內縮 10px），
   與麻將那條的 `left/right: 10px` 同寬 —— 使用者要的是「像麻將那樣」，寬度也算在內。 */
/* [claude code] 2026-08-14 v2.93 🔴 **通用倍率條 host**（合併原本的 .cash-multbar / .bm-multbar）。
   長相都在 `.ui-multbar`；這裡只管「貼在哪」：
   - `.pos-tight`：負 margin 壓進盤面 padding（花蜜採集 —— 盤面高、要省高度）
   - `.pos-row`  ：正 margin 空出**獨立一列**（爆裂礦坑 / 淨化光稜 —— 盤面矮、不缺高度）
   ⚠️ 麻將胡牌了的 `.mw-multbar` 不走這裡（絕對定位 append 在盤面內）。 */
.game-multbar { position: relative; z-index: 6; padding: 0 10px; }
.game-multbar.pos-tight { margin: 0 0 -7px; }
.game-multbar.pos-row { margin: 0 0 8px; }
/* 只彈 chips、不彈整條（v2.92 使用者：「不要整個綠框一起跳」）。
   ⚠️ `.ui-mchip.on` 平常就帶 scale(1.16) → 100% 要寫 1.16，寫 1 會在收尾瞬間縮一下。 */
.game-multbar.pop .ui-mchip { animation: bmChipPop .42s cubic-bezier(.2,1.5,.4,1); }
.game-multbar.pop .ui-mchip.on { animation: bmChipPopOn .42s cubic-bezier(.2,1.5,.4,1); }

/* [claude code] 2026-08-16 v3.13 語言切換選單（頂列 🌐）。
   🔴 用 absolute 掛在 .lang-wrap 底下：頂列本身是 flex，選單若參與排版會把整列撐開。 */
.lang-wrap { position: relative; display: inline-flex; }
.lang-menu {
  position: absolute; top: calc(100% + 6px); right: 0; z-index: 60;
  background: var(--panel, #171a2b); border: 1px solid rgba(255,255,255,.14);
  border-radius: 10px; padding: 4px; min-width: 128px;
  box-shadow: 0 8px 24px rgba(0,0,0,.5);
}
.lang-item {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 8px 10px; border: 0; border-radius: 7px; cursor: pointer;
  background: transparent; color: var(--text, #e8ecf8); font-size: 13.5px; text-align: left;
  white-space: nowrap;
}
.lang-item:hover { background: rgba(255,255,255,.08); }
.lang-item.on { background: rgba(255,255,255,.12); font-weight: 800; }
.lang-item .lg-short { font-size: 11px; opacity: .7; min-width: 20px; }

/* ===== [claude code] 2026-08-16 烈火燎原（blaze）=====
   🔴 火勢等級用**大小**做階梯，不用顏色 —— 人眼有內建次序的只有「數量 / 大小 / 明度 / 填滿程度」，
   色相（藍焰比紅焰熱）是要背的知識，不是常識。所以 bz-f1..bz-f5 只變大小與光暈強度，色相一路是火色。 */
.cell.bz-block { filter: grayscale(.75) brightness(.62); }         /* 燒不掉的東西：一眼看出它是死的 */
.cell.bz-block .glyph { opacity: .8; }
.cell.bz-entry { box-shadow: inset 0 0 0 2px var(--gold), 0 0 12px rgba(255,190,60,.55); border-radius: 8px;
  animation: bzEntry .5s ease-in-out infinite alternate; }
@keyframes bzEntry { from { box-shadow: inset 0 0 0 2px var(--gold), 0 0 6px rgba(255,190,60,.35); }
  to { box-shadow: inset 0 0 0 2px var(--gold), 0 0 18px rgba(255,190,60,.75); } }

/* 🔴 火種：**火先出現在最底那排的某一格**（使用者要「看得到火從哪來」），停一拍才開始往外燒。
   跟 bz-fire 共用同一顆 🔥，差別是**格子本身還沒被燒掉**（符號完好、只有火壓在上面 + 底下一圈餘燼光）。 */
.cell.bz-seed { position: relative; border-radius: 8px;
  background: radial-gradient(circle at 50% 80%, rgba(255,160,40,.34), transparent 70%); }
.cell.bz-seed::after { content: "🔥"; position: absolute; inset: 0; display: flex; align-items: center;
  justify-content: center; pointer-events: none;
  animation: bzSeedIn .34s cubic-bezier(.2,1.6,.4,1) both, bzFlame .9s ease-in-out .34s infinite alternate; }
@keyframes bzSeedIn { from { opacity: 0; transform: translateY(10px) scale(.4); }
  to { opacity: 1; transform: translateY(0) scale(1); } }

.cell.bz-fire { position: relative; border-radius: 8px;
  background: radial-gradient(circle at 50% 72%, rgba(255,140,30,.42), rgba(190,40,10,.14) 62%, transparent 78%); }
.cell.bz-fire .glyph { animation: bzBurn .42s ease-out both; }
@keyframes bzBurn { 0% { transform: scale(1); filter: none; }
  55% { transform: scale(1.18); filter: brightness(1.5) saturate(1.4); }
  100% { transform: scale(.86); opacity: .34; filter: brightness(.8) saturate(.7); } }
/* 火本體：疊在格子上的 🔥，大小 = 火勢等級 */
.cell.bz-fire::after { content: "🔥"; position: absolute; inset: 0; display: flex; align-items: center;
  justify-content: center; pointer-events: none; animation: bzFlame .9s ease-in-out infinite alternate; }
@keyframes bzFlame { from { transform: translateY(1px) scale(.94); } to { transform: translateY(-2px) scale(1.06); } }
.cell.bz-f1::after { font-size: .62em; filter: drop-shadow(0 0 3px rgba(255,150,40,.6)); }
.cell.bz-f2::after { font-size: .82em; filter: drop-shadow(0 0 5px rgba(255,150,40,.7)); }
.cell.bz-f3::after { font-size: 1.02em; filter: drop-shadow(0 0 8px rgba(255,140,30,.8)); }
.cell.bz-f4::after { font-size: 1.24em; filter: drop-shadow(0 0 12px rgba(255,120,20,.9)); }
.cell.bz-f5::after { font-size: 1.5em; filter: drop-shadow(0 0 18px rgba(255,90,10,1)); }
/* 那格值多少（第二拍才冒出來：先燒起來 → 才知道拿多少） */
.cell .bz-pay { position: absolute; left: 50%; bottom: 6%; transform: translateX(-50%);
  font-size: 11px; font-weight: 900; color: #fff; background: rgba(200,40,0,.85);
  border: 1px solid rgba(255,200,90,.9); border-radius: 999px; padding: 1px 6px; white-space: nowrap;
  z-index: 3; animation: bzPay .45s cubic-bezier(.2,1.5,.4,1) both; }
@keyframes bzPay { from { opacity: 0; transform: translate(-50%, 8px) scale(.7); }
  to { opacity: 1; transform: translate(-50%, 0) scale(1); } }
/* 🔥 火勢等級標在格子上（使用者：「只看到一堆火,但沒有看到火幾」）——
   大小看得出強弱、數字才算得出賠付（那格的價錢 × 火幾）。🔴 點著就不熄:標記留到整轉結束。 */
.cell .bz-lv { position: absolute; top: 2px; left: 3px; z-index: 3;
  font-size: 10px; font-weight: 900; line-height: 1; color: #ffe0a8;
  text-shadow: 0 1px 2px rgba(0,0,0,.9), 0 0 6px rgba(255,120,20,.9); pointer-events: none;
  animation: bzLv .3s ease-out both; }
@keyframes bzLv { from { opacity: 0; transform: scale(.5); } to { opacity: 1; transform: scale(1); } }

/* 🔴 直向長跑道：整個 run 是一根連續的直條，鏡頭跟著火往上搖（做法照潛水航道）。
   舊的「兩倍高、一層換一層」整段作廢 —— 那是換頁不是鏡頭，而且方向做反過（新的一層從下面頂上來）。 */
.bz-view { position: fixed; overflow: hidden; z-index: 30; border-radius: 12px; pointer-events: none;
  /* 🔴 一定要**不透明**(底色同 .board):它是疊在真盤面上的,沒底色的話下面那盤會透上來 → 雙重影像。
     🔴 z-index 要在 .win-overlay(40) **底下** —— 原本 55 會讓 BIG WIN 被火蓋住 / 疊在一起。 */
  background: #070a14; }
.bz-run { position: absolute; left: 0; top: 0; width: 100%; height: 100%; will-change: transform; }
.bzs-cell { position: absolute; display: flex; align-items: center; justify-content: center;
  border-radius: 8px; background: var(--surface-2); font-size: inherit;
  box-sizing: border-box; }   /* 底色與字級對齊真正的 .cell,疊上去看不出接手 */
.bzs-glyph { line-height: 1; }
.bzs-block { filter: grayscale(.75) brightness(.62); }
.bzs-seed { background: radial-gradient(circle at 50% 80%, rgba(255,160,40,.34), transparent 70%); }
.bzs-seed::after, .bzs-fire::after { content: "🔥"; position: absolute; inset: 0; display: flex;
  align-items: center; justify-content: center; animation: bzFlame .9s ease-in-out infinite alternate; }
.bzs-seed::after { animation: bzSeedIn .34s cubic-bezier(.2,1.6,.4,1) both, bzFlame .9s ease-in-out .34s infinite alternate; }
.bzs-fire { background: radial-gradient(circle at 50% 72%, rgba(255,140,30,.42), rgba(190,40,10,.14) 62%, transparent 78%); }
.bzs-fire .bzs-glyph { animation: bzBurn .42s ease-out both; }
.bzs-fire.bz-f1::after { font-size: .62em; filter: drop-shadow(0 0 3px rgba(255,150,40,.6)); }
.bzs-fire.bz-f2::after { font-size: .82em; filter: drop-shadow(0 0 5px rgba(255,150,40,.7)); }
.bzs-fire.bz-f3::after { font-size: 1.02em; filter: drop-shadow(0 0 8px rgba(255,140,30,.8)); }
.bzs-fire.bz-f4::after { font-size: 1.24em; filter: drop-shadow(0 0 12px rgba(255,120,20,.9)); }
.bzs-fire.bz-f5::after { font-size: 1.5em; filter: drop-shadow(0 0 18px rgba(255,90,10,1)); }
.bzs-cell .bz-lv { position: absolute; top: 2px; left: 3px; z-index: 3;
  font-size: 10px; font-weight: 900; line-height: 1; color: #ffe0a8;
  text-shadow: 0 1px 2px rgba(0,0,0,.9), 0 0 6px rgba(255,120,20,.9);
  animation: bzLv .3s ease-out both; }
/* 🔴 燒到錢的那一格要**看得出來不一樣**（使用者:「沒有燒到錢的快樂感」）—— 金框 + 金光一閃 */
.bzs-cash { box-shadow: inset 0 0 0 2px var(--gold, #ffcf4a), 0 0 16px rgba(255,200,80,.6); }
.bzs-cash::before { content: ""; position: absolute; inset: 0; border-radius: 8px;
  background: radial-gradient(circle, rgba(255,220,120,.85), transparent 65%);
  animation: bzCash .5s ease-out both; pointer-events: none; }
@keyframes bzCash { from { opacity: .95; transform: scale(.6); } to { opacity: 0; transform: scale(1.5); } }
.bzs-cell .bz-pay { position: absolute; left: 50%; bottom: 4%; transform: translateX(-50%);
  font-size: 11px; font-weight: 900; color: #fff; background: rgba(200,40,0,.88);
  border: 1px solid rgba(255,200,90,.9); border-radius: 999px; padding: 1px 6px; white-space: nowrap;
  z-index: 4; animation: bzPay .45s cubic-bezier(.2,1.5,.4,1) both; }

/* 錢飛向計分帶 */
.bz-fly { position: fixed; z-index: 35; pointer-events: none; font-weight: 900; font-size: 15px;
  color: var(--gold, #ffcf4a); text-shadow: 0 2px 6px rgba(0,0,0,.85);
  animation: bzFly var(--fly-ms, 620ms) cubic-bezier(.35,.7,.4,1) both; }
@keyframes bzFly {
  0% { transform: translate(-50%,-50%) scale(.7); opacity: 0; }
  18% { transform: translate(-50%,-50%) scale(1.15); opacity: 1; }
  100% { transform: translate(calc(-50% + var(--fly-x)), calc(-50% + var(--fly-y))) scale(.75); opacity: .15; }
}

/* 🔴 盤面下方的計分帶:左邊「這一格怎麼算的」、右邊「累計」。
   使用者:「我也看不到、也算不著,他到底燒到了多少錢」—— 版型 v2 把 #winBanner 藏起來,
   中獎當下訊息帶又切去顯示贏分,寫在那裡的算式從頭到尾沒露臉 → 這款要有自己的位置。
   ⚠️ 它在盤面**下面** → boardHeightBudget 要扣它(手機一屏可見鐵則)。 */
.bz-tally { display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin: 6px auto 0; padding: 6px 12px; max-width: 560px; min-height: 30px;
  border-radius: 10px; background: rgba(255,170,60,.12);
  border: 1px solid rgba(255,170,60,.3); font-size: 13px; }
.bzt-eq { color: #ffd9a6; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bzt-sum { color: var(--text, #eee); white-space: nowrap; }
.bzt-sum b { color: var(--gold, #ffcf4a); font-size: 16px; font-weight: 900; }
.bzt-sum.pop { animation: bzSumPop .32s cubic-bezier(.2,1.6,.4,1) both; }
@keyframes bzSumPop { 0% { transform: scale(1); } 45% { transform: scale(1.18); } 100% { transform: scale(1); } }

/* 細單（🔍 明細）用的盤面 */
.dt-slot.dt-blaze .dt-scell { font-size: 16px; }
.dt-scell.dt-bzcell { position: relative; }
.dt-scell.bzblock { opacity: .42; }
.dt-scell.bzburn { background: rgba(220,70,20,.24); border-color: rgba(255,150,60,.6);
  box-shadow: inset 0 0 0 1px rgba(255,150,60,.5); }
.dt-scell.bzgoods { background: rgba(240,110,20,.34); }
.dt-scell.bzentry { box-shadow: inset 0 0 0 2px var(--gold); }
.dt-scell .dt-bzlv { position: absolute; top: 1px; right: 2px; font-size: 9px; font-weight: 800;
  color: #ffd08a; line-height: 1; }
.dt-scell .dt-bzpay { font-size: 10px; font-weight: 800; color: var(--gold); line-height: 1; }

/* ═══ [claude code] 2026-09-01 v3.72 🔥 不熄之火（everfire）═══════════════════
   主題：燒起來的暖橙 + 炭黑。與 🔥 烈火燎原（wildfire / blaze）刻意分開 ——
   那款是山野蔓延（草綠→焦黑），這款是柴房裡越燒越旺的一團火。 */
body[data-theme="everfire"] { --neon: #ff7a1a; --neon-2: #ffb347; --gold: #ffd24a; }

/* 🔥 火（百搭）：盤面上要一眼認出來 —— 它是這款唯一「不會被燒掉」的東西。
   🔴 用光暈 + 微微呼吸，不要用邊框：邊框是「中獎」的視覺通道（.cell.win 用金框），
      兩種標記搶同一個通道時，後來的那個要換通道（v3.69 雙生鏡界那條教訓）。 */
body[data-theme="everfire"] .cell.sym-fire .glyph {
  filter: drop-shadow(0 0 6px rgba(255,122,26,.85)) drop-shadow(0 0 14px rgba(255,90,0,.45));
  animation: efBreathe 1.8s ease-in-out infinite;
}
@keyframes efBreathe { 0%,100% { transform: scale(1); } 50% { transform: scale(1.08); } }

/* 被燒掉的格：先燒紅一下再消失（消除動畫本身走通用的 .cs-clear） */
.cell.ef-burn { background: radial-gradient(circle at 50% 60%, rgba(255,96,0,.45), rgba(120,20,0,.15) 70%); }

/* [claude code] 2026-09-06 v3.74 一種可燃物演一段：**把沒中的壓暗**，中的維持原亮度自己跳出來。
   🔴 改對比的方向（不是把中獎的弄更亮）—— 同 `.mw-board.mw-hl`，那條走過兩次極端才收斂成這個作法：
      提亮會過曝、只加描邊看不見。⚠️ 跟「提示樣式不可動亮度」不衝突：那條講的是**未揭曉**的格，
      這裡結果已定、而且變暗的是**沒中的**，不會讓人誤判。 */
.board.cs-hl .cell:not(.cs-win):not(.ef-help):not(.cs-clear) {
  opacity: .3; filter: saturate(.5) brightness(.78); transition: opacity .18s ease, filter .18s ease; }
/* 中獎的那一種：金框（通用 .cell.cs-win 只有 .glyph 在脈動、沒有框）。
   🔴 只在 .cs-hl 內生效 → 不影響其他共用這支 CSS 的款。 */
.board.cs-hl .cell.cs-win {
  box-shadow: inset 0 0 0 2.5px rgba(255,225,120,.9), 0 0 16px rgba(255,200,60,.5); border-radius: 8px; }
/* 🔥 幫這一條連起來的火：橘框 + 微亮。**跟 .cs-win 的金框刻意不同色** ——
   它跟中獎的可燃物是兩種身分（一個等一下要被燒掉、一個不會），同色的話就白分了。 */
.cell.ef-help { z-index: 4; box-shadow: inset 0 0 0 2.5px rgba(255,138,43,.9), 0 0 14px rgba(255,110,0,.55);
  border-radius: 8px; }
.cell.ef-help .glyph { animation: efHelp .5s ease-in-out infinite alternate; }
/* 差一軸：連起來了但不夠長 —— 用**灰白虛線框**，刻意跟中獎的金框 / 火的橘框都不一樣
   （它不是中獎，只是「你差一點」）。搭配 banner 那句話一起出現。 */
.cell.ef-near { z-index: 3; box-shadow: inset 0 0 0 2px rgba(200,215,235,.55); border-radius: 8px;
  outline: 2px dashed rgba(200,215,235,.35); outline-offset: -6px; }
@keyframes efHelp { from { transform: scale(1.02); } to { transform: scale(1.12); filter: drop-shadow(0 0 8px rgba(255,140,40,.9)); } }

/* 火勢升級：倍率條整條閃一下（因果鏈的第三拍 —— 燒完了所以更旺） */
#gameMult.ef-levelup .ui-multbar { box-shadow: 0 0 0 2px rgba(255,122,26,.8), 0 0 18px rgba(255,122,26,.6); }
.ui-multbar.ef-multbar .ui-mchip.on { background: linear-gradient(180deg, #ff8a2b, #e0510a); color: #fff4e6; }

/* 賠付表：符號 + 名稱並排（🔴 名稱要跟圖擺在一起 —— 只有這樣才看得出「名字對不對得上圖」） */
.ef-pt-sym { font-size: 20px; margin-right: 6px; }
.ef-pt-name { font-size: 12px; opacity: .85; }

/* 🔍 明細的靜態盤面 */
.dt-board.dt-ef { display: flex; gap: 3px; align-items: center; justify-content: center; padding: 4px 0; }
.dt-ef-reel { display: flex; flex-direction: column; justify-content: center; gap: 3px; }
.dt-ef-cell {
  width: 30px; height: 30px; border-radius: 6px; display: flex; align-items: center; justify-content: center;
  font-size: 17px; background: rgba(255,255,255,.05); animation: none !important;
}
.dt-ef-cell.dt-ef-fire { background: rgba(255,122,26,.18); }
.dt-ef-cell.dt-ef-hit  { box-shadow: inset 0 0 0 2px var(--win, #ffe169); }   /* 參與中獎（金框，跟遊戲畫面同一個語意） */
.dt-ef-cell.dt-ef-burn { background: rgba(255,96,0,.35); opacity: .55; }      /* 這一格等一下被燒掉 */

/* [claude code] 2026-09-07 v3.77 刪除帳號 —— Play 的帳號刪除規定（App 內入口）。
   🔴 刻意做成「找得到但不搶眼」：它與「登出」並列，但用暗紅描邊、不填色。
      填成整顆紅按鈕會讓每次登入都看到一個警告色的東西，那是在提醒玩家離開。 */
.la-btn.la-del { border-color: rgba(255, 90, 95, .35); color: #ff8a8f; }
.la-btn.la-del:hover { border-color: rgba(255, 90, 95, .7); color: #ff5a5f; background: rgba(255, 90, 95, .08); }

#delAcctModal .da-title { margin: 4px 0 12px; font-size: 18px; color: #ff8a8f; }
#delAcctModal .da-warn,
#delAcctModal .da-keep { font-size: 13px; line-height: 1.7; border-radius: 10px; padding: 10px 12px; margin-bottom: 10px; }
#delAcctModal .da-warn { background: rgba(255, 90, 95, .10); border: 1px solid rgba(255, 90, 95, .3); color: #ffc9cb; }
#delAcctModal .da-keep { background: rgba(255, 255, 255, .05); border: 1px solid rgba(255, 255, 255, .1); color: #b9c0d4; }
#delAcctModal .auth-submit.da-submit { background: linear-gradient(135deg, #b3323a, #7d1f26); }
#delAcctModal .auth-submit.da-submit:disabled { opacity: .55; }

/* [claude code] 2026-09-07 v3.80 商店（Google Play 買遊戲幣）。
   🔴 `.coins-plus` 預設 `display:none`（HTML 那邊寫死）—— 只有「真的買得到」才由 JS 打開。
      用瀏覽器開的人看到一顆按了沒反應的鈕，比看不到更糟。 */
.coins-plus { margin-left: 6px; border: 1px solid rgba(255,207,74,.5); background: rgba(255,207,74,.12);
  color: #ffcf4a; border-radius: 999px; width: 20px; height: 20px; line-height: 1; font-size: 13px;
  cursor: pointer; padding: 0; }
.coins-plus:hover { background: rgba(255,207,74,.25); }

.shop-card { max-width: 420px; }
.shop-title { margin: 4px 0 12px; font-size: 18px; }
/* 「為什麼不能買」——平常隱藏，只有買不到時才填（見 billing.js 的五道關卡） */
.shop-why { background: rgba(255,180,60,.10); border: 1px solid rgba(255,180,60,.35); color: #ffd9a0;
  border-radius: 10px; padding: 10px 12px; font-size: 13px; line-height: 1.7; margin-bottom: 10px; }
.shop-why .shop-detail { margin-top: 6px; font-size: 11px; opacity: .65; word-break: break-all; }
.shop-list { display: flex; flex-direction: column; gap: 8px; }
.shop-loading { text-align: center; opacity: .6; padding: 18px 0; }
.shop-item { display: grid; grid-template-columns: 1fr auto auto; align-items: center; gap: 10px;
  background: rgba(255,255,255,.05); border: 1px solid rgba(255,255,255,.12); border-radius: 10px;
  padding: 11px 13px; color: inherit; cursor: pointer; font-size: 14px; text-align: left; }
.shop-item:hover:not(:disabled) { background: rgba(255,255,255,.09); border-color: rgba(255,207,74,.4); }
.shop-item:disabled { opacity: .45; cursor: default; }
.shop-item .si-name { font-weight: 600; }
.shop-item .si-coins { color: #ffcf4a; font-variant-numeric: tabular-nums; }
.shop-item .si-price { min-width: 74px; text-align: right; opacity: .85; font-variant-numeric: tabular-nums; }
.shop-bonus { margin-left: 6px; font-size: 11px; color: #7ee08a; border: 1px solid rgba(126,224,138,.4);
  border-radius: 999px; padding: 1px 6px; }
/* 幣不可兌現的揭露 —— 🔴 平台第一條紅線，購買畫面上一定要看得到 */
.shop-foot { margin-top: 12px; font-size: 11px; line-height: 1.6; opacity: .55; }


/* [claude code] 2026-09-07 v3.81 帳號設定選單（⚙）。
   🔴 登出 / 刪除帳號收進來的理由：那兩顆是「很少按、但按錯很痛」的操作 ——
      擺在頂列既佔空間，刪除帳號又剛好在登出旁邊。 */
.la-gear-wrap { position: relative; display: inline-flex; }
.la-btn.la-gear { font-size: 15px; line-height: 1; padding: 4px 8px; }
.la-menu { position: absolute; right: 0; top: calc(100% + 6px); z-index: 60;
  background: #171a2b; border: 1px solid rgba(255,255,255,.14); border-radius: 10px;
  box-shadow: 0 8px 24px rgba(0,0,0,.5); padding: 5px; min-width: 132px; display: flex; flex-direction: column; }
.la-menu .la-mi { background: none; border: 0; color: inherit; text-align: left; padding: 9px 12px;
  border-radius: 7px; cursor: pointer; font-size: 13px; white-space: nowrap; }
.la-menu .la-mi:hover { background: rgba(255,255,255,.08); }
/* 危險項目分開放、上面一條分隔線 —— 不要讓它跟「登出」長得一模一樣 */
.la-menu .la-mi-danger { color: #ff8a8f; border-top: 1px solid rgba(255,255,255,.1); margin-top: 3px; padding-top: 10px; }
.la-menu .la-mi-danger:hover { background: rgba(255,90,95,.12); }

/* 儲值紀錄的商品名（第二行小字） */
.rc-row .rc-sub { color: #9fb4d8; font-size: 12px; }

/* [claude code] 2026-09-08 🎚️ 機率模型：「連到了卻沒錢」的 ✕。
   🔴 沿用 `.ef-near` 的灰白虛線語言（同一件事：連起來了但不算數），
      但**多疊一個真的 ✕** —— everfire 那個是「差一軸」，這個是「這一檔完全不算數」，
      後者更需要一眼看懂。
   ⚠️ 刻意**不用紅色** —— 紅在本平台是「賺 / 漲」，拿來標『沒中』會讀反。 */
.cell.cs-near { z-index: 3; border-radius: 8px;
  box-shadow: inset 0 0 0 2px rgba(200,215,235,.45);
  outline: 2px dashed rgba(200,215,235,.30); outline-offset: -6px; }
.cell.cs-near .glyph { filter: grayscale(.7); opacity: .5; }
.cell.cs-near::after { content: "✕"; position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 1.5em; font-weight: 700; color: rgba(220,230,245,.72);
  text-shadow: 0 1px 3px rgba(0,0,0,.6); pointer-events: none; z-index: 5; }

/* 🎨 [claude code] 2026-09-21 v4.51 大廳卡片左下：**這一款換上了專屬符號圖**。
   位置擺**左下**，避開左上的 🚧/🌐 徽章與右上的進入鈕（三個都在的款不會打架）。
   這個位置 2026-09-08 ~ 2026-09-21 掛的是「有兩個機率模型」的 `.card-mode`（📐 / 💎），
   使用者 2026-09-21 決定拿掉、換成這個。 */
.game-card { position: relative; }
.card-art-tag { position: absolute; left: 8px; bottom: 8px; z-index: 3;
  font-size: 15px; line-height: 1; opacity: .92; pointer-events: auto;
  filter: drop-shadow(0 1px 3px rgba(0,0,0,.55)); }

/* [claude code] 2026-09-17 v4.16 🖼 符號圖（app.js SYM_ART_BEGIN 掛 .has-art + --sym-art）。
   🔴 文字不拿掉，只是變透明：讀 textContent 的既有程式（複製格子、飛行動畫）照常運作；
      text-shadow 一定要關 —— 透明字 + 陰影會畫出一個 emoji 形狀的影子（那正是「emoji 換色」的原理）。
   🔴 圖畫在 ::before，不畫在元素自己的 background：好幾款的 .glyph 自己就有底色 / 框 / 100% 寬高
      （tv-cell、gq-drill、dv-cell、ant-cell…），畫在 background 會被那些選擇器蓋掉或撐滿整格。
   🔴 ::after 是 WILD / SCATTER / 顧客 角標 → 把 text-fill-color 還給它，不然角標的字會跟著透明。
   🔴 盤面 .glyph 本來就是 flex + relative，不要改它的 display / position；其餘都是行內 span。
   圖的大小統一由 --sym-art-size 決定（相對字級，跟原本 emoji 一樣大），要整體放大縮小只改這一個。 */
:root { --sym-art-size: 1.3em; }
/* [Codex 2026-09-23] 爆裂礦坑專屬美術。僅作用於遊戲 view，不影響大廳或其他款。 */
body[data-theme="boommine"] #view-game {
  background: #17120f url("../assets/games/boom_mine/background.webp?h=54c69ac225") center top / cover no-repeat;
  border-radius: 16px;
  --neon: #f4b253; --neon-2: #6fd9e6; --gold: #ffd27a;
}
body[data-theme="boommine"] .game-head {
  background: linear-gradient(90deg, transparent, rgba(20,12,7,.82) 20%, rgba(20,12,7,.82) 80%, transparent);
  color: #ffe5b2; text-shadow: 0 2px 4px #000;
}
body[data-theme="boommine"] .machine {
  background: rgba(18,13,10,.78); border-color: #ac7742;
  box-shadow: inset 0 0 0 2px #3b271a, 0 4px 18px #0009;
}
body[data-theme="boommine"] .board-wrap {
  border: 2px solid #bb884e; border-radius: 12px;
  background: rgba(12,17,21,.92);
  box-shadow: 0 0 0 3px #39291d, inset 0 0 22px #0009;
}
body[data-theme="boommine"] .reel { background: linear-gradient(90deg, #10191de8, #243036bb, #10191de8); }
body[data-theme="boommine"] #board .glyph.has-art { --sym-art-size: 1.65em; }
/* [Codex 2026-09-23] 礦石價值分層：H1 > H2 > H3 > H4 > L1 > L2 > L3 > L4。
   僅處理美術層，不把低賠誤畫成不會中獎；中獎時恢復光澤。 */
body[data-theme="boommine"] #board .cell:is(.sym-H1,.sym-H2,.sym-H3,.sym-H4) {
  background: radial-gradient(ellipse at center, #79603b55, #25232b 75%);
}
body[data-theme="boommine"] #board .cell:is(.sym-H1,.sym-H2,.sym-H3,.sym-H4):not(.win):not(.cs-win):not(.bm-blast) {
  box-shadow: inset 0 0 0 1px #cfa45e66;
}
body[data-theme="boommine"] #board .sym-H1 .glyph.has-art::before {
  filter: brightness(1.12) drop-shadow(0 0 5px #80eaff88);
}
body[data-theme="boommine"] #board .cell:is(.sym-L1,.sym-L2,.sym-L3) .glyph.has-art {
  --sym-art-size: 1.28em;
}
body[data-theme="boommine"] #board .cell:is(.sym-L1,.sym-L2,.sym-L3) .glyph.has-art::before {
  filter: saturate(.55) brightness(.75);
}
body[data-theme="boommine"] #board .sym-L4 .glyph.has-art { --sym-art-size: 1.16em; }
body[data-theme="boommine"] #board .sym-L4 .glyph.has-art::before {
  filter: saturate(.22) brightness(.62);
}
body[data-theme="boommine"] #board .cell:is(.win,.cs-win) .glyph.has-art::before {
  filter: brightness(1.15) drop-shadow(0 0 5px #ffe29299);
}

body[data-theme="boommine"] .ui-belt {
  background: linear-gradient(#34271c, #19140f); border-color: #bb884e; color: #ffe5b2;
}
body[data-theme="boommine"] .ui-money,
body[data-theme="boommine"] .ui-pad { background: rgba(17,12,9,.85); border-radius: 12px; }
body[data-theme="boommine"] .bm-cart-ov {
  background: linear-gradient(#100e0bcf, #221207eb), url("../assets/games/boom_mine/background.webp?h=54c69ac225") center bottom / cover;
  border: 1px solid #f0bb6d;
}
.bm-cart.bm-cart-art { top: -12px; width: 64px; height: 56px; font-size: 0; }
.bm-cart-img { width: 100%; height: 100%; object-fit: contain; filter: drop-shadow(0 3px 3px #0008); }
/* [Codex 2026-09-23] 招財海盜寶藏：海上船艙、紅木金框與真實碎片拼圖。 */
body[data-theme="pirate"] #view-game {
  background: #072b35 url("../assets/games/pirate_treasure/background.webp?h=3329861188") center top / cover no-repeat;
  border-radius: 16px;
}
body[data-theme="pirate"] .game-head {
  background: linear-gradient(90deg, transparent, #061b23cf 20%, #061b23cf 80%, transparent);
  color: #ffe6ac; text-shadow: 0 2px 4px #000;
}
body[data-theme="pirate"] .machine {
  background: #091d22df; border-color: #b98c49;
  box-shadow: inset 0 0 0 2px #4d3020, 0 4px 18px #0009;
}
body[data-theme="pirate"] .board-wrap {
  border: 2px solid #c99b52; border-radius: 12px; background: #09242b;
  box-shadow: 0 0 0 3px #422b1e, inset 0 0 24px #0008;
}
body[data-theme="pirate"] .reel { background: linear-gradient(90deg, #08242a, #123940, #08242a); }
body[data-theme="pirate"] #board .glyph.has-art { --sym-art-size: 1.65em; }
body[data-theme="pirate"] .cell.sym-EMPTY .glyph { opacity: .16; }
body[data-theme="pirate"] .cell.chest-open .glyph.has-art::before {
  background-image: var(--pirate-open_chest, var(--sym-art));
}
body[data-theme="pirate"] .cell.chest-open:has(.chest-piece) .glyph.has-art::before {
  background-image: var(--pirate-map_piece, var(--sym-art));
}
body[data-theme="pirate"] .ui-belt {
  background: linear-gradient(#103b40, #071b21); border-color: #be995c; color: #ffe4b1;
}
body[data-theme="pirate"] .ui-money,
body[data-theme="pirate"] .ui-pad { background: #071c24dc; border-radius: 12px; }
body[data-theme="pirate"] .treasure-map { padding: 5px 0; }
body[data-theme="pirate"] .treasure-map .tm-row {
  display: grid; grid-template-columns: repeat(4, 1fr); width: min(calc(56 * var(--vw)), 208px); gap: 2px;
  border: 2px solid #a67b40; border-radius: 7px; padding: 3px; background: #1c201acc;
}
body[data-theme="pirate"] .treasure-map .tm-slot {
  width: auto; height: auto; aspect-ratio: 1; border: 0; border-radius: 2px; overflow: hidden;
  background: #152b2a; box-shadow: inset 0 0 0 1px #a9946233;
}
body[data-theme="pirate"] .treasure-map .tm-slot::before {
  content: ""; position: absolute; inset: 0;
  background: url("../assets/games/pirate_treasure/map.webp?h=4ee90118a4") var(--map-x) var(--map-y) / 400% 200% no-repeat;
  opacity: .12; filter: grayscale(1);
}
body[data-theme="pirate"] .treasure-map .tm-slot.got::before { opacity: 1; filter: none; }
body[data-theme="pirate"] .treasure-map .tm-num {
  position: absolute; right: 2px; bottom: 2px; z-index: 1; color: #b5c6be; font-size: 10px;
  border-radius: 3px; padding: 0 3px; background: #071b23bd; text-shadow: 0 1px 2px #000;
}
body[data-theme="pirate"] .treasure-map .tm-slot.got .tm-num { color: #fff0bd; }
body[data-theme="pirate"] .treasure-bonus-ov {
  background: linear-gradient(#071c2366, #061318cc), url("../assets/games/pirate_treasure/background.webp?h=3329861188") center / cover;
}
body[data-theme="pirate"] .treasure-bonus-ov .tb-card {
  background: linear-gradient(145deg, #153b3fed, #081d24f5); border: 2px solid #ca9f57;
  box-shadow: 0 0 0 4px #513522, 0 12px 48px #000b;
}
.pirate-icon { position: relative; display: inline-block; width: 1.5em; height: 1.5em; vertical-align: middle; }
.pirate-icon-art { color: transparent; text-shadow: none; }
.pirate-icon-art::before {
  content: ""; position: absolute; inset: 0; background: var(--pirate-icon) center / contain no-repeat;
}
.treasure-bonus-ov .tb-box .pirate-icon { width: 48px; height: 48px; }
.has-art { color: transparent !important; -webkit-text-fill-color: transparent !important; text-shadow: none !important; }
.has-art::before {
  content: ""; position: absolute; left: 50%; top: 50%; z-index: 1; pointer-events: none;
  width: var(--sym-art-size); height: var(--sym-art-size); transform: translate(-50%, -50%);
  background: var(--sym-art) center / contain no-repeat;
  /* [claude code] 2026-09-24 v4.96 🔴 最大只佔格子的 90%(--sym-art-max 由各盤面依格子大小寫入;沒寫 = 不夾)。
     只動 ::before 的寬高 —— 中獎放大 / 掉落都是動 .glyph 的 transform,兩者不打架。 */
  width: min(var(--sym-art-size), var(--sym-art-max, 9999px)); height: min(var(--sym-art-size), var(--sym-art-max, 9999px));
}
.has-art::after { -webkit-text-fill-color: currentColor; }
.has-art:not(.glyph) { position: relative; display: inline-block; vertical-align: middle;
  min-width: var(--sym-art-size); min-height: var(--sym-art-size); white-space: nowrap; }
.sym-g { display: inline-block; }

/* [claude code] 2026-09-17 v4.17 🀄 麻將胡牌了的牌面圖（app.js mwTileFace / mwApplyTile）。
   牌面圖跟牌同比例（189×224）→ 鋪滿整張牌；百搭 / 奪寶是自己的形狀，用 contain 置中。
   🔴 金牌底只給「金牌」用（使用者 2026-09-17 決定）：一般牌維持原本的象牙色 CSS 牌底，
      金牌換成 tile_gold 圖 —— 圖自己就有牌的立體邊，所以拿掉原本的內框線，只留外光暈。 */
.mw-art { display: block; flex: 0 0 auto; width: 100%; height: 100%; pointer-events: none;
  background-position: center; background-size: contain; background-repeat: no-repeat; }
.mw-scat .mw-art { animation: mwScat 1.3s ease-in-out infinite alternate; }
.mw-pt-tile .mw-art, .mw-pp-face .mw-art, .dt-mw-cell .mw-art { animation: none; }
.mw-cell.mw-gold.mw-gold-art { background: var(--mw-tile-gold) center / 100% 100% no-repeat;
  box-shadow: 0 0 14px rgba(255,203,58,.7); }

/* [claude code] 2026-09-17 v4.20 🎱 開出來但卡上沒有的球淡掉（不算數）—— 跟命中的分得出來 */
.bd-chip.miss { opacity: .38; box-shadow: none; }

/* [claude code] 2026-09-17 v4.21 開球 / 手牌列固定高度：先鋪好的空位（開一顆 / 發一張就被換掉） */
.bd-chip.slot { background: transparent; color: transparent; box-shadow: inset 0 0 0 1px rgba(255,255,255,.08); }
.mj-record .mj-chip.mj-chip-slot { background: rgba(255,255,255,.04); box-shadow: inset 0 0 0 1px rgba(255,255,255,.1); }

/* [claude code] 2026-09-17 v4.22 🐉 闖關奪寶「龍珠探寶」:龍珠落進金罐(圖取自 amonovo_game 連環奪寶)。
   舞台用百分比排(釘子 / 罐子 / 龍珠的座標由 app.js 的 playGQPots 算),寬度跟著畫面、高寬比固定。 */
.gq-pots-ov { position: fixed; inset: 0; z-index: 70; display: flex; align-items: center; justify-content: center;
  background: #120a14 center / cover no-repeat; animation: gqOvIn .28s ease; }
.gq-pots-ov::before { content: ""; position: absolute; inset: 0; background: rgba(10,4,14,.35); }
.gp-box { position: relative; width: min(calc(94 * var(--vw)), 460px); max-height: 96vh; overflow-y: auto; text-align: center; padding: 0 10px 16px; }
.gp-header { display: block; width: 100%; height: auto; }
.gp-title { display: block; width: 72%; height: auto; margin: 4px auto 0; filter: drop-shadow(0 4px 10px rgba(0,0,0,.6)); }
.gp-sub { margin-top: 4px; font-size: 12.5px; font-weight: 700; color: #ffe7b0; text-shadow: 0 1px 3px rgba(0,0,0,.8); }
.gp-stage { position: relative; width: 100%; aspect-ratio: 1 / 1; margin-top: 6px; }
.gp-peg { position: absolute; width: 12%; height: auto; transform: translate(-50%, -50%);
  filter: drop-shadow(0 2px 4px rgba(0,0,0,.55)); font-size: 26px; line-height: 1; }
.gp-pot { position: absolute; width: 18%; transform: translate(-50%, -50%); display: flex; flex-direction: column; align-items: center; transition: opacity .3s; }
.gp-pot-img { position: relative; z-index: 1; width: 100%; height: auto; }
.gp-pot-amt { position: relative; z-index: 1; margin-top: -2px; font-size: 12.5px; font-weight: 900; color: #ffd76a;
  text-shadow: 0 1px 0 #40200a, 0 0 6px rgba(0,0,0,.9); white-space: nowrap; }
.gp-pot.dim { opacity: .45; }
.gp-pot.win { animation: gpPotWin .56s ease; }
.gp-pot.win .gp-pot-amt { color: #fff3b0; font-size: 15px; }
.gp-star { position: absolute; z-index: 0; left: 50%; top: 30%; width: 220%; height: auto; transform: translate(-50%, -50%);
  pointer-events: none; animation: gpStar 1.6s ease-in-out infinite alternate; }
@keyframes gpPotWin { 0%, 100% { transform: translate(-50%, -50%) scale(1); } 50% { transform: translate(-50%, -50%) scale(1.22); } }
@keyframes gpStar { from { opacity: .55; transform: translate(-50%, -50%) scale(.9) rotate(0); } to { opacity: 1; transform: translate(-50%, -50%) scale(1.08) rotate(20deg); } }
.gp-ball { position: absolute; z-index: 3; width: 11%; height: auto; transform: translate(-50%, -50%);
  filter: drop-shadow(0 3px 6px rgba(0,0,0,.7)); }
.gq-pots-ov .gq-ov-result { color: #fff; text-shadow: 0 2px 6px rgba(0,0,0,.9); }
@media (prefers-reduced-motion: reduce) { .gp-star, .gp-pot.win { animation: none; } }

/* ══ 🗿 瑪雅黃金（topway）══════════════════════════════════════════════
   [claude code] 2026-09-20 建立。6 軸 ways + 連鎖 + 🔝 附加輪 + 大符號 + 金框計數百搭。

   🔴 版面的關鍵在 JS 那邊的 `twBlockH(h) = cellH*h + gap*(h-1)`：
      一軸的內容高度 = Σ blockH + gap*(塊數-1) 恆等於 cellH*格數 + gap*(格數-1)
      → 不管這一軸是 6 塊小的還是 3 塊大的，**高度都一樣**，盤面不會忽高忽低。
      所以這裡的 `.tw-reel` 只要 `justify-content: flex-end`（底部對齊）就夠了 ——
      外側兩軸只有 5 格，空出來的那一格自然留在上面，正好給附加輪那一排。 */
/* 🔴 `padding-top: 24px` 是**讓給上緣路數標**的（JS 的 TW_LAB 要跟這個數一致）。
   box-sizing: border-box ⇒ JS 設的 height 是「內容 + padding」，內容高才等於 railH。 */
.board.tw-board { display: flex !important; position: relative; gap: 5px; box-sizing: border-box;
  padding: 24px 6px 6px; align-items: flex-end; justify-content: center; overflow: visible;
  background:
    radial-gradient(ellipse at 50% -12%, rgba(242,193,78,.20), transparent 60%),
    radial-gradient(ellipse at 50% 112%, rgba(63,163,122,.14), transparent 58%),
    linear-gradient(168deg, #23201a 0%, #191712 58%, #12100d 100%);
  box-shadow: inset 0 0 0 1px rgba(242,193,78,.16), inset 0 0 42px rgba(0,0,0,.55); }

/* 🔴 底部對齊：主盤面（5 格）一定切齊下緣，附加輪長在上面。
   置中對齊的話，外側兩軸會往上浮半格，主盤面就對不齊了。 */
.tw-reel { display: flex; flex-direction: column; justify-content: flex-end; position: relative; }

.tw-cell { position: relative; display: flex; align-items: center; justify-content: center;
  border-radius: 8px; box-sizing: border-box;
  background: linear-gradient(180deg, rgba(232,223,200,.13), rgba(140,130,114,.10));
  box-shadow: inset 0 0 0 1px rgba(232,223,200,.16); }
.tw-cell > .glyph { line-height: 1; }

/* 📐 大符號：石板邊更厚、底色更暖 —— 一眼看得出「這是一塊，不是三格剛好一樣」 */
.tw-cell.tw-big { background: linear-gradient(180deg, rgba(242,193,78,.16), rgba(184,122,30,.12));
  box-shadow: inset 0 0 0 2px rgba(242,193,78,.34), 0 2px 10px rgba(0,0,0,.35); }

/* 🟨 金框：沒有美術圖時用 CSS 畫一圈金（有圖就走下面的 .tw-gold-art） */
.tw-cell.tw-gold { box-shadow: inset 0 0 0 3px rgba(242,193,78,.92), inset 0 0 14px rgba(242,193,78,.30), 0 0 12px rgba(242,193,78,.25); }
/* 🔴 有美術圖時**把 CSS 那一圈關掉** —— 兩層一起畫會變成「框裡面還有一圈框」。
   框是鏤空 PNG，用 ::after 疊在符號上面（符號本身還看得見，那正是金框的意思）。 */
.tw-cell.tw-gold.tw-gold-art { box-shadow: none; }
.tw-cell.tw-gold-art::after { content: ""; position: absolute; inset: -2px; z-index: 2; pointer-events: none;
  background-image: var(--tw-frame); background-size: 100% 100%; background-repeat: no-repeat; }

/* 💠 百搭：全盤最亮的一塊 */
.tw-cell.tw-wild { background: linear-gradient(180deg, rgba(242,193,78,.34), rgba(184,122,30,.22));
  box-shadow: inset 0 0 0 2px rgba(255,226,150,.9), 0 0 16px rgba(242,193,78,.45); }
/* 🔴 百搭的數字 = 它還能再幫你連幾次。沒有這個數字，玩家只看得到「一顆百搭」，
   完全讀不出「它會撐 4 次」——那正是這一款的招牌。 */
.tw-cell .tw-n { position: absolute; right: 3px; bottom: 2px; z-index: 3;
  min-width: 1.15em; padding: 0 .18em; border-radius: 6px;
  font-size: .72em; font-weight: 800; line-height: 1.25; text-align: center;
  /* 🔴 **深底金字，不是金底深字** —— 這個角標一定會疊在 💠 百搭上，而百搭本身是全盤最金的一塊。
     金疊金的話邊界會糊掉，而「還能撐幾次」正是這一款最需要讀得到的數字。 */
  color: #ffe08a; background: linear-gradient(180deg, #2a1c05, #15100a);
  box-shadow: 0 0 0 1px rgba(255,226,150,.75), 0 1px 3px rgba(0,0,0,.6); }

/* 🔝 附加輪：跟主盤面之間留一道縫（margin-bottom 由 JS 設成 TW_SEP），
   再用一條細線把「這是獨立的一排」講清楚。 */
.tw-cell.tw-top { box-shadow: inset 0 0 0 1px rgba(63,163,122,.40), 0 2px 0 rgba(242,193,78,.18); }
.tw-cell.tw-top::after { content: ""; position: absolute; left: -2px; right: -2px; bottom: -5px; height: 2px;
  border-radius: 2px; background: linear-gradient(90deg, transparent, rgba(242,193,78,.45), transparent); }

/* 中獎時整盤壓暗，只留亮起來的那幾塊（與 cs-win / cs-clear 那一組共用） */
.board.tw-board.tw-hl .tw-cell { filter: brightness(.55) saturate(.8); transition: filter .18s linear; }
.board.tw-board.tw-hl .tw-cell.cs-win,
.board.tw-board.tw-hl .tw-cell.tw-turn { filter: none; }
/* 🟨 金框中獎：不爆，改成「框在抖、準備脫落」 */
.tw-cell.tw-turn { animation: twTurn .5s ease-in-out infinite;
  box-shadow: inset 0 0 0 3px rgba(255,226,150,1), 0 0 18px rgba(242,193,78,.6); }
@keyframes twTurn { 0%,100% { transform: translateY(0) } 50% { transform: translateY(-3px) } }

/* 🔝 附加輪橫移（倖存者往左靠 / 新的從右端進來）—— transform 由 JS 設，這裡只負責不被裁掉 */
.tw-cell.tw-slide { will-change: transform, opacity; z-index: 2; }

/* ── 🎰 轉軸落盤 ──────────────────────────────────────────────
   🔝 **最上面那一列（附加輪）由右往左轉**、其餘六軸的主盤面**由上往下轉**；
   🔴 **第 1 軸停住的同時附加輪也停住**（使用者 2026-09-20 指定），其餘軸繼續由左往右停。
   ⚠️ 轉的時候才裁切（`.spinning`）—— 常態不裁，不然金框 / 百搭的外發光會被切掉
      （mjway v2.76 踩過：一停下來 overflow 恢復，那圈光整個跑出來，看起來像盤面往左右撐開）。 */
/* ── 🪨 near win（期待停軸）──
   已經落了「差一個就開免費」的石碑數 → 下一軸慢停 + 打光 + 壓暗其他軸。
   🔴 class 名字刻意跟傳統轉輪那一套（`.reel.anticipate` / `.board-wrap.anticipating`）分開：
      那一套是掛在 `.reel` 上的，而這一款轉的時候 `.tw-reel` 裡是 strip 不是格子。 */
.tw-reel.tw-antic { animation: anticPulse .5s ease-in-out infinite; z-index: 3; border-radius: 8px; }
.board.tw-board.tw-anticing .tw-reel:not(.tw-antic) { filter: brightness(.5); transition: filter .25s; }
.board.tw-board.tw-anticing .tw-topband { filter: brightness(.5); transition: filter .25s; }
.tw-reel.spinning { justify-content: flex-end; }
.tw-mainbox { position: relative; overflow: hidden; width: 100%; }
.tw-strip { position: absolute; left: 0; right: 0; top: 0; display: flex; flex-direction: column;
  will-change: transform; }
.tw-topband { position: absolute; z-index: 3; overflow: hidden; border-radius: 8px; }
.tw-topstrip { position: absolute; left: 0; top: 0; display: flex; flex-direction: row;
  will-change: transform; }
/* 🔴 `--tw-loop` 是「一個週期的位移」，由 JS 依實際格距算好灌進來 ——
   寫死 px 的話換螢幕尺寸就接不起來（接縫會跳）。 */
@keyframes twLoopY { from { transform: translateY(0) } to { transform: translateY(var(--tw-loop, -400px)) } }
@keyframes twLoopX { from { transform: translateX(0) } to { transform: translateX(var(--tw-loop, -400px)) } }

/* 路數標 —— 🔴 擺在盤面**上緣**。
   放下緣的話它會擠在盤面邊框與訊息帶之間（2026-09-20 使用者截圖回報：字疊到邊框上）。
   上緣是空的（外側兩軸只有 5 格、附加輪那一排才 6 格），本來就有位置。 */
.tw-wayslab { position: absolute; left: 0; right: 0; top: 4px; z-index: 4;
  display: flex; align-items: baseline; justify-content: center; gap: 6px;
  line-height: 1; pointer-events: none; }
.tw-wayslab .tw-w-now { font-size: 14px; font-weight: 800; letter-spacing: .03em;
  color: #ffe08a; text-shadow: 0 1px 3px rgba(0,0,0,.8); }
/* 落盤中每停一軸就換一次數字 → 換的時候彈一下，玩家才注意到「它在長」 */
.tw-wayslab .tw-w-now { animation: twWaysPop .26s ease-out; }
@keyframes twWaysPop { 0% { transform: scale(.82); opacity: .35 } 100% { transform: scale(1); opacity: 1 } }
/* 倍率條只有免費局才出現（主遊戲的 ladder 是 [1]）。
   🔴 [claude code] 2026-09-21 v4.51 從「盤面上方 −34px」改成**盤面自己的上緣、靠右**。
   病根：`top: -34px` 是照麻將的 `.mw-multbar` 抄的，但麻將那條**配了**
   `.board.mw-board { margin-top: 12px }` 把整塊盤面往下讓（v2.73 的註解寫得很清楚），
   這裡**只抄了一半** —— 盤面沒有讓開，而抬頭與盤面之間本來只有 12px（小螢幕 6px），
   27px 的條往上戳 34px ⇒ 直接壓到 ← 與 ⓘ（2026-09-21 使用者截圖回報）。
   🔴 **沒有選「把盤面往下推」那條路** —— 那要永久讓出 26~32px、每格小 4~5px，
      而這條只有免費局才出現。memory「不要為了塞進一屏而縮主體」：該夾的是 HUD 不是盤面。
   ⇒ 塞進盤面自己的上緣留白（`padding-top: 24px` = JS 的 `TW_LAB`，路數標就住在那裡）：
     路數維持置中、倍率條靠右，兩個都看得到，而且**零額外高度、免費局進出不會跳版**。
   ⚠️ 高度收成 24px 對齊那條留白；`.ui-mchip.on` 的 `scale(1.16)` 會稍微凸出一點點，
     那是所有倍率條共同的長相，不要為了這裡去動它。 */
.tw-multbar { position: absolute; top: 0; right: 8px; left: auto; z-index: 5;
  height: 24px; padding: 0 3px; }

/* ── 🔍 細單裡的小盤面 ── */
.dt-tw-board { display: flex; gap: 3px; justify-content: center; align-items: flex-end;
  margin: 6px 0; padding: 6px; border-radius: 8px; background: rgba(255,255,255,.04); }
.dt-tw-reel { display: flex; flex-direction: column; gap: 3px; justify-content: flex-end; }
.dt-tw-cell { position: relative; width: 26px; display: flex; align-items: center; justify-content: center;
  height: calc(var(--tw-h, 1) * 22px + (var(--tw-h, 1) - 1) * 3px);
  border-radius: 5px; font-size: 14px; line-height: 1;
  background: rgba(255,255,255,.06); box-shadow: inset 0 0 0 1px rgba(255,255,255,.10); }
.dt-tw-cell.dt-tw-gold { box-shadow: inset 0 0 0 2px rgba(242,193,78,.9); }
.dt-tw-cell.dt-tw-hit { background: rgba(242,193,78,.28); box-shadow: inset 0 0 0 2px rgba(242,193,78,.75); }
.dt-tw-cell.dt-tw-framed { background: rgba(242,193,78,.42); }
.dt-tw-cell.dt-tw-tick { background: rgba(63,163,122,.30); }
.dt-tw-cell .dt-tw-n { position: absolute; right: 1px; bottom: 0; font-size: 9px; font-weight: 800;
  color: #2a1c05; background: #f2c14e; border-radius: 4px; padding: 0 2px; line-height: 1.3; }

/* [Codex 2026-09-23] 麻將胡牌了：依目前賠付牌種分層，金色底仍專屬金牌。 */
.mw-cell:is([data-mw-symbol="5"],[data-mw-symbol="4"],[data-mw-symbol="6"]):not(.mw-gold) .mw-art {
  filter: contrast(1.12) brightness(1.04) drop-shadow(0 1px 2px #183e4566);
}
.mw-cell:is([data-mw-symbol="14"],[data-mw-symbol="27"],[data-mw-symbol="20"]):not(.mw-gold) .mw-art {
  filter: saturate(.7) brightness(.9);
}
.mw-cell:is([data-mw-symbol="29"],[data-mw-symbol="26"],[data-mw-symbol="17"]) .mw-art {
  filter: saturate(.12) brightness(.68); opacity: .65;
}
.mw-cell.cs-win .mw-art { filter: brightness(1.12); opacity: 1; }
/* 幸運賓果號碼無高低價：光澤代表命中、連線及金球，不代表號碼大小。 */
body[data-theme="bingo"] .bingo-cell:not(.marked):not(.free) {
  color: #9299aa; background: #111727;
}
body[data-theme="bingo"] .bingo-cell.marked:not(.gold):not(.in-line):not(.free) {
  background: #264865; color: #e5f2ff; box-shadow: inset 0 0 0 1px #759cb0;
}
body[data-theme="bingo"] .bingo-cell.in-line:not(.gold) {
  background: linear-gradient(145deg, #35685c, #173c36); color: #fff8d5;
}
body[data-theme="bingo"] .bingo-cell.gold {
  background: radial-gradient(circle at 35% 25%, #fff0a1, #e2ad3d 62%, #9f681c);
  color: #34220a; font-weight: 900;
}
body[data-theme="bingo"] .bingo-cell.gold::after {
  content: "✦"; color: #684009; font-size: .55em;
}
body[data-theme="bingo"] .bingo-cell.free:not(.in-line) {
  background: #283544; color: #d5dfe8; box-shadow: inset 0 0 0 1px #728393;
}
body[data-theme="bingo"] .bingo-cell.free:not(.in-line) .bc-free { text-shadow: none; }
body[data-theme="bingo"] .bd-chip.hit:not(.gold) { box-shadow: inset 0 0 0 1px #759cb0; }
body[data-theme="bingo"] .bd-chip.gold.hit {
  background: linear-gradient(145deg, #ffe89a, #c88b2a); color: #352409;
}

/* [Codex 2026-09-23] v4.66 麻將翡翠牌桌 / 賓果深藍舞台。 */
body[data-theme="mahjong-gold"] #view-game {
  background: #082b23 url("../assets/games/mahjong_gold/background.webp?h=d7e0c5b824") center / cover no-repeat;
  border-radius: 16px; --neon: #70d8b0; --neon-2: #e0bd75; --gold: #f1ce80;
}
body[data-theme="mahjong-gold"] .game-head {
  color: #fff0c7; text-shadow: 0 2px 4px #061d15;
  background: linear-gradient(90deg, transparent, #082d25e0 20%, #082d25e0 80%, transparent);
}
body[data-theme="mahjong-gold"] .machine {
  background: #08261edb; border-color: #b58a4c;
  box-shadow: inset 0 0 0 2px #533c24, 0 8px 24px #0006;
}
body[data-theme="mahjong-gold"] .board-wrap {
  background: #07281fdb; border: 1px solid #b79962; border-radius: 12px;
  box-shadow: 0 0 0 3px #392a1d, inset 0 0 24px #001b15;
}
body[data-theme="mahjong-gold"] .board.mw-board {
  background: radial-gradient(ellipse at center, #23634c9c, #0a3027);
  box-shadow: inset 0 0 22px #041b1499;
}
body[data-theme="mahjong-gold"] .mw-deco-c { opacity: .17; }
body[data-theme="mahjong-gold"] .ui-belt {
  background: linear-gradient(120deg, #0a332ade, #10261fe8); border-color: #aa8c52;
}
body[data-theme="mahjong-gold"] :is(.ui-money,.ui-pad) {
  background: #092b24e8; border-radius: 12px;
}
body[data-theme="mahjong-gold"] .pad-spin:not(.auto) {
  background: linear-gradient(145deg, #b2edce, #58b994 52%, #2d8068); color: #062e25;
  box-shadow: inset 0 0 0 2px #f0d999, inset 0 3px 8px #ffffff66, 0 6px 20px #001b18aa;
}
body[data-theme="mahjong-gold"] .mw-paypop { background: linear-gradient(145deg, #19513e, #092e26); }
body[data-theme="bingo"] #view-game {
  background: #06172b url("../assets/games/lucky_bingo/background.webp?h=7436520ccf") center / cover no-repeat;
  border-radius: 16px; --neon: #74bedf; --neon-2: #81dbd5; --gold: #f7cf79;
}
body[data-theme="bingo"] .game-head {
  color: #e5f6ff; text-shadow: 0 2px 5px #001127;
  background: linear-gradient(90deg, transparent, #092542e8 20%, #092542e8 80%, transparent);
}
body[data-theme="bingo"] .machine {
  background: #081a30dc; border-color: #7799ad;
  box-shadow: inset 0 0 0 2px #172c44, 0 8px 24px #0007;
}
body[data-theme="bingo"] .board-wrap { background: #08192fe8; border-radius: 14px; }
body[data-theme="bingo"] .board.bingo-board {
  background: linear-gradient(145deg, #224361, #0b1e35);
  box-shadow: inset 0 0 0 1px #8eb7c5, inset 0 0 0 4px #263c51, 0 4px 14px #0007;
}
body[data-theme="bingo"] .bingo-cell { border-radius: 9px; }
body[data-theme="bingo"] .bingo-tray {
  background: linear-gradient(150deg, #19344ae8, #071b30f5);
  box-shadow: inset 0 0 0 1px #64869f88, 0 3px 8px #0005;
}
body[data-theme="bingo"] .bt-current {
  background: radial-gradient(circle at 30% 22%, #fff, #d8e9ed 32%, #789bab 74%, #38566b);
  color: #15354b; box-shadow: inset -2px -3px 5px #153e5966, 0 4px 10px #0007;
  border: 1px solid #adc4ce;
}
body[data-theme="bingo"] .bt-current:has(.bball.gold) {
  background: radial-gradient(circle at 30% 22%, #fffbe0, #ffe293 30%, #d3a137 68%, #78501e);
  border-color: #ffe2a0; box-shadow: inset -2px -3px 5px #8b571666, 0 0 14px #e4b94d55;
}
body[data-theme="bingo"] .bt-current .bball {
  justify-content: center; min-width: 1.5em; height: 1.5em; border-radius: 50%;
  background: #f8fcf2d9; box-shadow: inset 0 0 0 1px #ffffff88;
}
body[data-theme="bingo"] .bd-chip.hit:not(.gold) {
  background: radial-gradient(circle at 32% 25%, #6188a4, #294662 76%);
}
body[data-theme="bingo"] .ui-belt {
  background: linear-gradient(120deg, #112c43ed, #0a1c30ed); border-color: #74909d;
}
body[data-theme="bingo"] :is(.ui-money,.ui-pad) {
  background: #0a2139ed; border-radius: 12px;
}
body[data-theme="bingo"] .pad-spin:not(.auto) {
  background: linear-gradient(145deg, #d1efff, #72c0df 52%, #32799f); color: #092b45;
  box-shadow: inset 0 0 0 2px #ced9b6, inset 0 3px 8px #ffffff66, 0 6px 20px #001a2eaa;
}

/* [Codex 2026-09-23] v4.67 手機優先：背景與遊戲共用直式外框，桌面不再鋪成寬桌布。 */
body:is([data-theme="mahjong-gold"],[data-theme="bingo"],[data-theme="maya-gold"],[data-theme="zodiac"],[data-theme="gemquest"],[data-theme="pirate"],[data-theme="boommine"],[data-theme="icecream"],[data-theme="wolf"],[data-game="blue_walk"],[data-game="nectar_rush"],[data-game="opera_faces"],[data-game="night_mahjong"],[data-game="twin_mirror"],[data-game="everfire"]) #view-game {
  width: 100%; max-width: 480px; box-sizing: border-box;
  margin: 0 auto; padding: 10px 10px max(16px, env(safe-area-inset-bottom));
  background-size: 100% 100%; background-position: center top;
  border: 1px solid #9eb8ad33; border-radius: 18px;
  box-shadow: 0 10px 36px #0007;
}
body:is([data-theme="mahjong-gold"],[data-theme="bingo"],[data-theme="maya-gold"],[data-theme="zodiac"],[data-theme="gemquest"],[data-theme="pirate"],[data-theme="boommine"],[data-theme="icecream"],[data-theme="wolf"],[data-game="blue_walk"],[data-game="nectar_rush"],[data-game="opera_faces"],[data-game="night_mahjong"],[data-game="twin_mirror"],[data-game="everfire"]) #view-game .game-stage {
  width: 100%; max-width: none; box-sizing: border-box; padding: 0;
}
body:is([data-theme="mahjong-gold"],[data-theme="bingo"],[data-theme="maya-gold"],[data-theme="zodiac"],[data-theme="gemquest"],[data-theme="pirate"],[data-theme="boommine"],[data-theme="icecream"],[data-theme="wolf"],[data-game="blue_walk"],[data-game="nectar_rush"],[data-game="opera_faces"],[data-game="night_mahjong"],[data-game="twin_mirror"],[data-game="everfire"]) #view-game .game-head {
  min-height: 38px; margin: 0 0 8px; border-radius: 10px;
}
body:is([data-theme="mahjong-gold"],[data-theme="bingo"],[data-theme="maya-gold"],[data-theme="zodiac"],[data-theme="gemquest"],[data-theme="pirate"],[data-theme="boommine"],[data-theme="icecream"],[data-theme="wolf"],[data-game="blue_walk"],[data-game="nectar_rush"],[data-game="opera_faces"],[data-game="night_mahjong"],[data-game="twin_mirror"],[data-game="everfire"]) #view-game .machine {
  padding: 7px; border-radius: 14px;
}
body:is([data-theme="mahjong-gold"],[data-theme="bingo"],[data-theme="maya-gold"],[data-theme="zodiac"],[data-theme="gemquest"],[data-theme="pirate"],[data-theme="boommine"],[data-theme="icecream"],[data-theme="wolf"],[data-game="blue_walk"],[data-game="nectar_rush"],[data-game="opera_faces"],[data-game="night_mahjong"],[data-game="twin_mirror"],[data-game="everfire"]) #view-game .ui-belt {
  height: 38px; margin: 6px 0; border-radius: 10px;
}
body:is([data-theme="mahjong-gold"],[data-theme="bingo"],[data-theme="maya-gold"],[data-theme="zodiac"],[data-theme="gemquest"],[data-theme="pirate"],[data-theme="boommine"],[data-theme="icecream"],[data-theme="wolf"],[data-game="blue_walk"],[data-game="nectar_rush"],[data-game="opera_faces"],[data-game="night_mahjong"],[data-game="twin_mirror"],[data-game="everfire"]) #view-game .ui-money {
  margin: 0; padding: 7px 4px 4px; border-radius: 12px 12px 0 0;
}
body:is([data-theme="mahjong-gold"],[data-theme="bingo"],[data-theme="maya-gold"],[data-theme="zodiac"],[data-theme="gemquest"],[data-theme="pirate"],[data-theme="boommine"],[data-theme="icecream"],[data-theme="wolf"],[data-game="blue_walk"],[data-game="nectar_rush"],[data-game="opera_faces"],[data-game="night_mahjong"],[data-game="twin_mirror"],[data-game="everfire"]) #view-game .ui-pad {
  padding: 6px 4px 9px; border-radius: 0 0 12px 12px;
}
body[data-theme="mahjong-gold"] #view-game .mw-deco { display: none; }
body[data-theme="bingo"] #view-game .bingo-tray { padding: 8px; margin-top: 7px; }
body[data-theme="bingo"] #view-game .bt-current-wrap { gap: 8px; margin-bottom: 6px; }
body[data-theme="bingo"] #view-game .bt-stat { font-size: 12px; line-height: 1.5; }
@media (max-width: 480px) {
  body:is([data-theme="mahjong-gold"],[data-theme="bingo"],[data-theme="maya-gold"],[data-theme="zodiac"],[data-theme="gemquest"],[data-theme="pirate"],[data-theme="boommine"],[data-theme="icecream"],[data-theme="wolf"],[data-game="blue_walk"],[data-game="nectar_rush"],[data-game="opera_faces"],[data-game="night_mahjong"],[data-game="twin_mirror"],[data-game="everfire"]) #view-game {
    border-radius: 0; border-left: 0; border-right: 0; padding-top: 8px;
  }
}

/* [Codex 2026-09-23] v4.68 已重新設計標示：明確文字，與符號圖標記分開。 */
.card-redesign { display: inline-block; align-self: flex-start; margin: 3px 0 4px; padding: 2px 7px;
  border: 1px solid #80dfc78a; border-radius: 6px; background: #173d3b;
  color: #baffeb; font-size: 10px; font-weight: 700; letter-spacing: .04em; }
body[data-theme="maya-gold"] #view-game {
  background-image: url("../assets/games/maya_gold/background.webp?h=556778749e"); background-color: #0b2523;
  --neon: #79c5a6; --neon-2: #dbb667; --gold: #f3d186; --redesign-panel: #102e27ee; --redesign-rim: #b69854;
}
body[data-theme="zodiac"] #view-game {
  background-image: url("../assets/games/zodiac_gather/background.webp?h=090789f794"); background-color: #11152f;
  --neon: #98b6ee; --neon-2: #c3a5ed; --gold: #f0d38a; --redesign-panel: #181c3bed; --redesign-rim: #8e88bb;
}
body[data-theme="gemquest"] #view-game {
  background-image: url("../assets/games/gem_quest/background.webp?h=eeca97150b"); background-color: #0c2029;
  --neon: #73cbbd; --neon-2: #c6a775; --gold: #f0cf87; --redesign-panel: #102b32ed; --redesign-rim: #9f865c;
}
body:is([data-theme="maya-gold"],[data-theme="zodiac"],[data-theme="gemquest"]) #view-game .game-head {
  background: var(--redesign-panel); color: #f2e8ce; text-shadow: 0 2px 4px #0009;
}
body:is([data-theme="maya-gold"],[data-theme="zodiac"],[data-theme="gemquest"]) #view-game .machine {
  background: var(--redesign-panel); border-color: var(--redesign-rim);
  box-shadow: inset 0 0 0 2px #0005, 0 6px 18px #0008;
}
body:is([data-theme="maya-gold"],[data-theme="zodiac"],[data-theme="gemquest"]) #view-game :is(.ui-belt,.ui-money,.ui-pad) {
  background: var(--redesign-panel); border-color: var(--redesign-rim);
}
body:is([data-theme="maya-gold"],[data-theme="zodiac"],[data-theme="gemquest"]) #view-game .pad-spin:not(.auto) {
  background: linear-gradient(145deg, var(--neon), var(--neon-2));
  box-shadow: inset 0 0 0 2px #f7e2a999, 0 5px 16px #0008;
}
body[data-theme="maya-gold"] .board.tw-board {
  background: radial-gradient(ellipse at center, #214039, #101e1c);
}
body[data-theme="maya-gold"] #board .cell:is(.sym-A,.sym-K,.sym-Q,.sym-J,.sym-TEN) .glyph.has-art::before {
  filter: saturate(.45) brightness(.78);
}
body[data-theme="maya-gold"] #board .cell:is(.sym-MASK,.sym-SERPENT,.sym-SUNDISC) .glyph.has-art::before {
  filter: brightness(1.08) drop-shadow(0 1px 3px #eed39544);
}
body[data-theme="zodiac"] .zod-panel { background: #11182be8; box-shadow: inset 0 0 0 1px #9e92bd77; }
body[data-theme="zodiac"] .zq:not(.on) { box-shadow: inset 0 0 0 1px #aba2c333; }
body[data-theme="zodiac"] .zq.on { background-color: #725c284d; }
body[data-theme="zodiac"] .zmr-mask { background-color: #111932; }
body[data-theme="gemquest"] .gq-boss { background: #142c34ee; border-color: #ae9260; }
body[data-theme="gemquest"] #board .sym-G0 .glyph.has-art::before { filter: saturate(.5) brightness(.76); }
body[data-theme="gemquest"] #board .sym-G1 .glyph.has-art::before { filter: saturate(.75) brightness(.9); }
body[data-theme="gemquest"] #board :is(.sym-G3,.sym-G4) .glyph.has-art::before {
  filter: brightness(1.1) drop-shadow(0 0 3px #efd48866);
}
body:is([data-theme="maya-gold"],[data-theme="gemquest"]) #board .cell.cs-win .glyph.has-art::before {
  filter: brightness(1.2) drop-shadow(0 0 5px #ffe5a788);
}

/* [Codex 2026-09-24] v4.69 推動格不能隱形；金框仍只框住生效格。 */
.zmr-cell.push { background: radial-gradient(circle, #785034, #281c20 76%);
  box-shadow: inset 0 0 0 1px #e5b67388; }
.zmr-cell.push .zmr-val { color: #ffe1a2; font-size: clamp(12px, calc(3.5 * var(--vw)), 20px); }
/* 瑪雅：圖像填滿石板中心，保持低賠字牌的收斂；高賠不再像小貼紙。 */
body[data-theme="maya-gold"] #board .glyph.has-art { --sym-art-size: 1.65em; }
body[data-theme="maya-gold"] #board .cell:is(.sym-A,.sym-K,.sym-Q,.sym-J,.sym-TEN) .glyph.has-art {
  --sym-art-size: 1.38em;
}
body[data-theme="maya-gold"] .board.tw-board { border-radius: 10px;
  background: linear-gradient(160deg, #183932, #091b19); }
body[data-theme="maya-gold"] .tw-cell:not(.tw-gold):not(.cs-win):not(.tw-turn) {
  background: linear-gradient(155deg, #315048, #182d29);
  box-shadow: inset 0 1px 0 #a9c2a52b, inset 0 0 0 1px #77948255;
}
body[data-theme="maya-gold"] #view-game { background-image:
  linear-gradient(#061d1733, #061d1766), url("../assets/games/maya_gold/background.webp?h=556778749e"); }
body[data-theme="maya-gold"] #view-game .ui-money { border-bottom: 1px solid #c7af7140; }
body[data-theme="maya-gold"] #view-game .ui-pad { padding-top: 9px; }

/* [Codex 2026-09-24] v4.70 海盜與礦坑沿用直式外框，控制區連成一體。 */
body[data-theme="pirate"] #view-game .ui-money { border-bottom: 1px solid #b89d6340; }
body[data-theme="boommine"] #view-game .ui-money { border-bottom: 1px solid #b9854c40; }

/* [Codex 2026-09-24] v4.71 夏日冰舖與月夜狼王，手機直式美術。 */
body[data-theme="icecream"] #view-game {
  background-image: url("../assets/games/sunny_scoop/background.webp?h=f796bdc5ff"); background-color: #a6d2cc;
  --neon: #84e0cf; --neon-2: #ffce9d; --gold: #ffdb94;
}
body[data-theme="icecream"] #view-game .game-head { background: #134840ed; color: #fff1d7; }
body[data-theme="icecream"] #view-game .machine { background: #174b46f0; border-color: #ffe2b1;
  box-shadow: inset 0 0 0 2px #a2d8c955, 0 4px 16px #163c3c66; }
body[data-theme="icecream"] #board { background: #153f3c; }
body[data-theme="icecream"] #board .cell { background: #24504b; border-color: #173c38; }
body[data-theme="icecream"] #board .glyph.has-art { --sym-art-size: 1.5em; }
body[data-theme="icecream"] #board :is(.sym-F3,.sym-F4) .glyph.has-art::before { filter: saturate(.7) brightness(.86); }
body[data-theme="icecream"] #board :is(.sym-F1,.sym-F2) .glyph.has-art::before { filter: brightness(1.08); }
body[data-theme="icecream"] #view-game :is(.ui-belt,.ui-money,.ui-pad) { background: #13443eed; border-color: #e3c598; }
body[data-theme="icecream"] #view-game .pad-spin:not(.auto) { background: linear-gradient(145deg, #fff0c9, #ffbf8a); color: #543b28;
  box-shadow: inset 0 0 0 2px #fff2d8, 0 5px 16px #123d3e66; }
body[data-theme="wolf"] #view-game {
  background-image: url("../assets/games/wolf_hunt/background.webp?h=59812f4639"); background-color: #101e30;
  --neon: #a3c4e4; --neon-2: #6595b6; --gold: #ead5a2;
}
body[data-theme="wolf"] #view-game .game-head { background: #142a40e8; color: #eef6ff; }
body[data-theme="wolf"] #view-game .machine { background: #102238ed; border-color: #97afc4;
  box-shadow: inset 0 0 0 2px #344858, 0 6px 18px #0007; }
body[data-theme="wolf"] #board { background: #071523; }
body[data-theme="wolf"] #board .cell { background: #192b40; border-color: #0b1929; }
body[data-theme="wolf"] #board .glyph.has-art { --sym-art-size: 1.58em; }
body[data-theme="wolf"] #board :is(.sym-A,.sym-K,.sym-Q) .glyph.has-art { --sym-art-size: 1.22em; }
body[data-theme="wolf"] #board :is(.sym-A,.sym-K,.sym-Q) .glyph.has-art::before { filter: saturate(.3) brightness(.7); }
body[data-theme="wolf"] #board :is(.sym-HARE,.sym-SQUIRREL) .glyph.has-art::before { filter: saturate(.7) brightness(.88); }
body[data-theme="wolf"] #board .sym-WILD .glyph.has-art::before { filter: brightness(1.12) drop-shadow(0 0 4px #b0e7ff88); }
body[data-theme="wolf"] #view-game :is(.ui-belt,.ui-money,.ui-pad) { background: #11263deb; border-color: #98afbf; }
body[data-theme="wolf"] #view-game .pad-spin:not(.auto) { background: linear-gradient(145deg, #e5f2ff, #8fb4d1 55%, #6586aa); color: #182c40;
  box-shadow: inset 0 0 0 2px #e6e1c4, 0 5px 16px #0007; }
body:is([data-theme="icecream"],[data-theme="wolf"]) #board .cell:is(.win,.cs-win) .glyph.has-art::before {
  filter: brightness(1.15) drop-shadow(0 0 4px #ffe6ad88);
}

/* [Codex 2026-09-24] v4.72 狼王換牌：退場、牌背、逐軸翻開。
   只動 glyph / 牌背，不能蓋掉 treadmill 格子本身的定位 transform。 */
body[data-theme="wolf"] .cell.walk-flee .glyph {
  animation: wolfFlee var(--wolf-flee-ms, 360ms) ease-in both;
}
@keyframes wolfFlee {
  0% { transform: translateX(0) scale(1); opacity: 1; }
  25% { transform: translateX(-8%) scale(.92); }
  100% { transform: translateX(90%) scale(.65); opacity: 0; }
}
body[data-theme="wolf"] .cell.walk-covered .glyph { opacity: 0; animation: none; }
body[data-theme="wolf"] .cell.walk-covered::before { display: none; }
body[data-theme="wolf"] .cell.walk-covered::after {
  content: "✦"; position: absolute; inset: 3px; display: grid; place-items: center;
  border: 1px solid #728da7; border-radius: 6px; color: #afc5db; font-size: .55em;
  background: repeating-linear-gradient(135deg, #183048 0 7px, #203c55 7px 8px);
  box-shadow: inset 0 0 0 3px #0c2035, inset 0 0 15px #050c18;
}
body[data-theme="wolf"] .cell.walk-opening::after {
  animation: wolfCardClose var(--wolf-flip-ms, 180ms) ease-in both;
}
body[data-theme="wolf"] .cell.walk-reveal .glyph {
  animation: wolfCardOpen var(--wolf-flip-ms, 180ms) ease-out both;
}
@keyframes wolfCardClose { from { transform: perspective(350px) rotateY(0); } to { transform: perspective(350px) rotateY(90deg); } }
@keyframes wolfCardOpen { from { transform: perspective(350px) rotateY(-90deg); opacity: .4; } to { transform: perspective(350px) rotateY(0); opacity: 1; } }

.wolf-cue { display: none; }
body[data-theme="wolf"] .ui-belt.wolf-guiding :is(.belt-marquee,.belt-win) { display: none; }
body[data-theme="wolf"] .ui-belt.wolf-guiding .wolf-cue {
  display: block; color: #e3effb; font-size: clamp(11px, calc(3.2 * var(--vw)), 14px); text-align: center;
}

/* [Codex 2026-09-24] v4.73 潛水探險專用；不影響共用 ocean 主題的其他遊戲。 */
body[data-game="blue_walk"] #view-game { background-image: url("../assets/games/blue_walk/background.webp?h=5c4ece2a95"); background-color: #061e35; --neon: #70e4e0; --gold: #f4d48c; }
body[data-game="blue_walk"] #view-game :is(.game-head,.ui-belt,.ui-money,.ui-pad) { background: #082b3fe8; border-color: #6cbbc266; }
body[data-game="blue_walk"] #view-game .machine { background: #052438ce; border-color: #72c9d1; box-shadow: inset 0 0 0 2px #74cbcf22, 0 5px 22px #00172699; }
body[data-game="blue_walk"] .board.dv-choose { padding: 8px; gap: 8px; background: #0521348c; }
body[data-game="blue_walk"] .dv-ch-head { color: #d3ffff; letter-spacing: .08em; padding-bottom: 3px; }
body[data-game="blue_walk"] .dv-zone { position: relative; width: 100%; padding: 9px 12px; font: inherit; border-radius: 11px; border: 1px solid #a4efe657; border-left: 4px solid #83e8d3; background: linear-gradient(115deg,#166b73ee,#135765ce); box-shadow: inset 0 1px #c9ffff22; }
body[data-game="blue_walk"] .dv-zone.z1 { background: linear-gradient(115deg,#10556cee,#0d3b58e8); border-left-color: #60cbe1; }
body[data-game="blue_walk"] .dv-zone.z2 { background: linear-gradient(115deg,#12385aee,#0b2444eb); border-left-color: #8ba7e8; }
body[data-game="blue_walk"] .dv-zone.z3 { background: linear-gradient(115deg,#252946ee,#0b152aee); border-left-color: #e3bc7b; }
body[data-game="blue_walk"] .dv-zone:focus-visible { outline: 2px solid #fff1b5; outline-offset: 2px; }
body[data-game="blue_walk"] .dv-zone:hover { border-color: #c6ffff; }
body[data-game="blue_walk"] .dv-z-name { font-size: 16px; }
body[data-game="blue_walk"] .dv-z-emoji { font-size: 22px; }
body[data-game="blue_walk"] .dv-z-top { color: #cce8ef; }
body[data-game="blue_walk"] .dv-z-sub { color: #d0e3eb; }
body[data-game="blue_walk"] .dv-z-meta { color: #aad4dd; }
body[data-game="blue_walk"] .dv-ch-info { color: #c1d8e1; display: block; }
body[data-game="blue_walk"] .dv-hud { background: #06283eeb; border: 1px solid #73cbd255; border-radius: 10px; }
body[data-game="blue_walk"] .dv-view { background: linear-gradient(#0b344ddd,#031226f2); }
body[data-game="blue_walk"] .dv-cell { background: #214b622e; box-shadow: inset 0 0 0 1px #6bc0cd1c; }
body[data-game="blue_walk"] .dv-cell.dv-hidden { background: #010d20a6; box-shadow: none; }
body[data-game="blue_walk"] .dv-value-low .glyph { scale: .8; filter: saturate(.5) brightness(.8); }
body[data-game="blue_walk"] .dv-value-high { background: #d9b56d16; box-shadow: inset 0 0 0 1px #bfa66e66; }
body[data-game="blue_walk"] .dv-value-high .glyph { filter: drop-shadow(0 0 4px #e7c27766); }
body[data-game="blue_walk"] .dv-cell.lit { box-shadow: inset 0 0 0 2px #fff0aa, 0 0 15px #e5c96b66; background: #dec77326; }
body[data-game="blue_walk"] .dv-cell.dv-sea .glyph { opacity: .16; scale: .7; }
body[data-game="blue_walk"] .dv-cell.dv-oxy2 { box-shadow: inset 0 0 0 1px #6ceee099; background: #54c9c61a; }
body[data-game="blue_walk"] .dv-cell.dv-gate2 { box-shadow: inset 0 0 0 1px #eac17fbb; background: #cba05726; }
body[data-game="blue_walk"] .dv-val { font-size: 11px; padding: 2px 5px; }
body[data-game="blue_walk"] .dv-missed { background: #0b2136ed; border-color: #7195b044; }
body[data-game="blue_walk"] #view-game .pad-spin:not(.auto) { background: linear-gradient(145deg,#def9f0,#75d2c9 55%,#37999e); color: #083e4e; box-shadow: inset 0 0 0 2px #d7f3d9,0 4px 15px #0005; }

/* [Codex 2026-09-24] v4.74 四潛點背景與未選點狀態。 */
body[data-game="blue_walk"][data-dive-spot="coastal"] #view-game { background-image: url("../assets/games/blue_walk/coastal.webp?h=2b63147805"); }
body[data-game="blue_walk"][data-dive-spot="offshore"] #view-game { background-image: url("../assets/games/blue_walk/deep.webp?h=6dbacd3db6"); }
body[data-game="blue_walk"][data-dive-spot="abyss"] #view-game { background-image: url("../assets/games/blue_walk/abyss.webp?h=2e06241431"); }
body[data-game="blue_walk"] #view-game .pad-spin.needs-spot { opacity: .45; filter: grayscale(.8); box-shadow: inset 0 0 0 2px #9facb3; }
body[data-game="blue_walk"] .pad-spin.needs-spot :is(.ps-ring,.ps-ticks) { animation: none; }
body[data-game="blue_walk"] .dv-cell .glyph.has-art { --sym-art-size: 1.5em; }

/* [Codex 2026-09-24] v4.75 花蜜採集：手機花園、開花後才顯示價值分層。 */
body[data-game="nectar_rush"] #view-game { background-image: url("../assets/games/nectar_rush/background.webp?h=d1d07b726a"); background-color: #143926; --neon: #c1df9b; --gold: #ffe09a; }
body[data-game="nectar_rush"] #view-game .game-head { margin-bottom: 46px; background: #143a2deb; border: 1px solid #e1bc7066; color: #fff1bf; }
body[data-game="nectar_rush"] #view-game .machine { background: #122e23ed; border: 1px solid #dab16e; box-shadow: inset 0 0 0 3px #614b2b88,0 6px 20px #08160c88; padding: 9px; }
body[data-game="nectar_rush"] #board { background: #0e281e; border-radius: 10px; }
body[data-game="nectar_rush"] #board .cell { background: linear-gradient(150deg,#345a40,#1a392b); border-color: #87a67538; border-radius: 9px; }
body[data-game="nectar_rush"] #board .cell.sym-EMPTY { background: #10271e; border-color: #84a77515; }
body[data-game="nectar_rush"] #board .sym-EMPTY .glyph { opacity: .12; }
body[data-game="nectar_rush"] #board .glyph.has-art { --sym-art-size: 1.46em; }
body[data-game="nectar_rush"] #board .sym-NECTAR .glyph.nectar-open { translate: 0 -5px; }
body[data-game="nectar_rush"] #board .nectar-low .glyph.has-art { --sym-art-size: 1.17em; }
body[data-game="nectar_rush"] #board .nectar-low .glyph::before { filter: saturate(.65); }
body[data-game="nectar_rush"] #board .nectar-high { background: linear-gradient(145deg,#62623a,#24412c); box-shadow: inset 0 0 0 1px #d9b568aa; }
body[data-game="nectar_rush"] #board .nectar-high .glyph::before { filter: drop-shadow(0 1px 3px #e9b34d66); }
body[data-game="nectar_rush"] #board .sym-BEE { background: #554526; box-shadow: inset 0 0 0 1px #edc470; }
body[data-game="nectar_rush"] #board .sym-QUEEN { background: linear-gradient(145deg,#4f365a,#263f34); }
body[data-game="nectar_rush"] #board .nectar-val { bottom: 3px; padding: 3px 7px; font-size: clamp(10px,calc(2.8 * var(--vw)),13px); background: #e5ebca; color: #173b26; box-shadow: 0 1px 3px #0006; }
body[data-game="nectar_rush"] #board .nectar-high .nectar-val { background: linear-gradient(#fff1b1,#e7bd61); color: #49300c; }
body[data-game="nectar_rush"] #board .cash-bee { box-shadow: inset 0 0 0 2px #ffe8a1,0 0 16px #edbb58aa; }
body[data-game="nectar_rush"] #view-game :is(.ui-belt,.ui-money,.ui-pad) { background: #163a2aed; border-color: #d8ba7277; }
body[data-game="nectar_rush"] #view-game .ui-multbar { background: linear-gradient(#477349,#254c35); border-color: #dbbc6d; }
body[data-game="nectar_rush"] #view-game .pad-spin:not(.auto) { background: linear-gradient(145deg,#fff1bd,#e5bc63 60%,#b78638); color: #24402b; box-shadow: inset 0 0 0 2px #fff0b9,0 4px 16px #0006; }
body[data-game="nectar_rush"] .flower-cell { grid-template-columns: 44px 1fr auto; }
body[data-game="nectar_rush"] .flower-cell .fl-glyph { --sym-art-size: 1.6em; margin: 3px 0; }

/* [Codex 2026-09-24] v4.76 真正停在花上的蜂群與原位採集金額。 */
.cash-swarm-bee { position: fixed; left: 0; top: 0; width: 0; height: 0; z-index: 45; pointer-events: none; }
.cash-swarm-bee > .sym-g { position: absolute; left: -18px; top: -22px; font-size: 25px; --sym-art-size: 36px; filter: drop-shadow(0 2px 4px #0008); }
.cash-honey-load { display: none; position: absolute; left: 5px; top: 4px; font-size: 16px; }
.cash-swarm-bee.loaded .cash-honey-load { display: block; }
.cash-swarm-count { position: absolute; top: -32px; left: 7px; background: #294937; color: #fff2bd; border: 1px solid #dfbe69; border-radius: 8px; padding: 1px 4px; font-size: 12px; font-weight: 900; }
.cash-swarm-bee.harvesting > .sym-g { animation: cashSip .28s ease-in-out infinite alternate; }
@keyframes cashSip { to { translate: 0 5px; rotate: 9deg; } }
.cash-swarm-bee.departing > .sym-g, .cash-swarm-bee.departing .cash-honey-load { transition: translate .5s ease-in, opacity .5s; translate: 0 -65px; opacity: 0; }
body[data-game="nectar_rush"] #board .cash-away > .glyph { opacity: .14; }
body[data-game="nectar_rush"] #board .cash-harvesting { box-shadow: inset 0 0 0 3px #fff1a4, 0 0 16px #f6d96799; }
body[data-game="nectar_rush"] #board .cash-picked .nectar-val { opacity: .5; }
body[data-game="nectar_rush"] #board .cash-picked::after { content: '✓'; position: absolute; right: 3px; bottom: 3px; color: #d5f5aa; font-size: 12px; }
.cash-flower-credit { position: fixed; z-index: 46; pointer-events: none; transform: translate(-50%,-20%); display: grid; text-align: center; min-width: 52px; padding: 3px 6px; border: 1px solid #fff2ac; border-radius: 8px; background: #203c21f5; color: #fff3bc; box-shadow: 0 3px 12px #0008; }
.cash-flower-credit small { font-size: 11px; white-space: nowrap; }
.cash-flower-credit strong { font-size: 21px; line-height: 1.15; color: #ffe183; }
@media (prefers-reduced-motion: reduce) { .cash-swarm-bee.harvesting > .sym-g { animation: none; } }

/* [Codex 2026-09-24] v4.78 花園場景分層：底景、採蜜架、透明前景、木桌操作區。
   前景跟隨 machine 尺寸，不跟整頁拉伸；裝飾不攔截點擊與蜂群。 */
body[data-game="nectar_rush"] #view-game {
  background-image: url("../assets/games/nectar_rush/scene-background.webp?h=148efa6878");
  background-color: #698348;
  padding: 8px 6px max(18px, env(safe-area-inset-bottom));
}
body[data-game="nectar_rush"] #view-game .game-head {
  margin: 0 6px 44px; border: 0; border-radius: 0;
  background: linear-gradient(90deg, #173c2500, #173c25cc 28%, #173c25cc 72%, #173c2500);
  text-shadow: 0 2px 3px #17351e;
}
body[data-game="nectar_rush"] #view-game .machine {
  isolation: isolate; overflow: visible;
  padding: 38px 9% 28px; border: 0; border-radius: 0;
  background: none; box-shadow: none;
}
body[data-game="nectar_rush"] #view-game .machine::before {
  content: ""; position: absolute; inset: 7% 7% 6%; z-index: -1;
  border-radius: 12px;
  background: linear-gradient(140deg, #29472bcc, #173d26b8);
  box-shadow: inset 0 4px 18px #0d281ccc, 0 10px 22px #15372270;
  pointer-events: none;
}
body[data-game="nectar_rush"] #view-game .machine::after {
  content: ""; position: absolute; inset: 0; z-index: 8;
  background: url("../assets/games/nectar_rush/scene-frame-slim.webp?h=dd2221ad58") center / 100% 100% no-repeat;
  pointer-events: none;
}
body[data-game="nectar_rush"] #board { background: transparent; padding: 2px; border-radius: 0; }
body[data-game="nectar_rush"] #board .reel { background: transparent; }
body[data-game="nectar_rush"] #board .cell {
  background: linear-gradient(145deg, #5f824342, #183d2738);
  border-color: #c1d68e22; border-radius: 10px;
}
body[data-game="nectar_rush"] #board .cell.sym-EMPTY { background: #1a382925; border-color: #b9d59012; }
body[data-game="nectar_rush"] #board .cell.nectar-high {
  background: radial-gradient(ellipse, #d9b95a66, #547c3338);
  box-shadow: inset 0 0 0 1px #f6d987a6;
}
body[data-game="nectar_rush"] #board .cell.sym-BEE { background: #ad80385e; }
body[data-game="nectar_rush"] #board .cell.sym-QUEEN { background: #754b785e; }
body[data-game="nectar_rush"] #board .cell.cash-harvesting {
  box-shadow: inset 0 0 0 3px #fff1a4, 0 0 16px #f6d96799;
}
body[data-game="nectar_rush"] #view-game .ui-multbar {
  background: linear-gradient(#648243bb, #345830dd); border-color: #dbc07988;
  box-shadow: 0 2px 7px #172d1d66;
}
body[data-game="nectar_rush"] #view-game .ui-belt {
  margin: 0 5% 4px; border: 1px solid #f0ce8766; border-radius: 5px 5px 16px 16px;
  background: linear-gradient(#36532ddb, #203e27eb);
  box-shadow: 0 4px 8px #23351c55; color: #fff2cb;
}
body[data-game="nectar_rush"] #view-game :is(.ui-money,.ui-pad) {
  background: transparent; border: 0; border-radius: 0; box-shadow: none;
}
body[data-game="nectar_rush"] #view-game .ui-money { padding: 10px 12px 6px; }
body[data-game="nectar_rush"] #view-game .um-cell {
  background: #3d321fdb; border: 1px solid #efce8b66; border-radius: 9px;
  color: #fff0be; box-shadow: inset 0 1px 3px #20160f88;
}
body[data-game="nectar_rush"] #view-game .ui-pad { padding: 7px 6px 14px; }
body[data-game="nectar_rush"] #view-game .pad-btn:not(.pad-spin) {
  background: #49351cda; border-color: #f6d69080; color: #ffedba;
  box-shadow: inset 0 2px 2px #fff0bd26, 0 4px 6px #35220e66;
}
body[data-game="nectar_rush"] #view-game .pad-spin:not(.auto) {
  box-shadow: inset 0 0 0 3px #fff0b9, inset 0 -7px 8px #98672f66, 0 7px 9px #392b1677;
}

/* [Codex 2026-09-24] v4.79 四邊安全區：場景裝飾在玩法層之下，數字永不被框遮住。 */
body[data-game="nectar_rush"] #view-game .machine::after { z-index: 0; }
body[data-game="nectar_rush"] #view-game .machine > :is(.board-wrap,.game-multbar) { position: relative; z-index: 1; }
body[data-game="nectar_rush"] #view-game .machine { padding: 38px 9% 32px; }

/* 礦坑：背景洞壁、獨立坑道支架與操作工作台。 */
body[data-game="boom_mine"] #view-game {
  background-image: url("../assets/games/boom_mine/scene-background.webp?h=d9338c9737");
  background-size: 100% 100%; padding: 8px 6px max(18px, env(safe-area-inset-bottom));
}
body[data-game="boom_mine"] #view-game .game-head {
  margin: 0 6px 38px; border: 0; border-radius: 0;
}
body[data-game="boom_mine"] #view-game .machine {
  isolation: isolate; overflow: visible; padding: 32px 8% 28px;
  background: none; border: 0; border-radius: 0; box-shadow: none;
}
body[data-game="boom_mine"] #view-game .machine::before {
  content: ""; position: absolute; inset: 7%; z-index: -1; pointer-events: none;
  background: linear-gradient(140deg, #102129cf, #161d23a8);
  box-shadow: inset 0 3px 18px #000b, 0 6px 16px #0006;
}
body[data-game="boom_mine"] #view-game .machine::after {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: url("../assets/games/boom_mine/scene-frame.webp?h=bee3c5a34f") center / 100% 100% no-repeat;
}
body[data-game="boom_mine"] #view-game .machine > :is(.board-wrap,.game-multbar) { position: relative; z-index: 1; }
body[data-game="boom_mine"] #view-game .board-wrap {
  background: transparent; border: 0; border-radius: 0; box-shadow: none;
}
body[data-game="boom_mine"] #board { background: transparent; padding: 2px; gap: 3px; }
body[data-game="boom_mine"] #board .reel { background: transparent; }
body[data-game="boom_mine"] #board .cell { background: #12212a48; border-color: #a9c1c117; border-radius: 6px; }
body[data-game="boom_mine"] #board .cell:is(.sym-H1,.sym-H2,.sym-H3,.sym-H4) {
  background: radial-gradient(ellipse, #ac87454d, #13263345);
}
body[data-game="boom_mine"] #view-game .ui-multbar {
  background: linear-gradient(#4c3b25ed, #29291fe8); border-color: #d0a86b;
}
body[data-game="boom_mine"] #view-game .ui-belt {
  margin: 0 5% 5px; border-radius: 5px 5px 13px 13px;
  background: linear-gradient(#493721e8, #241f18e8); border-color: #cda36680;
}
body[data-game="boom_mine"] #view-game :is(.ui-money,.ui-pad) {
  background: transparent; border: 0; box-shadow: none;
}
body[data-game="boom_mine"] #view-game .ui-money { padding: 10px 12px 6px; }
body[data-game="boom_mine"] #view-game .ui-pad { padding: 8px 6px 20px; }
body[data-game="boom_mine"] #view-game .um-cell {
  background: #141d23e0; border: 1px solid #b5966766; border-radius: 8px;
}
body[data-game="boom_mine"] #view-game .pad-btn {
  background: #242a2bef; border-color: #bda77c88; color: #f6d69b;
  box-shadow: inset 0 2px #fff1, 0 4px 6px #0008;
}
body[data-game="boom_mine"] #view-game .pad-spin:not(.auto) {
  background: linear-gradient(145deg,#ffe9a5,#cda654 60%,#7d6439); color: #213033;
  box-shadow: inset 0 0 0 3px #ffe8ac, inset 0 -6px 8px #5a432955, 0 7px 10px #0009;
}


/* [Codex 2026-09-24] v4.80 九款場景拆層。圖框只作裝飾，內容永遠在上方。
   潛點背景仍由 data-dive-spot 選擇；絕不改寫牌軸／效果的定位。 */
body[data-game="pirate_treasure"] #view-game { --scene-ink: #062b35; --scene-rim: #d6b679; --scene-frame: url("../assets/games/pirate_treasure/scene-frame.webp?h=f05a878ea4"); background-image: url("../assets/games/pirate_treasure/scene-background.webp?h=1e27603857"); }
body[data-game="mahjong_gold"] #view-game { --scene-ink: #103a2b; --scene-rim: #d7bd7d; --scene-frame: url("../assets/games/mahjong_gold/scene-frame.webp?h=307fd3e309"); background-image: url("../assets/games/mahjong_gold/scene-background.webp?h=5d41948921"); }
body[data-game="lucky_bingo"] #view-game { --scene-ink: #102a43; --scene-rim: #a2c8d9; --scene-frame: url("../assets/games/lucky_bingo/scene-frame.webp?h=c2684d25c4"); background-image: url("../assets/games/lucky_bingo/scene-background.webp?h=a7f3a4f2ac"); }
body[data-game="maya_gold"] #view-game { --scene-ink: #13372c; --scene-rim: #d1b166; --scene-frame: url("../assets/games/maya_gold/scene-frame.webp?h=8e032c35eb"); background-image: url("../assets/games/maya_gold/scene-background.webp?h=3c17a40f1b"); }
body[data-game="zodiac_gather"] #view-game { --scene-ink: #181d39; --scene-rim: #c3b5de; --scene-frame: url("../assets/games/zodiac_gather/scene-frame.webp?h=cbf197eeb5"); background-image: url("../assets/games/zodiac_gather/scene-background.webp?h=581a4fa9b8"); }
body[data-game="gem_quest"] #view-game { --scene-ink: #122f35; --scene-rim: #b8ab7c; --scene-frame: url("../assets/games/gem_quest/scene-frame.webp?h=79ba86aa3c"); background-image: url("../assets/games/gem_quest/scene-background.webp?h=b5d9811065"); }
body[data-game="sunny_scoop"] #view-game { --scene-ink: #20514b; --scene-rim: #f0d6ac; --scene-frame: url("../assets/games/sunny_scoop/scene-frame.webp?h=ff82b8091c"); background-image: url("../assets/games/sunny_scoop/scene-background.webp?h=9616b6ae9f"); }
body[data-game="wolf_hunt"] #view-game { --scene-ink: #11263b; --scene-rim: #a7bfd1; --scene-frame: url("../assets/games/wolf_hunt/scene-frame.webp?h=25c3308499"); background-image: url("../assets/games/wolf_hunt/scene-background.webp?h=eabb65faec"); }
body[data-game="blue_walk"] #view-game { --scene-ink: #082a3c; --scene-rim: #a2d6d2; --scene-frame: url("../assets/games/blue_walk/scene-frame.webp?h=ffb8e2e87c"); }

/* [claude code] 2026-09-24 v4.94 🖼 美術外框款「設計寬 480 + 整頁等比縮放」(app.js fitStage)。
   .game-stage 的寬 / transform / 負 margin-bottom 與 #view-game 的寬都由 JS 寫 inline style;
   這裡只負責縮放的原點。v4.96 起整站鎖手機直式 → 每一款都套(含尋寶掃雷 #view-mines),不再有清單。 */
body[data-fit="1"] :is(#view-game,#view-mines) .game-stage { transform-origin: top left; max-width: none; }

body:is([data-game="pirate_treasure"],[data-game="mahjong_gold"],[data-game="lucky_bingo"],[data-game="maya_gold"],[data-game="zodiac_gather"],[data-game="gem_quest"],[data-game="sunny_scoop"],[data-game="wolf_hunt"],[data-game="blue_walk"],[data-game="opera_faces"],[data-game="night_mahjong"],[data-game="twin_mirror"],[data-game="everfire"]) #view-game { background-size: 100% 100%; padding: 8px 6px max(18px, env(safe-area-inset-bottom)); }
body:is([data-game="pirate_treasure"],[data-game="mahjong_gold"],[data-game="lucky_bingo"],[data-game="maya_gold"],[data-game="zodiac_gather"],[data-game="gem_quest"],[data-game="sunny_scoop"],[data-game="wolf_hunt"],[data-game="blue_walk"],[data-game="opera_faces"],[data-game="night_mahjong"],[data-game="twin_mirror"],[data-game="everfire"]) #view-game .game-head { margin: 0 6px 32px; border: 0; border-radius: 0;
  background: linear-gradient(90deg, transparent, var(--scene-ink) 24%, var(--scene-ink) 76%, transparent);
  text-shadow: 0 2px 4px #0009; }
body:is([data-game="pirate_treasure"],[data-game="mahjong_gold"],[data-game="lucky_bingo"],[data-game="maya_gold"],[data-game="zodiac_gather"],[data-game="gem_quest"],[data-game="sunny_scoop"],[data-game="wolf_hunt"],[data-game="blue_walk"],[data-game="opera_faces"],[data-game="night_mahjong"],[data-game="twin_mirror"],[data-game="everfire"]) #view-game .machine { isolation: isolate; overflow: visible; padding: 38px 9% 32px;
  background: none; border: 0; border-radius: 0; box-shadow: none; }
body:is([data-game="pirate_treasure"],[data-game="mahjong_gold"],[data-game="lucky_bingo"],[data-game="maya_gold"],[data-game="zodiac_gather"],[data-game="gem_quest"],[data-game="sunny_scoop"],[data-game="wolf_hunt"],[data-game="blue_walk"],[data-game="opera_faces"],[data-game="night_mahjong"],[data-game="twin_mirror"],[data-game="everfire"]) #view-game .machine::before { content: ""; position: absolute; inset: 7%; z-index: -1;
  pointer-events: none; border-radius: 8px;
  background: color-mix(in srgb, var(--scene-ink) 78%, transparent);
  box-shadow: inset 0 4px 16px #0007, 0 5px 15px #0005; }
body:is([data-game="pirate_treasure"],[data-game="mahjong_gold"],[data-game="lucky_bingo"],[data-game="maya_gold"],[data-game="zodiac_gather"],[data-game="gem_quest"],[data-game="sunny_scoop"],[data-game="wolf_hunt"],[data-game="blue_walk"],[data-game="opera_faces"],[data-game="night_mahjong"],[data-game="twin_mirror"],[data-game="everfire"]) #view-game .machine::after { content: ""; position: absolute; inset: 0; z-index: 0;
  pointer-events: none; background: var(--scene-frame) center / 100% 100% no-repeat; }
body:is([data-game="pirate_treasure"],[data-game="mahjong_gold"],[data-game="lucky_bingo"],[data-game="maya_gold"],[data-game="zodiac_gather"],[data-game="gem_quest"],[data-game="sunny_scoop"],[data-game="wolf_hunt"],[data-game="blue_walk"],[data-game="opera_faces"],[data-game="night_mahjong"],[data-game="twin_mirror"],[data-game="everfire"]) #view-game .machine > :is(.board-wrap,.game-multbar) { position: relative; z-index: 1; }
body:is([data-game="pirate_treasure"],[data-game="mahjong_gold"],[data-game="lucky_bingo"],[data-game="maya_gold"],[data-game="zodiac_gather"],[data-game="gem_quest"],[data-game="sunny_scoop"],[data-game="wolf_hunt"],[data-game="blue_walk"],[data-game="opera_faces"],[data-game="night_mahjong"],[data-game="twin_mirror"],[data-game="everfire"]) #view-game .board-wrap { background: transparent; border: 0; border-radius: 0; box-shadow: none; }
body:is([data-game="pirate_treasure"],[data-game="mahjong_gold"],[data-game="lucky_bingo"],[data-game="maya_gold"],[data-game="zodiac_gather"],[data-game="gem_quest"],[data-game="sunny_scoop"],[data-game="wolf_hunt"],[data-game="blue_walk"],[data-game="opera_faces"],[data-game="night_mahjong"],[data-game="twin_mirror"],[data-game="everfire"]) #view-game #board { background: transparent; box-shadow: none; }
body:is([data-game="pirate_treasure"],[data-game="mahjong_gold"],[data-game="lucky_bingo"],[data-game="maya_gold"],[data-game="zodiac_gather"],[data-game="gem_quest"],[data-game="sunny_scoop"],[data-game="wolf_hunt"],[data-game="blue_walk"],[data-game="opera_faces"],[data-game="night_mahjong"],[data-game="twin_mirror"],[data-game="everfire"]) #view-game #board .reel { background: transparent; }
body:is([data-game="pirate_treasure"],[data-game="mahjong_gold"],[data-game="lucky_bingo"],[data-game="maya_gold"],[data-game="zodiac_gather"],[data-game="gem_quest"],[data-game="sunny_scoop"],[data-game="wolf_hunt"],[data-game="blue_walk"],[data-game="opera_faces"],[data-game="night_mahjong"],[data-game="twin_mirror"],[data-game="everfire"]) #view-game .ui-belt { margin: 0 5% 5px; border-radius: 5px 5px 13px 13px;
  background: color-mix(in srgb, var(--scene-ink) 90%, transparent);
  border: 1px solid color-mix(in srgb, var(--scene-rim) 65%, transparent); }
body:is([data-game="pirate_treasure"],[data-game="mahjong_gold"],[data-game="lucky_bingo"],[data-game="maya_gold"],[data-game="zodiac_gather"],[data-game="gem_quest"],[data-game="sunny_scoop"],[data-game="wolf_hunt"],[data-game="blue_walk"],[data-game="opera_faces"],[data-game="night_mahjong"],[data-game="twin_mirror"],[data-game="everfire"]) #view-game :is(.ui-money,.ui-pad) { background: transparent; border: 0; box-shadow: none; border-radius: 0; }
body:is([data-game="pirate_treasure"],[data-game="mahjong_gold"],[data-game="lucky_bingo"],[data-game="maya_gold"],[data-game="zodiac_gather"],[data-game="gem_quest"],[data-game="sunny_scoop"],[data-game="wolf_hunt"],[data-game="blue_walk"],[data-game="opera_faces"],[data-game="night_mahjong"],[data-game="twin_mirror"],[data-game="everfire"]) #view-game .ui-money { padding: 10px 12px 6px; }
body:is([data-game="pirate_treasure"],[data-game="mahjong_gold"],[data-game="lucky_bingo"],[data-game="maya_gold"],[data-game="zodiac_gather"],[data-game="gem_quest"],[data-game="sunny_scoop"],[data-game="wolf_hunt"],[data-game="blue_walk"],[data-game="opera_faces"],[data-game="night_mahjong"],[data-game="twin_mirror"],[data-game="everfire"]) #view-game .ui-pad { padding: 8px 6px 18px; }
body:is([data-game="pirate_treasure"],[data-game="mahjong_gold"],[data-game="lucky_bingo"],[data-game="maya_gold"],[data-game="zodiac_gather"],[data-game="gem_quest"],[data-game="sunny_scoop"],[data-game="wolf_hunt"],[data-game="blue_walk"],[data-game="opera_faces"],[data-game="night_mahjong"],[data-game="twin_mirror"],[data-game="everfire"]) #view-game .um-cell { background: color-mix(in srgb, var(--scene-ink) 92%, transparent);
  border: 1px solid color-mix(in srgb, var(--scene-rim) 55%, transparent); border-radius: 8px; }
body:is([data-game="pirate_treasure"],[data-game="mahjong_gold"],[data-game="lucky_bingo"],[data-game="maya_gold"],[data-game="zodiac_gather"],[data-game="gem_quest"],[data-game="sunny_scoop"],[data-game="wolf_hunt"],[data-game="blue_walk"],[data-game="opera_faces"],[data-game="night_mahjong"],[data-game="twin_mirror"],[data-game="everfire"]) #view-game .pad-btn { background: color-mix(in srgb, var(--scene-ink) 93%, transparent);
  border-color: var(--scene-rim); box-shadow: inset 0 2px #fff2, 0 4px 7px #0007; }
body:is([data-game="pirate_treasure"],[data-game="mahjong_gold"],[data-game="lucky_bingo"],[data-game="maya_gold"],[data-game="zodiac_gather"],[data-game="gem_quest"],[data-game="sunny_scoop"],[data-game="wolf_hunt"],[data-game="blue_walk"],[data-game="opera_faces"],[data-game="night_mahjong"],[data-game="twin_mirror"],[data-game="everfire"]) #view-game .pad-spin:not(.auto) { box-shadow: inset 0 0 0 3px var(--scene-rim), inset 0 -6px 8px #0003, 0 7px 10px #0007; }
/* 牌桌自帶上緣倍率條，留足高度；功能 HUD 保留自己的對比底。 */
body[data-game="mahjong_gold"] #view-game .machine { padding-top: 46px; }
body[data-game="maya_gold"] #view-game .machine { padding-top: 40px; }
body[data-game="lucky_bingo"] #view-game .bingo-tray { background: #092238b8; box-shadow: inset 0 1px #92b3c566; }
body[data-game="zodiac_gather"] #view-game .zod-panel { background: #121a32b8; position: relative; z-index: 1; }
body[data-game="zodiac_gather"] #view-game .zod-snowbar { position: relative; z-index: 1; }
body[data-game="gem_quest"] #view-game .gq-boss { background: #132c36cc; z-index: 1; }
body[data-game="blue_walk"] #view-game .dv-hud { background: #06283ecc; position: relative; z-index: 1; }
body[data-game="lucky_bingo"] #view-game .bingo-tray { position: relative; z-index: 1; }
body[data-game="sunny_scoop"] #view-game .gmd-mini {
  background: #17473fed; border-color: #c3a978; opacity: 1;
}
body[data-game="sunny_scoop"] #view-game .gmd-lab { color: #d5e9df; }
/* 選點卡在窄框內會換行；以內容高度取代舊 JS 的一屏高度，避免文字互壓。 */
body[data-game="blue_walk"] #view-game #board.dv-choose { height: auto !important; }
body[data-game="blue_walk"] #view-game .dv-zone { flex: 0 0 auto; min-height: 92px; }
body[data-game="blue_walk"] #view-game .dv-z-top { flex-basis: 100%; margin-left: 0; }
body[data-game="blue_walk"] #view-game .dv-head { flex-wrap: wrap; row-gap: 6px; }
body[data-game="blue_walk"] #view-game .dv-pick { flex: 0 0 auto; white-space: nowrap; }


/* [Codex 2026-09-24] v4.82 倍率與第一排分開；短軸出口加翡翠包邊。
   裝飾置於獨立覆層，不插入 reel.children（牌索引依賴 children 順序）。 */
#view-game .game-multbar:is(.pos-tight,.pos-row) { margin: 0 0 16px; }
body[data-game="mahjong_gold"] #view-game .board.mw-board { margin-top: 24px; }
body[data-game="mahjong_gold"] #view-game .mw-multbar { top: -37px; }
body[data-game="maya_gold"] #view-game .tw-multbar { top: -12px; }
body[data-game="mahjong_gold"] #view-game .mw-deco.mw-edge-deco { display: block; z-index: 7; }
body[data-game="mahjong_gold"] #view-game .mw-edge-cap {
  position: absolute; height: 14px; pointer-events: none;
  background: url("../assets/games/mahjong_gold/reel-lip.svg?h=720037bde8") center / 100% 100% no-repeat;
  filter: drop-shadow(0 2px 3px #082e24bb);
}
body[data-game="mahjong_gold"] #view-game .mw-edge-cap.bottom { transform: rotate(180deg); }
/* 滾動時只在出口的 7px 內遮罩，牌心與完整符號保持可見。 */
body[data-game="mahjong_gold"] #board .mw-reel.spinning:is(:first-child,:nth-child(5)) {
  mask-image: linear-gradient(to bottom, transparent, #000 7px, #000 calc(100% - 7px), transparent);
}


/* [Codex 2026-09-24] v4.83 附加輪嵌入瑪雅石座；圖層在牌面下方。 */
body[data-game="maya_gold"] #board .tw-top-cradle {
  position: absolute; z-index: 0; pointer-events: none;
  background: url("../assets/games/maya_gold/top-cradle.webp?h=48a1831272") center / 100% 100% no-repeat;
  filter: drop-shadow(0 3px 3px #061c18aa);
}
body[data-game="maya_gold"] #board .tw-reel { z-index: 1; }
body[data-game="maya_gold"] #board .tw-top:not(.tw-gold-art)::after { display: none; }


/* v4.84: separate scenery behind gems, never inside the indexed cell collection. */
body[data-game="gem_quest"] { --gq-scenery: url("../assets/games/gem_quest/scenery-lv1.webp?h=b9a46442d0"); }
body[data-game="gem_quest"][data-gq-level="2"] { --gq-scenery: url("../assets/games/gem_quest/scenery-lv2.webp?h=57325e2764"); }
body[data-game="gem_quest"][data-gq-level="3"] { --gq-scenery: url("../assets/games/gem_quest/scenery-lv3.webp?h=078e431040"); }
/* The machine has a stable width; the board shrinks/grows from 4 to 6 columns. */
.gq-scenery { display: none; }
body[data-game="gem_quest"] #view-game .gq-scenery {
  display: block; position: absolute; z-index: 0; pointer-events: none;
  left: 3%; right: 3%; bottom: 32px; height: 58%;
  background: var(--gq-scenery) center bottom / 100% 100% no-repeat;
  filter: drop-shadow(0 5px 5px #020d12aa);
  transition: opacity .3s ease;
}

body[data-game="gem_quest"] #board { z-index: 1; }
body[data-game="gem_quest"] .gq-hpbar {
  height: 18px; padding: 2px; border-radius: 4px; box-sizing: border-box;
  background: #08191e; overflow: hidden;
}
body[data-game="gem_quest"] .gq-hpfill {
  display: grid; grid-template-columns: repeat(var(--gq-hp-total, 15), minmax(0, 1fr));
  gap: 2px; width: 100%; height: 100%; background: none; border-radius: 0; transition: none;
}
.gq-hp-segment { border-radius: 2px; background: #233b40; box-shadow: inset 0 0 0 1px #68818740; }
.gq-hp-segment.lit { background: linear-gradient(#ffd372, #ff9c38 50%, #e35733); box-shadow: inset 0 1px 0 #ffe9a3aa; }

/* v4.85: weapon arrivals, illustrated bosses, and a deliberate stage reveal. */
body[data-game="gem_quest"] .gq-boss-glyph { width: 64px; height: 64px; }
.gq-boss-art { display: block; width: 100%; height: 100%; object-fit: contain; }
.gq-flying-weapon { position: fixed; z-index: 76; width: 48px; height: 48px; object-fit: contain; pointer-events: none; filter: drop-shadow(0 0 7px #ffd16a); }
.gq-defeated-boss { position: fixed; z-index: 75; width: 128px; height: 128px; pointer-events: none; }
.gq-weapon-slash { width: 60px; height: 60px; background: url("../assets/games/gem_quest/weapon.webp?h=ad0974f4e9") center / contain no-repeat; }
.gq-impact { width: 42px; height: 42px; background: radial-gradient(ellipse, #fff9c7 0%, #ffc95e 15%, transparent 62%); }
body[data-game="gem_quest"] #view-game .board-wrap { transition: opacity .3s ease; }
body[data-game="gem_quest"] #view-game .gq-changing > :is(.gq-scenery,.board-wrap) { opacity: 0; }
.gq-stage-card { position: absolute; z-index: 8; pointer-events: none; left: 8%; right: 8%; top: 40%; display: flex; align-items: center; flex-direction: column; padding: 15px 10px; gap: 6px; color: #ffe5a7; background: linear-gradient(90deg, transparent, #071c25f5 20%, #071c25f5 80%, transparent); text-align: center; }
.gq-stage-card strong { font-size: 26px; letter-spacing: .15em; }
.gq-stage-card span { font-size: 15px; }
.gq-stage-portrait { width: 112px; height: 112px; filter: drop-shadow(0 0 15px #e8bb6466); }
@media (max-width: 360px) { body[data-game="gem_quest"] .gq-boss-glyph { width: 52px; height: 52px; } }
@media (prefers-reduced-motion: reduce) { body[data-game="gem_quest"] #view-game :is(.gq-scenery,.board-wrap) { transition: none; } }

/* [Codex 2026-09-24] v4.86 upper hanging props share the fixed scenery layer. */
body[data-game="gem_quest"] { --gq-upper-scenery: url("../assets/games/gem_quest/upper-lv1.webp?h=e70ad2822c"); }
body[data-game="gem_quest"][data-gq-level="2"] { --gq-upper-scenery: url("../assets/games/gem_quest/upper-lv2.webp?h=4114acd1d6"); }
body[data-game="gem_quest"][data-gq-level="3"] { --gq-upper-scenery: url("../assets/games/gem_quest/upper-lv3.webp?h=99e3395d62"); }
body[data-game="gem_quest"] #view-game .gq-scenery::before {
  content: ""; position: absolute; pointer-events: none;
  left: 0; right: 0; top: -25%; height: 70%;
  background: var(--gq-upper-scenery) center top / 100% 100% no-repeat;
  /* Keep the central falling lane clear even if an asset contains stray glow. */
  -webkit-mask-image: linear-gradient(to right, #000 0 24%, transparent 24% 76%, #000 76% 100%);
  mask-image: linear-gradient(to right, #000 0 24%, transparent 24% 76%, #000 76% 100%);
}

/* [Codex 2026-09-24] Opera theatre: independent scenery and applause-driven reveal. */
body[data-game="opera_faces"] #view-game {
  --scene-ink: #32101b; --scene-rim: #d4a44b;
  --scene-frame: url("../assets/games/opera_faces/scene-frame.webp?h=48dee0e678");
  background-image: url("../assets/games/opera_faces/scene-background.webp?h=1ff343b496");
  background-color: #210b16; --gold: #f7d17c; --neon: #ed9e74;
}
body[data-game="opera_faces"] #view-game .machine { padding: 130px 8% 80px; }   /* v4.96 外框改九宮格後布幔 / 舞台地板照原比例畫(比拉扁時大)→ 盤面讓開(原 64px 8% 30px) */
body[data-game="opera_faces"] #view-game :is(.game-head,.ui-belt) { background: #310d1dde; border-color: #d4a44b88; }
body[data-game="opera_faces"] #view-game .reel { background: linear-gradient(90deg,#230917b0,#53182b66,#230917b0); border-radius: 5px; }
body[data-game="opera_faces"] #view-game .cell { border-bottom: 1px solid #dfab4822; }
body[data-game="opera_faces"] #view-game .game-multbar { margin-bottom: 18px; }
body[data-game="opera_faces"] #view-game .cell.sym-AUDIENCE { background: radial-gradient(ellipse,#b8752766,transparent 70%); }
body[data-game="opera_faces"] .fo-performing .board-wrap { filter: brightness(.42); }
.fo-stage-show { position: absolute; z-index: 12; inset: 16% 5% 6%; pointer-events: none; display: grid; place-items: center; overflow: hidden; background: radial-gradient(ellipse,#ffd47b44,transparent 68%); transition: opacity .15s; }
.fo-stage-mask { position: absolute; width: 46%; max-width: 160px; max-height: 85%; object-fit: contain; filter: drop-shadow(0 8px 15px #080006) drop-shadow(0 0 20px #ffc96888); }
.fo-stage-sleeve { position: absolute; width: 130%; height: 300%; object-fit: fill; opacity: 0; z-index: 2; }
.fo-cell-sleeve { position: absolute; top: -200%; left: -50%; width: 200%; height: 500%; z-index: 10; pointer-events: none; opacity: 0; }
body[data-game="opera_faces"] .cell.fo-landed .glyph { filter: drop-shadow(0 0 8px #ffe098); }

body[data-game="opera_faces"] #view-game .board-wrap { transition: filter .18s ease; }

body[data-game="opera_faces"] #view-game .ui-multbar { background: linear-gradient(#782b35,#391321); border-color: #e2b863; }
body[data-game="opera_faces"] #view-game .pad-spin:not(.auto) { background: linear-gradient(145deg,#ffeab0,#e0ad50 62%,#9c5b27); color: #441323; }
body[data-game="opera_faces"] #view-game .cell { background: linear-gradient(145deg,#39142acc,#1e081caa); }


/* v4.88: audience faces the slot stage; controls stay above the decorative layer. */
body[data-game="opera_faces"] #view-game .ui-pad {
  position: relative;
  isolation: isolate;
  padding-bottom: 48px;
  gap: clamp(3px, calc((calc(100 * var(--vw)) - 308px) / 6), 14px);
}
body[data-game="opera_faces"] #view-game .ui-pad::before {
  content: "";
  position: absolute;
  z-index: -1;
  pointer-events: none;
  inset: 0;
  overflow: hidden;
  mask-image: linear-gradient(to bottom, transparent, #000 22px);
  background: url("../assets/games/opera_faces/audience-foreground.webp?h=945549528c") center bottom / 100% auto no-repeat;
}
body[data-game="opera_faces"] #view-game .ui-pad > button {
  position: relative;
  z-index: 1;
}
body[data-game="opera_faces"] #view-game .ui-pad .pad-btn {
  background-color: #32101bf2;
}

/* v4.89: keep the audience inside the controls, below the money row. */
body[data-game="opera_faces"] #view-game .ui-pad { overflow: hidden; }
body[data-game="opera_faces"] #view-game .ui-money { position: relative; z-index: 2; }
body[data-game="opera_faces"] .fo-multbar { gap: 12px; min-height: 36px; }
.fo-mult-source, .fo-mult-faces, .fo-multbar .ui-mchip.on {
  display: inline-flex; align-items: center; gap: 3px;
}
.fo-mult-source { color: #ffe7b1; font-weight: 800; font-size: 16px; }
.fo-mult-art { width: 25px; height: 29px; object-fit: contain; }
.fo-mult-arrow { margin-left: 5px; opacity: .75; }
.fo-mult-faces { margin-right: 5px; gap: 0; }
.fo-mult-faces .fo-mult-art { width: 21px; }


/* v4.90: night-market table, ivory draws and unmistakable golden bonus tiles. */
body[data-game="night_mahjong"] #view-game {
  --scene-ink: #16372e; --scene-rim: #c6934e;
  --scene-frame: url("../assets/games/night_mahjong/scene-frame.webp?h=e56c6ea398");
  background-image: url("../assets/games/night_mahjong/scene-background.webp?h=6ffa7d6c28");
  background-color: #143329; --gold: #ffd574; --neon: #9cdec8;
}
body[data-game="night_mahjong"] #view-game .machine { padding: 48px 13% 42px; }
body[data-game="night_mahjong"] #view-game .game-head { margin-bottom: 32px; }
body[data-game="night_mahjong"] #view-game .game-multbar {
  position: relative; inset: auto; width: 100%; margin: 0 0 12px; transform: none;
}
body[data-game="night_mahjong"] #view-game .ui-multbar {
  background: linear-gradient(#246650,#133f32); border-color: #d8b86b; min-height: 30px;
}
.nm-gold-tile { display:inline-block; width:17px; height:23px; margin-right:7px; vertical-align:middle; border-radius:4px;
  background:linear-gradient(135deg,#fff2ab,#ffc638 60%,#b77b1b); border:1px solid #95621a;
  box-shadow:inset 0 2px #fff8, inset 0 -3px #9d611f; }
body[data-game="night_mahjong"] #view-game #board {
  padding: 3px; gap: 5px; overflow: visible;
}
body[data-game="night_mahjong"] #view-game .mj-cell {
  border:1px solid #ddc8a3; border-radius:5px; background:linear-gradient(145deg,#fff9e9,#eadbbd);
  box-shadow:inset 0 2px #ffffef, inset 0 -4px #b8ab8d,0 3px 3px #001e19aa;
}
body[data-game="night_mahjong"] #view-game .mj-cell.dim { opacity:.64; filter:saturate(.5) brightness(.78); }
body[data-game="night_mahjong"] #view-game .mj-cell.lit {
  border-color:#f9edcd; box-shadow:inset 0 2px #fff, inset 0 -3px #cabc9a,0 0 0 1px #8ddac6,0 3px 4px #001a17;
}
body[data-game="night_mahjong"] #view-game .mj-cell.mj-gold {
  background:linear-gradient(140deg,#fff7bb,#ffcc40 55%,#db911c);
  border-color:#ffe6a0; box-shadow:inset 0 2px #fff9d3,inset 0 -4px #b87519,0 0 11px #ffcb5266;
}
body[data-game="night_mahjong"] #view-game .mj-cell.mj-gold::after {
  content:"✦"; position:absolute; top:0; right:2px; color:#7d440b; font-size:10px;
}
body[data-game="night_mahjong"] #view-game .mj-cell.mj-back {
  background:linear-gradient(135deg,#408b71,#16513e);border-color:#79b394;
  box-shadow:inset 0 2px #a6cfa4,inset 0 -4px #0c362b,0 3px 4px #001e19aa;
}
body[data-game="night_mahjong"] #view-game #mjTray {
  position:relative; z-index:1; background:linear-gradient(#2d1e13e8,#513723e8); border:1px solid #b8894d;
  border-radius:7px; margin-top:14px; box-shadow:inset 0 2px #e1b96b33;
}
body[data-game="night_mahjong"] #view-game .mj-record { gap:4px; }
body[data-game="night_mahjong"] #view-game .ui-pad { gap:clamp(3px,calc((calc(100 * var(--vw)) - 308px) / 6),14px); }
body[data-game="night_mahjong"] #view-game .pad-spin:not(.auto) {
  background:linear-gradient(145deg,#ffebac,#d8ab54 65%,#91602d);color:#213c2b;
}
body[data-game="night_mahjong"] #view-game .ui-belt { background:#193d30ed; }
/* The new cloth has an opaque centre; overscan all four edges at the covered keyframe. */
.fo-stage-show { inset: 6% 2% 3%; }
.fo-stage-sleeve { width:150%; height:150%; max-width:none; object-fit:fill; }
.fo-cell-sleeve { top:-25%; left:-25%; width:150%; height:150%; }

/* v4.91: illustrated tile atlases share one renderer across board, hand and history. */
/* v4.93: artwork fills its tile; narrow the tile base, not the inner image. */
.nm-tile-art { display:block; width:100%; height:100%; flex:1 1 auto; border-radius:inherit;
  background-size:300% 300%; background-repeat:no-repeat; pointer-events:none; }
.mj-gold .nm-tile-art, .mj-chip.gold .nm-tile-art, .mj-cur-face.gold .nm-tile-art { mix-blend-mode:multiply; }
body[data-game="night_mahjong"] .mj-current:has(.mj-cur-face.gold) { background:linear-gradient(140deg,#fff6ac,#ffc435); }

/* v4.93: each tile base is 20% narrower; preserve grid tracks and line centres. */
body[data-game="night_mahjong"] #board > .mj-cell {
  width:80%; height:100%; justify-self:center; box-sizing:border-box;
}
body[data-game="night_mahjong"] #mjCurrent {
  width:36.8px; min-width:36.8px; padding-inline:0; flex:0 0 36.8px;
}
body[data-game="night_mahjong"] #mjRecord .mj-chip {
  width:20.8px; min-width:20.8px; flex:0 0 20.8px;
}

/* ================= [claude code] 2026-09-24 v4.96 🖼 外框九宮格 =================
   使用者:「狼王夜襲好像比例不太對」。原因:框圖(多數 1000×1000)用 `background: … / 100% 100%` 硬拉滿外框區,
   而外框區的比例跟著盤面走(狼王 5×3 是 1.40:1)→ 直向壓到 71%,四角的圓月變成橢圓;梨園變臉 0.8 直式框塞進橫框更嚴重。
   改成 border-image 九宮格:四角照原比例(跟著寬度等比縮)、只有邊條伸縮。
   · --ft/--fr/--fb/--fl = 切點(**圖的 px**,量四角裝飾的範圍定的;要調就改這幾個數字)
   · --frame-k = 外框區寬 ÷ 圖寬(app.js fitStage 寫入;整站鎖設計寬,預設 .466 = 466 / 1000)
   · --frame-iw = 圖寬(不是 1000 的才寫)
   🔴 新款接外框:在這裡加一行切點 + 加進下面的選擇器清單。 */
body[data-game="pirate_treasure"] #view-game { --ft: 170; --fr: 120; --fb: 170; --fl: 120; }
body[data-game="mahjong_gold"] #view-game { --ft: 90; --fr: 80; --fb: 100; --fl: 80; }
body[data-game="lucky_bingo"] #view-game { --ft: 80; --fr: 80; --fb: 80; --fl: 80; }
body[data-game="maya_gold"] #view-game { --ft: 130; --fr: 130; --fb: 130; --fl: 130; }
body[data-game="zodiac_gather"] #view-game { --ft: 130; --fr: 130; --fb: 130; --fl: 130; }
body[data-game="gem_quest"] #view-game { --ft: 110; --fr: 110; --fb: 110; --fl: 110; }
body[data-game="sunny_scoop"] #view-game { --ft: 130; --fr: 110; --fb: 130; --fl: 110; }
body[data-game="wolf_hunt"] #view-game { --ft: 130; --fr: 130; --fb: 130; --fl: 130; }
body[data-game="blue_walk"] #view-game { --ft: 100; --fr: 100; --fb: 100; --fl: 100; }
body[data-game="opera_faces"] #view-game { --ft: 380; --fr: 210; --fb: 200; --fl: 210; }
body[data-game="night_mahjong"] #view-game { --ft: 300; --fr: 150; --fb: 280; --fl: 150; --frame-iw: 1122; }
body[data-game="boom_mine"] #view-game { --ft: 300; --fr: 110; --fb: 240; --fl: 130; --scene-frame: url("../assets/games/boom_mine/scene-frame.webp?h=bee3c5a34f"); }
body[data-game="nectar_rush"] #view-game { --ft: 90; --fr: 90; --fb: 90; --fl: 90; --scene-frame: url("../assets/games/nectar_rush/scene-frame-slim.webp?h=dd2221ad58"); }
body:is([data-game="pirate_treasure"],[data-game="mahjong_gold"],[data-game="lucky_bingo"],[data-game="maya_gold"],[data-game="zodiac_gather"],[data-game="gem_quest"],[data-game="sunny_scoop"],[data-game="wolf_hunt"],[data-game="blue_walk"],[data-game="opera_faces"],[data-game="night_mahjong"],[data-game="boom_mine"],[data-game="nectar_rush"],[data-game="twin_mirror"],[data-game="everfire"]) #view-game .machine::after {
  background: none;
  border-style: solid; border-color: transparent;
  border-width: calc(var(--ft) * var(--frame-k, .466) * 1px) calc(var(--fr) * var(--frame-k, .466) * 1px) calc(var(--fb) * var(--frame-k, .466) * 1px) calc(var(--fl) * var(--frame-k, .466) * 1px);
  border-image: var(--scene-frame) var(--ft) var(--fr) var(--fb) var(--fl) fill stretch;
}

/* ================= [claude code] 2026-09-24 v4.97 📱 大廳小卡:一列 3 款 =================
   使用者:「單一遊戲大廳資訊太多了, 變成卡太大張 … 看看能有什麼可以讓一列有 2~3 個遊戲」→ 選 3 款。
   卡片只剩:遊戲圖(整張卡寬的正方形)+ 名稱 + 星星 + ☆ 收藏(貼在圖的右上角);app.js buildGameCard 已不再畫其他欄位。
   放在檔尾 → 蓋過上面那組大卡的舊規則(舊規則沒刪:改回大卡只要拿掉這一段)。 */
#view-lobby.view { padding: 12px 12px 48px; }
.lobby-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
.game-card { padding: 7px 7px 9px; border-radius: 14px; align-items: stretch; text-align: center; }
.game-card:hover { transform: translateY(-2px); }
.game-card .card-emoji-row { display: block; margin: 0; }
.game-card.wip .card-emoji-row, .game-card.demo .card-emoji-row { margin-top: 0; }
.game-card .card-emoji { width: 100%; height: auto; aspect-ratio: 1 / 1; flex: none; font-size: calc(13 * var(--vw)); }
.game-card .card-art { border-radius: 11px; }
.game-card .card-name { margin-top: 6px; font-size: 13.5px; line-height: 1.25;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.game-card .card-stars { justify-content: center; margin-top: 3px; font-size: 11px; }
.game-card .card-fav { top: 10px; right: 10px; bottom: auto; background: rgba(8,10,22,.55); border-radius: 999px; }
.game-card .card-redesign-tag { position: absolute; left: 10px; top: 10px; z-index: 4; pointer-events: none;
  font-size: 9.5px; font-weight: 800; line-height: 1; padding: 3px 6px; border-radius: 999px;
  color: #7ff0c4; background: rgba(6,32,26,.82); border: 1px solid rgba(127,240,196,.55); }   /* v4.99 取代 🎨 專屬符號圖標記 */
.game-card :is(.card-dev,.card-demo) { position: static; align-self: center; order: 9; margin-top: 5px;
  font-size: 9.5px; padding: 1px 6px; }
.game-card .card-detail { align-self: center; font-size: 9.5px; padding: 1px 6px; margin-top: 4px; }
#view-lobby > .lobby-docs { margin: 28px auto 8px; }   /* 搬到最下面:跟遊戲清單拉開一點 */

/* [Codex 2026-09-24] Mirror palace / eternal forge: separate scene and foreground. */
body[data-game="twin_mirror"] #view-game {
  --scene-ink:#111d34; --scene-rim:#d9c38a; --gold:#f8d788; --neon:#99d9f3;
  --scene-frame:url("../assets/games/twin_mirror/scene-frame.webp?h=fc19f6a9f7");
  background-image:url("../assets/games/twin_mirror/scene-background.webp?h=3022dee3f3");
  background-color:#101b30;
}
body[data-game="everfire"] #view-game {
  --scene-ink:#251910; --scene-rim:#bf8a43; --gold:#ffcf76; --neon:#ff9f4a;
  --scene-frame:url("../assets/games/everfire/scene-frame.webp?h=b83aed8c5a");
  background-image:url("../assets/games/everfire/scene-background.webp?h=c44ea163d1");
  background-color:#21150f;
}
body:is([data-game="twin_mirror"],[data-game="everfire"]) #view-game .machine { padding:46px 10% 38px; }
body:is([data-game="twin_mirror"],[data-game="everfire"]) #view-game .game-head { margin-bottom:42px; }
body:is([data-game="twin_mirror"],[data-game="everfire"]) #view-game .game-multbar {
  position:relative; inset:auto; width:100%; transform:none; margin:0 0 18px;
}
body:is([data-game="twin_mirror"],[data-game="everfire"]) #view-game .cell {
  border:1px solid #a1bfd421; border-radius:8px;
  background:linear-gradient(145deg,#14253b88,#07111d77);
  box-shadow:inset 0 1px #ffffff0a;
}
body[data-game="everfire"] #view-game .cell {
  background:linear-gradient(145deg,#40302388,#170e0a88); border-color:#da9c3f22;
}
body[data-game="twin_mirror"] #view-game .cell:is(.sym-WILD,.sym-SCATTER,.sym-MIRROR) {
  background:radial-gradient(ellipse,#58718a88,#14243755); border-color:#e7c66e88;
}
body[data-game="everfire"] #view-game .cell:is(.sym-fire,.sym-blast) {
  background:radial-gradient(ellipse,#b8522066,#3d1b1044); border-color:#ffa53799;
}
body[data-game="twin_mirror"] #view-game .cell:is(.sym-A,.sym-K,.sym-Q,.sym-J) .glyph.has-art { opacity:.65; filter:saturate(.35); }
body[data-game="everfire"] #view-game .cell:is(.sym-news,.sym-scroll,.sym-bamboo,.sym-book) .glyph.has-art { opacity:.72; filter:saturate(.5); }
body[data-game="twin_mirror"] #view-game .ui-multbar { background:linear-gradient(90deg,#164261,#282b40,#654723); border-color:#d7c895; }
body[data-game="everfire"] #view-game .ui-multbar { background:linear-gradient(#56291b,#271910); border-color:#bb7d40; }
body[data-game="twin_mirror"] #view-game .pad-spin:not(.auto) { background:linear-gradient(125deg,#b9edfa,#dfdbb2 55%,#dbaf5f); color:#15243c; }
body[data-game="everfire"] #view-game .pad-spin:not(.auto) { background:linear-gradient(145deg,#ffe4a0,#fba23d 55%,#b6551c); color:#3d1b0c; }
body:is([data-game="twin_mirror"],[data-game="everfire"]) #view-game .ui-pad { padding-bottom:26px; }
body[data-game="everfire"] #view-game .cell.ef-help { box-shadow:inset 0 0 0 2px #ffc46a,0 0 16px #fb7a28a0; }
body[data-game="twin_mirror"] #view-game .cell.sy-src { box-shadow:inset 0 0 0 2px #ffd282,0 0 12px #ffc35d99; }
body[data-game="twin_mirror"] #view-game .cell.sy-dst { outline:2px dashed #94e7ff; outline-offset:-3px; }

body[data-game="twin_mirror"] #view-game { --ft: 270; --fr: 225; --fb: 230; --fl: 225; --frame-iw: 1122; }
body[data-game="everfire"] #view-game { --ft: 250; --fr: 220; --fb: 290; --fl: 220; --frame-iw: 1122; }
body:is([data-game="twin_mirror"],[data-game="everfire"]) #view-game .machine { padding:82px 12% 65px; }

body[data-game="everfire"] #view-game .machine { padding:100px 15% 90px; }
