/* 四季语义色：春为默认，夏为月夜，秋为暖杏，冬为日间雪景。 */
:root,
:root[data-theme='spring'] {
  color-scheme: light;
  --bg: #e9eeea;
  --bg-soft: #fafbf7;
  --bg-card: #fbfcf6;
  --bg-raise: #f0f4ed;
  --line: #d8e2d7;
  --line-soft: #d8e2d7;
  --text: #344c45;
  --text-dim: #617769;
  --text-faint: #617769;
  --gold: #456e59;
  --wolf: #994b59;
  --village: #376c4b;
  --seer: #466ba3;
  --witch: #875b94;
  --hunter: #a46b32;
  --idiot: #66737c;
  --ring: #29483b;
  --wolf-soft: color-mix(in srgb, var(--wolf) 12%, transparent);
  --village-soft: color-mix(in srgb, var(--village) 12%, transparent);
  --ring-glow: color-mix(in srgb, var(--ring) 28%, transparent);
  --gold-soft: #e3ece2;
  --wolf-wash: #b8687710;
  --wolf-line: #d7b8b9;
  --turn-text: #963c4c;
  --fault-text: #963c4c;
  --good-text: #376c4b;
  --felt-border: #b5c9b2;
  --felt-inner: inset 0 0 60px #8da68c10, 0 0 0 6px #e1e9d8, 0 0 0 7px #b5c9b2;
  --chart-grid: #d8e2d7;
  --chart-text: #617769;
  --seat-you-border: #d8a5a1;
  --radius: 15px;
  --season-top: #f8faf6;
  --season-floor: linear-gradient(145deg,#f4f7ef,#e9f0e9 50%,#f3e9e8);
  --season-accent: #608776;
  --season-accent-deep: #345f50;
  --season-accent-ink: #f7f7e8;
  --season-button: #ffffff55;
  --season-shadow: #425c4710;
  --season-sheen: #ffffffbb;
  --season-felt: radial-gradient(circle at 42% 28%,#f7f9ee,#e5efdf 60%,#d6e4d4);
  --season-seat: #fbfcf6;
  --season-seat-line: #c7d9c8;
  --season-you: linear-gradient(140deg,#bc7a78,#9d5a64);
  --season-you-shadow: #ad6b6728;
  --season-entry: #f0f4ed;
}

:root[data-theme='summer'] {
  color-scheme: dark;
  --bg: #071c22;
  --bg-soft: #0e292f;
  --bg-card: #1c3d40;
  --bg-raise: #153338;
  --line: #2a4649;
  --line-soft: #2a4649;
  --text: #d1e5dc;
  --text-dim: #98b9af;
  --text-faint: #98b9af;
  --gold: #b9ce98;
  --wolf: #dfa293;
  --village: #98caa9;
  --seer: #83b6cc;
  --witch: #d3b0db;
  --hunter: #deb27b;
  --idiot: #b9c8c8;
  --ring: #f0fff6;
  --wolf-soft: color-mix(in srgb, var(--wolf) 12%, transparent);
  --village-soft: color-mix(in srgb, var(--village) 12%, transparent);
  --ring-glow: color-mix(in srgb, var(--ring) 28%, transparent);
  --gold-soft: #acc59715;
  --wolf-wash: #cc897510;
  --wolf-line: #704f4c;
  --turn-text: #efb6ac;
  --fault-text: #efb6ac;
  --good-text: #a8d3bc;
  --felt-border: #557362;
  --felt-inner: inset 0 0 60px #00181e55, 0 0 0 6px #203d3d, 0 0 0 7px #557362;
  --chart-grid: #2a4649;
  --chart-text: #98b9af;
  --seat-you-border: #c99683;
  --radius: 15px;
  --season-top: #0d282e;
  --season-floor: radial-gradient(ellipse at 70% 0%,#173b3e,#0c2b31 48%,#102e31);
  --season-accent: #b9ce98;
  --season-accent-deep: #678c73;
  --season-accent-ink: #0b2829;
  --season-button: #17343a66;
  --season-shadow: #020e1c38;
  --season-sheen: #d4f0ce0d;
  --season-felt: radial-gradient(circle at 43% 25%,#244a47,#153b3c 62%,#112e34);
  --season-seat: #1c3d40;
  --season-seat-line: #416367;
  --season-you: linear-gradient(140deg,#b57a6d,#885057);
  --season-you-shadow: #c6866725;
  --season-entry: #153338;
}

:root[data-theme='autumn'] {
  color-scheme: light;
  --bg: #eae0d2;
  --bg-soft: #fbf5ea;
  --bg-card: #fff6e5;
  --bg-raise: #f5ecd9;
  --line: #e0cdb4;
  --line-soft: #e0cdb4;
  --text: #574332;
  --text-dim: #82684e;
  --text-faint: #82684e;
  --gold: #92592f;
  --wolf: #a04e3b;
  --village: #536c32;
  --seer: #516e9b;
  --witch: #8b5888;
  --hunter: #9c632b;
  --idiot: #756c60;
  --ring: #4e3927;
  --wolf-soft: color-mix(in srgb, var(--wolf) 12%, transparent);
  --village-soft: color-mix(in srgb, var(--village) 12%, transparent);
  --ring-glow: color-mix(in srgb, var(--ring) 28%, transparent);
  --gold-soft: #eddec6;
  --wolf-wash: #aa5c4610;
  --wolf-line: #d7b398;
  --turn-text: #913e32;
  --fault-text: #913e32;
  --good-text: #536c32;
  --felt-border: #c4a876;
  --felt-inner: inset 0 0 60px #97763712, 0 0 0 6px #e8d4ad, 0 0 0 7px #c4a876;
  --chart-grid: #e0cdb4;
  --chart-text: #82684e;
  --seat-you-border: #d39470;
  --radius: 15px;
  --season-top: #f8f1e5;
  --season-floor: linear-gradient(145deg,#f8efdd,#efe2cb 65%,#e7d3b8);
  --season-accent: #a0693c;
  --season-accent-deep: #794b32;
  --season-accent-ink: #fff3dc;
  --season-button: #ffffff33;
  --season-shadow: #73572e10;
  --season-sheen: #ffffff99;
  --season-felt: radial-gradient(circle at 42% 28%,#fcf2dc,#eddbb6 65%,#dfc89f);
  --season-seat: #fff6e5;
  --season-seat-line: #d9bf94;
  --season-you: linear-gradient(140deg,#ba6753,#913f3a);
  --season-you-shadow: #ab69452b;
  --season-entry: #f5ecd9;
}

:root[data-theme='winter'] {
  color-scheme: light;
  --bg: #e5edf1;
  --bg-soft: #f9fcfd;
  --bg-card: #fafdff;
  --bg-raise: #edf4f8;
  --line: #c8d9e2;
  --line-soft: #c8d9e2;
  --text: #304b5b;
  --text-dim: #607989;
  --text-faint: #607989;
  --gold: #426b80;
  --wolf: #926578;
  --village: #416f64;
  --seer: #4a75a2;
  --witch: #7e638e;
  --hunter: #98643d;
  --idiot: #617989;
  --ring: #254c63;
  --wolf-soft: color-mix(in srgb, var(--wolf) 12%, transparent);
  --village-soft: color-mix(in srgb, var(--village) 12%, transparent);
  --ring-glow: color-mix(in srgb, var(--ring) 28%, transparent);
  --gold-soft: #709cb514;
  --wolf-wash: #ad7d9310;
  --wolf-line: #d9c5ce;
  --turn-text: #884858;
  --fault-text: #884858;
  --good-text: #416f64;
  --felt-border: #aec6d3;
  --felt-inner: inset 0 0 60px #86aec318, 0 0 0 6px #e3eef3, 0 0 0 7px #aec6d3;
  --chart-grid: #c8d9e2;
  --chart-text: #607989;
  --seat-you-border: #c19cab;
  --radius: 15px;
  --season-top: #f5f9fb;
  --season-floor: radial-gradient(ellipse at 22% 12%,#fffdf4 0%,#e1edf3 37%,#d5e5ed 72%,#eef5f8);
  --season-accent: #426b80;
  --season-accent-deep: #64899b;
  --season-accent-ink: #f8fcff;
  --season-button: #ffffff70;
  --season-shadow: #587b9112;
  --season-sheen: #ffffffcc;
  --season-felt: radial-gradient(circle at 37% 24%,#ffffff,#f0f7fa 56%,#ddeaf1);
  --season-seat: #fafdff;
  --season-seat-line: #b4cad7;
  --season-you: linear-gradient(140deg,#a67787,#785d78);
  --season-you-shadow: #976f8a25;
  --season-entry: #edf4f8;
}

* { box-sizing: border-box; }

/* .round-badge / .modal 等设了 display，会盖过浏览器对 [hidden] 的默认处理 */
[hidden] { display: none !important; }

html, body {
  margin: 0;
  height: 100%;
  background: var(--bg);
  color: var(--text);
  font-family: "PingFang SC", "Microsoft YaHei", "Hiragino Sans GB", system-ui, sans-serif;
  font-size: 15px;
  line-height: 1.65;
}

body {
  display: flex;
  flex-direction: column;
  height: 100vh;
  overflow: hidden;
}

/* ── 顶栏 ── */
.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 20px;
  border-bottom: 1px solid var(--line);
  background: var(--bg-soft);
  flex-shrink: 0;
}
.brand { display: flex; align-items: center; gap: 12px; }
.brand-mark {
  width: 38px; height: 38px;
  display: grid; place-items: center;
  background: linear-gradient(140deg, var(--wolf), #8e2f2c);
  border-radius: 9px;
  font-size: 20px; font-weight: 700;
  color: #fff;
}
.brand h1 { margin: 0; font-size: 16px; font-weight: 600; letter-spacing: 0.3px; }
.brand-sub { margin: 0; font-size: 12px; color: var(--text-faint); }

.topbar-right { display: flex; align-items: center; gap: 14px; }
.round-badge { display: flex; align-items: center; gap: 8px; }
.round-num { font-size: 20px; font-weight: 700; color: var(--gold); }
.round-label { font-size: 12px; color: var(--text-dim); }
.phase-chip {
  padding: 3px 11px;
  border-radius: 999px;
  background: var(--bg-raise);
  border: 1px solid var(--line);
  font-size: 12px;
  color: var(--text-dim);
}
.btn-ghost {
  padding: 6px 14px;
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 7px;
  color: var(--text-dim);
  font-size: 13px;
  font-family: inherit;
  cursor: pointer;
  transition: all 0.15s;
}
.btn-ghost:hover { border-color: var(--text-faint); color: var(--text); }
.btn-ghost.danger:hover { border-color: var(--wolf); color: var(--wolf); }
/* 语音开关：开启时点亮成金色，一眼看出当前状态 */
.btn-ghost.on { border-color: var(--gold); color: var(--gold); }
.btn-ghost.on:hover { border-color: var(--gold); color: var(--gold); filter: brightness(1.15); }

.voice-unlock-modal {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: grid;
  place-items: center;
  padding: 18px;
  background: rgba(5, 8, 16, 0.76);
}
.voice-unlock-card {
  width: min(100%, 480px);
  padding: 30px;
  border: 2px solid var(--gold);
  border-radius: 14px;
  background: var(--bg-card);
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.38);
  text-align: center;
}
.voice-unlock-icon { font-size: 42px; line-height: 1; }
.voice-unlock-card h2 { margin: 12px 0 8px; color: var(--gold); }
.voice-unlock-card p { margin: 0 0 22px; color: var(--text-dim); }
.voice-unlock-card .btn-primary { display: block; width: 100%; font-size: 17px; }
.voice-unlock-card .btn-ghost { margin-top: 10px; }
#enableVoiceBtn:not([hidden]) { border-color: var(--gold); color: var(--gold); font-weight: 700; }

/* ── 舞台：中牌桌 · 分隔条 · 右列（上历史 下操作） ── */
.stage {
  flex: 1;
  display: grid;
  /* 默认左右各半：JS 启动时会把 --rail-w 写成具体像素，这里的兜底算法和
     app.js 的 railHalf() 必须一致（百分比基数是内容盒，所以要再扣掉分隔条 7 + gap 20） */
  grid-template-columns: 1fr 7px var(--rail-w, calc((100% - 27px) / 2));
  gap: 10px;
  padding: 12px 20px;
  min-height: 0;
}

/* 右列：历史吃掉剩余高度，执行面板压在右下，高度随内容但封顶 */
.right-col {
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-height: 0;
  min-width: 0;
}
.right-col .rail-panel { flex: 1; min-height: 120px; }
.ops-panel { flex-shrink: 0; max-height: 50vh; }

/* ── 右下：执行面板 ── */
.ops-inner {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 11px 12px;
  display: flex;
  flex-direction: column;
}
/* 轮到你动手时整块面板变红。红边压在顶部——面板在右下角，顶部粗边比左侧
   更能把"这块归你操作"和上面的历史区分开 */
.ops-panel.your-turn {
  border-color: var(--wolf-line);
  background: linear-gradient(180deg, var(--wolf-wash), var(--bg-soft) 42%);
  box-shadow: inset 0 3px 0 var(--wolf);
}
.ops-panel.your-turn .action-prompt { color: var(--text); }
.ops-panel.your-turn .action-prompt b { color: var(--turn-text); }
.ops-panel.your-turn .action-prompt b::before {
  content: '';
  display: inline-block;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--wolf);
  margin-right: 8px;
  vertical-align: middle;
  animation: pulse 1.1s ease-in-out infinite;
}

/* 拖动改右栏宽度。热区只有 7px 但视觉上是一条可点的细线 */
.resizer {
  position: relative;
  cursor: col-resize;
  touch-action: none; /* 触屏上拖动时不要顺手把页面滚走 */
  border-radius: 4px;
}
.resizer::after {
  content: '';
  position: absolute;
  left: 3px; top: 6px; bottom: 6px;
  width: 1px;
  background: var(--line);
  transition: background 0.15s, width 0.15s;
}
.resizer:hover::after { background: var(--gold); width: 2px; }
.resizer.on::after { background: var(--gold); width: 2px; }
/* 拖动期间锁掉选字，否则会从逐字稿里划出一大段选中态 */
body.resizing { cursor: col-resize; user-select: none; }

.floor {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 0;
  min-width: 0;
  padding: 10px 14px 0;
  /* 牌桌区要有"牌桌"的氛围，和右侧的文档感拉开层次 */
  background:
    radial-gradient(115% 75% at 50% -12%, rgba(216, 169, 74, 0.08), transparent 58%),
    var(--bg-soft);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}

.panel {
  background: var(--bg-soft);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
}
.panel-head {
  padding: 9px 14px;
  border-bottom: 1px solid var(--line-soft);
  font-size: 12px;
  color: var(--text-faint);
  letter-spacing: 1px;
  flex-shrink: 0;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
}
.rail-sub { font-size: 10px; letter-spacing: 2px; opacity: 0.7; }

/* ── 圆桌：座位环 ──
   座位用百分比定位（JS 按角度算 left/top），所以牌桌尺寸可以随窗口缩放，
   不必像固定像素那样在窄屏上溢出。你固定在正下方，其余按座位号顺时针排。 */
.table {
  position: relative;
  width: min(100%, 60vh, 580px);
  aspect-ratio: 1 / 1;
  flex-shrink: 0;
}
.felt {
  position: absolute;
  inset: 12%;
  border-radius: 50%;
  background: var(--season-felt);
  border: 1px solid var(--felt-border);
  box-shadow: var(--felt-inner);
}

/* 中央态势：现在是什么阶段、轮到你干什么 */
.center {
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: 46%;
  max-width: 250px;
  text-align: center;
}
.board-phase { font-size: 10px; letter-spacing: 3px; color: var(--text-faint); }
.board-title { font-size: 21px; font-weight: 600; letter-spacing: 2px; color: var(--gold); margin: 3px 0 4px; }
.board-note { font-size: 11.5px; color: var(--text-dim); line-height: 1.6; }
.board-slot:empty { display: none; }
/* 开场时牌桌没有座位，正中这块地方留给开场卡，可以放宽一些。
   样版 C 的卡是 560 宽的不透明面板（2026-09-26 玩家选的）：felt 圆退成背景，
   圆边不再从卡片文字中间切过去——以前卡比圆高 126px，「先看玩法介绍」掉在圆外 */
.center.wide { width: 86%; max-width: 560px; }
/* 开场卡比态势信息高得多，所以开局前整张桌子也放大一圈，免得卡片顶到桌沿外面；
   开局后恢复原尺寸给座位环留出空间。窄屏那档单独再给一个上限，因为堆叠布局里
   牌桌能占的高度小得多（:has 的选择器权重高于媒体查询里的 .table，必须在那边再写一条） */
.table:has(.center.wide) { width: min(100%, 66vh, 680px); }
/* 底部头像下的多行身份标签会超出座位圆周，给它们留出与图例的间距。 */
.table:has(.seat) { margin-bottom: 40px; }

/* 开场卡：不透明面板盖在牌桌正中。块数从 8 降到 5（标题行／一行小字／牌墙／目标行／chips＋行动条） */
.start-card {
  margin-top: 4px;
  background: var(--bg-card);
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 15px 17px 14px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.14);
}
.start-title-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.start-card h2 { margin: 0; font-size: 17px; letter-spacing: 1px; }
/* 介绍＋牌池＋耗时并成一行小字。高度固定三行：这行随桌尺寸变长变短，
   不钉死高度换桌时会把下面的牌墙顶得上下跳（旧布局的同一条规矩，只是换了地方）。
   三行是窄卡（328px 实测）的 worst case；宽卡两行、末行留空 */
.start-sub {
  margin: 7px 0 11px !important;
  font-size: 11.5px !important;
  color: var(--text-dim) !important;
  line-height: 1.65;
  height: 57px;
  overflow: hidden;
}
.start-card .action-row { justify-content: center; }
.start-actions { display: flex; flex-direction: row; gap: 10px; align-items: center; margin-top: 13px; }
.start-actions .btn-start { flex: 1; }
.start-actions .btn-draft { flex: 0 0 auto; }

/* 12 个座位：窄屏下标签会互相压到（实测牌桌 434px 时 4 对重叠、横向挤 20px），
   所以标签压窄、头像缩一号。**环半径不动**——缩半径会让弧长更短，挤得更狠。 */
.table.dense .seat { --seat-size: 44px; width: 66px; }
.table.dense .seat-disc { font-size: 12.5px; }
.table.dense .seat-name { font-size: 9.5px; }
.table.dense .seat-votes { right: 4px; }

/* 开场卡底部的设置 chips：一整排都是按钮（点哪粒都开设置弹窗）。
   人数不在这里重复——标题行右侧的分段控件已经说过 */
.set-chips { display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; margin-top: 12px; }
/* 不复用全局 .chip：那颗带「+」前缀和虚线描边，是发言框里"怀疑标签"的语义 */
.set-chips .set-chip {
  padding: 4px 10px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--bg-card);
  color: var(--text-dim);
  font: inherit; font-size: 11px;
  cursor: pointer;
  transition: all 0.15s;
}
.set-chips .set-chip:hover { border-color: var(--gold); color: var(--gold); }

/* ── 设置弹窗 ── */
.settings-card { max-width: 460px; }
.set-note { margin: 0; font-size: 12.5px; color: var(--text-dim); }
.set-note b { color: var(--gold); }
.set-hint { margin: 8px 0 0; font-size: 12px; color: var(--text-faint); line-height: 1.65; }

/* 桌尺寸：标题行右侧的分段控件（样版 C，2026-09-26 玩家选的）。
   两段连体等宽，比角色牌次要一档；选中态沿用原来的蓝 */
.size-row { display: flex; flex: 0 0 auto; border: 1px solid var(--line); border-radius: 8px; overflow: hidden; }
.size-card {
  padding: 5px 14px;
  background: var(--bg-card);
  border: 0;
  color: var(--text-dim);
  font: inherit; font-size: 12.5px;
  cursor: pointer;
  transition: all 0.15s;
}
.size-card + .size-card { border-left: 1px solid var(--line); }
.size-card:hover { color: var(--text); }
.size-card.on { background: rgba(108, 143, 221, 0.12); color: var(--seer); font-weight: 700; }

/* 开场卡上的选角：七张牌（含随机）4 列排满。9 人桌收掉白痴后是 6＋随机占两格，
   12 人桌是 7＋随机占两格——两种桌都正好两行满格，所以换桌尺寸不再上下跳
   （旧布局靠 min-height 预留三行硬压那 31px，网格把跳的根子去掉了）。
   选中后下面那行"你的目标"跟着换——角色之间看得到什么、要做什么差得很远，
   光给个名字新手挑不出区别 */
.role-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 7px; }
.role-card {
  padding: 8px 2px 7px;
  background: var(--bg-card);
  border: 1px solid var(--line);
  border-radius: 9px;
  color: var(--text-dim);
  font: inherit;
  cursor: pointer;
  text-align: center;
  transition: all 0.15s;
}
/* 七张牌填 4×2 会剩一个空位：随机横占两格，牌墙不留洞 */
.role-card.any { grid-column: span 2; }
/* 9 人桌收掉白痴后少一格：随机改占三格补齐末行 */
.role-row.no-idiot .role-card.any { grid-column: span 3; }
.role-card b { display: block; font-size: 12.5px; color: var(--text); }
.role-card span { display: block; font-size: 9.5px; letter-spacing: 0.3px; margin-top: 2px; }
.role-card.wolf b { color: var(--wolf); }
.role-card.god b { color: var(--witch); }
.role-card.man b { color: var(--village); }
.role-card.any b { color: var(--gold); }
.role-card:hover { border-color: var(--text-faint); }
.role-card.on {
  border-color: var(--gold);
  background: var(--gold-soft);
  box-shadow: 0 0 0 1px var(--gold-soft);
}
.role-goal {
  /* 内嵌一行：角色名加粗做导语＋目标正文。高度按最长的这条（女巫那句带自救警告）
     预留两行：不预留的话换角色时这段文字一会长一会短，会把上面的牌墙顶得上下跳 */
  display: flex;
  gap: 7px;
  align-items: baseline;
  margin: 9px 0 0 !important;
  padding: 7px 10px;
  background: var(--bg-raise);
  border-radius: 8px;
  font-size: 11px !important;
  color: var(--text-dim) !important;
  line-height: 1.6;
  /* 三行＋内边距：窄卡（328px）上女巫那句带自救警告要绕三行，height 是 border-box，
     少算 padding 就会把第三行剪掉（实测剪过）。宽卡两行、末行留空 */
  height: 67px;
  overflow: hidden;
}
.role-goal b { color: var(--gold); font-size: 11px; white-space: nowrap; }
.role-goal span { flex: 1; }

.seat {
  --seat-size: 52px;
  position: absolute;
  /* 圆周坐标对应头像圆心；身份标签的行数不能参与纵向居中。 */
  transform: translate(-50%, calc(var(--seat-size) / -2));
  width: 88px;
  text-align: center;
  cursor: default;
}
.seat-disc {
  position: relative;
  width: var(--seat-size); height: var(--seat-size);
  margin: 0 auto;
  border-radius: 50%;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  background: var(--bg-card);
  border: 2px solid var(--line);
  font-size: 14px; font-weight: 700;
  color: var(--text-dim);
  transition: border-color 0.2s, box-shadow 0.2s, transform 0.2s;
}
.seat-id { line-height: 1; }
.seat-model {
  max-width: 44px;
  margin-top: 1px;
  font-size: 9px; font-weight: 600; line-height: 1.1;
  letter-spacing: 0;
  color: var(--gold);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.table.dense .seat-model { max-width: 38px; font-size: 8px; }
.seat.you .seat-model { color: #ffe7a3; }
/* 发言进度用右下角小点，避免和中央态势抢注意力 */
.seat-disc::after {
  content: '';
  position: absolute; right: 0; bottom: 2px;
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--village);
  border: 2px solid var(--bg-soft);
  opacity: 0;
}
.seat.spoke .seat-disc::after { opacity: 1; }
.seat.unspoken .seat-disc::after { opacity: 1; background: var(--bg-raise); }
/* 投票阶段换掉发言点：投完的人右下角打钩，没投的不画 */
.seat.voted .seat-disc::after {
  content: '✓';
  opacity: 1;
  width: 14px; height: 14px;
  border-radius: 50%;
  background: var(--village);
  color: #fff;
  font-size: 10px; font-weight: 700; line-height: 14px; text-align: center;
}
.seat.claim .seat-disc { border-color: var(--seer); box-shadow: 0 0 16px color-mix(in srgb, var(--seer) 30%, transparent); }
/* 在盯你：只给金色外圈，不给具体数字——游戏中刻意只给模糊提示 */
.seat.watch .seat-disc { border-color: var(--gold); box-shadow: 0 0 18px color-mix(in srgb, var(--gold) 38%, transparent); }
/* 既跳了身份又被盯上时两个信号都得看得见：后写的 .watch 会盖掉 .claim 的蓝圈，
   所以这里补一圈内阴影把蓝色还回来 */
.seat.claim.watch .seat-disc { box-shadow: 0 0 18px color-mix(in srgb, var(--gold) 38%, transparent), inset 0 0 0 2px color-mix(in srgb, var(--seer) 60%, transparent); }
.seat.you .seat-disc {
  background: linear-gradient(150deg, var(--wolf), #8e2f2c);
  border-color: var(--seat-you-border); color: #fff;
  box-shadow: 0 0 24px var(--season-you-shadow);
}
/* 思考标的呼吸：缓慢的明暗起伏（2.4s ease-in-out），颜色始终是灰。
   2026-09-26 前这里是完全静止的——当年金色脉冲和"正在说话"分不清，干脆不动。
   玩家要呼吸感之后改成"动，但性格不同"：区分两个信号靠颜色＋波形（这里是原地明暗，
   readpulse 是金色向外扩散），不再靠静止。 */
.seat.thinking .seat-disc { border-style: dashed; animation: thinkbreathe 1.8s ease-in-out infinite; }
@keyframes thinkbreathe {
  /* 波谷落到和普通边框同色＝几乎隐身，波峰提亮＋一圈 halo：幅度拉满才看得出在呼吸。
     峰值仍停在 text-dim 的灰，不碰白色——白环是"轮到你选"的语义 */
  0%, 100% { border-color: var(--line); box-shadow: 0 0 0 0 color-mix(in srgb, var(--text-dim) 0%, transparent); }
  50% { border-color: var(--text-dim); box-shadow: 0 0 14px 3px color-mix(in srgb, var(--text-dim) 60%, transparent); }
}
/* 「思考中」文字标不参与呼吸：外圈已经在动了，两个东西一起闪反而看不出主次（2026-09-26 玩家指的） */
.seat-status.thinking, .lg-badge.thinking { opacity: 1; }
/* 排队等槽：调用已发起但还没拿到并发槽。静止的虚线环＋时钟标——
   和在飞的呼吸环分开，玩家才看得出"几家供应商各自在飞几条、谁还在等"（2026-09-26 玩家选的③） */
.seat.queued .seat-disc { border-style: dashed; border-color: var(--line); }
.seat-status.queued, .lg-badge.queued { color: var(--text-faint); border-color: var(--line); }
/* 正在发音：向外扩散的一圈，动得最明显——它才是"这个人在说话"的信号 */
.seat.reading .seat-disc { border-color: var(--gold); animation: readpulse 1.15s ease-out infinite; }
@keyframes readpulse {
  0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--gold) 55%, transparent); }
  70% { box-shadow: 0 0 0 9px transparent; }
  100% { box-shadow: 0 0 0 0 transparent; }
}
.seat.dead { opacity: 0.4; }
.seat.dead .seat-disc { border-style: dashed; }
.seat.dead .seat-id { text-decoration: line-through; }
.seat-name { font-size: 10.5px; color: var(--text-faint); line-height: 1.4; margin-top: 4px; }
.seat-name b { display: block; font-size: 11px; color: var(--text-dim); font-weight: 600; }
.seat-votes {
  position: absolute; top: -6px; right: 8px;
  min-width: 18px; padding: 0 4px; height: 18px;
  border-radius: 9px; background: var(--wolf); color: #fff;
  font-size: 10px; font-weight: 700; line-height: 18px; text-align: center;
}
/* 警徽：圆盘左下角一枚盾牌星徽（盾轮廓＋内嵌五角星，2026-09-26 玩家从三份样版里选的 C）。
   位置沿用原来那颗金点的挂点：左下角是空位，右上票数角标（3.5 这种小数有 24px 宽）
   和左上的发言状态图标都不在这一侧——两枚角标会重叠 6~9px 是量出来的结论，别挪。
   实现是 SVG 做 mask、var(--gold) 上色：形状在遮罩里、颜色跟主题走，不必为各个主题重复存图。
   名字行还会再写一次「警长」，颜色不是唯一通道。
   ⚠ 盾牌是镂空的（轮廓＋星，中间透底），而挂点正压在座位圈的描边上——自称/在盯你的蓝圈金圈
   会从镂空里穿过去，看着像圈把警徽切开了（2026-09-26 玩家截图）。所以垫一层盾形实心底
   （::before，牌面底色），金盾画在它上面（::after）：圈被挡在底后面，盾牌形状不变。 */
.seat-shield { position: absolute; left: -2px; bottom: 0; width: 15px; height: 15px; }
.seat-shield::before {
  content: '';
  position: absolute; inset: -1.5px;
  background: var(--bg-card);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 .8 L14.2 3.2 V7.6 C14.2 11.6 8 15.2 8 15.2 C8 15.2 1.8 11.6 1.8 7.6 V3.2 Z'/%3E%3C/svg%3E") center / 100% 100% no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 .8 L14.2 3.2 V7.6 C14.2 11.6 8 15.2 8 15.2 C8 15.2 1.8 11.6 1.8 7.6 V3.2 Z'/%3E%3C/svg%3E") center / 100% 100% no-repeat;
}
.seat-shield::after {
  content: '';
  position: absolute; inset: 0;
  background: var(--gold);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M8 .8 L14.2 3.2 V7.6 C14.2 11.6 8 15.2 8 15.2 C8 15.2 1.8 11.6 1.8 7.6 V3.2 Z M8 2.7 L12.7 4.5 V7.6 C12.7 10.6 8 13.5 8 13.5 C8 13.5 3.3 10.6 3.3 7.6 V4.5 Z M8 4.7 L8.95 6.8 L11.2 7 L9.5 8.5 L10 10.7 L8 9.5 L6 10.7 L6.5 8.5 L4.8 7 L7.05 6.8 Z'/%3E%3C/svg%3E") center / 100% 100% no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M8 .8 L14.2 3.2 V7.6 C14.2 11.6 8 15.2 8 15.2 C8 15.2 1.8 11.6 1.8 7.6 V3.2 Z M8 2.7 L12.7 4.5 V7.6 C12.7 10.6 8 13.5 8 13.5 C8 13.5 3.3 10.6 3.3 7.6 V4.5 Z M8 4.7 L8.95 6.8 L11.2 7 L9.5 8.5 L10 10.7 L8 9.5 L6 10.7 L6.5 8.5 L4.8 7 L7.05 6.8 Z'/%3E%3C/svg%3E") center / 100% 100% no-repeat;
}

/* ── 轮到你选目标：整张圆桌变成按钮组 ──
   能提交的人选亮一圈白环并轻微呼吸，不能选的淡下去（点下去仍然跳他的发言）。
   用白色是因为金色光圈已经被"正在发音"和"在盯你"占了两种语义 */
.seat.pickable { cursor: pointer; z-index: 3; }
.seat.pickable .seat-disc {
  border-color: var(--ring);
  box-shadow: 0 0 0 2px var(--ring), 0 0 20px var(--ring-glow);
  animation: pickpulse 1.4s ease-in-out infinite;
}
@keyframes pickpulse {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.07); }
}
.seat.off:not(.dead) { opacity: 0.45; }
/* 女巫点了但还没决定救还是毒：把这一位标成"已选中"，弹层挂在座位下方 */
.seat.picked { z-index: 6; }
.seat.picked .seat-disc {
  animation: none;
  border-color: var(--gold);
  box-shadow: 0 0 0 2px var(--gold), 0 0 20px color-mix(in srgb, var(--gold) 50%, transparent);
}
.pick-pop {
  position: absolute;
  top: calc(100% + 2px); left: 50%;
  transform: translateX(-50%);
  display: flex; flex-direction: column; gap: 3px;
  width: 96px;
  padding: 5px;
  background: var(--bg-soft);
  border: 1px solid var(--gold);
  border-radius: 8px;
  box-shadow: 0 8px 22px rgba(0, 0, 0, 0.55);
}
.pick-pop button {
  padding: 4px 6px;
  background: var(--bg-card);
  border: 1px solid var(--line);
  border-radius: 6px;
  color: var(--text);
  font: inherit; font-size: 11px;
  cursor: pointer;
  transition: all 0.15s;
}
.pick-pop .pick-save { border-color: rgba(79, 168, 107, 0.6); color: var(--village); }
.pick-pop .pick-poison { border-color: color-mix(in srgb, var(--witch) 60%, transparent); color: var(--witch); }
.pick-pop .pick-cancel { border-style: dashed; color: var(--text-faint); }
.pick-pop button:hover { filter: brightness(1.25); }
.lg-pick { border: 2px solid var(--ring); background: none; box-shadow: 0 0 10px var(--ring-glow); }

/* 座位标记的图例——颜色语义不写出来没人知道金圈是什么意思 */
.legend {
  display: flex; gap: 14px; flex-wrap: wrap; justify-content: center;
  padding: 8px 0 9px; font-size: 10.5px; color: var(--text-faint); flex-shrink: 0;
}
.legend span { display: inline-flex; align-items: center; gap: 5px; }
/* 状态角标：压在头像左上角——右下是发言进度点、右上是得票，只有左上是空的。
   图例里放的是同款，所以两边共用一套样式 */
.seat-status,
.lg-badge {
  width: 20px; height: 20px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--bg-soft);
  border: 1px solid var(--line);
  line-height: 0;
  flex-shrink: 0;
}
.seat-status { position: absolute; left: -6px; top: -5px; }
.seat-status.reading, .lg-badge.reading { color: var(--gold); border-color: var(--gold); }
.seat-status.thinking, .lg-badge.thinking { color: var(--text-dim); border-color: var(--text-faint); }

.lg { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }
.lg-spoke { background: var(--village); }
.lg-voted {
  width: 12px; height: 12px;
  background: var(--village); color: #fff;
  font-size: 9px; font-weight: 700; font-style: normal;
  line-height: 12px; text-align: center;
}
.lg-claim { border: 2px solid var(--seer); background: none; }
.lg-watch { border: 2px solid var(--gold); background: none; }
/* 图例里那枚警徽：和座位上是同一个形状，只是小到 12px——遮罩复用同一条 data URI 的写法 */
.lg-sheriff {
  width: 12px; height: 12px; border-radius: 0;
  background: var(--gold);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M8 .8 L14.2 3.2 V7.6 C14.2 11.6 8 15.2 8 15.2 C8 15.2 1.8 11.6 1.8 7.6 V3.2 Z M8 2.7 L12.7 4.5 V7.6 C12.7 10.6 8 13.5 8 13.5 C8 13.5 3.3 10.6 3.3 7.6 V4.5 Z M8 4.7 L8.95 6.8 L11.2 7 L9.5 8.5 L10 10.7 L8 9.5 L6 10.7 L6.5 8.5 L4.8 7 L7.05 6.8 Z'/%3E%3C/svg%3E") center / 100% 100% no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M8 .8 L14.2 3.2 V7.6 C14.2 11.6 8 15.2 8 15.2 C8 15.2 1.8 11.6 1.8 7.6 V3.2 Z M8 2.7 L12.7 4.5 V7.6 C12.7 10.6 8 13.5 8 13.5 C8 13.5 3.3 10.6 3.3 7.6 V4.5 Z M8 4.7 L8.95 6.8 L11.2 7 L9.5 8.5 L10 10.7 L8 9.5 L6 10.7 L6.5 8.5 L4.8 7 L7.05 6.8 Z'/%3E%3C/svg%3E") center / 100% 100% no-repeat;
}
.lg-dead { border: 2px dashed var(--text-faint); background: none; }

.pgender { font-weight: 400; font-size: 11px; opacity: 0.6; margin-left: 1px; }
/* 女性标记淡紫、男性标记淡蓝，只是辅助识别语音人设 */
.pgender.f { color: var(--witch); opacity: 0.9; }
.pgender.m { color: var(--seer); opacity: 0.9; }
.ptag { font-size: 11px; color: var(--text-faint); }
.ptag.wolf { color: var(--wolf); }
.ptag.village { color: var(--village); }
.ptag.seer { color: var(--seer); }
.ptag.witch { color: var(--witch); }
.ptag.hunter { color: var(--hunter); }
.ptag.idiot { color: var(--idiot); }
.ptag.werewolf { color: var(--wolf); }
.ptag.villager { color: var(--village); }
/* 发言进度：金绿已发 / 灰未发 */
.ptag.spoken { color: var(--village); }
.ptag.unspoken { color: var(--text-faint); opacity: 0.7; }
/* 身份声称：金色描边，一眼看到谁跳了什么 */
/* 自称身份：描边跟着职位色走（currentColor），文字颜色由上面的职位规则决定 */
.ptag.claim {
  border: 1px solid currentColor;
  border-radius: 4px;
  padding: 0 5px;
}

/* ── 伪装压力（游戏中只给模糊提示，刻意不给百分比数字） ── */
.pressure {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--line-soft);
  text-align: left;
}
.pressure-head {
  display: flex; justify-content: space-between;
  font-size: 11px; color: var(--text-dim); margin-bottom: 6px;
}
.pressure-tag { font-weight: 600; }
.pressure-track {
  height: 5px; background: var(--bg-raise);
  border-radius: 999px; overflow: hidden;
}
.pressure-fill {
  height: 100%; width: 0%;
  border-radius: 999px;
  background: var(--village);
  transition: width 0.6s ease, background 0.6s ease;
}
.pressure-hint { margin: 7px 0 0; font-size: 11px; color: var(--text-faint); line-height: 1.5; }

/* ── 逐字稿 ── */
.log { flex: 1; overflow-y: auto; padding: 12px 14px; }
.log-empty { margin: 6px 2px 0; font-size: 12px; color: var(--text-faint); line-height: 1.7; }

.entry { margin-bottom: 13px; animation: fade 0.25s ease; }
@keyframes fade { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }

.entry-narration {
  padding: 9px 13px;
  background: var(--bg-card);
  border-left: 2px solid var(--line);
  border-radius: 0 7px 7px 0;
  font-size: 13px;
  color: var(--text-dim);
}
.entry-narration.warn { border-left-color: var(--wolf); color: var(--fault-text); }
.entry-narration.good { border-left-color: var(--village); color: var(--good-text); }

.entry-speech { display: flex; gap: 10px; }
/* 点座位跳过来的那条发言要闪一下——逐字稿很长，否则看不出刚落点在哪 */
.entry-speech.flash { animation: flash 1.2s ease; border-radius: 8px; }
@keyframes flash {
  0%, 55% { background: var(--gold-soft); }
  100% { background: transparent; }
}
.sp-avatar {
  width: 30px; height: 30px; border-radius: 7px;
  display: grid; place-items: center;
  background: var(--bg-raise); font-size: 12px; font-weight: 600;
  flex-shrink: 0;
}
.sp-avatar.you { background: var(--wolf); color: #fff; }
.sp-body { flex: 1; min-width: 0; }
.sp-head {
  display: flex;
  align-items: center;
  gap: 5px;
  font-size: 12px;
  color: var(--text-faint);
  margin-bottom: 3px;
}
.sp-head b { color: var(--text-dim); font-weight: 600; }
/* 座位号只在头像上出现一次，姓名行只放身份线索——原来这里"P5 P5（你）"写了两遍 */
.sp-role { font-size: 11px; color: var(--text-faint); }
.sp-role.you { color: var(--wolf); font-weight: 600; }
.sp-role.wolf { color: var(--wolf); }
/* 自称身份：描边 + 职位色，和座位标签用同一套语义 */
.sp-role.claim { border: 1px solid currentColor; border-radius: 4px; padding: 0 5px; }
.sp-role.seer { color: var(--seer); }
.sp-role.witch { color: var(--witch); }
/* 竞选发言：和"自称身份"同款描边，但用警长的金色——它是体裁标记，不是身份标记 */
.sp-role.elect { color: var(--gold); border: 1px solid currentColor; border-radius: 4px; padding: 0 5px; }
/* 按座位覆盖的发言模型标签：属于元信息，比身份线索弱一档（虚线 + 半透明）。
   ⚠ [hidden] 那条必须显式写：上面这条一旦给 .model 加了 display，UA 的 hidden 样式就会被盖掉，
   于是"没配覆盖的座位"会渲染出一枚空芯片。 */
.sp-role.model { color: var(--text-faint); border: 1px dashed currentColor; border-radius: 4px; padding: 0 4px; opacity: 0.75; }
.sp-role.model[hidden] { display: none; }
.sp-role.hunter { color: var(--hunter); }
.sp-role.villager { color: var(--village); }

/* 发言旁的喇叭按钮（姓名左侧）：点击重听；正在发音时声波条做起伏动画 */
.sp-speak {
  width: 22px; height: 22px;
  margin-right: 3px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  flex-shrink: 0;
  background: transparent;
  border: none;
  border-radius: 5px;
  color: var(--text-faint);
  cursor: pointer;
  transition: color 0.15s, background 0.15s;
}
.sp-speak:hover { color: var(--gold); background: var(--bg-raise); }
.sp-speak .wv {
  opacity: 0.5;
  transform-box: fill-box;
  transform-origin: center;
  transition: opacity 0.15s;
}
.sp-speak.speaking { color: var(--gold); }
.sp-speak.speaking .wv { opacity: 1; animation: soundwave 0.7s ease-in-out infinite; }
.sp-speak.speaking .wv2 { animation-delay: 0.12s; }
.sp-speak.speaking .wv3 { animation-delay: 0.24s; }
@keyframes soundwave {
  0%, 100% { transform: scaleY(0.3); }
  50% { transform: scaleY(1); }
}
.sp-text {
  font-size: 14px;
  color: var(--text);
  white-space: pre-wrap;
  word-break: break-word;
}
.sp-suspects { margin-top: 5px; font-size: 11px; color: var(--text-faint); }
.sp-cursor {
  display: inline-block; width: 7px; height: 15px;
  background: var(--gold); vertical-align: text-bottom;
  animation: blink 1s step-end infinite;
}
@keyframes blink { 50% { opacity: 0; } }

.entry-vote {
  display: flex; align-items: center; gap: 8px;
  font-size: 13px; color: var(--text-dim);
  padding: 5px 0;
}
.vote-arrow { color: var(--text-faint); }
.vote-target { color: var(--wolf); font-weight: 600; }
.vote-reason { font-size: 12px; color: var(--text-faint); font-style: italic; }
.entry-vote.you .vote-target { color: var(--gold); }
/* 竞选票的箭头写的是"警徽 →"，标成金色，和"投谁出局"那类一眼分开 */
.entry-vote.election .vote-arrow { color: var(--gold); }

.entry-result { padding: 9px 13px; background: var(--bg-card); border-radius: 7px; font-size: 13px; }
.count-cap { font-size: 11px; color: var(--text-faint); margin-bottom: 4px; }
.count-row { display: flex; align-items: center; gap: 9px; margin: 3px 0; }
.count-name { width: 34px; color: var(--text-dim); font-size: 12px; }
.count-bar { height: 15px; background: var(--bg-raise); border-radius: 3px; overflow: hidden; flex: 1; }
/* 必须是块级：它是 <span>，而 .count-bar 不是 flex/grid 容器，行内元素上 width/height 一律不生效——
   没有这行的话柱子是 0×0，历史区和结算弹窗都只剩一条空轨道加右边那个数字（2026-09-26 实测抓到） */
.count-fill { display: block; height: 100%; background: var(--line); border-radius: 3px; transition: width 0.4s; }
.count-fill.top { background: var(--wolf); }
/* 竞选票里"最高"是当选，不是出局——所以那条柱子是警长的金色，不是红 */
.entry-result.election .count-fill.top { background: var(--gold); }
/* 警长一票 1.5，票数会出现 3.5 这种小数，20px 宽度会被挤断 */
.count-num { width: 27px; text-align: right; font-size: 12px; color: var(--text-dim); }

.entry-system {
  text-align: center; font-size: 11px; color: var(--text-faint);
  padding: 5px 0; letter-spacing: 0.5px;
}

/* 主持人播报：金色居中，和普通旁白区分开 */
.entry-host {
  text-align: center;
  font-size: 13px;
  font-weight: 600;
  color: var(--gold);
  padding: 8px 0;
  letter-spacing: 0.5px;
}

/* 「该你了」提示条：玩家的注意力在日志区，所以提示要出现在这里而不只是底部 */
.entry-turn {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 11px 15px;
  background: var(--wolf-soft);
  border: 1px solid var(--wolf-line);
  border-radius: 8px;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--turn-text);
}
.entry-turn::before {
  content: '';
  flex-shrink: 0;
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--wolf);
  animation: pulse 1.1s ease-in-out infinite;
}
@keyframes pulse {
  0%, 100% { opacity: 0.3; transform: scale(0.8); }
  50% { opacity: 1; transform: scale(1.2); }
}

/* 阶段进度：横排在右下这块宽度里刚好一行放得下，折起来反而难读 */
.stepper {
  display: flex;
  align-items: center;
  gap: 3px;
  flex-wrap: wrap;
  margin-bottom: 10px;
  font-size: 11px;
}
.step {
  padding: 2px 9px;
  border-radius: 999px;
  background: var(--bg-card);
  border: 1px solid var(--line-soft);
  color: var(--text-faint);
  transition: all 0.2s;
}
.step.done { opacity: 0.5; }
.step.active {
  background: var(--bg-raise);
  border-color: var(--text-faint);
  color: var(--text);
  font-weight: 600;
}
/* 带圆点的步骤 = 需要玩家亲自操作的，一眼看出哪几步是自己的活 */
.step.mine::before {
  content: '';
  display: inline-block;
  width: 4px; height: 4px;
  border-radius: 50%;
  background: var(--wolf);
  margin-right: 5px;
  vertical-align: middle;
  opacity: 0.8;
}
.step.active.mine {
  background: var(--wolf-soft);
  border-color: var(--wolf);
  color: var(--turn-text);
}
.step-sep { color: var(--line); }

/* 等待态：说清楚在等谁、接下来是什么，不能只写「等待中」 */
.action-waiting {
  display: flex;
  align-items: center;
  gap: 9px;
  margin: 0;
  font-size: 13px;
  color: var(--text-faint);
}
.action-waiting::before {
  content: '';
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--gold);
  animation: pulse 1.4s ease-in-out infinite;
}

.action-prompt { margin: 0 0 9px; font-size: 13px; color: var(--text-dim); }
.action-prompt b { color: var(--text); }
.action-tip { margin: -3px 0 9px; font-size: 11px; color: var(--text-faint); }

.action-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }

.btn-target {
  padding: 7px 16px;
  background: var(--bg-card);
  border: 1px solid var(--line);
  border-radius: 7px;
  color: var(--text);
  font-size: 13px;
  font-family: inherit;
  cursor: pointer;
  transition: all 0.15s;
}
.btn-target:hover { border-color: var(--wolf); background: var(--wolf-soft); }
.btn-target.selected {
  background: var(--wolf); border-color: var(--wolf);
  color: #fff; font-weight: 600;
}
.btn-target small { display: block; font-size: 10px; opacity: 0.75; line-height: 1.45; margin-top: 2px; }
/* 候选人按钮下面那行上下文里的语义色：金=自称身份/在盯你，红=狼队友 */
.btn-target small em { font-style: normal; color: var(--gold); }
.btn-target small i { font-style: normal; color: var(--wolf); }

/* 女巫的两瓶药分两块区：把它们排成一排，玩家要猜哪个按钮是救、哪个是毒 */
.ops-group { margin-bottom: 12px; }
.ops-group-head { display: flex; align-items: baseline; gap: 8px; margin-bottom: 6px; }
.ops-group-head b { font-size: 12px; color: var(--text); letter-spacing: 1px; }
.ops-group-head span { font-size: 11px; color: var(--text-faint); }
.ops-group-note { font-size: 11.5px; color: var(--text-faint); line-height: 1.6; }
.btn-target.save { border-color: rgba(79, 168, 107, 0.55); }
.btn-target.save:hover { border-color: var(--village); background: var(--village-soft); }

.btn-primary {
  padding: 8px 22px;
  background: var(--wolf);
  border: 1px solid var(--wolf);
  border-radius: 7px;
  color: #fff;
  font-size: 13px; font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  transition: filter 0.15s;
}
.btn-primary:hover { filter: brightness(1.12); }
.btn-primary:disabled { opacity: 0.35; cursor: not-allowed; filter: none; }

/* AI 代写：金色描边，和红色的「发送」区分开，暗示它是半自动的辅助 */
.btn-draft {
  padding: 8px 18px;
  background: transparent;
  border: 1px solid var(--gold);
  border-radius: 7px;
  color: var(--gold);
  font-size: 13px;
  font-family: inherit;
  cursor: pointer;
  white-space: nowrap;
  transition: all 0.15s;
}
.btn-draft:hover:not(:disabled) { background: var(--gold-soft); }
.btn-draft:disabled {
  opacity: 0.55; cursor: default;
  border-color: var(--line); color: var(--text-faint);
}
.draft-hint {
  flex: 1;
  min-width: 150px;
  font-size: 11px;
  color: var(--text-faint);
}
/* 左栏窄，代写的说明单独占一行，和按钮挤在一起会互相压缩 */
.ops-inner .draft-hint { flex-basis: 100%; min-width: 0; order: 3; }

.btn-start {
  padding: 11px 34px; font-size: 15px;
  background: linear-gradient(140deg, var(--wolf), #a33834);
  border: none; border-radius: 9px; color: #fff;
  font-family: inherit; font-weight: 600; cursor: pointer;
  transition: filter 0.15s;
}
.btn-start:hover { filter: brightness(1.12); }

.speech-input {
  width: 100%;
  min-height: 62px;
  padding: 10px 13px;
  background: var(--bg-card);
  border: 1px solid var(--line);
  border-radius: 8px;
  color: var(--text);
  font-family: inherit;
  font-size: 14px;
  resize: vertical;
  outline: none;
  transition: border-color 0.15s;
}
.speech-input:focus { border-color: var(--wolf); }
.speech-input::placeholder { color: var(--text-faint); }

.chip-label { font-size: 11px; color: var(--text-faint); margin: 9px 0 7px; }
.chip-row { gap: 6px; }
/* 做成「标签」而不是「按钮」：未选中的用虚线描边 + 加号前缀，
   和投票按钮那种实线方块区分开——之前有玩家在发言阶段把这排误认成投票选项。 */
.chip {
  padding: 3px 12px;
  border-radius: 999px;
  background: transparent;
  border: 1px dashed var(--line);
  color: var(--text-faint);
  font-size: 12px;
  font-family: inherit;
  cursor: pointer;
  transition: all 0.15s;
}
.chip::before {
  content: '+';
  margin-right: 5px;
  opacity: 0.7;
  font-weight: 400;
}
.chip:hover { border-color: var(--text-faint); color: var(--text-dim); }
.chip.on {
  background: var(--wolf-soft);
  border: 1px solid var(--wolf);
  color: var(--wolf);
  font-weight: 600;
}
.chip.on::before { content: '✓'; opacity: 1; }

/* ── 结算弹窗 ── */
.modal {
  position: fixed; inset: 0;
  background: rgba(6, 8, 14, 0.82);
  display: grid; place-items: center;
  padding: 24px; z-index: 50;
  animation: fade 0.3s ease;
}
.modal-card {
  background: var(--bg-soft);
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 26px 30px;
  max-width: 640px; width: 100%;
  max-height: 88vh; overflow-y: auto;
}
.result-dialog { position: relative; max-width: 640px; width: 100%; }
.result-dialog .modal-card { max-width: none; }
.result-close {
  position: absolute; top: 14px; right: 14px; z-index: 2;
  background: var(--bg-soft); white-space: nowrap;
}
.call-vote-modal { z-index: 70; }
.call-vote-card { max-width: 470px; border: 2px solid var(--wolf); box-shadow: 0 20px 70px rgba(0, 0, 0, 0.45); }
.call-vote-label { display: inline-block; color: var(--turn-text); font-size: 13px; font-weight: 700; letter-spacing: .08em; }
.call-vote-card h2 { margin: 12px 0; color: var(--text); font-size: clamp(21px, 4vw, 27px); }
.call-vote-card p { color: var(--text-dim); line-height: 1.7; }
.call-vote-progress { margin: 16px 0 4px; font-weight: 700; }
.call-vote-countdown { margin: 0; font-variant-numeric: tabular-nums; color: var(--gold) !important; font-weight: 700; }
.call-vote-countdown.urgent { color: var(--turn-text) !important; font-size: 22px; animation: countdown-pulse .7s ease-in-out infinite alternate; }
.call-vote-error { color: var(--turn-text) !important; }
.call-vote-actions { flex-wrap: wrap; }
.call-vote-actions button { flex: 1 1 180px; min-height: 43px; }
.verdict-tag {
  display: inline-block; padding: 3px 13px;
  border-radius: 999px; font-size: 12px; font-weight: 600;
  margin-bottom: 13px;
}
.verdict-perfect { background: var(--village-soft); color: var(--village); }
.verdict-narrow { background: var(--gold-soft); color: var(--gold); }
.verdict-survived { background: var(--bg-raise); color: var(--text-dim); }
.verdict-exposed { background: var(--wolf-soft); color: var(--wolf); }
/* 夜里被毒/被枪：既不是"被识破"也不是"藏住了但输了"，得有自己的颜色 */
.verdict-killed { background: var(--wolf-soft); color: var(--hunter); }

/* 两套档位不能互比，所以好人那张卡顶部先说清"这次评的是什么" */
.camp-note {
  background: var(--village-soft); border-left: 2px solid var(--village);
  border-radius: 0 7px 7px 0; padding: 9px 13px; margin: 0 0 4px !important;
  font-size: 12.5px !important; color: var(--text-dim) !important; line-height: 1.7;
}
.camp-note b { color: var(--village); }
/* 胜负原因：引擎数出来的机械条件（屠神／屠民／狼被清干净）。和复盘档位分开写——
   档位评的是"你打得怎么样"，这一行评的是"这局为什么结束"（2026-09-26 玩家要的） */
.win-reason {
  background: var(--bg-card); border-left: 2px solid var(--gold);
  border-radius: 0 7px 7px 0; padding: 8px 13px; margin: 0 0 10px !important;
  font-size: 12.5px !important; color: var(--text-dim) !important; line-height: 1.6;
}
.fault-item {
  padding: 9px 13px; margin-bottom: 7px;
  background: var(--bg-card); border-left: 2px solid var(--wolf);
  border-radius: 0 7px 7px 0; font-size: 12.5px; line-height: 1.7; color: var(--fault-text);
}
.hl-item {
  padding: 9px 13px; margin-bottom: 7px;
  background: var(--bg-card); border-left: 2px solid var(--line);
  border-radius: 0 7px 7px 0; font-size: 12.5px; line-height: 1.7; color: var(--text-dim);
}

/* ── 玩法介绍弹窗 ── */
.rules-card { max-width: 720px; }
.rules-lead { font-size: 14px; line-height: 1.8; color: var(--text-dim); }
.rules-lead b { color: var(--text); }

.rules-flow { margin: 0; padding: 0; list-style: none; font-size: 13px; color: var(--text-dim); }
.rules-flow li { display: flex; gap: 9px; align-items: baseline; padding: 6px 0; border-bottom: 1px dashed var(--line-soft); }
.rules-flow li:last-child { border-bottom: none; }
.rules-flow b { color: var(--text); }
.rf-k {
  flex-shrink: 0; font-size: 10px; letter-spacing: 1px; color: var(--text-faint);
  border: 1px solid var(--line); border-radius: 4px; padding: 0 5px;
}

.rules-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.rules-grid > div {
  background: var(--bg-card); border: 1px solid var(--line-soft);
  border-radius: 8px; padding: 9px 12px;
}
.rules-grid b { display: block; margin-bottom: 3px; font-size: 13px; color: var(--text); }
.rules-grid span { color: var(--text-dim); font-size: 12.5px; line-height: 1.65; }
.rules-grid em { font-style: normal; color: var(--gold); }
.rules-grid .vp { color: var(--village); }
.rules-grid .vn { color: var(--gold); }
.rules-grid .vs { color: var(--text-dim); }
.rules-grid .ve { color: var(--wolf); }
.rules-grid .vk { color: var(--hunter); }

.rules-note { margin: 10px 0 0; font-size: 12px; color: var(--text-faint); line-height: 1.6; }

/* 核心机制单独成块：新手最需要记住的就是这一条 */
.rules-key {
  background: var(--wolf-soft); border: 1px solid var(--wolf-line);
  border-radius: 9px; padding: 11px 14px; font-size: 13.5px;
}
.rules-key b { color: var(--turn-text); }
.rules-key span { display: block; margin-top: 5px; font-size: 12.5px; color: var(--fault-text); line-height: 1.7; }

.rules-tips { margin: 0; padding-left: 18px; font-size: 13px; color: var(--text-dim); }
.rules-tips li { padding: 3px 0; line-height: 1.7; }
.rules-tips b { color: var(--text); }
.rules-tips .gd { color: var(--gold); }

.modal-card h2 { margin: 0 0 10px; font-size: 21px; }
.modal-card > p { margin: 0 0 20px; color: var(--text-dim); font-size: 14px; }

.section-title {
  font-size: 12px; color: var(--text-faint);
  letter-spacing: 1px; margin: 20px 0 10px;
  padding-bottom: 6px; border-bottom: 1px solid var(--line-soft);
}

.chart { width: 100%; height: 170px; }
.chart-labels { display: flex; justify-content: space-between; font-size: 11px; color: var(--text-faint); margin-top: 5px; }
.chart-legend { display: flex; gap: 15px; flex-wrap: wrap; margin-top: 11px; font-size: 12px; }
.legend-item { display: flex; align-items: center; gap: 6px; color: var(--text-dim); }
.legend-dot { width: 9px; height: 9px; border-radius: 2px; }

.expose-item {
  padding: 11px 14px;
  background: var(--bg-card);
  border-left: 2px solid var(--wolf);
  border-radius: 0 7px 7px 0;
  margin-bottom: 9px;
  font-size: 13px;
}
.expose-head { color: var(--wolf); font-weight: 600; font-size: 12px; margin-bottom: 4px; }
.expose-item ul { margin: 5px 0 0; padding-left: 17px; color: var(--text-dim); font-size: 12px; }
.expose-item li { margin: 2px 0; }

/* 结算弹窗里的「谁投了谁」：一行一票，理由只留第一句。
   不用 .expose-item 那套卡片——它左边一道红杠是"有人在指你"的意思，而这里是全桌票型 */
.tally-cap { margin-top: 12px; }
.tally-line { display: flex; gap: 8px; align-items: baseline; font-size: 12px; margin: 3px 0; }
.tally-vote { color: var(--text-dim); white-space: nowrap; }
.tally-reason { color: var(--text-faint); }

.modal-actions { margin-top: 24px; display: flex; gap: 10px; }
.modal-actions .btn-ghost { padding: 8px 22px; }
.draft-note {
  width: 100%;
  margin-top: 7px;
  padding: 7px 10px;
  background: var(--bg-raise);
  border: 1px solid var(--line);
  border-radius: 7px;
  color: var(--text);
  font-family: inherit;
  font-size: 12px;
}
.draft-note:focus { outline: none; border-color: var(--gold); }

/* 多人房间 */
.rooms-shell { flex: 1; overflow: auto; width: min(1120px, 100%); margin: 0 auto; padding: 44px 24px 64px; }
.rooms-hero { max-width: 660px; margin-bottom: 32px; }
.rooms-eyebrow { color: var(--gold); font-size: 11px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; }
.rooms-hero h2 { margin: 7px 0 9px; font-size: clamp(28px, 4vw, 42px); line-height: 1.2; }
.rooms-hero p, .rooms-hint { color: var(--text-dim); margin: 0; }
.rooms-grid { display: grid; grid-template-columns: minmax(0, .85fr) minmax(0, 1.15fr); gap: 20px; }
.rooms-card { background: var(--bg-card); border: 1px solid var(--line); border-radius: 14px; padding: 26px; box-shadow: 0 12px 36px rgba(0,0,0,.11); }
.rooms-card h3 { margin: 0 0 20px; font-size: 21px; }
.rooms-card-head { display: flex; justify-content: space-between; align-items: center; gap: 12px; }
.rooms-card-head h3 { margin-bottom: 0; }
.rooms-card label { display: grid; gap: 7px; color: var(--text-dim); font-size: 12px; font-weight: 600; margin-bottom: 15px; }
.rooms-card input:not([type=checkbox]), .rooms-card select { width: 100%; padding: 10px 12px; border: 1px solid var(--line); border-radius: 8px; background: var(--bg-raise); color: var(--text); font: inherit; font-size: 14px; }
.rooms-card input:focus, .rooms-card select:focus { outline: 2px solid var(--gold); outline-offset: 1px; }
.rooms-form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.rooms-card .rooms-check { align-self: center; display: flex; align-items: center; gap: 8px; margin: 0; }
.rooms-main-btn { width: 100%; margin-top: 6px; }
.rooms-list { margin-top: 23px; color: var(--text-dim); }
.rooms-list-item, .rooms-seat { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 14px 0; border-top: 1px solid var(--line-soft); }
.rooms-list-item b, .rooms-seat b { display: block; color: var(--text); font-size: 14px; }
.rooms-list-item small, .rooms-seat span { display: block; color: var(--text-faint); font-size: 12px; }
.rooms-lobby { max-width: 800px; margin: 0 auto; }
.rooms-lobby .rooms-card-head h3 { margin: 0; }
.rooms-hint { margin-top: 16px; font-size: 13px; }
.rooms-section-title { margin: 27px 0 8px; padding-bottom: 6px; border-bottom: 1px solid var(--line-soft); color: var(--text); font-size: 13px; font-weight: 700; }
.rooms-section-title small { color: var(--text-faint); font-weight: 400; }
.rooms-camp-choices { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.rooms-camp-choices button { padding: 15px; color: var(--text); background: var(--bg-raise); border: 1px solid var(--line); border-radius: 9px; cursor: pointer; font: inherit; font-weight: 700; }
.rooms-camp-choices button.active { border-color: var(--gold); background: var(--gold-soft); color: var(--gold); }
.rooms-camp-choices button:hover { border-color: var(--gold); }
.rooms-lobby-actions { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 28px; }
.rooms-lobby-actions > div { display: flex; align-items: center; gap: 10px; color: var(--text-dim); font-size: 13px; }
.rooms-message { min-height: 27px; margin: 18px 0; color: var(--turn-text); }
.call-vote-bar { display: flex; align-items: center; gap: 6px; }
.call-vote-status { color: var(--text-dim); font-size: 12px; white-space: nowrap; }
.input-countdown { padding: 8px 12px; border: 1px solid var(--line); border-radius: 7px; margin: 6px 0 10px; color: var(--gold); font-variant-numeric: tabular-nums; font-weight: 700; }
.input-countdown.urgent { border-color: var(--wolf); background: var(--wolf-soft); color: var(--turn-text); font-size: 18px; animation: countdown-pulse .7s ease-in-out infinite alternate; }
@keyframes countdown-pulse { from { box-shadow: 0 0 0 0 var(--wolf-soft); } to { box-shadow: 0 0 0 5px var(--wolf-soft); } }

/* ── 滚动条 ── */
::-webkit-scrollbar { width: 9px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--line); border-radius: 5px; }
::-webkit-scrollbar-thumb:hover { background: var(--text-faint); }

/* 窄屏：依次堆成 牌桌+实况 → 操作面板 → 历史。
   .right-col 用 display:contents 摊平，才能让它的两个子节点参与舞台的排序 */
@media (max-width: 960px) {
  body { height: auto; min-height: 100vh; }
  .topbar { flex-wrap: wrap; align-items: start; gap: 8px; padding: 10px 15px; }
  .brand { width: 100%; min-width: 0; }
  .brand h1 { white-space: nowrap; }
  .brand-sub { white-space: nowrap; }
  .topbar-right { width: 100%; flex-wrap: wrap; gap: 6px; }
  .topbar-right > * { flex-shrink: 0; }
  .topbar-right .btn-ghost { padding: 5px 9px; font-size: 12px; white-space: nowrap; }
  .call-vote-bar { width: 100%; order: -1; }
  .call-vote-bar .btn-ghost { border-color: var(--wolf-line); color: var(--turn-text); }
  .rooms-grid { grid-template-columns: 1fr; }
  .rooms-shell { padding: 24px 15px 40px; }
  .rooms-card { padding: 19px; }
  .rooms-lobby-actions { align-items: stretch; flex-direction: column; }
  .rooms-page .brand-sub { display: none; }
  .stage { display: flex; flex-direction: column; flex: 0 0 auto; padding: 12px 15px; }
  .resizer { display: none; }
  .right-col { display: contents; }
  .floor { order: 0; overflow: visible; padding-bottom: 12px; }
  .ops-panel { order: 1; max-height: none; }
  .rail-panel { order: 2; min-height: 240px; }
  .table { width: min(100%, 44vh); }
  /* 开场卡要占更多竖向空间，但堆叠布局里牌桌只有这么大可用 */
  .table:has(.center.wide) { width: min(100%, 52vh); }
  .rules-grid { grid-template-columns: 1fr; }
}
