/* 爐火與麥酒 — 階段 0 前端樣式。溫暖酒館色調。 */

/* ── 像素字型（ADR-037 → ADR-090）──────────────────────────────────────
   俐方體 11 號（Cubic 11，https://github.com/ACh-K/Cubic-11），自行託管（CSP 是 font-src 'self'，外部 CDN 會被擋）。
   **授權**：SIL Open Font License 1.1 —— 可免費商用；跟著字型檔散布時要附授權檔（同資料夾的 Cubic_11-OFL.txt）；
   不能單獨賣字型檔；改過的字型不能沿用「Cubic / 俐方體」這個名字。
   以前用的 Zpix 商用要 USD $1000，換掉的原因之一。
   要換字型只改下面這一個 @font-face 與 --font-pixel 就好，其餘 CSS 都走變數。

   **字級必須是 12 的整數倍**（12 / 24 / 36）—— Cubic 11 衍生自 M⁺ gothic 12r：em 1200 單位、每個像素 100 單位，
   12px 時一單位剛好一個螢幕像素；非整數倍會讓筆畫落在半個像素上，整片糊掉。所以全站只有 12px 與 24px 兩級。
   12px 時：中文字寬 13px（字身 11px + 字距 2px，跟 Zpix 一樣）、英數比 Zpix 寬 1～2px、預設行高 14px（Zpix 12px）。
   收字約一萬字（常用國字、Big5 第一字面等），介面文字全部涵蓋；AI 講出很冷僻的字時會落到後面的備援字型。 */
@font-face {
  font-family: "Cubic 11";
  src: url("/fonts/Cubic_11.woff2") format("woff2");
  font-display: swap;
  font-weight: normal;
  font-style: normal;
}
:root {
  --bg: #211812;
  --panel: #2c2018;
  --panel-2: #34261c;
  --line: #45342610;
  --border: #4b3928;
  --ink: #f2e8d8;
  --ink-soft: #c3b199;
  --ink-faint: #8f7c64;
  --amber: #e0a64b;
  --amber-deep: #b4741f;
  --verd: #7bb39f;
  --system: #b79a6e;

  /* 換字型只要改這一行（連同上面的 @font-face）。後面備援是給字型還沒載完的那幾毫秒。 */
  --font-pixel: "Cubic 11", "Noto Sans TC", "Microsoft JhengHei", monospace;
  /* 9-slice 像素邊框：切片 6 來源像素，border-width 用 12px = 整數 2 倍放大 */
  --frame: url("/assets/ui_frame.png") 6 repeat;
  --frame-amber: url("/assets/ui_frame_amber.png") 6 repeat;
}

* { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0;
  background:
    radial-gradient(1200px 700px at 50% -10%, #3a2a1c 0%, var(--bg) 60%);
  color: var(--ink);
  font-family: var(--font-pixel);
  /* 像素字型絕對不能抗鋸齒 —— 一平滑就失去銳利的邊，整個效果就沒了 */
  -webkit-font-smoothing: none;
  -moz-osx-font-smoothing: grayscale;
  font-smooth: never;
}
.hidden { display: none !important; }

/* ---- 進場覆蓋層 ---- */
.overlay {
  position: fixed; inset: 0; display: grid; place-items: center;
  background: rgba(20, 14, 10, .72); z-index: 10;
}
.join-card {
  background: var(--panel); padding: 34px 30px; width: min(92vw, 420px);
  text-align: center; box-shadow: 0 6px 0 rgba(0,0,0,.5);
  border: 12px solid transparent; border-image: var(--frame);
  image-rendering: pixelated;
}
.join-card h1 { margin: 0 0 8px; font-size: 24px; color: var(--amber); letter-spacing: 2px; }
.join-sub { margin: 0 0 22px; color: var(--ink-soft); font-size: 12px; }
.join-form { display: flex; flex-direction: column; gap: 12px; }
input, button { font: inherit; }
.join-input, #chat-input {
  background: var(--panel-2); border: 2px solid var(--border); color: var(--ink);
 padding: 12px 14px; outline: none;
}
.join-input:focus, #chat-input:focus { border-color: var(--amber); }
.join-role { display: flex; flex-direction: column; gap: 5px; text-align: left; }
.join-role span { font-size: 12px; color: var(--ink-faint); }
#role { background: var(--panel-2); border: 2px solid var(--border); color: var(--ink);
 padding: 10px 12px; outline: none; }
#role:focus { border-color: var(--amber); }
button {
  cursor: pointer; border: none;  background: linear-gradient(180deg, var(--amber) 0%, var(--amber-deep) 100%);
  color: #2a1c0c; font-weight: 700; padding: 12px 16px; transition: filter .15s;
}
button:hover:not(:disabled) { filter: brightness(1.08); }
button:disabled { opacity: .45; cursor: not-allowed; }
.join-note { margin: 20px 0 0; font-size: 12px; color: var(--ink-faint); }
/* 「註冊」是次要動作：外框按鈕，不跟主要的「推開木門」搶視線（ADR-054） */
.join-secondary { background: transparent; color: var(--ink-soft); border: 2px solid var(--border); font-weight: 400; }
.join-secondary:hover:not(:disabled) { color: var(--amber); border-color: var(--amber); filter: none; }
#password-form + .join-or { margin-top: 18px; }
.google-btn { display: block; text-decoration: none; text-align: center; cursor: pointer;
  background: #fff; color: #3c4043; font-weight: 700; padding: 12px 16px;  margin-bottom: 14px; border: 1px solid #dadce0; }
.google-btn:hover { filter: brightness(.97); }
.join-or { font-size: 12px; color: var(--ink-faint); margin: 0 0 12px; position: relative; }

/* ---- 主畫面：像素酒館為主體，HUD 疊在上面 ---- */
.app { height: 100vh; display: flex; padding: 12px; }
.stage {
  /* min-width: 0 —— flex item 預設 min-width:auto 會被 .room 的固定 px 寬撐住，視窗縮小時容器就縮不了，
     SceneView.#fit 也就量不到新的可用寬度。 */
  --bar-t: 44px;   /* 頂欄高（SceneView.#fit 量實際 offsetHeight，這兩個變數只給浮動面板算 bottom 用） */
  --bar-b: 32px;   /* 底欄高 */
  position: relative; margin: auto; width: 100%; min-width: 0;
  display: flex; flex-direction: column;
  max-width: min(1060px, calc((100vh - 24px - var(--bar-t) - var(--bar-b)) * 1.5)); /* 依視窗高度上限，房間不會過高 */
}
#scene.scene { display: block; }

/* ---- 頂欄 / 底欄（ADR-058）：房間的「框」，深木色平面 + 像素邊線，不用模糊、不用圓角 ---- */
.topbar, .bottombar {
  display: flex; align-items: center; gap: 10px; flex: none;
  background: #2b1d16;
  box-shadow: inset 0 0 0 2px #150c08, inset 0 0 0 4px #4d2f28;   /* 外黑線 + 內木色線（實線，非模糊） */
  padding: 0 10px; color: var(--ink-soft); font-size: 12px; image-rendering: pixelated;
}
.topbar { height: var(--bar-t); margin-bottom: 6px; position: relative; }   /* 編輯器面板以頂欄為定位基準（貼房間左 / 右緣） */
.bottombar { height: var(--bar-b); margin-top: 6px; justify-content: space-between; }
.tb-left, .tb-right { display: flex; align-items: center; gap: 8px; flex: none; }
.tb-center { flex: 1 1 auto; min-width: 0; display: flex; justify-content: center; }
.tb-right { margin-left: auto; }

/* 頂欄 / 底欄裡的小標籤：統一成 chip（同高、同邊線），不再各自一套底色 */
.chip { display: inline-flex; align-items: center; gap: 6px; height: 24px; padding: 0 8px;
  background: #3a271e; color: var(--ink-soft); font-size: 12px; font-weight: 700; white-space: nowrap;
  box-shadow: inset 0 0 0 2px #150c08; border: 0; font-family: inherit; }
button.chip { cursor: pointer; }
button.chip:hover { filter: brightness(1.2); }
.brand { color: var(--amber); font-weight: 700; font-size: 12px; white-space: nowrap; }
.status { color: var(--ink-soft); }
.dot { width: 9px; height: 9px; background: var(--ink-faint); transition: background .2s; }
.dot.on { background: #6fbf73; box-shadow: 0 0 0 2px #6fbf7355; }
.dot.off { background: #cf5b4e; }
.dot.wait { background: var(--amber); }
/* 身分：class 用 role-* 前綴（曾經用 .admin 撞到系統管理面板的 .admin，ADR-058） */
.role-badge.role-admin { color: #2a1c0c; background: var(--amber); }
.role-badge.role-gm { color: #10241d; background: var(--verd); }
.role-badge.role-free { color: var(--ink-soft); }
.wallet-badge { color: var(--amber); }
.wallet-badge.claimable { cursor: pointer; background: var(--amber); color: #2a1c0c; }
.wallet-badge.claimable:hover { filter: brightness(1.1); }
.logout-btn { color: var(--ink-soft); }

/* 在場：頂欄只放「在場 N」按鈕，名單是往下掉的小面板（不再把整排擠爆） */
.presence { position: relative; }
.presence-h b { color: var(--ink); }
.presence-pop { position: absolute; right: 0; top: calc(100% + 6px); z-index: 30; min-width: 150px;
  list-style: none; margin: 0; padding: 8px 10px; display: flex; flex-direction: column; gap: 4px;
  background: rgba(20,14,10,.96); border: 12px solid transparent; border-image: var(--frame); image-rendering: pixelated; }
.presence-pop[hidden] { display: none; }
.presence li { font-size: 12px; display: flex; align-items: center; gap: 4px; }
.presence li .pv-name { flex: 1 1 auto; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.presence li.me { color: var(--verd); font-weight: 700; }
/* GM/Admin 的禁言 / 請離小按鈕 */
.presence li .pv-mod { flex: none; border: 0; background: transparent; cursor: pointer;
  display: flex; align-items: center; line-height: 1; padding: 1px 2px; opacity: .55; }
.presence li .pv-mod:hover { opacity: 1; background: rgba(255,255,255,.1); }

/* 房間（ADR-097）：.room-frame = 上方多畫的一段北牆（.room-wall-top）+ 房間本體（.room = 網格）。
   尺寸由 SceneView.#fit 以「整數像素格 × 格數」設成 px（content-box，邊框另加）；
   這裡的 width / aspect-ratio 只是 #fit 還沒跑（容器未佈局）時的百分比備援。
   外框負責裁切：.room 本身不裁，高的家具、頭上的泡泡可以伸進上方那段牆。 */
.room-frame {
  /* ADR-100：不再有 3px 的 CSS 邊框——畫面最外圈只留 Cozy 收邊木條（.room-trim inset:0）。
     使用者：「原始產品包是用來框在畫面最外面的」。SceneView 的 ROOM_BORDER 跟著改 0。 */
  position: relative; box-sizing: content-box; margin: 0 auto;
  width: 100%;
  overflow: hidden;
  box-shadow: 0 6px 0 rgba(0,0,0,.5);
}
/* 牆頂上方的留空（ADR-116）：什麼都不畫（牆後面的暗處），高的家具圖往上長到這裡不會被切掉。 */
.room-headroom { aspect-ratio: var(--ar-head); height: var(--headroom-h, auto); }
.room-headroom[hidden] { display: none; }
.room-wall-top {
  aspect-ratio: var(--ar-top); height: var(--wall-extra-h, auto);
  /* 加高那段用牆面素材的「上段」（ADR-116，木裙板牆接純石牆），沒有就用同一張 */
  background-image: var(--wall-upper, var(--wall)); background-size: var(--wx) var(--wy); background-position: left bottom;
  image-rendering: pixelated;
  box-shadow: inset 0 18px 24px -12px rgba(0,0,0,.45);   /* 牆頂往上漸暗，像天花板的陰影 */
}
.room-wall-top[hidden] { display: none; }
/* 室外（ADR-130）：沒有牆 —— 地板鋪滿整個網格（--wall-*-px 全是 0），不畫室內的木條收邊與南牆下緣的陰影；
   四邊輕輕壓暗一圈，讓地面有邊界感，不像被裁掉。 */
.room-frame.outdoor .room { background-image: none; box-shadow: inset 0 0 36px -6px rgba(0,0,0,.45); }
.room-frame.outdoor .room-trim { display: none; }
.room {
  position: relative; box-sizing: content-box;
  width: 100%; aspect-ratio: var(--ar);
  background-image: var(--wall); background-size: var(--wx) var(--wy);
  image-rendering: pixelated;
  /* 以前四邊內陰影；上緣現在接著上方那段北牆，四邊都壓暗會在交界出現一條暗縫，所以只壓南牆的下緣 */
  box-shadow: inset 0 -24px 30px -18px rgba(0,0,0,.45);
}
.floor-layer {
  /* 內縮牆帶：北 / 南各一個瓷磚、左右 0（ADR-097；一格 16px，ADR-063） */
  position: absolute;
  left: var(--wall-side-px); right: var(--wall-side-px); top: var(--wall-top-px); bottom: var(--wall-bottom-px);
  background-image: var(--floor); background-size: var(--fx) var(--fy); image-rendering: pixelated;
}
/* 邊框（ADR-097 自動畫；ADR-099 改用 Cozy 材質包的收邊圖，使用者：「我挺喜歡 cozy 的邊框」）。
   收邊圖是一個瓷磚一張（32×32，木條貼在其中一邊），所以跟地板一樣照瓷磚鋪：四條邊沿著地板外圈重複，四個角蓋在最上層。
   背景清單**前面的畫在上面** → 角放最前面。檔名跟圖的方向對不上（ADR-057 轉檔時的命名），以圖為準：
     c_down_left = ┌、c_down_right = ┐、c_up_left = └、c_up_right = ┘、down_left / down_right = 左 / 右直條。
   材質包若拿掉，這裡要換回自己的邊框（git 裡 ADR-097 的 room_trim.png + border-image 版本）。 */
.room-trim {
  /* ADR-100：框整個場景外緣（連北 / 南牆帶一起框），不是地板範圍——以前夾在牆與地板之間，看起來像「框在牆內」。
     木條壓在最外一排格子上，會蓋住牆面 / 左右地板約 3～4px；角色站到最邊時木條在腳下（家具層之下）。 */
  position: absolute; pointer-events: none; inset: 0;
  top: calc(-1 * var(--wall-extra-px, 0px));   /* 框到加高那段北牆的頂端（ADR-116），不框牆頂上方的留空 */
  background-image:
    url("/assets/cozy_trim_c_down_left.png"), url("/assets/cozy_trim_c_down_right.png"),
    url("/assets/cozy_trim_c_up_left.png"), url("/assets/cozy_trim_c_up_right.png"),
    url("/assets/cozy_trim_top.png"), url("/assets/cozy_trim_bottom.png"),
    url("/assets/cozy_trim_down_left.png"), url("/assets/cozy_trim_down_right.png");
  background-position: left top, right top, left bottom, right bottom, left top, left bottom, left top, right top;
  background-repeat: no-repeat, no-repeat, no-repeat, no-repeat, repeat-x, repeat-x, repeat-y, repeat-y;
  background-size: var(--wx) var(--wy);
  image-rendering: pixelated;
}
.room { cursor: pointer; }   /* 點哪走哪（ADR-049）；編輯模式改成 crosshair */
.room .sprite { position: absolute; image-rendering: pixelated; transition: filter .25s; }
.room .sprite.off { filter: brightness(.32) saturate(.35); }   /* 家具被「關掉」（燈 / 爐火熄了） */
/* sprite sheet 動畫（ADR-110）：外框 = 一格（裁切），裡面整條直排影格條用 translate 往上推、steps(N) 一格一格跳。
   為什麼不用 background-position 百分比：那是以「容器 − 圖」為基準，算不到格子邊界；translate 自己的高度 −100% ÷ N 剛好一格。
   animation 由 JS 寫在 img 上（時長 = 每格 ms × 格數、steps(格數)）。 */
.room .sprite-anim { overflow: hidden; }
.room .sprite-anim > img { position: absolute; left: 0; top: 0; width: 100%; height: auto; image-rendering: pixelated; will-change: transform; }
@keyframes sprite-sheet { to { translate: 0 -100%; } }       /* 直排：往上推 */
@keyframes sprite-sheet-h { to { translate: -100% 0; } }     /* 橫排（材質包慣例 spr_xxx_stripN）：往左推（ADR-112） */
@media (prefers-reduced-motion: reduce) { .room .sprite-anim > img { animation: none !important; } }
/* 調色盤縮圖：sprite sheet 只看第一格（正方形框、cover；對齊左或上由 JS 依橫直排設） */
.ed-item-sheet { object-fit: cover; object-position: left top; }
/* 逐格表面覆蓋層：在地板 / 牆之上、家具之下；不吃點擊 */
.tile-layer { position: absolute; inset: 0; pointer-events: none; }
.tile-layer .tile { position: absolute; image-rendering: pixelated; }
/* 家具層：整層可重畫；不吃點擊，讓編輯時點擊穿透到房間格子 */
.furniture-layer { position: absolute; inset: 0; pointer-events: none; }
/* 編輯中：房間加一圈提示外框 */
.room.editing { outline: 3px dashed var(--amber); outline-offset: -3px; cursor: crosshair; }
/* 旋轉預覽（ADR-100）：游標框裡放一張半透明的家具圖，套上目前的旋轉 / 翻面；紅框時也畫（看得出為什麼放不下） */
.grid-cursor-img { position: absolute; opacity: .6; image-rendering: pixelated; pointer-events: none; }
.grid-cursor-img[hidden] { display: none; }

/* 編輯用網格＋游標格：只有編輯模式顯示（不吃點擊） */
.grid-layer { position: absolute; inset: 0; pointer-events: none; display: none; z-index: 5; }
/* 場景光照（ADR-038）：一張很小的 canvas 拉大鋪滿房間。
   z-index 6 = 蓋得住角色（走進暗處人也會暗），但在對話氣泡（8）與 HUD 之下。
   pixelated 是重點 —— 低解析度 + 最近鄰放大才會是一格一格的光，不是柔光。 */
.light-layer {
  /* 往上多蓋一段：上方多畫的北牆也要跟著暗、被壁燈照亮（ADR-097；SceneView 把光源往下挪同樣格數） */
  position: absolute; left: 0; right: 0; bottom: 0; width: 100%;
  top: calc(-1 * var(--above-px, 0px)); height: calc(100% + var(--above-px, 0px));   /* 連牆頂上方的留空一起（ADR-116） */
  pointer-events: none; z-index: 6; image-rendering: pixelated;
}
.light-layer[hidden] { display: none; }
.room.editing .grid-layer {
  display: block;
  background-image:
    linear-gradient(to right, rgba(224,166,75,.30) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(224,166,75,.30) 1px, transparent 1px);
  background-size: var(--cw) var(--ch);
}
/* 加高的那段北牆也畫網格線（ADR-117：靠牆家具 / 疊放物可以擺進去）。用偽元素補在上面 ——
   不能把 .grid-layer 本身往上拉：游標框是用百分比相對它定位的。 */
.room.editing .grid-layer::before {
  content: ""; position: absolute; left: 0; right: 0;
  top: calc(-1 * var(--wall-extra-px, 0px)); height: var(--wall-extra-px, 0px);
  background-image: inherit; background-size: inherit; background-position: left bottom;
}
.grid-cursor { position: absolute; display: none; pointer-events: none;
  background: rgba(224,166,75,.22); box-shadow: inset 0 0 0 2px var(--amber); }
/* 佔位預覽（ADR-083）：游標 = 整件家具佔的格子。綠 = 放得下、紅 = 會被擋（原因寫在框上）、
   紅框淡底 = 這一下會移除的那件。顏色沿用 HUD 的連線燈號，不另立一套。 */
.grid-cursor.ok     { background: rgba(111,191,115,.22); box-shadow: inset 0 0 0 2px #6fbf73; }
.grid-cursor.bad    { background: rgba(207,91,78,.28);   box-shadow: inset 0 0 0 2px #cf5b4e; }
.grid-cursor.remove { background: rgba(207,91,78,.14);   box-shadow: inset 0 0 0 2px #cf5b4e; }
.grid-cursor.bad:not([data-reason=""])::after {
  content: attr(data-reason);
  position: absolute; top: 2px; left: 50%; transform: translateX(-50%);
  background: #cf5b4e; color: #fff; font-size: 12px; line-height: 1; padding: 3px 6px; white-space: nowrap;
}

/* 反應式場景：說書時整個房間調暗＋暖色暈邊（角色仍亮，見 .char z-index） */
.room::after {
  content: ""; position: absolute; inset: 0; top: calc(-1 * var(--above-px, 0px)); pointer-events: none; z-index: 1;
  background:
    radial-gradient(130% 95% at 50% 62%, transparent 28%, rgba(9,5,2,.6) 100%),
    rgba(9,5,2,.26);
  opacity: 0; transition: opacity .8s ease;
}
.room.dimmed::after { opacity: 1; }

/* 角色 */
/* 位置走 translate：只走合成器，不像 left/top 每幀觸發 layout（ADR-030）。
   **沒有 transition** —— CSS 的插值是連續的，會路過一堆次像素位置；
   走路改由 SceneView 的 rAF 迴圈自己算並量化成整數 px（ADR-049）。*/
.char { position: absolute; z-index: 3; }
.char.me { z-index: 4; }
/* 角色不畫任何陰影（ADR-060 拿掉 drop-shadow；ADR-093 連精靈圖裡的腳邊壓暗、暖暖的影子光暈也拿掉，使用者：「在場景內反而很怪」）。
   精靈圖由 tools/gen_chars.py 產生，40×56、跟家具同一個像素密度。
   .char-img 是一張 40×56 的 <canvas>，SceneView 把影格表裡該播的那一格畫上去（ADR-096），這裡只負責拉大。 */
.char-img { display: block; width: 100%; height: 100%; image-rendering: pixelated; }
/* 朝向由 JS 直接設 .char-img 的 inline transform（scaleX(±1)）——這是 .char-img 上唯一的 transform。 */

/* 坐下：角色定位在椅子格上，影格換成坐姿那一行（ADR-096）；名牌淡一點。 */
.char.seated .char-name { opacity: .7; }

/* 「點一下坐下 / 起身」提示：浮在目標家具上方的像素小標 */
.interact-prompt {
  position: absolute; z-index: 8; pointer-events: none;
  transform: translate(-50%, -115%);
  background: #f3ead6; color: #241a10;
  font-size: 12px; font-weight: 700; line-height: 1;
  padding: 3px 6px; white-space: nowrap; image-rendering: pixelated;
  box-shadow:
    0 -3px 0 #241a10, 0 3px 0 #241a10, -3px 0 0 #241a10, 3px 0 0 #241a10,
    3px 5px 0 rgba(0,0,0,.3);
}

/* ---- 賭桌開獎動畫（SceneView.updateGame 依 gameId 分流；浮在桌子中央，不吃點擊） ---- */
/* 骰盅：三顆骰子。rolling 抖動 + 點數亂跳；result 定住顯示點數。 */
.dice-fx { position: absolute; z-index: 9; pointer-events: none; display: flex; gap: 4px;
  transform: translate(-50%, -50%); }
.dice-fx .die { width: 14px; height: 14px; background: #f6f1e4; color: #241a10; text-align: center;
  font: 700 10px/14px ui-monospace, monospace; image-rendering: pixelated;
  box-shadow: 0 -2px 0 #241a10, 0 2px 0 #241a10, -2px 0 0 #241a10, 2px 0 0 #241a10, 2px 4px 0 rgba(0,0,0,.35); }
.dice-fx.rolling .die { animation: die-shake .16s steps(2, end) infinite; }
.dice-fx.rolling .die:nth-child(2) { animation-delay: .05s; }
.dice-fx.rolling .die:nth-child(3) { animation-delay: .1s; }
.dice-fx.settled .die { animation: die-land .35s ease-out; }
@keyframes die-shake { 0% { transform: translate(-1px, -7px) rotate(-10deg); } 100% { transform: translate(1px, 0) rotate(10deg); } }
@keyframes die-land { 0% { transform: translateY(-10px); } 60% { transform: translateY(2px); } 100% { transform: translateY(0); } }

/* 輪盤：轉盤（37 格 conic-gradient，JS 產生）+ 指針（小球 ADR-106 拿掉了：指針已經指出落點）。
   rolling 期間 JS 每幀加角度（不用 CSS animation，避免切到落點時跳一下）；
   result 時把最終角度設成「落在開出號碼 + 兩圈」並開 transition，慢慢減速停住，再亮出號碼。 */
.wheel-fx { position: absolute; z-index: 9; pointer-events: none; transform: translate(-50%, -50%); }
/* .wheel 是一顆 SVG（號碼 / 分隔線 / 外圈 / 轂都畫在裡面），整顆轉；陰影用 drop-shadow 才會跟著圓形。 */
.wheel-fx .wheel { display: block; width: 100%; height: 100%; overflow: visible;
  filter: drop-shadow(0 4px 0 rgba(0,0,0,.35)); will-change: transform; transform-origin: 50% 50%; }
.wheel-fx.landing .wheel { transition: transform 1.4s cubic-bezier(.1, .8, .2, 1); }
.wheel-fx .pin { position: absolute; left: 50%; top: -3px; transform: translateX(-50%); width: 0; height: 0;
  border-left: 5px solid transparent; border-right: 5px solid transparent; border-top: 9px solid #f3ead6;
  filter: drop-shadow(0 1px 0 #241a10) drop-shadow(1px 0 0 #241a10) drop-shadow(-1px 0 0 #241a10); }
.wheel-fx .num { position: absolute; left: 50%; bottom: 100%; transform: translate(-50%, -8px);
  background: #f3ead6; color: #241a10; font-size: 12px; font-weight: 700; line-height: 1;
  padding: 3px 6px; white-space: nowrap; image-rendering: pixelated; opacity: 0;
  box-shadow: 0 -3px 0 #241a10, 0 3px 0 #241a10, -3px 0 0 #241a10, 3px 0 0 #241a10, 3px 5px 0 rgba(0,0,0,.3); }
.wheel-fx .num.red { color: #a8261f; }
.wheel-fx .num.green { color: #1f6b3a; }
.wheel-fx.settled .num { opacity: 1; animation: die-land .35s ease-out; }

/* 上桌者視角（.big）：動畫放大到房間中央，房間打暗成聚光燈（.room.spotlight；說書的 .dimmed 優先）。 */
.room.spotlight:not(.dimmed)::after { opacity: .55; }
.dice-fx.big { gap: 14px; }
.dice-fx.big .die { width: 44px; height: 44px; font: 700 30px/44px ui-monospace, monospace;
  box-shadow: 0 -4px 0 #241a10, 0 4px 0 #241a10, -4px 0 0 #241a10, 4px 0 0 #241a10, 5px 8px 0 rgba(0,0,0,.35); }
.wheel-fx.big .wheel { filter: drop-shadow(0 8px 0 rgba(0,0,0,.35)); }
.wheel-fx.big .pin { top: -6px; border-left-width: 9px; border-right-width: 9px; border-top-width: 16px; }
.wheel-fx.big .num { font-size: 24px; padding: 6px 12px; transform: translate(-50%, -12px);
  box-shadow: 0 -4px 0 #241a10, 0 4px 0 #241a10, -4px 0 0 #241a10, 4px 0 0 #241a10, 4px 7px 0 rgba(0,0,0,.3); }

/* 一次性反應動畫（發話 / 表演）。動的是 .char 外框的 `transform`；位置走的是獨立的 `translate` 屬性，
   兩者相乘疊加、不會互相蓋掉（這正是位置改用 translate 而非 transform 的原因）。 */
.char.speaking { animation: npc-speak .5s steps(3, end); }
.char.emote { animation: npc-emote .7s ease-out; }
.char.perform { animation: npc-perform 1.6s ease-out; }
.char.perform .char-img { filter: drop-shadow(2px 0 0 var(--amber)) drop-shadow(-2px 0 0 var(--amber)) drop-shadow(0 -2px 0 var(--amber)) drop-shadow(0 2px 0 var(--amber)); }
@keyframes npc-speak { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-7%); } }
@keyframes npc-emote { 0%, 100% { transform: translateY(0); } 35% { transform: translateY(-14%); } }
@keyframes npc-perform { 0% { transform: translateY(0); } 18% { transform: translateY(-18%); } 45% { transform: translateY(-6%); } 100% { transform: translateY(0); } }
.char-name {
  position: absolute; left: 50%; transform: translateX(-50%); bottom: -12px;
  font-size: 12px; line-height: 1; white-space: nowrap; color: var(--ink-soft);
  background: rgba(20,14,10,.72); padding: 2px 4px; pointer-events: none;
}
.char.me .char-name { color: var(--verd); font-weight: 700; }
.char.other .char-name { color: #8fb7e6; } /* 其他玩家：淡藍名牌，與 NPC、自己區隔 */

/* 頭上像素對話氣泡
   造型全靠 clip-path 切出「階梯狀」輪廓：四角是 2 階台階（像素化的半圓弧），
   底部中央是 2 階的像素尖角（指向角色）。深色外框不用 border（會被 clip-path 切掉），
   改用一疊 0 模糊、8 方向的 drop-shadow —— 它沿著裁切後的形狀描一圈等寬像素邊，
   連尖角與台階都描得到；最後一個 drop-shadow 是右下的硬陰影。
   6px = 2 個像素格；12px = 角落(6)＋尖角(6)。 */
.bubble {
  position: absolute; left: 50%; bottom: 100%; transform: translateX(-50%);
  margin-bottom: 6px; z-index: 30; pointer-events: none;
  background: #f3ead6; color: #241a10;
  padding: 5px 9px 12px;            /* 底部留白讓文字避開 6px 高的尖角區 */
  font-size: 12px; line-height: 1.3;
  width: max-content; min-width: 34px; max-width: 150px;
  text-align: center; word-break: break-word;
  image-rendering: pixelated;
  clip-path: polygon(
    6px 0, calc(100% - 6px) 0,
    calc(100% - 6px) 3px, calc(100% - 3px) 3px, calc(100% - 3px) 6px, 100% 6px,
    100% calc(100% - 12px),
    calc(100% - 3px) calc(100% - 12px), calc(100% - 3px) calc(100% - 9px),
    calc(100% - 6px) calc(100% - 9px), calc(100% - 6px) calc(100% - 6px),
    calc(50% + 6px) calc(100% - 6px), calc(50% + 6px) calc(100% - 3px),
    calc(50% + 3px) calc(100% - 3px), calc(50% + 3px) 100%,
    calc(50% - 3px) 100%, calc(50% - 3px) calc(100% - 3px),
    calc(50% - 6px) calc(100% - 3px), calc(50% - 6px) calc(100% - 6px),
    6px calc(100% - 6px),
    6px calc(100% - 9px), 3px calc(100% - 9px), 3px calc(100% - 12px), 0 calc(100% - 12px),
    0 6px, 3px 6px, 3px 3px, 6px 3px
  );
  filter:
    drop-shadow(3px 0 0 #241a10) drop-shadow(-3px 0 0 #241a10)
    drop-shadow(0 3px 0 #241a10) drop-shadow(0 -3px 0 #241a10)
    drop-shadow(3px 3px 0 #241a10) drop-shadow(-3px 3px 0 #241a10)
    drop-shadow(3px -3px 0 #241a10) drop-shadow(-3px -3px 0 #241a10)
    drop-shadow(4px 6px 0 rgba(0,0,0,.32));
  animation: bubblein .12s steps(3, end);
}
.bubble.me { background: #d8efe2; }
.bubble.fade { opacity: 0; transition: opacity .3s steps(4, end); }
@keyframes bubblein {
  from { opacity: 0; transform: translateX(-50%) translateY(3px); }
  to   { opacity: 1; transform: translateX(-50%) translateY(0); }
}

/* HUD 疊層 */
/* （舊的浮動 HUD 藥丸 .hud / .hud-tl / .hud-tr 已由頂欄 / 底欄取代，ADR-058） */

/* 左下內嵌對話框 */
.chat-overlay {
  position: absolute; left: 12px; bottom: calc(var(--bar-b) + 12px); z-index: 20;
  width: min(370px, 48%); display: flex; flex-direction: column; gap: 8px;
  background: rgba(20,14,10,.62);  padding: 10px;
  border: 12px solid transparent; border-image: var(--frame);
  image-rendering: pixelated;
}
/* 標題列：收合 / 展開。收合時只剩這列 + 輸入框（訊息列表 display:none），房間左下不會被蓋住。 */
.chat-head { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--ink-soft); }
.chat-head-title { font-weight: 700; color: var(--amber); }
.chat-unread { min-width: 18px; padding: 1px 6px; text-align: center;
  font-size: 12px; font-weight: 700; color: #2a1c0c; background: var(--amber); }
.chat-toggle { margin-left: auto; padding: 3px 9px; font-size: 12px; font-weight: 600;
  background: rgba(255,255,255,.06); color: var(--ink-soft); border: 1px solid var(--border); }
.chat-toggle:hover { color: var(--ink); }
.chat-overlay.collapsed .messages { display: none; }
/* 裝潢中整個收起（ADR-085）：收合後的標題列 + 輸入框仍會蓋住房間左下角，那些格子點不到 */
.chat-overlay.suspended { display: none; }
.messages { max-height: 30vh; min-height: 60px; overflow-y: auto; display: flex;
  flex-direction: column; gap: 6px; padding-right: 2px; }
.msg { max-width: 90%; padding: 6px 10px; line-height: 1.45; font-size: 12px; word-break: break-word; }
.msg .who { font-size: 12px; color: var(--amber); font-weight: 700; margin-bottom: 1px; }
.msg.player { align-self: flex-start; background: var(--panel-2); border: 1px solid var(--border); }
.msg.me { align-self: flex-end; background: #43331f; border: 1px solid var(--amber-deep); }
.msg.me .who { color: var(--verd); }
.msg.system { align-self: center; max-width: 96%; background: transparent; color: var(--system);
  font-size: 12px; font-style: italic; padding: 1px 6px; }
.msg.npc { align-self: flex-start; background: #302636; border: 1px solid #4f4060; }
.msg.npc .who { color: #c3a8e6; }
.msg.npc.perform { border-left: 3px solid var(--amber); }
/* 輸入框 min-width:0 —— <input> 的 flex 最小寬是「size=20 個字」，字型一寬（像素字型沒載到、系統字型較寬）
   就把送出鈕擠出框外、鈕還折成兩行（ADR-062 修）。鈕固定寬、不折行。 */
.chat-form { display: flex; gap: 8px; }
.chat-form #chat-input { flex: 1 1 0; min-width: 0; font-size: 12px; }   /* 12 的倍數：Cubic 11 不糊（ADR-101） */
.chat-form button { flex: none; white-space: nowrap; padding: 8px 12px; }

/* 裝潢編輯器（管理員限定，上方置中） */
/* 編輯器住在頂欄中央；切換鈕在欄內，調色盤面板往下掉、蓋在房間上 */
.editor { display: flex; flex-direction: column; align-items: center; }
.ed-toggle { background: linear-gradient(180deg, var(--amber) 0%, var(--amber-deep) 100%);
  color: #2a1c0c; font-weight: 700; padding: 7px 14px; font-size: 12px; }
.ed-toggle.on { background: #3a2c1a; color: var(--amber); box-shadow: inset 0 0 0 1px var(--amber-deep); }
/* 面板停靠在房間左緣（預設）或右緣（.dock-right），不擋中間——擋在正中央會點不到中間的格子（ADR-061）。
   定位基準是 .topbar（position: relative），所以 left:0 / right:0 就是房間的左右緣。 */
.ed-body { position: absolute; top: calc(100% + 10px); left: 0; z-index: 25;
  background: rgba(20,14,10,.9);  padding: 10px; box-shadow: 0 4px 0 rgba(0,0,0,.5);
  border: 12px solid transparent; border-image: var(--frame);
  image-rendering: pixelated;
}
.ed-body.dock-right { left: auto; right: 0; }
.ed-dock-row { display: flex; justify-content: flex-end; margin-bottom: 6px; }
.ed-dock-btn { background: var(--panel-2); color: var(--ink-soft); border: 2px solid var(--border);
  font-family: inherit; font-size: 12px; padding: 2px 8px; cursor: pointer; }
.ed-dock-btn:hover { border-color: var(--amber-deep); }
.ed-tabs { display: flex; gap: 4px; margin-bottom: 8px; }
.ed-tab { flex: 1; background: var(--panel-2); color: var(--ink-soft); border: 2px solid var(--border);
 padding: 5px 6px; font-size: 12px; font-weight: 700; }
.ed-tab:hover { border-color: var(--amber-deep); }
.ed-tab.on { background: #43331f; color: var(--ink); border-color: var(--amber); }
.ed-palette { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; align-content: start; }   /* 固定高度時格子不要被撐高 */
/* 調色盤換頁列（ADR-120）：素材多了不再把面板往下撐爆，一頁固定 3 排 */
.ed-pager { display: flex; align-items: center; justify-content: center; gap: 10px; margin-top: 6px; }
.ed-pager[hidden] { display: none; }
.ed-pager-btn { background: var(--panel-2); color: var(--ink-soft); border: 2px solid var(--border);
  font-family: inherit; font-size: 12px; font-weight: 700; min-width: 32px; padding: 2px 8px; cursor: pointer; }
.ed-pager-btn:hover:not(:disabled) { border-color: var(--amber-deep); color: var(--ink); }
.ed-pager-btn:disabled { opacity: .35; cursor: default; }
.ed-pager-label { font-size: 12px; color: var(--ink-soft); min-width: 72px; text-align: center; }
/* 精簡模式（ADR-062）：選定素材後把頁籤 / 調色盤 / 上傳收起來，只留「目前拿著什麼」+ 朝向 + 完成鈕，
   面板變矮、名稱完整顯示（調色盤格子太窄，長名稱只看得到前兩個字）。按「完成」回到調色盤。 */
.ed-body.compact .ed-tabs, .ed-body.compact .ed-palette, .ed-body.compact .ed-pager, .ed-body.compact .ed-upload,
.ed-body.compact .ed-dock-row { display: none; }
.ed-current { display: none; align-items: center; gap: 8px; min-width: 240px; }
.ed-body.compact .ed-current { display: flex; }
.ed-current-img { width: 30px; height: 30px; object-fit: contain; image-rendering: pixelated; flex: none; }
.ed-current-name { flex: 1 1 auto; min-width: 0; font-size: 12px; color: var(--ink); }
.ed-current-done { flex: none; background: var(--panel-2); color: var(--amber); border: 2px solid var(--amber-deep);
  font-family: inherit; font-size: 12px; font-weight: 700; padding: 3px 10px; cursor: pointer; }
.ed-current-done:hover { filter: brightness(1.15); }
.ed-orient { display: flex; align-items: center; gap: 6px; margin-top: 8px; }
.ed-orient-btn { background: var(--panel-2); color: var(--ink-soft); border: 2px solid var(--border);
 padding: 5px 10px; font-size: 12px; font-weight: 700; }
.ed-orient-btn:hover { border-color: var(--amber-deep); }
.ed-orient-btn.on { border-color: var(--amber); background: #43331f; color: var(--ink); }
.ed-orient-state { font-size: 12px; color: var(--ink-faint); margin-left: auto; }
.ed-orient-sep { width: 2px; height: 18px; background: var(--border); margin: 0 4px; }   /* 整片｜逐格 與 旋轉｜翻面 之間 */
.ed-item { display: flex; flex-direction: column; align-items: center; gap: 3px;
  background: var(--panel-2); border: 2px solid var(--border);  padding: 6px 4px 4px; width: 62px; color: var(--ink-soft); }
.ed-item:hover { border-color: var(--amber-deep); }
.ed-item.on { border-color: var(--amber); background: #43331f; color: var(--ink); }
.ed-item-img { width: 30px; height: 30px; object-fit: contain; image-rendering: pixelated; transition: transform .12s; }
.ed-item-x { width: 30px; height: 30px; display: grid; place-items: center; font-size: 12px; color: #cf5b4e; }
/* 名稱最多兩行（「高腳凳 · Cozy」折成兩行），超過才截；不再一行就「…」（ADR-064） */
.ed-item-cap { font-size: 12px; line-height: 1.15; text-align: center; max-width: 100%; overflow: hidden;
  white-space: normal; word-break: break-all; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.ed-item.erase, .ed-item.tool { grid-column: 1 / -1; width: auto; flex-direction: row; justify-content: center; }
.ed-item.erase .ed-item-x, .ed-item.tool .ed-item-x { width: 20px; height: 20px; font-size: 12px; }
.ed-item.tool .ed-item-x { color: var(--verd); }
.ed-hint { margin: 8px 2px 0; font-size: 12px; color: var(--ink-faint); text-align: center; max-width: 320px; }
/* 裝潢動作被伺服器擋下時的提示（showReject）：琥珀色、稍微顯眼，幾秒後自動還原。 */
.ed-hint.reject { color: var(--amber); font-weight: 600; }

.ed-upload { margin-top: 8px; border-top: 1px solid var(--border); padding-top: 8px; }
.ed-upload-toggle { display: block; box-sizing: border-box; text-align: center; text-decoration: none;
 color: var(--ink-soft); border: 1px dashed var(--border); padding: 4px 10px; font-size: 12px; font-weight: 700; width: 100%; }
.ed-upload-toggle:hover { border-color: var(--amber-deep); color: var(--ink); }

.move-hint { font-size: 12px; color: var(--ink-faint); pointer-events: none; }

/* 系統管理面板（Admin） —— 住在底欄右側，面板往上展開、蓋在房間上 */
.admin { position: relative; z-index: 26; display: flex; flex-direction: column; align-items: flex-end; }
.adm-body { position: absolute; right: 0; bottom: calc(100% + 10px); }
.adm-toggle { background: linear-gradient(180deg, var(--amber) 0%, var(--amber-deep) 100%);
  color: #2a1c0c; font-weight: 700; padding: 7px 14px; font-size: 12px; }
.adm-body { width: 320px; max-height: 50vh; overflow-y: auto;
  background: rgba(20,14,10,.92);  padding: 10px; box-shadow: 0 4px 0 rgba(0,0,0,.5);
  border: 12px solid transparent; border-image: var(--frame);
  image-rendering: pixelated;
}
.adm-bar { display: flex; gap: 4px; margin-bottom: 6px; }
.adm-search { flex: 1; min-width: 0; background: var(--panel-2); color: var(--ink);
  border: 2px solid var(--border); padding: 4px 6px; font-size: 12px; }
.adm-reload { background: var(--panel-2); color: var(--ink-soft);
  border: 2px solid var(--border); padding: 4px 9px; font-size: 12px; }
.adm-status { margin: 2px 0 6px; font-size: 12px; color: var(--ink-faint); }
.adm-list { display: flex; flex-direction: column; gap: 4px; }
.adm-row { display: flex; align-items: center; gap: 6px; padding: 4px 6px;
  background: var(--panel-2); }
.adm-meta { flex: 1; min-width: 0; }
.adm-name { font-size: 12px; color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.adm-id { font-size: 12px; color: var(--ink-faint);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.adm-sub { flex: none; display: inline-flex; align-items: center; gap: 4px; font-size: 12px; color: var(--ink-soft); }
.adm-sub-date { background: var(--panel); color: var(--ink); border: 2px solid var(--border); font-family: inherit; font-size: 12px; padding: 2px 4px; }
.adm-role { flex: none; background: var(--panel); color: var(--ink);
  border: 2px solid var(--border); padding: 3px 4px; font-size: 12px; }
/* 後台分頁：帳號 / AI 用量（ADR-033） */
.adm-tabs { display: flex; gap: 4px; margin-bottom: 8px; }
.adm-tab { flex: 1; background: var(--panel-2); color: var(--ink-faint);
  border: 2px solid var(--border); padding: 4px 6px; font-size: 12px; }
.adm-tab.on { background: var(--panel); color: var(--ink); border-color: var(--amber); }
/* AI 用量面板：今天的花費放大當標題，token 三欄並排，下面是分桶與前幾天 */
.adm-usage { display: flex; flex-direction: column; gap: 4px; }
.adm-usage-head { text-align: center; padding: 6px 0 2px; }
.adm-usage-cost { font-size: 24px; font-weight: 700; color: var(--amber); line-height: 1.1; }
.adm-usage-sub { font-size: 12px; color: var(--ink-faint); }
.adm-usage-toks { display: flex; gap: 4px; margin: 6px 0 2px; text-align: center; }
.adm-usage-toks > div { flex: 1; min-width: 0; background: var(--panel-2);
 padding: 5px 2px; }
.adm-usage-tok { font-size: 12px; color: var(--ink); }
.adm-usage-h { font-size: 12px; color: var(--ink-soft); margin: 8px 0 2px;
  border-bottom: 1px solid var(--border); padding-bottom: 3px; }
.adm-usage-rowcost { flex: none; font-size: 12px; color: var(--amber); }
/* 預算條：滿了轉紅，跟「NPC 已降級成劇本模式」對應 */
.adm-budget { height: 6px; background: var(--panel-2); overflow: hidden; }
.adm-budget-fill { height: 100%; background: var(--amber); }
.adm-budget.over .adm-budget-fill { background: #c0392b; }
/* 傳送門的門標記：貼在門所在格，暖色微光讓玩家看得出「這裡可以踩」 */
/* ── 傳送門：像素 sprite（ADR-036，取代 ADR-035 的 CSS 漸層版）────────────
   為什麼不再用 CSS 漸層：漸層是**向量**的 —— 就算用硬色停做出分明的色階，橢圓外框仍然是
   平滑曲線、色帶仍然是連續的，放大只會更平滑，永遠不會變成一格一格。真正的像素風必須
   每一格都對齊像素網格，所以改成「小圖 + image-rendering: pixelated 放大」，
   跟專案其他素材（32×32 家具 / 64×64 角色）同一條路。

   （ADR-104 之前是 assets/portal_amber.png / portal_blue.png 的 8 格漩渦動畫；現在門面是靜態木門，
   下面關於 sheet / steps(8) 的說明只留作歷史。）

   解析度對齊：地板 / 牆 / 家具是每格 32×32、一格 43 CSS px → 1 來源像素 = 1.34 CSS px。
   門顯示成 1.5 格寬 × 2 格高（48×64 → 64.5×86 CSS px）→ 同樣 1.34，顆粒大小才一致。

   播放方式：外層裁切、內層是 8 倍寬的整張 sheet，用 steps(8) 把它一格一格往左推。
   為什麼不用 background-position 百分比：百分比的基準是「容器寬 − 圖寬」，算出來不會落在
   格子邊界上。改成 translate 內層自己的寬度，-100% ÷ 8 = 剛好一格，而且只走合成器。
   ------------------------------------------------------------------------ */
.room .door {
  position: absolute; z-index: 2; pointer-events: none;
}

/* ADR-104：門面改用使用者自己的木門（assets/cozy_door.png，64×64 → 4×4 格，門板佔下 42px），
   不再放漩渦傳送門 —— 跟 Cozy 牆 / 地板同一套風格。門畫在**牆帶裡**：
   北牆的門錨在門格上緣再往下半格（門檻稍微壓到地板，跟家具貼牆的手感一樣），
   南牆（小屋出口）的門錨在房間底邊 —— 門板就落在南牆帶上、玩家站門格時在門前面。 */
.room .door-beam {
  position: absolute; left: 50%; bottom: 75%;
  width: 200%; height: 200%; translate: -50% 0;
  overflow: hidden;
}
.room .door.door-exit .door-beam { bottom: -100%; }
.room .door-frames {
  position: absolute; inset: 0;
  background-image: url("/assets/cozy_door.png");
  background-size: 100% 100%;
  image-rendering: pixelated;
}

/* 文字標籤：永遠可見，讓玩家一眼認出這是傳送門（早期測試玩家找不到門 —— 一格大的圖形
   在 24×16 的房間裡很容易被地板花紋吃掉）。北牆的門標籤放格子下方、南牆的放上方，
   才不會跑出房間外被切掉。字體等批次 A 換成像素字型時一起處理。 */
.room .door-label {
  position: absolute; left: 50%; translate: -50% 0; top: 100%; margin-top: 3px;
  white-space: nowrap; font-size: 12px; font-weight: 700; color: #f0d9a8;
  background: rgba(20,14,10,.72); padding: 1px 6px; pointer-events: none;
  z-index: 1;
}
.room .door.door-exit .door-label { top: auto; bottom: 100%; margin: 0 0 3px 0; color: #dbeaff; }

/* ── 遊戲內對話框（ADR-039）：取代 window.confirm / alert ────────────────
   原生對話框是瀏覽器畫的視窗、完全不能改樣式，只要還在用就不可能全畫面像素風。
   z-index 要比傳送門選單（40）更高 —— 它可能蓋在任何面板上。 */
.dlg-root {
  position: fixed; inset: 0; z-index: 60;
  display: flex; align-items: center; justify-content: center;
  background: rgba(9,5,2,.6);
}
.dlg-root[hidden] { display: none; }
.dlg-panel {
  width: min(360px, 84vw); background: rgba(20,14,10,.97);
  border: 12px solid transparent; border-image: var(--frame);
  image-rendering: pixelated;
  padding: 14px; box-shadow: 0 5px 0 rgba(0,0,0,.55);
  display: flex; flex-direction: column; gap: 10px;
}
.dlg-title { font-size: 12px; font-weight: 700; color: var(--amber); }
.dlg-body { margin: 0; font-size: 12px; line-height: 1.9; color: var(--ink); word-break: break-word; }
.dlg-actions { display: flex; justify-content: flex-end; gap: 8px; }
.dlg-btn {
  font-size: 12px; padding: 7px 14px; cursor: pointer;
  background: var(--panel-2); color: var(--ink-soft); border: 2px solid var(--border);
}
.dlg-btn:hover { filter: brightness(1.25); }
.dlg-btn:focus-visible { outline: 2px solid var(--amber); outline-offset: 2px; }
.dlg-ok {
  color: #2a1c0c; font-weight: 700; background: var(--amber);
  border: 12px solid transparent; border-image: var(--frame-amber);
  padding: 4px 10px;
}
.dlg-ok.dlg-danger { background: #c0563f; color: #fff2ea; }

/* 傳送門的房間選單：置中的小面板 */
.portal { position: absolute; inset: 0; z-index: 40;
  display: flex; align-items: center; justify-content: center;
  background: rgba(9,5,2,.55); }
.portal[hidden] { display: none; }
/* 八廳之後清單會變長（ADR-034）：限高 + 自己捲，別把「取消」擠出畫面 */
.portal-panel { width: min(320px, 82vw); max-height: 76vh; overflow-y: auto;
  background: rgba(20,14,10,.96);  padding: 14px; box-shadow: 0 5px 0 rgba(0,0,0,.55);
  display: flex; flex-direction: column; gap: 8px;
  border: 12px solid transparent; border-image: var(--frame);
  image-rendering: pixelated;
}
.portal-h { font-size: 12px; font-weight: 700; color: var(--ink); }
.portal-note { margin: 0; font-size: 12px; color: var(--ink-faint); }
.portal-room { display: flex; align-items: center; justify-content: space-between; gap: 8px;
  background: var(--panel-2); color: var(--ink); border: 2px solid var(--border);
 padding: 8px 10px; font-size: 12px; text-align: left; cursor: pointer; }
.portal-room:disabled { opacity: .55; cursor: default; }
.portal-room.portal-create { border-style: dashed; color: var(--amber); }
.portal-room-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.portal-room-meta { flex: none; font-size: 12px; color: var(--ink-faint); }
.portal-cancel { align-self: flex-end; background: var(--panel); color: var(--ink-soft);
  border: 2px solid var(--border); padding: 5px 12px; font-size: 12px; cursor: pointer; }

/* 捏角面板「我的角色」（ADR-128）：左邊大預覽、右邊分頁選項；窄螢幕上下排 */
.av-panel { width: min(640px, 94vw); max-height: 88vh; gap: 10px; overflow: hidden; }   /* 只讓選項區捲，底下的儲存鈕一直看得到 */
.av-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.av-sub { font-size: 12px; color: var(--ink-faint); }
.av-body { display: flex; gap: 14px; align-items: stretch; flex: 1 1 auto; min-height: 0; }
.av-left { flex: none; display: flex; flex-direction: column; align-items: center; gap: 6px; align-self: flex-start; }
.av-preview { width: 160px; height: 224px; image-rendering: pixelated;
  background: repeating-conic-gradient(#3a2b20 0% 25%, #2c2018 0% 50%) 0 0 / 16px 16px;
  box-shadow: inset 0 0 0 2px var(--border); }
.av-action { font-size: 12px; color: var(--ink-faint); min-height: 1.2em; }
.av-tools { display: flex; flex-direction: column; gap: 6px; width: 160px; }
.av-right { flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column; gap: 8px; }
.av-tabs { display: flex; flex-wrap: wrap; gap: 4px; }
.av-tab { padding: 4px 10px; font-size: 12px; font-weight: normal; background: var(--panel-2); color: var(--ink-soft);
  border: 2px solid var(--border); cursor: pointer; }
.av-tab.on { background: var(--panel); color: var(--amber); border-color: var(--amber-deep); }
.av-options { flex: 1 1 auto; min-height: 120px; overflow-y: auto; padding-right: 4px; }
.av-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(88px, 1fr)); gap: 6px; }
.av-opt { display: flex; flex-direction: column; align-items: center; gap: 2px; padding: 4px 2px 6px;
  background: var(--panel-2); border: 2px solid var(--border); color: var(--ink-soft); cursor: pointer; font-weight: normal; }
.av-opt:hover { border-color: var(--ink-faint); filter: none; }
.av-opt.on { border-color: var(--amber); color: var(--amber); }
.av-opt.locked .av-opt-pic { opacity: .7; }
.av-opt-pic { width: 80px; height: 112px; image-rendering: pixelated; }
.av-opt-name { display: inline-flex; align-items: center; gap: 3px; font-size: 12px; white-space: nowrap; }
.av-colors { display: flex; flex-direction: column; gap: 8px; }
.av-color-row { display: flex; flex-direction: column; gap: 4px; }
.av-color-label { font-size: 12px; color: var(--ink-soft); }
.av-swatches { display: flex; flex-wrap: wrap; gap: 4px; }
.av-swatch { width: 22px; height: 22px; padding: 0; border: 2px solid #150c08; cursor: pointer; }
.av-swatch:hover { border-color: var(--ink-faint); filter: none; }
.av-swatch.on { border-color: var(--amber); box-shadow: 0 0 0 1px var(--amber); }
.av-custom { background: conic-gradient(red, yellow, lime, cyan, blue, magenta, red); }
.av-custom::-webkit-color-swatch-wrapper { padding: 3px; }
.av-custom::-webkit-color-swatch { border: none; }
.av-custom::-moz-color-swatch { border: none; }
.av-note { margin: 0; min-height: 1.2em; font-size: 12px; color: var(--ink-soft); }
.av-note.warn { color: var(--amber); }
.av-save:disabled { opacity: .45; filter: grayscale(.85); cursor: default; }   /* 沒有要存的：灰掉，不要還像能按 */
@media (max-width: 560px) {
  .av-panel { overflow-y: auto; }   /* 窄螢幕上下排：整個面板捲 */
  .av-body { flex-direction: column; align-items: stretch; }
  .av-options { overflow: visible; }
  .av-left { flex-direction: row; justify-content: center; }
  .av-tools { width: auto; }
}

@media (max-width: 640px) {
  .chat-overlay { width: 64%; }
  .move-hint { display: none; }
  .presence ul { display: none; }
}

/* ---- 代幣錢包徽章 + 賭桌面板（ADR-C1，賭場移植）---- */
/* .wallet-badge 樣式併入頂欄的 .chip 區（ADR-058） */

.game-panel {
  position: absolute; right: 12px; bottom: calc(var(--bar-b) + 12px); z-index: 21; width: 250px;
  display: flex; flex-direction: column; gap: 8px; font-size: 12px; color: var(--ink-soft);
  background: rgba(20,14,10,.72);  padding: 10px;
  border: 12px solid transparent; border-image: var(--frame);
  image-rendering: pixelated;
  max-height: calc(100vh - var(--bar-b) - 72px); overflow-y: auto;   /* 矮螢幕不要頂出畫面（ADR-124 多了兩行說明） */
}
.game-panel button { border: 1px solid var(--border); background: rgba(255,255,255,.06);
  color: var(--ink-soft); cursor: pointer; transition: filter .12s; }
.game-panel button:hover:not(:disabled) { filter: brightness(1.25); }
.game-panel button:disabled { opacity: .5; cursor: default; }
.game-head { display: flex; justify-content: space-between; align-items: baseline; }
.game-title { font-weight: 700; color: var(--amber); font-size: 12px; }
.game-phase { font-size: 12px; color: var(--ink-faint); }
.game-options { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; }
.game-opt { padding: 6px 4px; font-size: 12px; line-height: 1.2; }
.game-opt b { display: block; font-size: 12px; color: var(--ink-faint); font-weight: 400; margin-top: 2px; }
.game-opt.won { outline: 2px solid var(--amber); }
/* 自己押過的格子（ADR-124）：金框 + 右上角標出押了多少 */
.game-opt { position: relative; }
.game-opt.staked { border-color: var(--amber-deep); }
.game-stake { position: absolute; bottom: 2px; right: 3px; font-style: normal; font-size: 12px; font-weight: 700;
  color: #2a1c0c; background: var(--amber); padding: 0 4px; line-height: 16px; }
.game-step { font-size: 12px; color: var(--ink-soft); }
.game-mine { font-size: 12px; color: var(--ink-faint); }
.game-mine.full { color: var(--amber); }
.game-chips { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; }   /* 6 顆籌碼排兩排，跟下面的格子對齊（ADR-124） */
/* 下注籌碼：class 叫 .bet-chip（ADR-064）——曾叫 .chip，跟頂欄小標籤的 .chip 撞名，
   inline-flex + 固定高 + 左右 padding 把「10」擠得只剩「0」。 */
.bet-chip { flex: 1; padding: 4px 0; font-size: 12px; white-space: nowrap; }
.bet-chip.selected { background: var(--amber); color: #2a1c0c; border-color: var(--amber); }
.game-bets { display: flex; flex-direction: column; gap: 2px; max-height: 84px; overflow-y: auto; font-size: 12px; }
.game-bet.muted { color: var(--ink-faint); font-style: italic; }
.game-bet.pot { color: var(--amber); font-weight: 700; margin-top: 2px; }
.game-result { font-size: 12px; color: var(--amber); min-height: 1.2em; }
.game-foot { display: flex; justify-content: space-between; align-items: center; }
.game-balance { font-weight: 700; color: var(--amber); }
.game-leave { padding: 4px 10px; font-size: 12px; }


/* ---- 小屋成員白名單（ADR-029）---- */
.pv-invite { /* 在場名單的「邀請」鈕沿用 .pv-mod 的外觀 */ }
.portal-members-link {
  display: block; width: 100%; margin-top: 4px; padding: 6px 10px;
  background: none; border: 1px dashed var(--line, #5a4a38);  color: var(--ink-dim, #cdbfa5); font: inherit; font-size: 12px; cursor: pointer;
}
.portal-members-link:hover { border-style: solid; color: var(--ink, #f0e6d2); }
.portal-member {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 6px 8px; border-bottom: 1px solid var(--line, #5a4a38);
}
.portal-member:last-of-type { border-bottom: none; }
.portal-member-name { font-size: 12px; }
.portal-member-remove {
  background: none; border: 1px solid var(--line, #5a4a38);  color: var(--ink-dim, #cdbfa5); font: inherit; font-size: 12px; padding: 2px 8px; cursor: pointer;
}
.portal-member-remove:hover { border-color: #a33; color: #f2b8b8; }

/* ---- 小屋設定（ADR-091）：沿用傳送門面板，分段排 ---- */
.bb-right { display: flex; align-items: center; gap: 8px; margin-left: auto; }
.portal-section { font-size: 12px; color: var(--amber); margin-top: 6px; }
.rs-panel { width: min(360px, 90vw); gap: 10px; }
.rs-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.rs-room { font-size: 12px; color: var(--ink-faint); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rs-section { display: flex; flex-direction: column; gap: 6px; padding-top: 8px; border-top: 1px solid var(--border); }
.rs-title { font-size: 12px; color: var(--ink-soft); }
.rs-seg { display: flex; gap: 6px; }
.rs-seg-btn { flex: 1; padding: 6px 8px; font-size: 12px; font-weight: normal;
  background: var(--panel-2); color: var(--ink-soft); border: 2px solid var(--border); }
.rs-seg-btn.on { background: var(--panel); color: var(--amber); border-color: var(--amber-deep); }
.rs-invite { display: flex; gap: 6px; }
.rs-input { flex: 1; min-width: 0; background: var(--panel-2); color: var(--ink); border: 2px solid var(--border);
  padding: 6px 8px; font: inherit; font-size: 12px; outline: none; }
.rs-input:focus { border-color: var(--amber); }
.rs-btn { padding: 6px 12px; font-size: 12px; }
.rs-tag { margin-left: 6px; font-size: 12px; color: var(--ink-faint); }
.rs-actions { display: flex; gap: 6px; flex: none; }
.rs-danger:hover { border-color: #a33; color: #f2b8b8; }
.rs-error { margin: 0; font-size: 12px; color: #e07b5b; }
.rs-foot { display: flex; justify-content: flex-end; gap: 6px; }
