/* style.css — 地下城笔谈：纸上墨书手稿风。手机优先。 */
/* ---------- C2 书法标题字体（20261013m）：霞鹜文楷 LXGW WenKai v1.522 Regular 子集（SIL OFL 1.1） ----------
   只覆盖标题类用字（tools/subset-font.py 生成，字符集留档 tools/fonts-src/charset-used.txt，79.5KB）；
   缺字逐字回退 Noto Serif SC/系统衬线；正文/输入/选项按钮不用本字体（书法体正文可读性差）。 */
@font-face {
  font-family: 'lxgw-brush';
  src: url('assets/fonts/lxgw-subset.woff2?v=20261013m') format('woff2');
  font-display: swap;
  font-weight: 400;
  font-style: normal;
}
:root {
  /* C1 色板五核心（20261013e）：B7 夜间模式只需替换这五个值即全站换肤；色值全取自原字面色，零新色 */
  --paper: #F4EFE4;     /* 宣纸底：页面/面板底色、深底上的亮字 */
  --ink: #2A251D;       /* 墨：正文、深色底、描边基色 */
  --cinnabar: #B03A2E;  /* 朱砂：强调/命中/危险 */
  --ocher: #b3541e;     /* 赭石：关键数值暖金（b.num，原字面色） */
  --paper-dim: #EDE6D6; /* 暗纸：宣纸深一档（原 --paper-2 更名，全站未使用故零影响） */
  --ink-dim: #6E6557;   /* 淡墨：次级文字（辅助档，派生自 --ink 家族） */
  --gold: #8C6A2F;      /* 金：引号/骰线/门 tile（辅助档） */
  --line: color-mix(in srgb, var(--ink) 22%, transparent); /* 等价原 rgba(42,37,29,.22) */
  --serif: 'Songti SC', 'STSong', 'Noto Serif SC', 'SimSun', serif;
  --brush: 'lxgw-brush', 'Noto Serif SC', serif; /* C2 书法标题：仅标题类元素，正文/按钮保持 --serif */
  --mono: ui-monospace, 'Cascadia Code', Menlo, Consolas, monospace;
  /* B7 阅读三件套（默认值=原现状，视觉零变化；app.js 随滑杆实时覆写 --read-*） */
  --read-fs: 16.5px;   /* 叙事正文字号（滑杆 15-22px） */
  --read-lh: 1.9;      /* 叙事正文行距（滑杆 1.5-2.1） */
  /* B7 C1 保留字面色变量化（默认值=原字面色，夜间由主题块覆写） */
  --lift-rgb: 255,255,255; /* 纸亮层 RGB：纸白/米黄=白提亮，墨夜=暖黑压深 */
  --gold-hi: #FFD9A0;      /* 墨底亮金（.turn-banner b） */
  --floor: #ece7da;        /* 地板 tile 纸基色 */
  --wash-rgb: 246,241,230; /* body 纸纹洗白层 RGB */
  --wash-a: .85;           /* 洗白层不透明度（夜间加深保纸感压暗） */
  color-scheme: light;
}
/* C1 保留字面色（B7 已变量化）：rgba(255,255,255,*) 纸亮层→--lift-rgb（12 处）；
   #FFD9A0→--gold-hi；#ece7da 地板 tile→--floor；body 洗白层→--wash-*。
   水地形 rgba(90,130,160,.45) 是半透明中间色、随底色自适应，留字面不改（2 处）。 */
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body { height: 100%; }
body {
  font-family: var(--serif);
  background: var(--paper);
  background-image: radial-gradient(color-mix(in srgb, var(--ink) 4.5%, transparent) 1px, transparent 1px);
  background-size: 22px 22px;
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
}
button { font-family: inherit; cursor: pointer; }
input, textarea { font-family: inherit; color: var(--ink); }

/* C2 书法标题应用点（20261013m）：游戏名/屏标题/档位名与徽标/轮转行/笔次分隔/抽屉标题。
   正文、输入框、选项按钮不在此列——书法体正文可读性差，按钮保持衬线可读优先。 */
.masthead h1, .bar-title, .tier b, .tier-chip, .turn-banner, .turn-sep, .sheet h2 {
  font-family: var(--brush);
}

.screen { min-height: 100dvh; }

/* ---------- 建卡页 ---------- */
.masthead { padding: max(28px, env(safe-area-inset-top)) 24px 10px; }
.masthead h1 { font-size: 34px; letter-spacing: 6px; font-weight: 700; }
.masthead h1::after { content: ''; display: block; width: 64px; height: 3px; background: var(--cinnabar); margin-top: 10px; }
.masthead-sub { color: var(--ink-dim); margin-top: 10px; font-size: 14px; }

.card { margin: 14px 16px; padding: 18px 16px; border: 1.5px solid var(--line); background: rgba(var(--lift-rgb), .4); /* B7：纸亮层 */ }
.f { display: block; margin: 12px 0; }
.f span, .f-label { display: block; font-size: 13px; color: var(--ink-dim); margin-bottom: 6px; letter-spacing: 2px; }
.f input, .row input, .code-in {
  width: 100%; padding: 10px 12px; font-size: 16px;
  border: 1.5px solid var(--line); background: rgba(var(--lift-rgb), .65); outline: none; /* B7：纸亮层 */
}
.f input:focus { border-color: var(--cinnabar); }

.class-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.cls {
  border: 1.5px solid var(--line); padding: 10px 12px; background: transparent; text-align: left;
}
.cls b { font-size: 16px; display: block; }
.cls span { font-size: 12px; color: var(--ink-dim); }
.cls.on { border-color: var(--cinnabar); box-shadow: inset 0 0 0 1px var(--cinnabar); } /* C6：选中 6% 朱砂底移入纸纹渐变栈顶层（background 简写会重置纸纹 image，见文件尾 C6 段） */

/* 局的类型三选卡（T1 快闪 / T2 标准 / T3 史诗，默认快闪） */
.tier-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.tier {
  border: 1.5px solid var(--line); background: transparent; padding: 8px 6px;
  text-align: center;
}
.tier b { font-size: 14px; display: block; letter-spacing: 1px; }
.tier span { font-size: 10.5px; color: var(--ink-dim); line-height: 1.5; display: block; margin-top: 3px; }
.tier.on { border-color: var(--cinnabar); box-shadow: inset 0 0 0 1px var(--cinnabar); } /* C6：同 .cls.on，选中底色移入纸纹栈 */

.attrs-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; margin-top: 8px; }
.attr { border: 1px solid var(--line); padding: 8px 4px; text-align: center; }
.attr b { font-size: 20px; }
.attr span { display: block; font-size: 11px; color: var(--ink-dim); letter-spacing: 2px; }

.primary {
  width: 100%; margin-top: 14px; padding: 13px; font-size: 17px; letter-spacing: 6px;
  background: var(--ink); color: var(--paper); border: none;
}
.primary:disabled { opacity: .4; }
.primary.round { width: 52px; height: 52px; margin: 0; border-radius: 50%; letter-spacing: 0; font-size: 18px; flex: none; }
.ghost { padding: 9px 14px; border: 1.5px solid var(--line); background: transparent; font-size: 14px; }
.mini { border: none; background: none; color: var(--cinnabar); font-size: 12px; text-decoration: underline; margin-left: 8px; }
.row { display: flex; gap: 8px; align-items: stretch; }
.tiny-tip { font-size: 12px; color: var(--ink-dim); margin-top: 10px; }

/* ---------- 冒险页 ---------- */
#screen-play { display: flex; flex-direction: column; height: 100dvh; }
.bar {
  display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 2px 8px;
  padding: max(10px, env(safe-area-inset-top)) 16px 10px;
  border-bottom: 1.5px solid var(--line); background: color-mix(in srgb, var(--paper) 92%, transparent); backdrop-filter: blur(4px);
}
.bar-title { font-size: 17px; letter-spacing: 3px; }
.code { font-family: var(--mono); font-size: 12px; color: var(--cinnabar); margin-left: 8px; letter-spacing: 2px; }
.tier-chip {
  display: inline-block; margin-left: 8px; padding: 2px 8px; vertical-align: 2px;
  font-size: 11px; letter-spacing: 1px; white-space: nowrap;
  color: var(--paper); background: var(--gold);
}
.bar-btn { border: 1.5px solid var(--line); background: transparent; padding: 6px 12px; font-size: 13px; }

.monsters {
  padding: 3px 10px; /* B10：细条态容器 padding（细条 22px + 上下 6px ≈28px 总高），横向滚动移交 .strip-thin */
  border-bottom: 1px solid var(--line); background: color-mix(in srgb, var(--cinnabar) 5%, transparent);
}
.mon { flex: none; font-size: 12px; border: 1px solid var(--line); padding: 4px 8px; background: var(--paper); }
.mon b { color: var(--cinnabar); }
.mon.dead { opacity: .4; text-decoration: line-through; }

.stream { flex: 1; overflow-y: auto; padding: 16px 16px 8px; scroll-behavior: smooth; }
.entry { margin-bottom: 16px; }
.dm-text { font-size: var(--read-fs); line-height: var(--read-lh); overflow-wrap: break-word; } /* B7：字号/行距滑杆只作用于叙事正文；C3：长 token 兜底换行（中文避头尾由浏览器默认行破规则处理，勿设 word-break） */
.dm-text p + p { margin-top: 0.6em; } /* C3：段落间距随字号滑杆等比（clreq 段距 < 行距的呼吸感） */
.dm-text::before { content: '❝ '; color: var(--gold); }

/* ---------- C3 首字下沉（20261013n）：DM 叙事第一段首字，朱砂书法体约两行高 ----------
   纯 CSS ::first-letter 裁定：打字机逐字只改 textContent、finish() 重建 <p>、回放 innerHTML、
   记录克隆 importNode 四条路全都首段结构不变，浏览器对首字实时重算但视觉稳定，零 JS 参与。
   S2 实测：IAB Chromium 的 initial-letter 渲染有缺陷（首字裁切+首行削顶），弃用；
   全引擎统一走经典 float 下沉（字号=2 行高估算式，line-height:1 浮动盒恰为两行）。 */
.dm-text > p:first-child::first-letter {
  float: left;
  font-family: var(--brush);
  color: var(--cinnabar);
  font-size: calc(var(--read-fs) * var(--read-lh) * 2); /* 恰为两行行高的盒 */
  line-height: 1;
  padding: 0 .1em 0 0;
}
.backlog-body .dm-text > p:first-child::first-letter {
  font-size: calc((var(--read-fs) - 2px) * var(--read-lh) * 2); /* 记录副本正文小一档，字号随之 */
}

/* ---------- C3 章节题条（竖排，20261013n）：开卷/换景时 app.js 在打字机前插入 ----------
   独立一行左置竖排窄条（≈33px 宽）+ 右延细墨线，375px 下不挤正文；宣纸底+细边框，
   题字竖排书法体朱砂；夜间经 --paper/--cinnabar/--line 自动适配。 */
.scene-mark { display: flex; align-items: stretch; gap: 10px; margin: 22px 0 14px; }
.scene-mark::after { content: ''; flex: 1; align-self: center; height: 1px; background: var(--line); }
.scene-mark-t {
  flex: none; writing-mode: vertical-rl;
  max-height: 240px; overflow: hidden;
  padding: 10px 8px;
  font-family: var(--brush); font-size: 15px; letter-spacing: 3px; line-height: 1;
  color: var(--cinnabar);
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  border: 1px solid var(--line); border-radius: 2px;
  box-shadow: 2px 2px 0 color-mix(in srgb, var(--ink) 10%, transparent);
}
.point-line {
  margin-top: 12px; padding: 7px 12px; font-size: calc(var(--read-fs) * .85); /* B7：随正文字号缩放（默认≈14px） */
  border-left: 3px solid var(--cinnabar); background: color-mix(in srgb, var(--cinnabar) 7%, transparent);
  color: var(--cinnabar); letter-spacing: 1px;
}

/* ---------- C5 事件插画卡（20261013y）：DM 声明 illustration 时 app.js 在叙事 entry 前插全宽水墨卡 ----------
   与 scene-mark 同语言：宣纸底 + 细墨线 + 错位落影（图 720x410 横幅自适应全宽）；
   img loading=lazy（app.js，按需加载不进首屏预算）；记录抽屉克隆天然携带（静图无动画）；
   墨夜主题降亮度滤镜（纸底图在暗底上过亮，压一档保阅读节奏），sepia/paper 不动。 */
.illus-card {
  margin: 18px 0 14px; padding: 6px;
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  border: 1px solid var(--line); border-radius: 4px;
  box-shadow: 2px 2px 0 color-mix(in srgb, var(--ink) 10%, transparent);
}
.illus-img { display: block; width: 100%; height: auto; border-radius: 2px; }
[data-theme="night"] .illus-img { filter: brightness(.82) saturate(.92); }
.player-text {
  margin-left: auto; max-width: 82%; width: fit-content;
  background: color-mix(in srgb, var(--ink) 6%, transparent); border-right: 3px solid var(--ink-dim);
  padding: 8px 12px; font-size: calc(var(--read-fs) * .909); color: var(--ink); /* B7：随正文字号缩放（默认≈15px） */
}
.engine-lines { margin: 6px 0; }
.engine-line {
  position: relative; /* C7：飘字 .fx-float 的定位锚（行即容器，不另包一层） */
  font-family: var(--mono); font-size: 12px; color: var(--ink-dim);
  padding: 3px 0; border-bottom: 1px dashed var(--line);
}
.engine-line b { color: var(--cinnabar); font-weight: 600; }
.dice-line { font-family: var(--mono); font-size: 11px; color: var(--gold); opacity: .85; }
.turn-sep { text-align: center; color: var(--ink-dim); font-size: 11px; letter-spacing: 4px; margin: 20px 0 12px; }

/* B4 选项拇指区（20261013e）：全宽大热区——min-height 44px、字号 16px、间距 8px；
   ≤4 条 + 末位固定「✎ 自行输入」由 app.js renderChoices 保证；选项区位于叙事流末尾与输入条之间，已在拇指易达区 */
.choices { padding: 4px 16px 8px; display: flex; flex-direction: column; gap: 8px; }
/* 移动端选项两列（S1 冒烟修正）：高度减半还给叙事流，按钮仍 ≥44px 热区 */
@media (max-width: 520px) {
  .choices { display: grid; grid-template-columns: 1fr 1fr; }
  .choice { font-size: 15px; padding: 11px 8px; }
}
.choice {
  border: 1.5px solid var(--line); background: rgba(var(--lift-rgb), .5); /* B7：纸亮层 */
  min-height: 44px; padding: 11px 12px; text-align: left; font-size: 16px;
}
.choice::before { content: '→ '; color: var(--cinnabar); }
.choice-free { border-style: dashed; } /* B4 末位「自行输入」键：虚线框区分（✎ 字形在部分设备缺字） */
.choice-free::before { content: ''; }
.choice:active { background: color-mix(in srgb, var(--cinnabar) 8%, transparent); }

.inputbar { border-top: 1.5px solid var(--line); background: color-mix(in srgb, var(--paper) 95%, transparent); padding: 8px 12px calc(8px + env(safe-area-inset-bottom)); }
.busy { font-size: 13px; color: var(--ink-dim); padding: 2px 4px 8px; }
.busy .dots i { animation: blink 1.2s infinite; font-style: normal; }
.busy .dots i:nth-child(2) { animation-delay: .2s; }
.busy .dots i:nth-child(3) { animation-delay: .4s; }
@keyframes blink { 0%, 60%, 100% { opacity: .2; } 30% { opacity: 1; } }
#in-text { flex: 1; resize: none; padding: 10px 12px; font-size: 16px; border: 1.5px solid var(--line); background: rgba(var(--lift-rgb), .7); outline: none; max-height: 96px; } /* B7：纸亮层 */
#in-text:focus { border-color: var(--cinnabar); }

/* ---------- 角色卡抽屉 ---------- */
.mask { position: fixed; inset: 0; background: color-mix(in srgb, var(--ink) 35%, transparent); z-index: 9; }
.sheet {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 10;
  background-color: var(--paper); border-top: 2px solid var(--ink); /* C6：纸纹 image 由文件尾 C6 段叠加 */
  padding: 20px 18px calc(20px + env(safe-area-inset-bottom));
  animation: up .22s ease-out;
  max-height: calc(100dvh - 40px); overflow-y: auto; /* B5：折叠区展开后抽屉总高不破视口 */
}
@keyframes up { from { transform: translateY(40%); opacity: .4; } }
.sheet h2 { letter-spacing: 4px; }
.dim { color: var(--ink-dim); font-size: 13px; margin: 4px 0 12px; }
.hp { position: relative; border: 1.5px solid var(--line); height: 26px; margin-bottom: 12px; background: rgba(var(--lift-rgb), .5); /* B7：纸亮层 */ }
.hp-bar { height: 100%; background: var(--cinnabar); transition: width .4s; }
.hp span { position: absolute; inset: 0; display: grid; place-items: center; font-size: 13px; font-family: var(--mono); }
/* B5 战斗大数字行：AC / 攻击修正从 kv 升格（暖金大数字，与 B3 b.num 同语言）；武器留折叠区 */
.sheet-vitals { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; margin-bottom: 12px; }
.vital { border: 1.5px solid var(--line); background: rgba(var(--lift-rgb), .5); /* B7：纸亮层 */ text-align: center; padding: 8px 4px 7px; }
.vital b { display: block; font-size: 30px; line-height: 1.15; color: var(--ocher); }
.vital span { font-size: 11px; color: var(--ink-dim); letter-spacing: 2px; }
/* B5 六维大数字卡片：sheet 内放大一档（建卡页 .attr 20px 不受影响） */
.sheet-attrs { margin-top: 0; }
#sheet .attr { padding: 10px 4px 8px; }
#sheet .attr b { font-size: 26px; line-height: 1.2; }
/* D5 点卡掷骰：六维/攻击修正为可点按钮（一切数字可点）；AC 是被动防御值保持 div 不可点。
   按钮重置为卡片原观感（font:inherit + 无底色），虚线下划线示意可掷 + 按压反馈；
   .sheet-hint 一行 dim 字说明「点数字即掷骰」。 */
#sheet button.vital, #sheet button.attr {
  font: inherit; color: inherit; background: none; cursor: pointer; padding: 8px 4px 7px;
}
#sheet button.attr { padding: 10px 4px 8px; }
#sheet button.vital b, #sheet button.attr b { border-bottom: 1px dashed color-mix(in srgb, var(--gold) 55%, transparent); }
#sheet button.vital:active, #sheet button.attr:active { transform: translateY(1px); background: color-mix(in srgb, var(--cinnabar) 6%, transparent); }
.sheet-hint { margin: 8px 0 0; font-size: 12px; }
/* B5 折叠区「装备/详情」：默认收起；44px 热区；grid-rows 0fr→1fr 过渡展开不抖动第一屏，
   visibility 随高度过渡把收起内容移出读屏/焦点序 */
.sheet-fold { margin-top: 12px; border: 1.5px solid var(--line); background: rgba(var(--lift-rgb), .35); /* B7：纸亮层 */ }
.fold-toggle {
  display: flex; width: 100%; min-height: 44px; align-items: center; justify-content: space-between;
  border: none; background: none; padding: 10px 12px;
  font-size: 14px; letter-spacing: 2px; color: var(--ink);
}
.fold-toggle::after { content: '▸'; color: var(--gold); font-size: 15px; }
.sheet-fold.open .fold-toggle::after { content: '▾'; }
.fold-toggle:active { background: color-mix(in srgb, var(--cinnabar) 6%, transparent); }
.fold-body { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .22s ease; }
.sheet-fold.open .fold-body { grid-template-rows: 1fr; }
.fold-inner { min-height: 0; overflow: hidden; visibility: hidden; transition: visibility .22s; }
.sheet-fold.open .fold-inner { visibility: visible; }
.fold-inner .kv { margin: 2px 12px 12px; }
.kv { display: grid; grid-template-columns: 5.5em 1fr; gap: 6px 14px; margin: 12px 0; font-size: 14px; align-items: baseline; }
.kv dt { color: var(--ink-dim); }
.kv dd { min-width: 0; overflow-wrap: anywhere; }
.sheet .ghost { width: 100%; margin-top: 8px; }

.toast {
  position: fixed; left: 50%; bottom: 90px; transform: translateX(-50%);
  background: var(--ink); color: var(--paper); font-size: 14px;
  padding: 9px 16px; z-index: 99; max-width: 86vw;
}
[hidden] { display: none !important; }
@media (min-width: 640px) {
  .stream, .inputbar, .bar, .monsters { max-width: 720px; margin-inline: auto; }
  .bar, .monsters { width: 100%; }
}

/* ---------- M2/M3：轮转条、队伍条、方格地图 ---------- */
.turn-banner {
  padding: 8px 16px; font-size: 14px; color: var(--paper);
  background: var(--ink); letter-spacing: 1px;
}
.turn-banner b { color: var(--gold-hi); } /* B7：墨底亮金→变量（夜间换暗铜） */
.party-strip {
  padding: 3px 10px; /* B10：细条态容器 padding（细条 22px + 上下 6px ≈28px 总高） */
  border-bottom: 1px solid var(--line); background: rgba(var(--lift-rgb), .35); /* B7：纸亮层 */
}
.pm { flex: none; font-size: 12px; border: 1px solid var(--line); padding: 4px 8px; background: var(--paper); color: var(--ink-dim); }
.pm b { color: var(--ink); }
.pm.is-me { border-color: var(--cinnabar); }
.pm.is-cur { background: color-mix(in srgb, var(--cinnabar) 10%, transparent); border-color: var(--cinnabar); }
.pm.is-done { opacity: .55; }

.map-panel { position: relative; border-bottom: 1.5px solid var(--line); background: rgba(var(--lift-rgb), .3); padding: 10px 16px 6px; } /* B7：纸亮层 */
.map-toggle { position: absolute; right: 12px; top: 8px; border: 1px solid var(--line); background: var(--paper); font-size: 12px; padding: 3px 8px; }
.map-grid {
  display: grid; gap: 1px; width: fit-content; margin: 6px auto;
  --cell: clamp(24px, 6.4vw, 34px);
  border: 1.5px solid var(--ink); background: var(--line);
  transform-origin: 0 0; will-change: transform; /* B9 手势： pinch/平移作用在整层，命中仍按格子算 */
}
/* B9 地图手势视口：缩放/平移的窗口（内容盒大小，不挤压叙事流）；touch-action:none 让 Pointer Events 全权接管 */
.map-viewport {
  position: relative; overflow: hidden; touch-action: none;
  user-select: none; -webkit-user-select: none; -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent; cursor: grab;
}
.map-viewport.is-drag { cursor: grabbing; }
.cell { width: var(--cell); height: var(--cell); position: relative; display: grid; place-items: center; }
.cell.floor { background: rgba(var(--lift-rgb), .55); } /* B7：纸亮层（tile 版在美术层用 --floor） */
.cell.wall { background: var(--ink); }
.cell.water { background: rgba(90,130,160,.45); } /* C1保留：水地形色 */
.cell.door { background: color-mix(in srgb, var(--gold) 50%, transparent); }
.cell.rubble { background: color-mix(in srgb, var(--ink-dim) 30%, transparent); }
.cell.reach { outline: 1.5px solid var(--cinnabar); outline-offset: -2px; cursor: pointer; background: color-mix(in srgb, var(--cinnabar) 14%, transparent); }
.tok {
  width: 78%; height: 78%; display: grid; place-items: center;
  font-size: calc(var(--cell) * .42); color: var(--paper); border-radius: 0;
  font-family: var(--serif); pointer-events: none;
}
.tok-party { background: var(--cinnabar); }
.tok-foe { background: var(--ink); }
.tok.is-me { box-shadow: 0 0 0 2px var(--gold); }
.map-hint { font-size: 12px; color: var(--ink-dim); text-align: center; padding: 2px 0 6px; }

/* ---------- E2 路线 A：CSS 斜视伪 3D 地图（20261013q 试点；20261013r 默认关 + 平铺命中层） ----------
   两级 transform 层级（自外向内）：
   ① #map-viewport —— B9/T11 手势层（overflow 窗口 + Pointer Events），只负责窗口；
   ② .map-stage —— 3D 姿态层：perspective()+rotateX/rotateZ 一次性静态变换，preserve-3d 向下透传；
   ③ #map-grid —— 手势层：JS 内联只写 translate+scale（B9 原样），与 stage 的 3D 变换互不覆写；
   ④ .cell / .tok —— translateZ 抬升地形 / 反向旋转立牌 token。
   E2A 命中层（20261013r）：IAB 内核下 3D transform 子树的命中测试与视觉投影不一致——
   elementFromPoint/真实点击落在 .map-grid 不下探 .cell，走位/宣攻全部失效（T19 预留兜底触发）。
   补 #map-hit：与 #map-grid 同规格的平铺透明网格盖在 stage 之上。3D 开启时 stage 整层
   pointer-events:none（视觉子树退出命中）、命中层接管点击（点击=平面坐标→逻辑格）；
   平面模式命中层 pointer-events:none，原格子照常原生命中。B9 手势/双击补发
   （elementFromPoint）天然落在这两层中的正确一层，无需改动。
   开关（20261013r 翻转）：默认平面——观感裁决：375px 下透视吃掉贴图细节、墙无立体侧面感、
   可读性不升反降；html[data-map3d="on"] 才启用下列 3D 规则，一瞬切换零 JS 重算
   （裁定留档 decisions.md T19 追记）。 */
:root { --map3d-tilt: 55deg; } /* 斜视角单一事实源：stage 姿态与 token 立牌共用 */
html[data-map3d="on"] .map-stage {
  transform: perspective(760px) rotateX(var(--map3d-tilt)) rotateZ(-12deg);
  transform-style: preserve-3d;
  pointer-events: none; /* E2A：3D 视觉子树整体退出命中，点击由 #map-hit 平铺层接管 */
}
html[data-map3d="on"] .map-grid { transform-style: preserve-3d; } /* 手势层不切断 3D 语境 */
/* 地形抬升：墙 14px / 门 8px（translateZ 出平面）+ 静态投影 shadow 增层高感（无逐帧成本）。
   裁定：只给抬升格上投影，地板/水/碎石不抬不上影——全格投影徒增合成面，层高感反而糊 */
html[data-map3d="on"] .cell.wall { transform: translateZ(14px); box-shadow: 1px 2px 4px rgba(0, 0, 0, .28); }
html[data-map3d="on"] .cell.door { transform: translateZ(8px); box-shadow: 1px 1px 3px rgba(0, 0, 0, .22); }
/* token 立牌：rotateZ 反转 -12° 微转 + rotateX 反转俯角面向镜头，底边铰链立起（origin 底） */
html[data-map3d="on"] .tok {
  transform: rotateZ(12deg) rotateX(calc(var(--map3d-tilt) * -1));
  transform-origin: 50% 100%;
}
/* 玩家 token 呼吸：全页唯一动画，纯 transform（合成层属性），2.6s 慢节奏单元素，无重排 */
html[data-map3d="on"] .tok.is-me { animation: tok-bob 2.6s ease-in-out infinite; }
@keyframes tok-bob {
  0%, 100% { transform: rotateZ(12deg) rotateX(calc(var(--map3d-tilt) * -1)) translateZ(0); }
  50% { transform: rotateZ(12deg) rotateX(calc(var(--map3d-tilt) * -1)) translateZ(3px); }
}
@media (prefers-reduced-motion: reduce) {
  html[data-map3d="on"] .tok.is-me { animation: none; }
}
/* 墨夜 tile 暗纱与 3D 抬升共存：B7 夜间 .cell inset 纱特异性 (0,2,1) 低于抬升格 (0,3,1)，
   外投影 box-shadow 会整个盖掉暗纱 → 夜间+3D 显式合并两组 shadow（暗纱罩底 + 外投影落层高） */
html[data-theme="night"][data-map3d="on"] .cell.wall { box-shadow: inset 0 0 0 999px rgba(26, 23, 18, .5), 1px 2px 4px rgba(0, 0, 0, .4); }
html[data-theme="night"][data-map3d="on"] .cell.door { box-shadow: inset 0 0 0 999px rgba(26, 23, 18, .5), 1px 1px 3px rgba(0, 0, 0, .35); }

/* ---------- E2A 平铺命中层 #map-hit（20261013r） ----------
   与 #map-grid 同规格（--cell/1px 间距/水平居中/同宽边框占位）的透明网格，renderMap 逐格
   填 .hit-cell（data-x/data-y + onCellClick）。默认 pointer-events:none 完全不拦截——
   平面模式原格原生命中（本档默认态）；仅 html[data-map3d="on"] 时翻为可点（上面 E2 段）。 */
.map-hit {
  --cell: clamp(24px, 6.4vw, 34px); /* 与 .map-grid 基准同值，窄屏/宽屏由下方同名组规则覆写 */
  position: absolute; top: 0; left: 0; right: 0;
  width: fit-content; margin: 6px auto 0; /* 同 #map-grid 的 margin:6px auto；绝对定位下 auto 左右居中 */
  display: grid; gap: 1px;
  border: 1.5px solid transparent; /* 与 grid 边框同宽占位，命中格与视觉格一一对位 */
  pointer-events: none;
}
.hit-cell { width: var(--cell); height: var(--cell); }
.hit-cell.reach { cursor: pointer; } /* 命中格保持透明，可走只给指针形态（视觉高亮仍在原格上） */
html[data-map3d="on"] .map-hit { pointer-events: auto; } /* 3D 开启才接管点击 */

.quick { gap: 6px; margin-bottom: 6px; }
.quick-btn {
  flex: 1; border: 1px solid var(--line); background: rgba(var(--lift-rgb), .5); /* B7：纸亮层 */
  font-size: 12px; padding: 6px 2px; color: var(--ink);
}
.quick-btn:disabled { opacity: .4; }

/* ---------- T33/D11 意图 seg（输入框上方）：这句话被当成什么（行动/对白/旁白）。
   选中朱砂、未选淡墨；.intent-tag 是文字流里 say/story 行动的前置淡墨小签 ---------- */
.intent-seg {
  display: inline-flex; border: 1px solid var(--line); background: rgba(var(--lift-rgb), .5);
  margin-bottom: 6px;
}
.intent-btn {
  border: 0; background: none; font-family: var(--serif); font-size: 11px;
  padding: 3px 10px; color: var(--ink-dim); cursor: pointer; line-height: 1.6;
}
.intent-btn + .intent-btn { border-left: 1px solid var(--line); }
.intent-btn.on { background: var(--cinnabar); color: var(--paper); }
.intent-tag {
  display: inline-block; font-size: 11px; line-height: 1.5; color: var(--ink-dim);
  border: 1px solid var(--line); padding: 0 4px; margin-right: 6px; vertical-align: 1px;
}

/* ---------- 美术资源层（20261012c；C8 起 tile 引用 .webp（同名 jpg 并存不删）；assets/ 由 tools/gen-art.mjs 生成，红线门禁 node tools/check-assets.mjs） ---------- */
body {
  background-image: linear-gradient(rgba(var(--wash-rgb), var(--wash-a)), rgba(var(--wash-rgb), var(--wash-a))), url('assets/bg-paper.jpg'); /* B7：宣纸洗白层→变量（夜间压暗保纸感） */
  background-size: auto, 512px;
}
/* 地图 tile：zoom-crop 裁掉生成图的宣纸边距 */
.cell.wall { background: var(--ink) url('assets/tile-wall.webp') center/135% 135%; }
.cell.floor { background: var(--floor) url('assets/tile-floor.webp') center/cover; } /* B7：地板 tile 纸基色→变量 */
.cell.water { background: rgba(90,130,160,.45) url('assets/tile-water.webp') center/138% 138%; } /* C1保留：水地形色 */
.cell.door { background: color-mix(in srgb, var(--gold) 50%, transparent) url('assets/tile-door.webp') center/125% 125%; }
.cell.rubble { background: color-mix(in srgb, var(--ink-dim) 30%, transparent) url('assets/tile-rubble.webp') center/cover; }
/* 队伍条职业头像（E1 接入点二）：idle 雪碧图首帧静图（auto 100% 整身等比缩到 17px 高，水平居中）。
   裁定：17px 下呼吸动效≈亚像素抖动只出锯齿，不做动画只取首帧（task 保底条款，见 style.css E1 段） */
.pm-av {
  display: inline-block; width: 17px; height: 17px; flex: none;
  background-size: auto 100%; background-position: center top;
  border: 1px solid var(--line); margin-right: 5px; vertical-align: -4px;
}
.pm { display: inline-flex; align-items: center; }
/* 角色卡立绘 */
.sheet-portrait {
  width: 200px; max-width: 55%; aspect-ratio: 1 / 1; margin: 8px 0 10px;
  background-size: cover; background-position: center top;
  border: 1.5px solid var(--line);
}
/* B5 矮屏兜底：立绘收一档，保证第一屏（立绘→HP→AC/攻修→六维）不滚动 */
@media (max-height: 700px) {
  .sheet-portrait { width: 132px; }
}
/* ---------- E1 立绘循环动画（20261013s）：CSS steps() 逐帧雪碧图（assets/spr/，128px 高 ×10 帧） ----------
   通用类 .spr-anim = 单帧窗口元素：aspect-ratio 定宽、background-size 1000% 100% 让十帧铺满窗宽
   （单帧显示宽恰=元素宽）。动画只写 background-position-x：百分比 p 的偏移=p·(w−10w)=−9wp，
   to 用 111.111%（=10/9）时 steps(10) 采样 p=k/90·10 → 偏移恰为 −kw，逐帧对齐零漂移，
   且与元素实际像素尺寸无关（响应式安全）；steps(10) 每周期仅 10 次重绘，无布局成本。
   开关：html[data-spr]（app.js 写入，dnd_spr 持久化，默认开；prefers-reduced-motion 时默认关，
   用户显式选「开」则尊重选择）。off=animation 不挂载，定格首帧。三个接入点：
   ①角色卡立绘 .spr-portrait（抽屉开时才存在）②队伍条 .pm-av 静帧不挂动画（17px 锯齿裁定，
   规则见 .pm-av 段）③怪物条展开态妖物图标 .mon-ico（细条态不渲染图标=天然不挂；
   attack-foe 前扑是大幅动作 14px 下仍可读）。地图 token 保持单字不动（E1 明确）。 */
.spr-anim {
  display: block;
  background-size: 1000% 100%;
  background-repeat: no-repeat;
  background-position: 0 0; /* off / 定格：首帧 */
}
html[data-spr="on"] .spr-anim { animation: spr-play var(--spr-dur, 2s) steps(10) infinite; }
@keyframes spr-play {
  from { background-position-x: 0%; }
  to { background-position-x: 111.111%; } /* 10/9：steps(10) 每步恰移一帧宽 */
}
/* 接入点一：角色卡立绘——#sh-portrait 200px 方框内的单帧窗口，等比放大（高=框高，≈1.56 倍），
   慢呼吸 2.2s；透明底透出宣纸，水墨框不变 */
.spr-portrait { height: 100%; aspect-ratio: var(--fw) / 128; margin: 0 auto; }
/* 接入点三：怪物条展开态图标——attack-foe 14px 高等比，前扑节奏 1.6s */
.mon-ico {
  display: inline-block; height: 14px; aspect-ratio: var(--fw) / 128;
  vertical-align: -3px; margin-right: 5px;
  border: 1px solid var(--line);
}
.mon:nth-of-type(n + 5) .spr-anim { animation: none; } /* 同屏动画 ≤6 预算：展开怪条第 5 只起静帧 */

/* ---------- 同屏布局（20261012d）：地图与 DM 叙事同时可见 ---------- */
/* 手机竖屏：游戏壳——顶栏/队伍/地图钉住，输入框钉底，故事区内部滚动 */
#screen-play { display: flex; flex-direction: column; height: 100dvh; overflow: hidden; }
#screen-play > .bar, #screen-play > .turn-banner, #screen-play > .party-strip,
#screen-play > .monsters, #screen-play > .map-panel, #screen-play > .choices,
#screen-play > .inputbar { flex: none; }
#screen-play > .stream { flex: 1 1 0; min-height: 0; overflow-y: auto; }
#screen-play > #stream-wrap { min-height: 0; }
/* B4：≤4 选项 + 「自行输入」共 5 键 ×44px + 间距 ≈252px，44vh 在 ≥573px 高的竖屏全容纳单屏可点；更矮屏选项区内部滚动兜底 */
#screen-play > .choices { max-height: 44vh; overflow-y: auto; }
#screen-play .map-grid, #screen-play .map-hit { --cell: clamp(15px, 4.4vw, 34px); }
#screen-play .map-panel { padding: 6px 12px 4px; }

/* 宽屏（手机横屏/平板/桌面 ≥900px）：左地图右故事，天然同屏 */
@media (min-width: 900px) {
  #screen-play {
    display: grid;
    grid-template-columns: minmax(300px, 30vw) 1fr;
    grid-template-rows: auto auto auto auto 1fr auto auto;
    grid-template-areas:
      "bar    bar"
      "banner banner"
      "party  stream"
      "mon    stream"
      "map    stream"
      "choices choices"
      "input  input";
    height: 100dvh; overflow: hidden;
  }
  #screen-play > .bar { grid-area: bar; }
  #screen-play > .turn-banner { grid-area: banner; }
  #screen-play > .party-strip { grid-area: party; }
  #screen-play > .monsters { grid-area: mon; }
  #screen-play > .map-panel { grid-area: map; overflow: hidden; } /* B9：原生横向滚动让位给拖拽平移+滚轮缩放 */
  #screen-play > #stream-wrap { grid-area: stream; }
  #screen-play > .choices { grid-area: choices; max-height: none; }
  #screen-play > .inputbar { grid-area: input; }
  /* 覆盖 640px 档的 720px 居中，恢复满宽分栏 */
  #screen-play .stream, #screen-play .inputbar, #screen-play .bar,
  #screen-play .monsters { max-width: none; margin-inline: 0; }
  /* 左栏地图格随栏宽自适应（最宽 14 列也放得下） */
  #screen-play .map-grid, #screen-play .map-hit { --cell: clamp(14px, 30vw / 16, 30px); }
  .map-hint { display: none; }
}

/* ---------- T1 新手引导层 coach-mark（仅快闪局） ---------- */
/* #tut 全屏容器吞掉一切点击：遮罩点击不前进，只有气泡内两个按钮可点 */
#tut { position: fixed; inset: 0; z-index: 50; }
#tut-spot {
  position: absolute; border: 2px solid var(--cinnabar); border-radius: 3px;
  box-shadow: 0 0 0 200vmax color-mix(in srgb, var(--ink) 58%, transparent);
  transition: left .18s ease, top .18s ease, width .18s ease, height .18s ease;
  pointer-events: none;
}
#tut-bubble {
  position: absolute; max-width: 300px; padding: 12px 14px 10px;
  background: var(--paper); border: 1.5px solid var(--ink);
  box-shadow: 4px 4px 0 color-mix(in srgb, var(--ink) 18%, transparent);
  animation: tutin .18s ease-out;
}
/* 指向目标的箭头（below=目标在下方 / above=目标在上方），位置随目标居中 */
#tut-bubble::before, #tut-bubble::after {
  content: ''; position: absolute; left: var(--ax, 24px); border: 8px solid transparent;
}
#tut-bubble.below::before { top: -8px; border-bottom-color: var(--ink); }
#tut-bubble.below::after { top: -6px; border-bottom-color: var(--paper); }
#tut-bubble.above::before { bottom: -8px; border-top-color: var(--ink); }
#tut-bubble.above::after { bottom: -6px; border-top-color: var(--paper); }
@keyframes tutin { from { opacity: 0; transform: translateY(5px); } }
#tut-text { font-size: 14.5px; line-height: 1.7; letter-spacing: .5px; }
.tut-row { display: flex; align-items: center; gap: 10px; margin-top: 10px; }
.tut-count { font-family: var(--mono); font-size: 11px; color: var(--ink-dim); margin-right: auto; }
.tut-btn { font-size: 13px; padding: 6px 12px; border: 1.5px solid var(--line); background: transparent; }
.tut-btn.tut-next { border-color: var(--ink); background: var(--ink); color: var(--paper); letter-spacing: 2px; }
.tut-btn.tut-skip { border: none; color: var(--ink-dim); text-decoration: underline; padding: 6px 2px; }

/* ---------- VN 三小键 + 冒险记录抽屉（20261013c，B1/B8） ---------- */
/* 叙事流包壳：三小键钉在流区右下角（输入条/选项上方，拇指可达），随 flex/grid 布局自适应 */
#stream-wrap { position: relative; flex: 1 1 0; min-height: 0; display: flex; flex-direction: column; }
#stream-wrap .stream { flex: 1 1 0; min-height: 0; padding-bottom: 42px; } /* 末行不被 VN 三小键盖住 */
#vn-keys { position: absolute; right: 10px; bottom: 10px; z-index: 5; display: flex; gap: 6px; }
.vn-key {
  border: 1.5px solid var(--line); background: color-mix(in srgb, var(--paper) 92%, transparent); color: var(--ink);
  font-size: 12px; letter-spacing: 1px; padding: 6px 10px;
  box-shadow: 2px 2px 0 color-mix(in srgb, var(--ink) 14%, transparent);
}
.vn-key:active { background: color-mix(in srgb, var(--cinnabar) 8%, transparent); }
.vn-key.on {
  border-color: var(--cinnabar); color: var(--cinnabar); background: color-mix(in srgb, var(--cinnabar) 10%, transparent);
  box-shadow: inset 0 0 0 1px var(--cinnabar);
}
/* 记录抽屉：壳沿用 .sheet（遮罩+滑出），内部改为可滚列表 */
.backlog { display: flex; flex-direction: column; max-height: 80dvh; }
.backlog-body {
  flex: 1 1 0; min-height: 0; overflow-y: auto; margin: 4px 0 10px;
  border: 1px solid var(--line); background: rgba(var(--lift-rgb), .35); /* B7：纸亮层 */
  padding: 12px 12px 6px;
}
.backlog-body .entry { margin-bottom: 12px; }
.backlog-body .dm-text { font-size: calc(var(--read-fs) - 2px); line-height: var(--read-lh); } /* B7：记录副本随滑杆，恒小正文一档 */
.backlog-body .player-text { font-size: 13.5px; }

/* ---------- 裁定行两层展开 + 关键数值放大（20261013d，B2/B3） ---------- */
/* 摘要行整体可点：button 继承行内字体，T5 两段式点击对 button 已放行 */
.engine-line.has-detail { padding: 0; }
.eng-toggle {
  display: block; width: 100%; text-align: left;
  border: none; background: none; padding: 3px 0;
  font-family: var(--mono); font-size: 12px; color: var(--ink-dim); line-height: 1.6;
}
.eng-toggle::before { content: '▸ '; color: var(--gold); }
.engine-line.open .eng-toggle::before { content: '▾ '; }
.eng-toggle:active { background: color-mix(in srgb, var(--cinnabar) 6%, transparent); }
/* 明细层：骰池原值/加减项/伤害表达式，小一号墨灰、左侧朱线 */
.eng-detail {
  margin: 1px 0 4px 1.1em; padding: 2px 8px 3px;
  border-left: 2px solid var(--line);
  font-family: var(--mono); font-size: 11px; color: var(--ink-dim); line-height: 1.7;
  overflow-wrap: anywhere;
}
.det-row { padding: 1px 0; }
.pool-used { font-style: normal; font-weight: 700; color: var(--cinnabar); }
/* B3 关键数值：暖金 ×1.3，行内元素收紧 line-height 不破行排（置于 .engine-line b 之后，金色胜出） */
b.num { color: var(--ocher); font-size: 1.3em; font-weight: 700; line-height: 1; padding: 0 1px; }

/* ---------- B6 说话人名牌（20261013h）：每条叙事自带「这是谁在说」，Character.AI/橙光式 ---------- */
/* DM 条目：左侧朱砂「DM」小方章（纯 CSS 印章，无新图片）+ 正文容器；章先于打字机就位 */
.entry.dm { display: flex; gap: 8px; align-items: flex-start; }
.dm-stamp {
  flex: none; width: 20px; height: 20px; margin-top: 4px;
  display: grid; place-items: center;
  border: 1.5px solid var(--cinnabar); border-radius: 2px;
  color: var(--cinnabar); font-size: 9px; font-weight: 700; line-height: 1;
  letter-spacing: 1px; padding-left: 1px; /* 补 letter-spacing 的视觉偏心 */
  transform: rotate(-4deg); user-select: none;
}
.dm-body { flex: 1; min-width: 0; }
/* 玩家行动条目：头像 + 名牌 + 行动文本，整组沿用原右对齐回声位（水墨纸面，非 IM 气泡）；
   名牌/头像来自 state.members 数据（回放按名字回查），非本地自我视角 */
.entry.act { display: flex; justify-content: flex-end; gap: 7px; align-items: flex-start; }
.act-av {
  flex: none; width: 18px; height: 18px; margin-top: 1px;
  background-size: cover; background-position: center top;
  border: 1px solid var(--line); border-radius: 2px;
}
.act-main { max-width: 82%; display: flex; flex-direction: column; align-items: flex-end; }
.entry.act .player-text { max-width: 100%; }
.act-name { font-size: 12px; color: var(--ink-dim); letter-spacing: 1px; margin: 0 2px 3px 0; }
/* 记录抽屉（B8 克隆）里的名牌随行，字号各收一档 */
.backlog-body .act-av { width: 16px; height: 16px; }
.backlog-body .act-name { font-size: 11px; }

/* ---------- B7 阅读设置 + 三主题（20261013i）：纸白（默认）/ 米黄 / 墨夜 ----------
   换肤只覆写 :root 变量，派生色（--line/高亮/遮罩）跟着根色走；WCAG 对比度实测见 decisions。
   墨夜=暗宣纸暖黑 + 米黄字（忌纯黑纯白）；米黄=中间档；字面色亮层 --lift-rgb 反向压深。 */
html[data-theme="sepia"] {
  --paper: #F0E6D2; --paper-dim: #E3D6B8;
  --ink-dim: #665D4F; --ocher: #9A4916; --gold: #775A27; /* 米黄底略深，次级色微调保 ≥4.5:1 */
  --wash-rgb: 240,230,210; --wash-a: .88;
}
html[data-theme="night"] {
  --paper: #1E1B16; --paper-dim: #15120E;      /* 暗宣纸：暖黑非纯黑 */
  --ink: #D8CFB8; --ink-dim: #B7AA8F;          /* 米黄字非纯白；淡墨 7.5:1 */
  --cinnabar: #E06A50; --ocher: #DCA055; --gold: #C6A052; /* 朱砂/暖金提亮保对比度 */
  --lift-rgb: 12,10,8;   /* 纸亮层反向：夜间压成暗纸层 */
  --gold-hi: #4A3512;    /* 墨底亮金→暗铜（亮条底此时是米色） */
  --floor: #363026;
  --wash-rgb: 30,27,22; --wash-a: .93;
  color-scheme: dark;
}
/* 墨夜压件：遮罩/引导压暗层原本是 --ink 透明层，夜间 --ink 变亮会成白纱，反转为暗纱 */
html[data-theme="night"] .mask { background: rgba(0,0,0,.55); }
html[data-theme="night"] #tut-spot { box-shadow: 0 0 0 200vmax rgba(0,0,0,.72); }
/* 墨夜纸纹/浅素材压一档：tile 暗纱罩面（罩在格底上、token/高亮 outline 之下），立绘头像轻压防刺眼 */
html[data-theme="night"] .cell { box-shadow: inset 0 0 0 999px rgba(26,23,18,.5); }
html[data-theme="night"] .pm-av, html[data-theme="night"] .act-av,
html[data-theme="night"] .sheet-portrait, html[data-theme="night"] .mon-ico { filter: brightness(.82) saturate(.92); }

/* B7 阅读设置抽屉（微信读书式 Aa 面板不离页）：壳沿用 .sheet；滑杆实时预览，不缩放 UI 控件 */
.bar-btns { display: flex; gap: 6px; }
.reader-row { display: flex; align-items: center; gap: 10px; margin: 14px 0; }
.read-label { flex: none; width: 2.8em; font-size: 13px; color: var(--ink-dim); letter-spacing: 2px; }
#m3d-label, #spr-label { width: auto; } /* E2「立体地图」/E1「立绘动画」四字放下（其余标签两字 2.8em 不变） */
.reader-row input[type="range"] { flex: 1; min-width: 0; accent-color: var(--cinnabar); }
.reader-row output { flex: none; min-width: 3em; text-align: right; font-family: var(--mono); font-size: 12px; }
.seg { display: flex; flex: 1; border: 1.5px solid var(--line); }
.seg-btn {
  flex: 1; min-height: 40px; border: none; background: transparent;
  font-size: 13px; letter-spacing: 1px; color: var(--ink);
}
.seg-btn + .seg-btn { border-left: 1.5px solid var(--line); }
.seg-btn.on { background: var(--ink); color: var(--paper); }

/* ---------- B10 状态条折叠细条（20261013k）：Choice of Games「Show Stats」按需唤出 ----------
   平时两行各收成 ≈28px 细条（容器 padding 3px + 细条 min-height 22px），点细条自身 toggle
   展开完整详情（原渲染保留在 .strip-full，默认不占位），新一轮开始自动收起；
   无存活怪时敌情行整行隐藏（语义同前）。T1 引导锚点与顶栏徽标不经过这两行，零影响。 */
.strip-thin {
  display: flex; align-items: center; gap: 10px; width: 100%; min-height: 22px; padding: 0 2px;
  border: none; background: none; font-family: inherit; overflow-x: auto;
  -webkit-tap-highlight-color: transparent;
}
.strip-thin:active { background: color-mix(in srgb, var(--cinnabar) 6%, transparent); }
.strip-thin::after { content: '▾'; flex: none; margin-left: auto; padding-left: 8px; color: var(--gold); font-size: 12px; }
.strip.open .strip-thin::after { content: '▴'; }
.strip-full { display: none; flex-wrap: wrap; gap: 6px; padding: 7px 2px 3px; }
.strip.open .strip-full { display: flex; }
/* 细条·队伍：小头像+名+微型血条；当前行动者=头像朱砂描边+名转朱（行动者一眼可见），已动半透明、离线灰化+⚡ */
.pmc { flex: none; display: inline-flex; align-items: center; gap: 4px; }
.pmc .pm-av { width: 16px; height: 16px; margin-right: 0; }
.pmc b { font-size: 11px; font-weight: 400; color: var(--ink); max-width: 4.5em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pm-hp { flex: none; width: 26px; height: 5px; background: color-mix(in srgb, var(--ink) 20%, transparent); }
.pm-hp i { display: block; height: 100%; background: var(--cinnabar); transition: width .4s; }
.pmc.is-cur .pm-av { box-shadow: 0 0 0 2px var(--cinnabar); }
.pmc.is-cur b { color: var(--cinnabar); font-weight: 700; }
.pmc.is-done { opacity: .55; }
.pmc.is-off { opacity: .45; }
.pmc.is-off .pm-av { filter: grayscale(1); }
.pmc .off-mark { flex: none; font-style: normal; font-size: 9px; color: var(--ink-dim); }
/* 细条·敌情：朱砂「敌情」标签 + 同名怪合并 ×N + 存活怪总血量微型条 */
.mon-label { flex: none; font-size: 11px; letter-spacing: 2px; color: var(--cinnabar); }
.moc { flex: none; display: inline-flex; align-items: baseline; font-size: 11px; color: var(--ink); }
.moc b { color: var(--cinnabar); font-weight: 400; }
.mon-hp { flex: none; width: 40px; height: 5px; background: color-mix(in srgb, var(--ink) 20%, transparent); }
.mon-hp i { display: block; height: 100%; background: var(--cinnabar); }
/* D2 状态效果小标签（名·剩N轮）：朱砂描边纸底小签，细条/展开态共用；无效果零输出 */
.fx-tag {
  flex: none; font-style: normal; font-size: 9px; line-height: 1.4; padding: 0 3px;
  border: 1px solid color-mix(in srgb, var(--cinnabar) 50%, transparent);
  color: var(--cinnabar); white-space: nowrap; margin-left: 2px;
}
.pmc .fx-tag { margin-left: 0; } /* .pmc 自带 gap:4px，不叠加 */

/* ---------- C6 阴阳师 UI 语言移植（20261013o）：印章 / 纸纹 / 竖排签——纸艺皮肤元素 ----------
   survey-art·阴阳师案例：纸、印、竖排与现有水墨 UI 同构，零冲突移植、低调点缀不喧宾。
   印 1 枚（建卡页标题旁，rotate(-3deg) 手钤感，纯 CSS 无新图片）；对局页顶栏刻意不加印
   ——B6 的 .dm-stamp 已在对局页承载印章语言，顶栏再钤即双重印喧宾（每屏一枚口径）。
   竖排签 1 枚（建卡页「局的类型」左缘「入局」）；竖排计数：建卡页 2（印+签）/ 对局页 1（C3 题条），均 ≤2。 */
.masthead h1 .seal {
  display: inline-grid; place-items: center;
  writing-mode: vertical-rl;
  width: 20px; height: 20px; margin-left: 6px; vertical-align: 2px;
  background: var(--cinnabar); color: var(--paper); /* 朱底反白字：夜间/米黄随 --cinnabar/--paper 自动换肤 */
  font-family: var(--brush); font-weight: 400; font-size: 9px; line-height: 1; letter-spacing: 1px; /* h1 的 700/34px/6px 字距全部收回，防 20px 印面溢出 */
  border-radius: 2px;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--paper) 45%, transparent),
    1px 1px 0 color-mix(in srgb, var(--ink) 14%, transparent); /* 内细框仿阴文印边 + 微投影落纸感 */
  transform: rotate(-3deg); user-select: none;
}
.card .f-label { position: relative; } /* 竖排签定位锚（无偏移，其余标签零视觉变化）；签不进 #tier-grid——app.js 对其 children 逐个绑 onclick */
.v-side {
  position: absolute; left: -15px; top: -3px;
  writing-mode: vertical-rl;
  padding: 6px 2px; font-size: 9px; line-height: 1; letter-spacing: 3px;
  color: var(--ink-dim); background: rgba(var(--lift-rgb), .5);
  border: 1px solid var(--line);
  user-select: none;
}
/* 纸纹层：职业卡/档位卡/三抽屉底。复用 body 同款 bg-paper.jpg（零新图片，浏览器已缓存）+
   body 同款「洗白层压纹理」法：纹理可见度 0.10（≤0.12 红线，不伤文字对比度），
   三主题随 --wash-rgb 家族自动适配；卡片由透底变实纸面（点阵不再透卡）是纸艺卡预期观感 */
.cls, .tier, .sheet {
  background-image: linear-gradient(rgba(var(--wash-rgb), .9), rgba(var(--wash-rgb), .9)), url('assets/bg-paper.jpg');
  background-size: auto, 512px;
}
.cls.on, .tier.on { /* 选中态：朱砂 6% 底必须放渐变栈顶层——垫在 .9 洗白层下会被盖没 */
  background-image:
    linear-gradient(color-mix(in srgb, var(--cinnabar) 6%, transparent), color-mix(in srgb, var(--cinnabar) 6%, transparent)),
    linear-gradient(rgba(var(--wash-rgb), .9), rgba(var(--wash-rgb), .9)), url('assets/bg-paper.jpg');
}

/* ---------- C7 CSS 动效体系（20261013w）：飘字 / 命中震屏 / 骰子翻滚——全 keyframes ----------
   性能预算（survey-art §六）：三条动画只写 transform/opacity（合成层属性），零逐帧 gif、
   零 JS 逐帧（唯一 JS 参与是震屏 animationend 移类）。总开关：html[data-fx]（app.js 写入，
   dnd_fx 持久化，默认开；prefers-reduced-motion: reduce 时默认关，显式选「开」尊重选择）。
   记录抽屉克隆容器挂 .no-anim：历史行不重播动画。 */

/* 飘字：伤害朱砂「-N」/ 未命中淡墨「miss」/ 治疗暖金「+N」。绝对定位不占布局，
   translateY(-18px) + opacity 0→1→0 共 1.1s，fill both 结束定格透明，无需 JS 清理 */
.fx-float {
  position: absolute; right: 2px; top: 0;
  font-size: 13px; font-weight: 600; line-height: 1;
  pointer-events: none;
  animation: fx-float 1.1s ease-out both;
}
.fx-dmg { color: var(--cinnabar); }
.fx-miss { color: var(--ink-dim); font-weight: 400; letter-spacing: 1px; }
.fx-heal { color: var(--ocher); }
@keyframes fx-float {
  0% { transform: translateY(0); opacity: 0; }
  18% { opacity: 1; }
  100% { transform: translateY(-18px); opacity: 0; }
}

/* 命中震屏：#screen-play 整体 translateX ±3px 共 0.3s（app.js 加 .shake，animationend 移类） */
#screen-play.shake { animation: fx-shake .3s linear; }
@keyframes fx-shake {
  0%, 100% { transform: translateX(0); }
  25% { transform: translateX(-3px); }
  50% { transform: translateX(3px); }
  75% { transform: translateX(-2px); }
}

/* 骰子翻滚：行首 🎲（app.js 包成 .fx-dice）rotate 360° + 中途 scale 弹一下，0.5s transform-only；
   inline-block 才可被 transform */
.fx-dice { display: inline-block; font-style: normal; transform-origin: 50% 60%; }
.fx-roll .fx-dice { animation: fx-roll .5s ease-out; }
@keyframes fx-roll {
  0% { transform: rotate(0deg) scale(1); }
  60% { transform: rotate(300deg) scale(1.35); }
  100% { transform: rotate(360deg) scale(1); }
}

/* 记录抽屉克隆（.no-anim）：飘字是瞬时装饰，历史行里直接隐藏；骰子定格末帧 */
.no-anim .fx-float { display: none; }
.no-anim .fx-roll .fx-dice { animation: none; transform: rotate(360deg); }

/* 总开关门 html[data-fx="off"]：三类动效全禁（属性选择器统一 gate，切换零重渲染） */
html[data-fx="off"] .fx-float { display: none; }
html[data-fx="off"] #screen-play.shake { animation: none; }
html[data-fx="off"] .fx-roll .fx-dice { animation: none; }

/* ---------- D9 终幕卡 + 终局键（20261013x）：game_over 时 app.js 追加/点亮 ----------
   终幕卡复用 C3 章节题条（scene-mark）同构语言：左置章条 + 右延细墨线；章字取墨色（纸字墨底，
   区别于章节题条的朱砂竖排），「落幕落款」语义。夜间经 --ink/--paper/--line 变量自动适配。 */
.end-mark { display: flex; align-items: center; gap: 10px; margin: 26px 0 14px; }
.end-mark::after { content: ''; flex: 1; height: 1px; background: var(--line); }
.end-mark-t {
  flex: none; display: inline-block; padding: 9px 11px;
  font-family: var(--brush); font-size: 18px; line-height: 1; letter-spacing: 0;
  color: var(--paper); background: var(--ink);
  border-radius: 2px; box-shadow: 2px 2px 0 color-mix(in srgb, var(--ink) 25%, transparent);
}
.end-mark-s { flex: none; font-size: 12px; color: var(--ink-dim); letter-spacing: 2px; }
/* 终局键：game_over 后出现在输入条（输入框已禁用），占满一行与选项按钮同热区规格 */
.newgame-btn { width: 100%; margin-bottom: 6px; min-height: 44px; font-size: 15px; letter-spacing: 2px; }

/* ---------- D12 双候选高光岔路卡（20261014a）：turn 带 narrative_alt 时 app.js renderFork 在本笔叙事末尾追加 ----------
   两张并排岔路卡（A=本笔叙事摘要 / B=narrative_alt 摘要，各 ≤60 字截断+「此路」按钮），岔路即选项
   （常规选项区此轮隐藏）。与 C5 插画卡同语言：宣纸底 + 细墨线 + 错位落影；选定后未选卡淡出、
   选中卡朱砂描边定格（记录抽屉 importNode 克隆天然携带定格态）。色值全走 --paper/--ink/--line/
   --cinnabar/--lift-rgb 变量，墨夜/米黄主题自动适配（夜间无图无需降亮度滤镜）。 */
.fork-card {
  margin: 14px 0; padding: 12px;
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  border: 1px solid var(--line); border-radius: 4px;
  box-shadow: 2px 2px 0 color-mix(in srgb, var(--ink) 10%, transparent);
}
.fork-head { font-family: var(--brush); font-size: 14px; letter-spacing: 2px; color: var(--cinnabar); margin-bottom: 10px; }
.fork-row { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.fork-opt {
  display: flex; flex-direction: column; gap: 6px; padding: 10px;
  border: 1.5px solid var(--line); border-radius: 3px;
  background: rgba(var(--lift-rgb), .5);
}
.fork-tag { font-family: var(--brush); font-size: 13px; letter-spacing: 1px; color: var(--ink-dim); }
.fork-text { flex: 1; font-size: 13px; line-height: 1.6; color: var(--ink); }
.fork-btn {
  min-height: 36px; font-size: 14px; letter-spacing: 2px;
  border: 1px solid var(--line); background: transparent; color: var(--cinnabar);
}
.fork-btn:active { background: color-mix(in srgb, var(--cinnabar) 8%, transparent); }
.fork-card.is-picked .fork-opt { opacity: .4; }
.fork-card.is-picked .fork-opt.is-chosen { opacity: 1; border-color: var(--cinnabar); box-shadow: inset 0 0 0 1px var(--cinnabar); }
