/* ============================================================
 * base.css —— 公共基础：变量 / 布局原语 / 按钮 / 弹窗 / 通用组件（所有页面加载）
 * ============================================================ */

:root {
  --bg: #10131a;
  --bg2: #171b24;
  --panel: #1d2330;
  --line: #2c3546;
  --txt: #d9dee8;
  --muted: #7d8798;
  --acc: #c9a45c;
  --acc2: #7aa6cf;
  --ok: #6fbf6f;
  --bad: #d0695b;
  --radius: 10px;
}

* { box-sizing: border-box; }
html, body { height: 100%; margin: 0; }
body {
  background: var(--bg);
  color: var(--txt);
  font-family: "PingFang SC", "Microsoft YaHei", system-ui, sans-serif;
  font-size: 15px;
  display: flex;
  min-height: 100vh;   /* 不支持 dvh 的浏览器回退 */
  min-height: 100dvh;
}

/* ---- header ---- */
#app-header {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 12px;
  /* APP 壳 edge-to-edge 时由 MainActivity 注入 --sat（状态栏高度），网页端回退 env() */
  padding-top: calc(8px + var(--sat, env(safe-area-inset-top, 0px)));
  background: var(--bg2);
  border-bottom: 1px solid var(--line);
  position: sticky; top: 0; z-index: 5;
}
.badge { background: var(--panel); border: 1px solid var(--line); border-radius: 20px; padding: 2px 10px; font-size: 12px; }
/* 头部等级徽标：被 min-height 撑高后内联 span 的文字会贴顶，用 flex 居中 */
#app-header .badge { display: inline-flex; align-items: center; justify-content: center; }

/* ---- story ---- */
.story {
  overflow-y: auto;
  padding: 12px;
  background: radial-gradient(1200px 600px at 50% -10%, #1b2231 0%, var(--bg) 60%);
}
.msg {
  margin-bottom: 14px;
  padding: 12px 14px;
  border-radius: var(--radius);
  line-height: 1.75;
  white-space: pre-wrap;
  word-break: break-word;
}
.msg.user { background: var(--panel); border: 1px solid var(--line); margin-left: 10%; }
.msg.narr { background: transparent; }
.msg.narr .msg-body { display: block; }
.msg.narr .msg-body p:last-child { margin-bottom: 0; }
/* 作者 HTML 开场（竞品式面板大量用表格/图片）：容器内默认观感兜底，
   具体样式以作者行内 style 为准，这里只管没写样式的裸标签 */
.msg-body table { border-collapse: collapse; max-width: 100%; }
.msg-body td, .msg-body th { border: 1px solid var(--line); padding: 4px 8px; word-break: break-word; }
.msg-body img { max-width: 100%; }
/* AI 生成内容显式标识：低调常驻，不抢正文观感 */
.ai-mark { margin-top: 4px; font-size: 11px; color: var(--muted, #8a8f98); opacity: .75; text-align: right; user-select: none; }
/* 页脚：备案号占位与 AI 内容提示（login/hall 共用） */
.page-foot { margin-top: auto; padding: 14px 16px 18px; text-align: center; font-size: 12px; color: var(--muted, #8a8f98); opacity: .85; }
.page-foot a { color: inherit; }
/* 最后一轮玩家输入行：✎ 编辑按钮与行内编辑态 */
.msg.user .input-edit-area {
  width: 100%;
  min-height: 72px;
  background: var(--bg);
  color: var(--txt);
  border: 1px solid var(--acc2);
  border-radius: 8px;
  padding: 8px;
  font-size: 14px;
  font-family: inherit;
  resize: vertical;
}
.msg.user .input-edit-actions { display: flex; gap: 8px; margin-top: 6px; }
.msg.user .input-edit-actions button {
  width: auto;
  margin: 0;
  padding: 4px 14px;
  font-size: 12px;
}
.msg.user .input-edit-save { border-color: var(--acc); color: var(--acc); }
.msg.user .input-edit-cancel { background: transparent; color: var(--muted); }
.msg.system { color: var(--muted); font-size: 13px; text-align: center; }
/* 剧情选项条带（桌面端）：链接样式，像文字一样依次排下去，放不下才换行。
   这里不能用 flex：flex 会把每个选项当成一个整块。
   注意别再把手机端的一行一个当成布局模式的锅：选项是整句话（实测 20-40 字，
   如「趁看守被那脚步声引开，立刻用断骨挖坑壁的落脚点，试图爬出坑。」），
   13px 中文一条就要 270-530px，而手机剧情栏可用宽度只有约 330px，
   于是 flex / inline-block 都必然一行一个。手机端因此在文件末尾的
   @media (max-width: 899px) 里刻意改成整行按钮列表。 */
.msg .options { display: block; margin-top: 8px; }
.msg .options button.opt-link {
  display: inline-block; width: auto; min-height: 0; margin: 0 5px; padding: 2px 0;
  font-size: 13px; line-height: 1.7; color: var(--acc); background: none; border: 0;
  border-radius: 0; text-align: left; text-decoration: underline;
  text-underline-offset: 3px; cursor: pointer;
}
.msg .options button.opt-link:hover { color: var(--acc2); }
.enemy-card { background: var(--panel); border: 1px solid var(--line); border-radius: 6px; padding: 6px 8px; margin: 4px 0; font-size: 13px; }
.enemy-card .enemy-name { color: var(--bad); font-weight: 600; }
.enemy-card .enemy-gear { color: var(--acc2); }
/* 中伏受创（开战 HP 减半）：标出让玩家知道卡面显示的是减半后的当前值 */
.enemy-card .enemy-ambush { color: var(--acc); font-size: 12px; }
.stage-badge { display: inline-block; font-size: 11px; padding: 1px 8px; border-radius: 10px; background: var(--panel); border: 1px solid var(--line); color: var(--muted); margin: 2px 4px; }
/* 战斗抉择行：可点击的「战斗/逃跑」指令 + 后端模拟胜率参考 */
.cmd-link { color: var(--acc); cursor: pointer; text-decoration: underline; }
.cmd-link:hover { filter: brightness(1.2); }
.sim-rate { color: var(--muted); font-size: 12px; margin-left: 4px; }
.sim-rate .sim-win, .sim-rate .sim-esc { color: var(--txt); font-weight: 600; }
/* 重算胜率：穿卸装备/换技能后按当前状态手动刷新（不消耗「战斗/逃跑」抉择） */
.rate-recalc {
  margin-left: 6px; padding: 1px 8px; font-size: 12px; cursor: pointer;
  background: var(--panel); color: var(--acc);
  border: 1px solid var(--line); border-radius: 10px;
}
.rate-recalc:hover:not(:disabled) { filter: brightness(1.2); }
.rate-recalc:disabled { cursor: default; color: var(--muted); }

/* ---- 战斗卡片：逐回合日志 → 战后收缩的战报 ----
   卡片建在玩家「战斗/逃跑」输入行之后，战斗中展开、结束后自动收缩，
   标题栏留下战斗结构摘要与胜负徽标。点条带任意位置展开/收缩。
   遭遇阶段（敌人一览 + 抉择 + 胜率）不走卡片，见下方 .enc-block。
   用 .msg.battle-card 提高一级优先级，压过 .msg.narr 的 transparent 背景。 */
.msg.battle-card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}
.battle-card .bc-meta:empty { display: none; }
/* 逐回合日志刻意不设 max-height：一回合套一个小滚动条既难看又难读，
   整张卡随剧情流自然增高即可（剧情区本来就是滚动容器）。 */

/* ---- 遭遇阶段（在玩家「战斗/逃跑」输入行之前）：敌人一览平铺，不套卡片 ----
   这一段是玩家做决定要看的材料，必须留在输入行前；战斗卡片则等在输入行之后。 */
.enc-block { border-left: 2px solid var(--acc2); padding-left: 8px; }
.enc-block .enc-head { color: var(--acc); font-size: 12px; margin-bottom: 4px; }

/* ---- 交易入口条与商品弹框 ---- */
.trade-tab.active { border-color: var(--acc); color: var(--acc); font-weight: 600; }
.trade-pane.active { display: block; }
/* 装备槽位：与背包条目里的槽位标注同色，一眼看出这件买回来能装哪 */
/* 穿戴需求：不满足就穿不上，用告警色单独一行，别混在 detail 里被截断 */
.trade-sum b { color: var(--txt); }
.gen-status.hidden { display: none; }
button {
  cursor: pointer;
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--txt);
  border-radius: 8px;
  padding: 8px 14px;
  font-size: 14px;
  touch-action: manipulation; /* 移动端快速连点不触发双击缩放 */
}
button.primary { background: var(--acc); color: #1a1406; border-color: var(--acc); font-weight: 600; }
button.ghost { background: transparent; }
#btn-stream.active { color: var(--acc); border-color: var(--acc); }
button.danger { background: transparent; border-color: rgba(231, 76, 60, 0.5); color: #e74c3c; }
button.danger:hover { background: rgba(231, 76, 60, 0.12); border-color: #e74c3c; }
button:disabled { opacity: .4; cursor: not-allowed; }
.tabs { display: flex; gap: 4px; padding: 6px 8px 0; overflow-x: auto; }
.tab { border: 0; background: transparent; color: var(--muted); padding: 10px 12px; font-size: 13px; border-radius: 8px 8px 0 0; white-space: nowrap; }
.tab.active { color: var(--acc); background: var(--panel); }
.tab-panes { flex: 1; overflow-y: auto; padding: 8px; }
/* 深色滚动条（Chrome 121+/Firefox，旧浏览器忽略走原样）：游戏视图三根滚动条
   （剧情区纵向/页签行横向/页签面板纵向）原来都是刺眼的白色系统样式 */
.story, .side .tabs, .side .tab-panes, .hall-main {
  scrollbar-width: thin; scrollbar-color: #3a4356 transparent;
}
.pane.active { display: block; }
/* 侧栏「✕ 收起」：仅移动端全屏面板打开时显示（见文件末尾移动端适配块） */
#side-close { display: none; }
/* 输入行左侧「☰」功能入口：仅移动端显示（功能按钮桌面端在头部） */
#btn-func { display: none; }

/* ---- widgets ---- */
.kv { display: flex; justify-content: space-between; gap: 8px; padding: 3px 0; border-bottom: 1px dashed var(--line); font-size: 13px; }
.kv .v { color: var(--txt); }
.hbar { height: 8px; background: var(--panel); border-radius: 4px; overflow: hidden; margin: 2px 0 6px; }
.hbar > i { display: block; height: 100%; background: linear-gradient(90deg, var(--ok), var(--acc2)); }
.hbar.hp > i { background: linear-gradient(90deg, #7fbf7f, #4a9f7a); }
.hbar.mp > i { background: linear-gradient(90deg, var(--acc2), #5a7fbf); }
.hbar.sp > i { background: linear-gradient(90deg, #d0a45b, #b07f3a); }
.skill-slots { display: flex; flex-wrap: wrap; gap: 4px; }
.skill-tag { background: var(--panel); border: 1px solid var(--acc); color: var(--acc); font-size: 11px; padding: 2px 8px; border-radius: 10px; cursor: pointer; }
.skill-list { display: flex; flex-direction: column; gap: 4px; }
.skill-row { display: grid; grid-template-columns: minmax(72px, auto) 44px 1fr auto; gap: 6px; align-items: center;
  background: var(--panel); border: 1px solid var(--line); border-radius: 6px; padding: 5px 8px; font-size: 12px; }
.skill-row .n { color: var(--acc); font-weight: 600; word-break: break-all; }
.skill-row .k { color: var(--muted); font-size: 11px; white-space: nowrap; }
.skill-row .d { color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.attr-row { display: flex; align-items: center; gap: 6px; padding: 4px 0; border-bottom: 1px dashed var(--line); font-size: 13px; }
.attr-row .name { width: 56px; color: var(--muted); }
.attr-row .val { flex: 1; }
.attr-row .add { width: 34px; padding: 2px 0; font-size: 14px; border-radius: 6px; }
/* 职业加点按钮：与属性加点的「+」同尺寸；chip 与按钮垂直居中对齐 */
.job-chips { display: flex; align-items: center; justify-content: flex-end; gap: 6px; flex-wrap: wrap; }
.job-chips .add { width: 34px; padding: 2px 0; font-size: 14px; border-radius: 6px; }
.pending-badge { color: var(--acc); font-size: 11px; font-weight: 600; margin-left: 3px; }
.grille { display: grid; gap: 10px; }
.item { background: var(--panel); border: 1px solid var(--line); border-radius: 8px; padding: 8px; font-size: 13px; }
.item.equipped { border-color: var(--acc); }
.item .n { color: var(--acc); font-weight: 600; }
.item .d { color: var(--muted); margin-top: 4px; font-size: 12px; }
.equip-btn { margin-top: 6px; margin-right: 4px; padding: 2px 10px; font-size: 12px; background: var(--acc); color: var(--bg); border: none; border-radius: 4px; cursor: pointer; }
.equip-btn:hover { opacity: 0.85; }
.unequip-btn { float: right; background: none; border: none; color: var(--muted); cursor: pointer; font-size: 14px; padding: 0 4px; }
.unequip-btn:hover { color: #e74c3c; }
.eq-tag { display: inline-block; margin-top: 4px; font-size: 11px; color: var(--acc); border: 1px solid var(--acc); border-radius: 3px; padding: 0 4px; }
.taverntext { font-size: 13px; padding: 8px; border-left: 3px solid var(--acc); background: var(--panel); margin-bottom: 8px; border-radius: 0 8px 8px 0; line-height: 1.6; }
.tavern-title { font-weight: 700; color: var(--acc); font-size: 13px; margin-bottom: 2px; }
.tavern-round { float: right; font-weight: 400; color: var(--muted); font-size: 11px; }
/* 聊天流里的本轮酒馆传闻：与侧栏 .taverntext 同一视觉语言（左缘线 + 面板底） */
.msg.system.tavern-note { color: var(--muted); border-left: 3px solid var(--acc); background: var(--panel); text-align: left; padding: 6px 10px; border-radius: 0 8px 8px 0; line-height: 1.6; margin: 4px 0; }
.msg.system.tavern-note b { color: var(--acc); }
.memory { font-size: 12px; color: var(--muted); padding: 6px 0; border-bottom: 1px dashed var(--line); }
.tok .r { display: flex; justify-content: space-between; padding: 2px 0; border-bottom: 1px dashed var(--line); }

/* 合并页签内的分段标题/分隔线 */
.sub-h { color: var(--acc); font-size: 12px; margin: 10px 0 6px; font-weight: 700; }

/* 紧凑列表行：名称 + 简略信息 */
.row-list { display: flex; flex-direction: column; gap: 4px; }
.row-item { display: flex; justify-content: space-between; align-items: baseline; gap: 8px;
  background: var(--panel); border: 1px solid var(--line); border-radius: 8px;
  padding: 7px 10px; font-size: 13px; cursor: pointer; }
.row-item:hover { border-color: var(--acc); }
.row-item .n { color: var(--acc); font-weight: 600; white-space: nowrap; }
.row-item .b { color: var(--muted); font-size: 12px; flex: 1; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: right; }
.row-item.equipped { border-color: var(--acc); }
/* 道具栏「使用」按钮 */
.use-btn { flex: none; padding: 1px 8px; font-size: 11px; line-height: 1.4;
  background: var(--acc); color: var(--bg); border: none; border-radius: 4px; cursor: pointer; }
.use-btn:hover { opacity: 0.85; }
.recover-note { color: var(--ok, #7c9); font-size: 12px; margin: 4px 0; }

/* 背包装备栏：每槽位独立一行 */
.eq-slots { display: flex; flex-direction: column; gap: 4px; margin-bottom: 4px; }
.eq-row { display: flex; justify-content: space-between; align-items: center; gap: 8px;
  background: var(--panel); border: 1px solid var(--line); border-radius: 8px;
  padding: 5px 10px; font-size: 12px; }
.eq-row .s { color: var(--muted); white-space: nowrap; }
.eq-row .v { color: var(--acc); font-weight: 600; text-align: right; cursor: pointer; }
.eq-row .v:hover { color: #e74c3c; }
.eq-row.none .v { color: var(--muted); font-weight: 400; cursor: default; }
.eq-row.none .v:hover { color: var(--muted); }
.unequip-x { color: var(--muted); margin-left: 4px; }

/* 封印装备（属性未觉醒）标识 */
.seal-chip { display: inline-block; margin-left: 6px; padding: 0 6px; border-radius: 8px;
  font-size: 10px; font-weight: 400; vertical-align: 1px;
  color: #b8860b; border: 1px solid #b8860b; opacity: .85; }
.seal-note { color: #b8860b; font-size: 12px; margin: 4px 0; }

/* 神术来源标识：技能名后标出「神术·X」（该神术来自所信仰的神祇），与普通法术区分 */
.divine-chip { display: inline-block; margin-left: 6px; padding: 0 6px; border-radius: 8px;
  font-size: 10px; font-weight: 400; vertical-align: 1px;
  color: var(--acc); border: 1px dashed var(--acc); opacity: .9; }

/* 「装备中」标识：交易卖出清单与赠送清单里的在穿装备（卖出/赠出会自动卸下） */
.equip-chip { display: inline-block; margin-left: 6px; padding: 0 6px; border-radius: 8px;
  font-size: 10px; font-weight: 400; vertical-align: 1px;
  color: var(--acc); border: 1px solid var(--acc); opacity: .9; }

/* 装备对比块（详情弹窗内） */
.cmp-block { border: 1px solid rgba(128,128,128,.35); border-radius: 8px; padding: 8px 10px; font-size: 13px; }
.cmp-head { display: flex; gap: 8px; align-items: center; margin-bottom: 6px; font-weight: 600; }
.cmp-row { display: flex; gap: 8px; align-items: baseline; line-height: 1.6; }
.cmp-row .k { min-width: 66px; color: var(--muted, #999); font-size: 12px; }
.cmp-row .v { min-width: 42px; }
.cmp-row .dv.up { color: #6dbe6d; font-weight: 600; }
.cmp-row .dv.down { color: #d06565; font-weight: 600; }
.cmp-bad { color: #d06565; }
/* 一件装备可装多槽时并列多块对比（单手武器=主手/副手）：块间留距，头部标出目标槽 */
.cmp-block + .cmp-block { margin-top: 8px; }
.cmp-head .cmp-slot { color: var(--acc); }
.cmp-note { color: var(--muted, #999); font-size: 12px; margin-bottom: 4px; }

/* 详情弹窗 */
.detail-card { max-width: 480px; max-height: 88dvh; display: flex; flex-direction: column; overflow: hidden; }
.detail-card.trade-open { max-width: 900px; }
.detail-card.party-open { max-width: 640px; }
/* 魔宠详情定高：弹窗大小固定，正文独占滚动（手机端在下方媒体查询里铺满遮罩） */
.detail-card.pet-open { height: min(86vh, 640px); height: min(86dvh, 640px); }
.detail-body { line-height: 1.75; font-size: 14px; margin-top: 4px; min-height: 0; overflow-y: auto; padding-right: 4px; }
/* 队友详情：属性双列 / 装备两列三行 / 区块限高滚动（赠送弹窗共用滚动规则） */
.kv-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 18px; }
.party-open .eq-slots { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.list-scroll { max-height: 34dvh; overflow-y: auto; padding-right: 4px; }
.kv.col { display: block; padding: 6px 0; }
.kv.col > span:first-child { display: block; color: var(--muted); font-size: 12px; margin-bottom: 2px; }
.kv.col .v { display: block; word-break: break-word; }
.detail-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; align-items: center; }
/* 用 ID 选择器压过后面 .card button 的 width:100%/margin-top，保证动作按钮紧凑一致 */
#detail-actions button { width: auto; margin: 0; padding: 5px 12px; font-size: 12px; }
#detail-actions .unequip-btn { float: none; }
/* 魔宠弹窗底部按钮（动作/出战/放生，含从自定义模板正文提升上来的）：
   等宽铺满一行，与模板里写的 flex 按钮行同观感。min-width 取 max-content：
   只有按钮文字真放不下才折行（别按固定宽度折成 3+1、落单那个还拉满整行） */
#detail-actions .pet-act-btn, #detail-actions .pet-battle-btn, #detail-actions .pet-release-btn {
  flex: 1 1 0; min-width: max-content; min-height: 40px; padding: 8px 10px;
  font-size: 13px; border-radius: 10px; text-align: center; white-space: nowrap; }
/* 窄屏一行四个真放不下时折成整齐的 2×2，不出孤儿按钮 */
@media (max-width: 420px) {
  #detail-actions .pet-act-btn, #detail-actions .pet-battle-btn, #detail-actions .pet-release-btn { flex-basis: 40%; }
}

/* ---- overlay ---- */
.mask {
  position: fixed; inset: 0; z-index: 50;
  background: rgba(8,10,14,.86);
  display: flex; align-items: center; justify-content: center; padding: 20px;
}
.mask.hidden, .toast.hidden { display: none; }
.card { position: relative; background: var(--panel); border: 1px solid var(--line); border-radius: 14px; padding: 20px; width: 100%; max-width: 420px; }
.card h2 { margin-top: 0; color: var(--acc); }
.card textarea { width: 100%; background: var(--bg); color: var(--txt); border: 1px solid var(--line); border-radius: 8px; padding: 10px; font-size: 14px; min-height: 90px; resize: vertical; font-family: inherit; }
.card.wide { max-width: 640px; }
.card input, .card select { width: 100%; background: var(--bg); color: var(--txt); border: 1px solid var(--line); border-radius: 8px; padding: 8px 10px; font-size: 14px; margin-bottom: 8px; }
.keyid { font-size: 12px; color: var(--muted); }
button.btn-test { flex: none; width: auto; margin-top: 0; padding: 6px 10px; font-size: 12px; }
.ok-msg { color: var(--ok); margin-left: 6px; font-size: 12px; }
.bad-msg { color: var(--bad); margin-left: 6px; font-size: 12px; }
.settings-card { position: relative; }
/* 用 .card 前缀提高优先级，压过下方 .card button 的 width:100%/margin-top，保证 ✕ 是右上角小圆钮。
   底片必须不透明：弹窗常把 ✕ 压在封面图/亮色内容上，透明底片会糊掉看不见 */
.card button.close-x { position: absolute; top: 10px; right: 12px; width: 32px; height: 32px; min-height: 32px; margin: 0; padding: 0; font-size: 16px; font-weight: 600; line-height: 1; border-radius: 50%; background: var(--panel); border: 1px solid var(--line); color: var(--txt); box-shadow: 0 2px 8px rgba(0,0,0,.55); }
.card button.close-x:hover { background: var(--acc); border-color: var(--acc); color: #1a1406; box-shadow: 0 2px 10px rgba(0,0,0,.6); }
.card button.close-x:active { background: #b8934c; border-color: #b8934c; }
/* 赠送弹窗右上角「返回」：与 ✕ 同一定位基准，紧邻其左侧 */
.card button.give-back { position: absolute; top: 10px; right: 48px; width: auto; margin: 0; padding: 4px 9px; font-size: 12px; border-radius: 8px; }
.settings-test { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; background: var(--bg); border: 1px dashed var(--line); border-radius: 8px; padding: 10px; }
.settings-test .result { flex-basis: 100%; margin: 4px 0 0 0; min-height: 16px; }
.card button { margin-top: 12px; width: 100%; }
.muted { color: var(--muted); font-size: 12px; margin-top: 8px; }

/* ---- 账目申诉弹窗 ---- */
.appeal-log .msg { margin-bottom: 0; padding: 8px 10px; border-radius: 8px; font-size: 13px; line-height: 1.6; }
.appeal-log .msg.user { margin-left: 14%; background: var(--panel); border: 1px solid var(--line); }
.appeal-log .msg.system { background: transparent; border: 1px dotted var(--line); color: var(--muted); text-align: left; }
#appeal-mask .card button#btn-appeal-send { width: auto; margin: 0; flex: none; align-self: flex-end; }

/* ---- 存档列表（继续游戏 / 记录回放共用） ---- */
.slot-list.hidden { display: none; }
.slot-item {
  width: 100%; display: grid;
  grid-template-columns: auto 1fr auto;
  grid-template-areas:
    "check name actions"
    "check meta actions";
  align-items: center; gap: 1px 8px;
  padding: 10px 12px; background: var(--bg); border: 1px solid var(--line); border-radius: 10px;
  cursor: pointer; text-align: left;
}
.slot-item:hover { border-color: var(--acc2); }
.slot-name { grid-area: name; color: var(--acc); font-weight: 600; }
.slot-item .slot-meta { grid-area: meta; color: var(--muted); font-size: 12px; }
.slot-item .slot-del { border: none; background: transparent; color: var(--muted); cursor: pointer; font-size: 14px; padding: 2px 6px; border-radius: 6px; }
.slot-item .slot-del:hover { color: #e74c3c; background: rgba(231, 76, 60, 0.12); }
.slot-item .slot-export { border: none; background: transparent; color: var(--muted); cursor: pointer; font-size: 14px; padding: 2px 6px; border-radius: 6px; }
.slot-item .slot-export:hover { color: var(--acc2); background: rgba(120, 160, 255, 0.12); }
.slot-item .slot-sync { display: inline-flex; align-items: center; gap: 4px; color: var(--muted); cursor: pointer; font-size: 12px; padding: 2px 6px; border-radius: 6px; white-space: nowrap; user-select: none; }
.slot-item .slot-sync:hover { color: var(--acc2); background: rgba(120, 160, 255, 0.12); }
.slot-item .slot-sync input { accent-color: var(--acc); margin: 0; cursor: pointer; }
.slot-item .slot-sync-on { color: var(--ok); }
.slot-item .slot-sync .sy-short { display: none; }
@media (max-width: 899px) {
  .slot-item .slot-sync .sy-long { display: none; }
  .slot-item .slot-sync .sy-short { display: inline; }
}
.slot-item.active { border-color: var(--acc); }
.slot-pager.hidden { display: none; }
.slot-pager .muted { flex: none; }
.slot-batch.hidden { display: none; }
.slot-batch .muted { margin: 0; flex: 1; }

/* ---- 通用确认/输入弹窗（替代原生 confirm/prompt） ---- */
.confirm-card, .prompt-card { max-width: 380px; text-align: left; }
.confirm-message { color: var(--txt); font-size: 14px; line-height: 1.7; margin-top: 4px; word-break: break-word; white-space: pre-wrap; }
.confirm-actions { display: flex; justify-content: center; gap: 10px; margin-top: 16px; }
.confirm-actions button { width: auto; margin: 0; padding: 7px 18px; font-size: 13px; }

/* ---- 创建角色弹窗 ---- */
.section-title { color: var(--acc); font-size: 13px; font-weight: 600; margin: 14px 0 8px; border-bottom: 1px dashed var(--line); padding-bottom: 4px; }
.rowlabel { display: block; font-size: 13px; color: var(--muted); margin-bottom: 14px; }
.rowlabel > input, .rowlabel > select {
  display: block; width: 100%; margin-top: 5px; margin-bottom: 0;
}
/* 验证码行：输入框与图片并排（.card input 是 width:100%，这里改回自适应）。
   放在 base.css 而不是 login.css：登录页与「需要登录」弹窗都要用，而弹窗会出现在
   任何页面上，那些页面并不加载 login.css。 */
.captcha-row { display: flex; align-items: center; gap: 8px; margin-top: 5px; }
.captcha-row > input { flex: 1 1 auto; min-width: 0; width: auto; margin-bottom: 0; }
.captcha-img {
  flex: 0 0 auto; width: 120px; height: 40px;
  border: 1px solid var(--line); border-radius: 8px; background: var(--bg);
  cursor: pointer;   /* 看不清就点图换一张（见 common.js bindAuthForm） */
}
/* 「发送验证码」与次要文字入口：.card button 默认 width:100% + margin-top:12px，
   这里压回自适应（选择器带上容器提高优先级） */
.captcha-row .send-code {
  flex: 0 0 auto; width: auto; margin-top: 0; white-space: nowrap;
  padding: 6px 10px; font-size: 13px;
}
.card .link-btn {
  width: auto; margin-top: 8px; padding: 4px 0; text-align: left;
  background: none; border: 0; color: var(--acc2); font-size: 13px;
}
.card .link-btn:hover { color: var(--txt); }
/* 表单模式标题（登录 / 注册新账号 / 找回密码）：登录页与弹窗共用 */
.auth-mode-title { font-size: 15px; font-weight: 600; color: var(--txt); margin-bottom: 12px; }
/* 注册协议勾选行：协议小字比正文小一号、行距放宽；链接给主题蓝并压掉浏览器默认的
   紫蓝下划线（暗色卡片上非常扎眼）；checkbox 摘掉 .card input 的通栏边框底色 */
.auth-agree { display: flex; align-items: flex-start; gap: 8px; font-weight: normal; text-align: left; font-size: 12px; line-height: 1.9; }
.auth-agree input[type="checkbox"] {
  width: auto; flex: none; margin: 5px 0 0; padding: 0;
  background: none; border: 0; accent-color: var(--acc);
}
.auth-agree a { color: var(--acc2); text-decoration: none; }
.auth-agree a:hover { text-decoration: underline; }
.auth-agree .agree-note { color: var(--muted); opacity: .75; }
.name-row { display: flex; gap: 8px; align-items: center; }
.name-row input { flex: 1; min-width: 0; margin-bottom: 0; }
button.mini { width: auto; margin-top: 0; padding: 6px 10px; font-size: 12px; }
button.api-open { margin-top: 12px; border-color: var(--acc2); color: var(--acc2); }
#create-pref { margin-bottom: 0; }
/* 提示条压在弹窗之上：详情/确认弹窗里点出来的提示（如「请输入要索要的金额」）落在
   遮罩背后就等于没提示，玩家只会觉得按钮没反应 */
.toast {
  position: fixed; left: 50%; top: calc(14px + var(--sat, env(safe-area-inset-top, 0px))); transform: translateX(-50%);
  background: var(--panel); border: 1px solid var(--acc); color: var(--txt);
  padding: 8px 16px; border-radius: 20px; font-size: 13px; z-index: 90;
  max-width: 86vw;
}

/* ---- 游戏页骨架（移动端兜底；桌面覆盖见下方 @media(min-900)，顺序不可颠倒） ---- */
#app {
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: auto 1fr auto;
  width: 100%;
  min-width: 0; /* body 是 flex 容器，防内容 min-content 把 #app 撑出视口 */
  /* 高度用 html/body 的 100% 百分比链撑满 WebView：实测小米 14 WebView 里
     100dvh 比可视区矮约 52px（导航栏 inset 被计入动态视口），页面会不贴底；
     页面宽度是准的，说明 ICB 可信，100% 可绕开该 quirk。 */
  height: var(--app-vh, 100%); /* common.js 用 innerHeight 校正；未设置时回退 ICB 百分比 */
  min-height: 100dvh; /* 兜底：以上都意外失效时不小于一屏 */
  /* 底部不留白：让侧栏（页签栏）背景一直延伸到屏幕底，
     留白由 #side 自己的 padding-bottom 承担（否则露出 body 底色像没贴底） */
}
/* 网格列 1fr 的 auto 最小尺寸会被内容 min-content 顶大（页签行/按钮行），
   乃至把 ICB 撑破（WebView setUseWideViewPort 下页面会被整体缩小）——全部钳到 0 */
#app > * { min-width: 0; }
/* 壳 edge-to-edge 时：侧栏（页签栏）背景向下延伸到屏幕物理底边，
   系统导航图标叠在其上；--sab 由壳注入（浏览器端为 0） */
body:not(.hall-mode) #side { padding-bottom: var(--sab, env(safe-area-inset-bottom, 0px)); }
.side {
  background: var(--bg2);
  border-top: 1px solid var(--line);
  display: flex; flex-direction: column;
  max-height: 42vh; /* 回退 */
  max-height: 42dvh;
  order: 3;
}

/* ---- desktop layout ---- */
@media (min-width: 900px) {
  #app {
    grid-template-columns: 1fr 340px;
    grid-template-rows: auto 1fr auto;
    grid-template-areas:
      "header header"
      "story side"
      "input side";
  }
  #app-header { grid-area: header; }
  .story { grid-area: story; }
  .side { grid-area: side; border-left: 1px solid var(--line); border-top: 0; max-height: none; order: 0; }
  #input-bar { grid-area: input; }
  /* 侧栏页签行收窄：模块化世界书最多 8 个页签（角色/背包/人物/任务/世界/地图/魔宠/领地），
     原 10px 12px 内边距一行只装得下 6 个，魔宠/领地被挤出可视区还横着一条滚动条。
     收窄后 8×38+14 间距 ≈ 330px < 340px 一行放下；超出仍由 overflow-x 兜底 */
  .side .tabs { gap: 2px; padding: 6px 6px 0; }
  .side .tab { padding: 10px 6px; }
}
/* ---- 世界书大厅（登录后主界面） ---- */
.hall { display: flex; width: min(1100px, 96vw); height: min(680px, 92vh);
  background: var(--bg2); border: 1px solid var(--line); border-radius: 16px; overflow: hidden; }
.hall-side { width: 200px; flex: none; display: flex; flex-direction: column;
  background: var(--panel); border-right: 1px solid var(--line); padding: 16px 12px; }
/* 品牌行：标题 + 右侧「📱 APP」下载入口并排（原在侧栏底部，2026-09-27 用户要求挪到顶部） */
.hall-brand-row { display: flex; align-items: center; justify-content: space-between;
  gap: 8px; padding: 4px 8px 18px; }
.hall-brand-row .ghost { flex: none; width: auto; margin: 0; padding: 5px 10px; font-size: 12px; }
.hall-brand { color: var(--acc); font-weight: 700; font-size: 17px; line-height: 1.4;
  letter-spacing: 1px; white-space: nowrap; }
.hall-nav { display: flex; flex-direction: column; gap: 6px; }
.hall-nav-btn { text-align: left; background: none; border: 1px solid transparent; color: var(--txt);
  padding: 10px 12px; border-radius: 10px; font-size: 14px; cursor: pointer; }
.hall-nav-btn:hover { background: var(--bg); }
.hall-nav-btn.active { background: var(--bg); border-color: var(--line); color: var(--acc); }
.hall-side-foot { margin-top: auto; border-top: 1px solid var(--line); padding: 12px 8px 4px;
  display: flex; flex-direction: column; gap: 8px; }
.hall-user { font-size: 13px; color: var(--muted); }
/* 用户名一行放不下时省略，右侧小邮件图标固定占位 */
.hall-user-row { display: flex; align-items: center; gap: 8px; min-width: 0; }
.hall-user-row .hall-user { flex: 1; min-width: 0; }
.hall-mail-icon {
  position: relative; flex: none; width: 30px; height: 30px;
  display: inline-flex; align-items: center; justify-content: center;
  background: none; border: 1px solid var(--line); border-radius: 50%;
  color: var(--muted); cursor: pointer; padding: 0;
}
.hall-mail-icon:hover { color: var(--acc); border-color: var(--acc); }
.hall-mail-icon svg { width: 15px; height: 15px; display: block; }
.hall-view.hidden { display: none; }
/* 用户信息页：左侧二级菜单 + 右侧内容区 */
.me-nav-btn.active { background: var(--bg); color: var(--acc); font-weight: 600; }
/* 配置服务商：我的页内嵌平铺面板；游戏内「切换模型」把同一面板搬进弹窗 */
#prov-mask .card.wide { width: min(1100px, 96vw); max-width: 96vw; max-height: 92vh; overflow-y: auto; }
#prov-popup-slot .prov-page { max-width: none; }
.prov-page { max-width: 900px; }
.prov-page-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 10px; }
.prov-page-head .section-title { margin: 0; }
.prov-page-head .ghost { width: auto; margin: 0; padding: 7px 14px; }
/* 全局 AI 参数行：助手输出预算（agent_max_tokens） */
.prov-agent-row { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.prov-agent-row .section-title { margin: 0; flex: none; }
.prov-agent-row input { width: 108px; height: 26px; margin: 0; padding: 2px 8px; font-size: 11px; }
.prov-agent-row .ghost { width: auto; margin: 0; padding: 5px 10px; font-size: 12px; }
/* 角色模型行：剧情输出与其他程序块各用一个模型（写入 role_models）。
   基础规则与 .prov-agent-row 同形，窄屏规则见下方 @media(max-width:899px)。
   另有快捷入口：服务商卡片里每个模型行的两个用途按钮（见 .model-row .m-roles） */
.prov-role-row { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; flex-wrap: wrap; }
.prov-role-row .section-title { margin: 0; flex: none; }
.prov-role-row select { width: 210px; height: 26px; margin: 0; padding: 2px 8px; font-size: 11px;
                        background: var(--bg); color: var(--txt);
                        border: 1px solid var(--line); border-radius: 8px; }
.prov-role-row .ghost { width: auto; margin: 0; padding: 5px 10px; font-size: 12px; }
.prov-page-body { display: flex; gap: 16px; align-items: flex-start; }
.prov-list { width: 250px; flex: none; display: flex; flex-direction: column; gap: 8px; }
.prov-item { position: relative; background: var(--panel); border: 1px solid var(--line); border-radius: 10px; padding: 10px 34px 10px 12px; cursor: pointer; }
.prov-item:hover { border-color: var(--acc2); }
.prov-item.editing { border-color: var(--acc); background: var(--bg2); }
.prov-item .pi-name { font-weight: 600; font-size: 14px; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.prov-item .pi-meta { font-size: 12px; color: var(--muted); margin-top: 4px; word-break: break-all; }
.prov-del { position: absolute; top: 8px; right: 8px; width: auto; margin: 0; padding: 2px 7px; font-size: 12px; }
.prov-detail { flex: 1; min-width: 0; background: var(--panel); border: 1px solid var(--line); border-radius: 12px; padding: 16px; display: flex; flex-direction: column; gap: 10px; }
.prov-detail-head { display: flex; align-items: center; gap: 10px; }
.prov-detail-head h3 { margin: 0; color: var(--acc); font-size: 16px; flex: 1; }
.prov-detail .row { display: flex; gap: 8px; align-items: center; }
.prov-detail .row > label { width: 72px; flex: none; font-size: 13px; color: var(--muted); }
.prov-detail .row input, .prov-detail .row select { flex: 1; min-width: 0; width: auto; margin-bottom: 0; background: var(--bg); color: var(--txt); border: 1px solid var(--line); border-radius: 8px; padding: 8px 10px; font-size: 14px; }
.prov-detail .row input.key-masked { color: var(--muted); letter-spacing: .3px; }
.prov-detail .mini { flex: none; }
.badge-on { color: var(--ok); font-size: 12px; flex: none; white-space: nowrap; }
.prov-models .section-title, .prov-keys .section-title { margin: 8px 0 4px; }
.prov-model-add { flex-wrap: wrap; }
/* 模型行允许换行：新增的两个用途按钮放不下时整块落到第二行，不挤模型名
   （原有单行内容在宽面板上仍是一行） */
.model-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; background: var(--bg); border: 1px solid var(--line); border-radius: 8px; padding: 6px 10px; font-size: 13px; }
.model-row.current { border-color: var(--acc); }
/* 模型名固定单行：过长首尾省略（完整名见 title），不让它折行把行高撑开 */
.model-row .m-name { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* 操作区定宽：使用中（徽标+删除）与未使用（设为使用+删除）两种行右缘对齐。
   宽度含行内 🧠 探测按钮（26px + 间距）与分工徽标（最长「使用中·其他 4/5」，比旧的「使用中」宽） */
.model-row .m-ops { flex: none; display: flex; align-items: center; justify-content: flex-end;
  gap: 6px; width: 200px; }
/* 每模型上下文容量输入：紧凑胶囊样式，右对齐数字，聚焦时亮主题色。
   选择器带 .model-row 提到 (0,2,0)，否则被 .card input 的 width:100% 压过、
   输入框撑满整行把模型名挤成一字一行 */
.model-row .ctx-in { flex: none; width: 108px; height: 26px; margin: 0; padding: 2px 8px;
  background: var(--bg2); color: var(--muted); border: 1px solid var(--line);
  border-radius: 13px; font-size: 11px; font-variant-numeric: tabular-nums;
  text-align: right; transition: border-color .15s, color .15s; }
.model-row .ctx-in::placeholder { color: color-mix(in srgb, var(--muted) 55%, transparent); }
.model-row .ctx-in:hover { border-color: color-mix(in srgb, var(--acc) 45%, var(--line)); }
.model-row .ctx-in:focus { outline: none; border-color: var(--acc); color: var(--txt); }
.model-row .ctx-in::-webkit-outer-spin-button,
.model-row .ctx-in::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.model-row .ctx-in[type="number"] { -moz-appearance: textfield; appearance: textfield; }
/* 每模型思考档位下拉：与上下文框同一胶囊风格（选择器带 .model-row 才压得过 .card select 的 width:100%）。
   实测过档位的模型，选项文案自带实测数字（如「中 · 412t」），所以宽度要留够。 */
.model-row .think-in { flex: none; width: 124px; height: 26px; margin: 0; padding: 0 6px;
  background: var(--bg2); color: var(--muted); border: 1px solid var(--line);
  border-radius: 13px; font-size: 11px; cursor: pointer; }
.model-row .think-in:hover { border-color: color-mix(in srgb, var(--acc) 45%, var(--line)); }
.model-row .think-in:focus { outline: none; border-color: var(--acc); color: var(--txt); }
.model-row .think-in:disabled { opacity: .6; cursor: not-allowed; }
/* 行内来源标记：一眼分清「已实测」与「按模型名推测的未实测」——手机上悬停提示点不开，
   所以这件事必须用可见文字说，不能只放在 title 里 */
.model-row .think-src { flex: none; font-size: 11px; color: var(--muted); white-space: nowrap; }
/* 每行 🧠：测的就是本行模型，不用先「设为使用」 */
.model-row .mini.think-probe { width: 26px; min-width: 26px; padding: 2px 0; }
/* 每行两个用途按钮：设为剧情输出模型 / 设为其他模型（点了即落盘）。
   单独一个容器：放不下就整块换到下一行，不会把模型名挤成省略号。
   (0,2,0) 起的选择器才压得过 .card button 的 width:100% */
.model-row .m-roles { flex: 1 1 auto; display: flex; align-items: center; justify-content: flex-end; gap: 6px; }
.model-row .role-btn { flex: none; width: auto; margin: 0; padding: 3px 8px; font-size: 11px;
  background: var(--bg2); color: var(--muted); border: 1px solid var(--line); border-radius: 8px;
  white-space: nowrap; }
.model-row .role-btn:hover { border-color: var(--acc2); color: var(--txt); }
/* 使用中的用途：亮色描边 + 主题色文字（点它不再发请求） */
.model-row .role-btn.on { color: var(--acc); border-color: var(--acc); }
/* 「其他」只切了一半（旧状态）：虚线提示点一下会补齐 */
.model-row .role-btn.partial { color: var(--acc2); border-style: dashed; }
.model-row .m-star { color: var(--acc); flex: none; width: 14px; }
.prov-keys { display: flex; flex-direction: column; gap: 6px; }
.key-row { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--muted); background: var(--bg); border: 1px solid var(--line); border-radius: 8px; padding: 5px 10px; }
.key-row .grow { flex: 1; min-width: 0; word-break: break-all; }
.prov-test-row { display: flex; align-items: center; gap: 10px; background: var(--bg); border: 1px dashed var(--line); border-radius: 8px; padding: 10px; flex-wrap: wrap; }
.prov-test-row .result { margin: 0; }
/* 逐档实测结果表：grid 而不是 table——窄屏不产生横向滚动条 */
.prov-probe { display: flex; flex-direction: column; gap: 4px; }
.prov-probe:empty { display: none; }
.prov-probe .pp-head { font-size: 12px; color: var(--muted); margin: 2px 0 2px; word-break: break-all; }
.prov-probe .pp-note { font-size: 12px; color: var(--acc2); margin-bottom: 2px; word-break: break-all; }
.prov-probe .pp-row { display: grid; grid-template-columns: 96px 1fr auto; gap: 8px; align-items: center;
  background: var(--bg); border: 1px solid var(--line); border-radius: 8px; padding: 4px 10px; font-size: 12px; }
.prov-probe .pp-row.running { border-color: var(--acc); }
.prov-probe .pp-lv { color: var(--acc); }
.prov-probe .pp-num { color: var(--muted); font-variant-numeric: tabular-nums; word-break: break-all; }
.prov-probe .pp-retry { flex: none; }
.prov-actions { display: flex; align-items: center; gap: 12px; margin-top: 2px; }
.prov-actions .primary { width: auto; margin: 0; padding: 8px 18px; }
.prov-actions .muted { margin: 0; }
@media (max-width: 899px) {
  .prov-page-body { flex-direction: column; }
  .prov-list { width: 100%; flex-direction: row; flex-wrap: wrap; }
  .prov-item { flex: 1 1 200px; }
  /* 手机端：两个模型下拉并排会挤到看不出选了什么，改成「标签一行、下拉一行」各占整行，
     下拉加高到 30px 便于手指点选（原生 select 在 WebView 里点开即是系统选择器）。 */
  .prov-role-row { gap: 6px; }
  .prov-role-row .section-title { flex: 1 1 100%; }
  .prov-role-row select { flex: 1 1 100%; width: auto; height: 30px; font-size: 13px; }
  /* 手机端一行挤不下「星标 + 模型名 + 上下文框 + 思考档位 + 来源标记 + 操作按钮 + 两个用途按钮」，
     改成四行：星标+模型名占满第一行，上下文框与档位下拉等分第二行，
     来源标记与操作按钮落到第三行（标记左、按钮右），两个用途按钮独占第四行各占半行。
     上下文框/下拉都用 flex:1 1 0 + min-width:0 等分，320px 窄屏也不会溢出。 */
  .model-row { flex-wrap: wrap; }
  .model-row .m-star { order: 1; }
  .model-row .m-name { order: 2; flex: 1 1 calc(100% - 22px); }
  .model-row .ctx-in { order: 3; flex: 1 1 0; min-width: 0; width: auto; }
  .model-row .think-in { order: 4; flex: 1 1 0; min-width: 0; width: auto; }
  /* 来源标记固定宽度：第三行先放它，剩下的空间都给右侧按钮组 */
  .model-row .think-src { order: 5; flex: none; }
  /* 手机端取消操作区定宽：窄屏（≤320px）也不会被挤到第四行，剩余空间右对齐 */
  .model-row .m-ops { order: 6; width: auto; flex: 1 1 auto; }
  /* 两个用途按钮：独占一行、各占半行，加高到 30px 便于手指点选 */
  .model-row .m-roles { order: 7; flex: 1 1 100%; gap: 6px; }
  .model-row .m-roles .role-btn { flex: 1 1 0; min-width: 0; min-height: 30px; padding: 6px 8px;
    font-size: 13px; white-space: normal; line-height: 1.25; }
  /* 测试行：两个按钮各占半行、结果占整行——手机上不挤成一坨 */
  .prov-test-row .btn-test { flex: 1 1 calc(50% - 5px); }
  .prov-test-row .result { order: 3; flex: 1 1 100%; }

  /* 实测结果表：左侧档位列收窄，数字列换行而不是撑出横向滚动 */
  .prov-probe .pp-row { grid-template-columns: 64px 1fr auto; padding: 5px 8px; }
}
.badge { border: 1px solid var(--line); border-radius: 999px; padding: 2px 10px;
  font-size: 12px; color: var(--acc2); }

/* 卡片墙 */

/* 卡片详情弹窗 */
/* 世界书详情弹窗：整体不超出屏幕（超高时卡片内部滚动），封面限高防撑爆 */
@media (max-height: 540px) {
  /* 矮窗口：隐藏封面与介绍，保证关闭按钮和列表可见 */
  .hall-book-card .hall-book-cover { display: none; }
  #hall-book-desc { display: none; }
}

/* ---- 大厅：登录后左侧导航常驻，主区按 body 状态切换 ---- */
#hall-mask { position: fixed; inset: 0; z-index: 40; display: flex; padding: 0;
  pointer-events: none; background: transparent; }
body:not(.hall-logged-in) #hall-mask { display: none; }
.hall { width: 100%; height: 100%; max-width: none; border: 0; border-radius: 0;
  background: transparent; }
.hall-side { width: 220px; background: var(--panel); pointer-events: auto; }
body.hall-mode .hall-main { display: block; flex: 1; overflow-y: auto; }
body.hall-logged-in #app { margin-left: 220px; }
@media (max-width: 899px) {
  /* 窄屏：回退为全屏大厅遮罩，游戏内不占位 */
  body.hall-logged-in #app { margin-left: 0; }
  body.hall-mode #hall-mask { background: var(--bg); }
  body.hall-mode:not(.hall-logged-in) #hall-mask { display: flex; }
}
.hall-me input { width: 100%; max-width: 320px; background: var(--bg); color: var(--txt);
  border: 1px solid var(--line); border-radius: 8px; padding: 8px 10px; font-size: 14px; }

/* ---- 创作页工具行 + 卡片操作 ---- */
.hall-toolbar input { width: 200px; background: var(--bg); color: var(--txt);
  border: 1px solid var(--line); border-radius: 8px; padding: 8px 10px; font-size: 14px; }
.hall-toolbar .primary { margin-left: auto; width: auto; }
.wb-card-actions .mini { width: auto; margin-top: 0; padding: 4px 14px; font-size: 12px;
  flex: none; white-space: nowrap; }

/* ---- 世界书工坊弹窗：限高内部滚动，manifest 编辑区不再把弹窗撑出一屏 ---- */
#worldbook-mask .card.wide, #wb-rec-mask .card.wide {
  max-height: 92vh; overflow-y: auto; padding-top: 0; }
/* 弹窗固定头：标题不随内容滚动（卡片 padding-top 已归零，吸顶无缝隙） */
.wb-dialog-head { position: sticky; top: 0; z-index: 2; display: flex; align-items: center;
  gap: 12px; background: var(--panel); margin: 0 -20px 14px; padding: 14px 20px 10px;
  border-bottom: 1px solid var(--line); }
.wb-dialog-head h2 { margin: 0; flex: 1; min-width: 0; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.wb-dialog-head .primary { width: auto; margin: 0; flex: none; }
.wb-dialog-head .mini { width: auto; margin: 0; flex: none; }
.wb-dialog-head .primary:disabled { opacity: .6; cursor: default; }
/* 保存反馈状态行：成功绿色 / 失败红色，配合全局 toast */
#wb-edit-status.ok { color: var(--ok); }
/* 编辑弹窗改为「表单区固定在上 + 条目区占满剩余高度内部滚动」，
   避免 manifest 大文本框把条目列表挤出可视区 */
#worldbook-mask .card.wide { display: flex; flex-direction: column; overflow: hidden; }
#worldbook-mask .card.wide .wb-dialog-head { flex: none; }
#wb-editor:not(.hidden) { display: flex; flex-direction: column; flex: 1; min-height: 0; }
/* 通用隐藏：配合各组件既有规则，保证 .hidden 永远生效 */
.hidden { display: none !important; }
/* 开局信息·按职业初始装备：一行一个职业（职业名 + 可搜索多选下拉） */

/* ---- 世界书编辑弹窗：左编辑区 + 右 AI 助手侧栏 ---- */
/* 覆盖 .card.wide 的 640px 上限（含 max-width，否则仅改 width 会被钳制） */
#worldbook-mask .card.wide { width: min(1180px, 96vw); max-width: min(1180px, 96vw); }
/* AI 助手侧栏：消息区内部滚动，头部/输入区/统计常驻 */
/* 头部两行（标题行 + 会话行）：控件统一 30px 高、6px 间距，垂直居中对齐 */
.wb-agent-head .mini { flex: none; width: 30px; height: 30px; margin: 0; padding: 0;
  display: inline-flex; align-items: center; justify-content: center; font-size: 13px; }
/* 会话下拉：与右侧图标按钮同高；.card select 的全局内边距在此被覆盖 */
/* 消息区：统一气泡圆角/内距，段落压紧（md() 逐行输出 <p>） */
#wb-agent-log .msg { font-size: 13px; line-height: 1.65; padding: 8px 11px;
  margin-bottom: 8px; border-radius: 10px; }
#wb-agent-log .msg p { margin: 0 0 4px; }
#wb-agent-log .msg p:last-child { margin-bottom: 0; }
#wb-agent-log .msg :is(h1, h2, h3, h4) { margin: 6px 0 4px; font-size: 13px; color: var(--acc); }
#wb-agent-log .msg.user { margin-left: 18%; margin-bottom: 8px;
  background: var(--bg); border: 1px solid var(--line); }
#wb-agent-log .msg.assistant { margin-right: 4%; margin-bottom: 8px;
  background: var(--panel); border: 1px solid var(--line); }
#wb-agent-log .msg.agent-activity { background: none; border: none; border-radius: 0;
  color: var(--muted); font-size: 11px; padding: 1px 4px; margin-bottom: 6px; text-align: center; }
#wb-agent-log .msg.agent-activity .mutated { color: var(--acc2); }
/* 工具步骤行：同 agent-activity 但左对齐（与思考状态行区分） */
#wb-agent-log .msg.agent-step { background: none; border: none; border-radius: 0;
  color: var(--muted); font-size: 11px; padding: 1px 4px; margin-bottom: 6px; text-align: left; }
#wb-agent-log .msg.agent-step .mutated { color: var(--acc2); }
/* 「已改草稿」前后对比：可点击标签 + 展开的差异块（等宽小字、增删行淡绿/淡红底） */
#wb-agent-log .msg .diff-toggle { cursor: pointer; }
#wb-agent-log .msg .diff-toggle:hover { text-decoration: underline; }
#wb-agent-log .msg .agent-diff { margin-top: 4px; padding: 4px 6px; text-align: left;
  background: color-mix(in srgb, var(--panel) 70%, transparent);
  border: 1px solid var(--line); border-radius: 4px;
  font-family: var(--mono, monospace); font-size: 10.5px; line-height: 1.6;
  word-break: break-all; white-space: pre-wrap; }
#wb-agent-log .msg .diff-line.diff-add { color: var(--ok, #4caf50); }
#wb-agent-log .msg .diff-line.diff-del { color: var(--danger, #e57373); text-decoration: line-through; }
#wb-agent-log .msg .diff-line .diff-old { color: var(--danger, #e57373); text-decoration: line-through; }
#wb-agent-log .msg .diff-line .diff-new { color: var(--ok, #4caf50); }
/* 思考面板：左标签 + 右侧滚动思考预览；点击展开 <pre> 全文（ZCode 式） */
#wb-agent-log .msg.agent-thinking { background: none; border: none; border-radius: 0;
  color: var(--muted); font-size: 11px; padding: 1px 4px; margin-bottom: 6px; text-align: left; }
#wb-agent-log .msg.agent-thinking .th-head { display: flex; align-items: baseline;
  gap: 6px; cursor: pointer; overflow: hidden; white-space: nowrap; }
#wb-agent-log .msg.agent-thinking .th-label { flex: none; color: var(--acc2); }
#wb-agent-log .msg.agent-thinking.done .th-label { color: var(--muted); }
#wb-agent-log .msg.agent-thinking .th-preview { flex: 1 1 auto; overflow: hidden;
  text-overflow: ellipsis; }
#wb-agent-log .msg.agent-thinking.done .th-preview { color: var(--muted); }
#wb-agent-log .msg.agent-thinking .th-caret { flex: none; }
#wb-agent-log .msg.agent-thinking .th-full { display: none; margin: 4px 0 0;
  padding: 6px 8px; border-left: 2px solid var(--line); font: inherit;
  white-space: pre-wrap; word-break: break-word; max-height: 220px; overflow-y: auto; }
#wb-agent-log .msg.agent-problem { background: rgba(208, 105, 91, .08);
  border: 1px solid rgba(208, 105, 91, .35); border-radius: 8px; color: var(--bad);
  font-size: 12px; padding: 5px 9px; margin-bottom: 6px; }
#wb-agent-log .msg img.agent-thumb { max-width: 110px; max-height: 82px; border-radius: 6px;
  border: 1px solid var(--line); display: block; margin-top: 6px; }
/* 待发送附件预览条 */
.wb-agent-attach.hidden { display: none !important; }
/* 输入区：三列等高网格（📎 / 输入框 / 发送），覆盖 .card textarea 的 min-height:90px */
/* 上下文容量条（ZCode 式）：细轨道 + 填充色，占用 <70% 绿 / 70-90% 黄 / >90% 红 */

/* 编辑器顶级页签（基本信息/设定条目/状态栏模板）：下划线式 */
.wb-top-tabs .tab { width: auto; margin: 0; background: none; border: none;
  border-radius: 0; position: relative; padding: 9px 18px 11px; font-size: 13px;
  color: var(--muted); white-space: nowrap; }
.wb-top-tabs .tab:hover { color: var(--txt); background: var(--bg2); }
.wb-top-tabs .tab.active { color: var(--acc); font-weight: 600; background: transparent; }
.wb-top-tabs .tab.active::after { content: ""; position: absolute;
  left: 8px; right: 8px; bottom: 0; height: 2px; background: var(--acc); }
.wb-top-pane.hidden { display: none !important; }

/* 基本信息页签：左标签列纵向对齐（两端对齐）+ 右控件区 */
#wb-pane-info .form-row > input, #wb-pane-info .form-row > textarea { flex: 1; min-width: 0; margin: 0; }

/* 关键词行内显示与编辑 */
/* 状态栏模板卡片 */
.wb-mod-table input[type="number"] { width: 64px; margin: 0; padding: 3px 6px;
  background: var(--bg2); color: var(--txt); border: 1px solid var(--line);
  border-radius: 6px; }
.wb-mod-table input[type="checkbox"] { width: auto; margin: 0; }
/* 模块详情 / 公共模板管理弹框 */
#wb-tpl-dialog .card.wide { max-height: 92vh; overflow-y: auto; width: min(720px, 96vw);
  padding-top: 0; }
#wb-tpl-dialog h2 { margin: 0 0 10px; padding: 14px 36px 0 0; }
.wb-tpl-mod input { width: auto; margin: 0; }
/* 预览里的按钮按游戏内实际样式渲染（压过 .card button 的 width:100%/margin-top，否则「使用」按钮在预览里被拉成整行） */
.wb-tpl-preview .use-btn { padding: 1px 8px; font-size: 11px; line-height: 1.4; border-radius: 4px; }
.wb-tpl-preview input { width: 100%; margin-bottom: 6px; padding: 5px 9px; font-size: 13px; }
/* 模板编辑弹窗标题行：标题居左，保存/重置按钮组居中且不换行 */
.wb-tpl-head-row { display: flex; align-items: center; gap: 8px; min-width: 0; }
.wb-tpl-head-row h2 { margin: 0; flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wb-tpl-head-row button { width: auto; margin: 0; flex: none; white-space: nowrap; }
/* 变量手册页（/docs/模板变量手册.html）为独立 HTML；此处保留表格样式兜底 */
.stpl-line { line-height: 1.7; }
/* 固定头里的关闭钮：跟随标题栏排列（压过 .card button.close-x 的绝对定位） */
.card .wb-dialog-head button.close-x { position: static; margin: 0; flex: none; }
.card button.close-x { z-index: 3; }

/* 卡片内 .tabs 页签统一压过 .card button 的 width:100%（页签应按内容宽） */
.card .tabs .tab { width: auto; margin: 0; }

/* 游玩记录弹窗：左存档列表 + 右详情 */
#wb-rec-mask .card.wide { max-height: 92vh; overflow-y: auto; width: min(860px, 94vw); }
.wb-rec-saves { flex: none; width: 250px; max-height: 60vh; overflow-y: auto;
  border-right: 1px solid var(--line); padding-right: 10px; }
.wb-rec-save.active { border-color: var(--acc); }

/* ---- 创作卡片操作 / 条目编辑 ---- */
#wb-ent-tabs .tab { font-size: 13px; padding: 6px 12px; flex: none; white-space: nowrap;
  width: auto; margin: 0; }
.wb-tab-arrow, .wb-tabs-bar .mini { width: auto; margin: 0; flex: none; padding: 4px 9px; font-size: 12px; }
.wb-ent-ops .mini { width: auto; margin-top: 0; padding: 4px 10px; font-size: 12px; }
.wb-ent-ops .danger { color: var(--bad); }
.wb-ent-pager .mini { width: auto; margin-top: 0; padding: 4px 12px; font-size: 12px; }
.wb-ent-pager .mini[disabled] { opacity: .45; cursor: default; }
.wb-ent input, .wb-ent textarea { width: 100%; background: var(--bg2); color: var(--txt);
  border: 1px solid var(--line); border-radius: 6px; padding: 6px 8px; font-size: 13px;
  margin-bottom: 6px; font-family: inherit; }
.wb-ent-head input { flex: 1; margin-bottom: 0; font-weight: 600; }
.wb-ent-head .mini { width: auto; margin: 0; flex: none; }

/* 从模板编辑预览里打开的样例详情弹窗：压过模板编辑弹框（同为 .mask，DOM 更早） */
#detail-mask { z-index: 70; }

/* 确认/输入弹窗会从详情弹窗**内部**打开（队友「请求授予」「索要金钱」、丢弃道具…）：
   必须压过 #detail-mask，否则确认框渲染在队友/道具面板背后，看着就像点了没反应 */
#confirm-mask, #prompt-mask { z-index: 80; }

/* ---- 只读回放（创作·记录 → 查看存档） ---- */
#btn-wbrec-back { display: none; }
body.wb-readonly #btn-wbrec-back { display: inline-block; }
body.wb-readonly #input-bar { display: none !important; }
body.wb-readonly #btn-new { display: none; }

/* ---- 头部返回记录按钮（只读回放）与记录弹窗双列 ---- */
body.wb-readonly #btn-appeal, body.wb-readonly #btn-records { display: none; }
#wb-rec-saves { flex: 1; width: auto; }

/* ---- 只读回放：头部只留必要按钮，「← 返回记录」悬浮固定在剧情区左上 ---- */
body.wb-readonly #btn-stream, body.wb-readonly #btn-tokens, body.wb-readonly #btn-settings { display: none; }
body.wb-readonly #btn-wbrec-back {
  display: inline-block;
  position: fixed;
  top: calc(var(--hdr-h, 56px) + 10px);
  left: 14px;
  z-index: 6;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.35);
}
body.wb-readonly #btn-wbrec-back { left: var(--wbrec-left, 234px); }

/* ---- 只读回放：禁用面板内容区的点击互动（保留页签切换、搜索框与详情弹窗查看） ---- */
body.wb-readonly #side .pane button,
body.wb-readonly #side .job-add-btn,
body.wb-readonly #side .unequip-btn,
body.wb-readonly #side .skill-unequip-btn,
body.wb-readonly #side .trade-entry,
body.wb-readonly #side .clickable {
  pointer-events: none;
  opacity: 0.55;
  cursor: default;
}
/* 详情/赠送弹窗可打开查看，但其中的操作按钮（使用/装备/丢弃/赠送/索要/关闭外的操作）不可点 */
body.wb-readonly #detail-mask button,
body.wb-readonly #give-mask button {
  pointer-events: none;
  opacity: 0.55;
  cursor: default;
}
body.wb-readonly #side .job-add-btn::after { content: ""; }

/* ---- 条目关联：chips + 选择面板 ---- */
.wb-rel-pager .mini { width: auto; margin-top: 0; padding: 2px 8px; font-size: 12px; }
.wb-rel-x, .card .wb-rel-x { border: 0; background: none; cursor: pointer; padding: 0 2px;
  color: var(--muted, #888); font-size: 11px;
  width: auto; flex: none; margin: 0; line-height: 1; }
.wb-rel-picker-head input { flex: 1 1 0%; min-width: 0; width: 0; }
.wb-rel-picker-head select, .wb-rel-picker-head input { margin: 0; }
#wb-rel-mask .card { width: 100%; max-width: 340px; }
/* 关联条目详情弹窗 */
#wb-rel-detail-mask .card { width: 100%; max-width: 480px; }
/* 条目编辑弹窗：内容过长时整体出滚动条，不再无限拉高 */
#wb-ent-mask .card { max-height: 92vh; max-height: 92dvh; overflow-y: auto; }
.wb-rel-item input[type="checkbox"] { width: 14px; height: 14px; flex: none;
  margin: 0; padding: 0; vertical-align: middle; }

/* ---- 世界书编辑器：基本信息标签行 / 条目注入方式复选组 ---- */
.wb-inj-checks input[type="checkbox"] { width: 14px; height: 14px; margin: 0; }
/* 游戏规则·系统开关：复选框与文字同行垂直居中（压过 .card input 的 width:100%）
   行内可挂「⚔ 战斗规则」按钮（勾选战斗系统才可点），红字提示独占一行 */
.wb-sys-row input[type="checkbox"] { width: 15px; height: 15px; flex: none; margin: 0;
  padding: 0; accent-color: var(--acc); }
.wb-sys-row .mini:disabled { opacity: .45; cursor: default; }
/* 战斗规则弹窗：加宽 + 限高滚动 + 开关行 */
#wb-combat-mask .card { width: min(94vw, 680px); max-width: 680px; max-height: 88vh;
  overflow-y: auto; scrollbar-width: thin; }
#wb-combat-body .section-title { margin: 10px 0 4px; }
.wb-combat-toggle input { width: 15px; height: 15px; flex: none; margin: 0; accent-color: var(--acc); }
#wb-economy-mask .card { width: min(94vw, 560px); max-width: 560px; max-height: 88vh;
  overflow-y: auto; scrollbar-width: thin; }
#wb-economy-body input, #wb-economy-body select { min-width: 0; }
/* 装备规则弹窗：加宽 + 限高滚动（默认卡片 420px 太窄，长说明文字挤出框外） */
#wb-equip-mask .card { width: min(94vw, 640px); max-width: 640px; max-height: 88vh;
  overflow-y: auto; scrollbar-width: thin; }
/* 游戏规则·三合一属性表：类型徽章 / 公式列 / 操作列 */
/* 游戏规则·属性表：圆角容器 + 斑马纹 + 行悬停 + 文字型操作按钮 */
.wb-rule-table .wb-tb-op .mini { margin: 0 0 0 6px; padding: 2px 6px; font-size: 12px;
  background: none; border: none; color: var(--acc2); }
.wb-rule-table .wb-tb-op .mini:hover { color: var(--acc); text-decoration: underline; }
.wb-rule-table .wb-tb-op .danger { color: var(--muted); }
.wb-rule-table .wb-tb-op .danger:hover { color: var(--bad); }

/* 技能规则网格：名称/等级/职业/说明/关键字/操作 */
.wb-rule-table.wb-skill-table tbody td input[type="checkbox"] { width: 14px; height: 14px;
  margin: 0; padding: 0; vertical-align: middle; }
/* 技能规则弹窗：同战斗规则弹窗限高滚动，内容再长也不盖满整个窗口 */
#wb-skill-mask .card.wide { max-height: 88vh; overflow-y: auto; scrollbar-width: thin; }
/* 校验问题清单（保存时红字汇总）限高，避免把弹窗撑到一屏放不下 */
/* 游戏规则·职业总览条目：单选可搜索下拉 + 解析出的职业 chips */
.wb-cls-input input { flex: 1; min-width: 0; margin-bottom: 0; }
.wb-cls-input .mini { flex: none; width: auto; margin: 0; }
/* 说明行（「解析出 N 个职业：」「已配置：」）独占一行：上下两块 chips 的左缘逐行垂直对齐 */
.wb-cls-chips .muted { flex: 0 0 100%; margin-top: 0; }

/* ---- 游戏规则·魔法修习规则：职业/种族绑定行（可搜索多选下拉）+ 神术绑定 ---- */
.wb-mg-row .wb-mg-pick input { width: 100%; margin-bottom: 0; }
/* chips 折叠态的「展开全部/收起」按钮：虚线胶囊区别于普通绑定标签；
   展开后完整铺开（滚动交给弹窗自身，不加内部滚动条） */
/* 魔法绑定行：类型小标 + 左侧职业/种族合并下拉 + 右侧魔法多选 + 删除按钮 */
.wb-mg-item-label input[type="checkbox"] { width: 14px; height: 14px; flex: none;
  margin: 0; padding: 0; pointer-events: none; accent-color: var(--acc, #c9a45c); }

/* ---- 可搜索下拉选择（单选/多选）：开局信息·出生地点 / 建卡·出生地点 ---- */
.ss-wrap { position: relative; width: 100%; }
.ss-box { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; min-height: 38px;
  box-sizing: border-box; padding: 4px 26px 4px 8px; border: 1px solid var(--line);
  border-radius: 8px; background: var(--bg); cursor: pointer; position: relative; }
.ss-box:hover, .ss-wrap.ss-open .ss-box { border-color: var(--acc2); }
.ss-arrow { position: absolute; right: 9px; top: 50%; transform: translateY(-50%);
  color: var(--muted, #888); font-size: 12px; pointer-events: none; }
.ss-placeholder { color: var(--muted, #888); font-size: 13px; }
.ss-value { font-size: 13px; color: var(--txt); overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; max-width: 100%; }
.ss-value.ss-warn { color: #8a6100; }
.ss-chip { display: inline-flex; align-items: center; gap: 5px; height: 24px; padding: 0 9px;
  font-size: 12px; line-height: 1; color: var(--txt); background: var(--bg2);
  border: 1px solid var(--line); border-radius: 999px; max-width: 100%; }
.ss-chip.ss-warn { color: #8a6100; background: #fff7e0; border-color: #e8d28a; }
.ss-chip-x { cursor: pointer; font-size: 12px; opacity: .55; font-weight: 400; }
.ss-chip-x:hover { opacity: 1; color: var(--bad, #c0392b); }
.ss-panel { position: absolute; z-index: 60; left: 0; right: 0; top: calc(100% + 4px);
  background: var(--panel, #fff); border: 1px solid var(--line); border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, .14); padding: 6px; }
.ss-search { width: 100%; box-sizing: border-box; margin: 0 0 6px; height: 30px;
  border: 1px solid var(--line); border-radius: 6px; padding: 0 8px; font-size: 12px;
  background: var(--bg); color: var(--txt); }
.ss-search:focus { border-color: var(--acc2); outline: none; }
.ss-list { max-height: 240px; overflow-y: auto; display: flex; flex-direction: column; gap: 1px; }
.ss-opt { display: flex; align-items: center; gap: 8px; padding: 5px 6px; border-radius: 6px;
  font-size: 13px; cursor: pointer; line-height: 1.4; }
.ss-opt:hover { background: var(--bg2, #f2f4f7); }
.ss-opt.sel { color: var(--acc); }
.ss-opt input[type="checkbox"] { width: 14px; height: 14px; flex: none; margin: 0; }
.ss-opt-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; text-align: left; }
.ss-opt.ss-warn .ss-opt-name { color: #8a6100; }
.ss-opt-group { flex: none; font-style: normal; font-size: 11px; color: var(--muted, #888);
  border: 1px solid var(--line); border-radius: 10px; padding: 0 6px; }
.ss-empty { color: var(--muted, #888); font-size: 12px; padding: 8px 6px; text-align: center; }

/* ---- 地图页签 ---- */
#pane-map { display: none; flex-direction: column; gap: 8px; height: 100%; }
#pane-map.active { display: flex; }
.map-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.map-switch { display: flex; gap: 4px; }
.map-mode-btn {
  border: 1px solid var(--line); background: var(--bg2); color: var(--muted);
  border-radius: 999px; padding: 3px 12px; font-size: 12px; cursor: pointer;
}
.map-mode-btn.active { color: var(--acc); border-color: var(--acc); }
.map-icon-btn {
  border: 1px solid var(--line); background: var(--bg2); color: var(--muted);
  border-radius: 6px; padding: 2px 8px; font-size: 13px; cursor: pointer;
}
.map-canvas {
  position: relative; flex: 1; min-height: 220px;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--bg2); overflow: hidden; touch-action: none;
}
#map-svg { width: 100%; height: 100%; display: block; cursor: grab; }
#map-svg:active { cursor: grabbing; }
.map-edge { stroke: #3d4759; stroke-width: 0.3; }
.map-node { cursor: pointer; }
.map-node text {
  fill: var(--txt); font-size: 2.4px; paint-order: stroke;
  stroke: var(--bg2); stroke-width: 0.55;
}
.map-node.player text { fill: #ffd76a; font-weight: bold; }
.map-empty {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; color: var(--muted);
  text-align: center; line-height: 1.8; pointer-events: none;
}
.map-empty.hidden { display: none; }
.map-detail {
  position: absolute; left: 8px; right: 8px; bottom: 8px;
  background: rgba(23, 27, 36, 0.95); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 8px 10px; font-size: 12px;
}
.map-detail.hidden { display: none; }
.map-detail-close {
  position: absolute; top: 4px; right: 6px; border: none; background: none;
  color: var(--muted); cursor: pointer; font-size: 12px;
}
.map-detail-name { color: var(--acc); font-weight: bold; }
.map-detail-name small { color: var(--muted); font-weight: normal; margin-left: 6px; }
.map-detail-desc { color: var(--txt); margin-top: 4px; line-height: 1.6; }
.map-adjust { display: flex; gap: 6px; }
.map-adjust input {
  flex: 1; min-width: 0; background: var(--bg2); border: 1px solid var(--line);
  border-radius: 8px; color: var(--txt); padding: 6px 10px; font-size: 12px;
}
.map-adjust button {
  border: 1px solid var(--line); background: var(--bg2); color: var(--txt);
  border-radius: 8px; padding: 4px 12px; font-size: 12px; cursor: pointer;
}
.map-adjust button:disabled { opacity: 0.5; cursor: default; }
#map-btn-adjust { color: var(--acc); border-color: var(--acc); }

/* ---- 战斗规则弹窗：分组内两列网格（数字项并列、公式/开关占整行），标签与输入框对齐 ---- */
#wb-combat-mask .card.wb-combat-card {
  max-width: 760px; width: min(760px, 96vw);
  max-height: 92vh; overflow-y: auto;
}
.wb-rule-grid > .rowlabel { margin-bottom: 8px; }
.wb-rule-grid > .rowlabel > input { margin-top: 4px; }
.wb-rule-grid > .wb-combat-toggle input { margin: 0; }

/* ============================================================
 * 移动端适配（手机 / 窄屏 ≤899px，与既有断点一致）
 * 大厅/工坊侧栏 → 顶部横条；弹框贴边；控件加大触摸面积。
 * 置于文件末尾获得级联优先；大厅相关用 body.hall-logged-in 提升优先级
 * 以压过 hall.css（其在本文件之后加载）。
 * ============================================================ */
@media (max-width: 899px) {
  /* ---- 触摸基础 ---- */
  button, .hall-nav-btn, .tab { touch-action: manipulation; -webkit-tap-highlight-color: transparent; }
  button { min-height: 40px; }
  button.mini, .msg.user .input-edit-actions button { min-height: 32px; }
  #input-bar #input, .card input, .card select, .hall-me input, .hall-toolbar input { font-size: 16px; }

  /* ---- 弹框：整张卡片不超过一屏、由卡片自己滚，标题吸顶 ----
     原来让 .mask 整体滚：内容长的弹窗（如条目编辑）一滚就把标题顶出屏幕，✕ 也随之消失 */
  .mask {
    padding: calc(10px + var(--sat, env(safe-area-inset-top, 0px))) 10px
             calc(10px + var(--sab, env(safe-area-inset-bottom, 0px)));
    overflow: hidden;
  }
  .card {
    max-width: 94vw; padding: 16px;
    /* 高度按遮罩的可用高度算（不依赖 --app-vh：键盘弹出时那个值会变小） */
    max-height: 100%;
    overflow-y: auto;
  }
  .card.wide { max-width: 94vw; }
  /* 魔宠详情弹窗：卡片自己不滚（正文独占滚动条），高度铺满遮罩可用高度 */
  #detail-mask .detail-card { overflow: hidden; }
  #detail-mask .detail-card.pet-open { height: 100%; }
  /* PC 上给这几个弹窗写死的 92vh，加上安全区会超出屏幕 → 统一按遮罩可用高度 */
  #prov-mask .card.wide, #worldbook-mask .card.wide, #wb-rec-mask .card.wide { max-height: 100%; }
  #prov-mask .card.wide { max-width: 100%; }
  /* 标题吸顶：滚动内容时始终可见；右侧留出关闭按钮（.close-x 绝对定位在右上角）的位置 */
  .card > h2 { position: sticky; top: 0; z-index: 2; background: var(--panel);
    margin-top: 0; padding: 10px 34px 8px 0; }
  /* 关闭按钮压在吸顶标题/吸顶头之上：两者都定位，DOM 里 ✕ 在前，不抬层级会被背景盖住 */
  .card .close-x { z-index: 3; }

  /* ---- 游戏页头部：横向滚动，按钮紧凑 ---- */
  #app-header { gap: 6px; overflow-x: auto; scrollbar-width: none; }
  #app-header::-webkit-scrollbar { display: none; }
  #app-header .ghost, #app-header .badge { flex: none; white-space: nowrap; min-height: 36px; }
  #app-header .ghost { padding: 7px 10px; font-size: 13px; }

  /* ---- 游戏页输入与页签：加大触摸面积 ---- */
  #input-bar #input { min-height: 44px; }
  /* 吸顶只给游戏页侧栏的页签行：其它页面的 .tabs（创作工具条、工坊页签、记录弹窗）
     不在滚动容器顶端，吸顶会滑到同排兄弟元素上面盖住它们 */
  body:not(.hall-mode) #side .tabs { position: sticky; top: 0; background: var(--bg2); z-index: 2; }
  .tabs .tab { padding: 12px 14px; font-size: 14px; }

  /* ---- 大厅/工坊：左侧栏 → 顶部条（品牌+用户/退出），导航行固定到屏幕底部 ---- */
  .hall { flex-direction: column; }
  body.hall-logged-in .hall-side {
    width: 100%; flex: none; flex-direction: row; flex-wrap: wrap; align-items: center;
    gap: 4px 8px; padding: calc(6px + var(--sat, env(safe-area-inset-top, 0px))) 10px 6px;
    border-right: 0; border-bottom: 1px solid var(--line);
  }
  body.hall-logged-in .hall-brand-row { padding: 2px 4px; }
  body.hall-logged-in .hall-brand { font-size: 16px; }
  body.hall-logged-in .hall-brand-row .ghost { min-height: 32px; padding: 5px 8px; }
  /* 手机端顶部不放 APP 下载入口（顶栏空间紧俏，桌面侧栏保留） */
  #hall-appdl { display: none; }
  /* 导航贴屏幕底部：等宽横排铺满一行，不再横向滚动（窄屏文字自动省略） */
  body.hall-logged-in .hall-nav {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 30; order: 0;
    flex-direction: row; gap: 0; overflow: hidden;
    padding: 0 4px var(--sab, env(safe-area-inset-bottom, 0px));
    background: var(--panel); border-top: 1px solid var(--line);
  }
  body.hall-logged-in .hall-nav-btn {
    flex: 1 1 0; min-width: 0; padding: 8px 2px; font-size: 12px; line-height: 1.3;
    text-align: center; border-radius: 8px;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  body.hall-logged-in .hall-side-foot {
    margin: 0 0 0 auto; padding: 0; border-top: 0;
    flex-direction: row; align-items: center; gap: 8px;
  }
  body.hall-logged-in .hall-user {
    font-size: 12px; white-space: nowrap; max-width: 38vw;
    overflow: hidden; text-overflow: ellipsis;
  }
  body.hall-logged-in .hall-side-foot .ghost { min-height: 36px; padding: 6px 10px; font-size: 13px; }
  /* 底部导航占位：主区留出等高内距，最后一行卡片不会被导航条盖住 */
  body.hall-logged-in .hall-main { padding: 14px 12px calc(66px + var(--sab, env(safe-area-inset-bottom, 0px))); }

  /* ---- 大厅内容：卡片更密、用户信息页纵排 ---- */
  body.hall-logged-in .hall-cards { grid-template-columns: repeat(auto-fill, minmax(158px, 1fr)); gap: 12px; }
  body.hall-logged-in .hall-head { flex-wrap: wrap; row-gap: 6px; }
  /* 创作视图工具条：PC 是「页签 + 搜索框 + 新建按钮」一行排布，窄屏挤成一团
     （页签会压到搜索框/按钮上）→ 页签独占一行，搜索框与按钮并排占下一行 */
  body.hall-logged-in .hall-toolbar {
    display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px; align-items: center;
  }
  body.hall-logged-in .hall-toolbar .tabs { grid-column: 1 / -1; overflow-x: auto; }
  body.hall-logged-in .hall-toolbar input { width: 100%; min-width: 0; }
  body.hall-logged-in .hall-toolbar .primary { margin-left: 0; width: auto; white-space: nowrap; }
  body.hall-logged-in .me-layout { flex-direction: column; }
  body.hall-logged-in .me-side { display: flex; width: 100%; flex-direction: row; overflow-x: auto; }
  /* 侧栏变底部导航：侧栏里的二级菜单展开项隐藏，页内横向页签顶上 */
  body.hall-logged-in .hall-subnav { display: none !important; }
  body.hall-logged-in .hall-me { max-width: none; }

  /* ---- 工坊：记录双列纵排 ---- */
  body.hall-logged-in .wb-rec-layout { flex-direction: column; }

  /* ---- 下载页（若被 APP 内打开）---- */
  body[data-page="download"] { padding: calc(24px + var(--sat, env(safe-area-inset-top, 0px))) 16px calc(24px + var(--sab, env(safe-area-inset-bottom, 0px))); }
}

/* 游戏视图（手机端）：隐藏大厅浮层侧栏（头部「大厅」按钮替代），避免叠压页头。
   合并主页面（data-page=hall）上同样生效：仅游戏视图隐藏，大厅视图保留侧栏 */
@media (max-width: 899px) {
  body:not(.hall-mode) #hall-mask { display: none !important; }
}

/* ---- 游戏页（手机端）：头部瘦身 + 侧栏折叠为全屏面板 ---- */
@media (max-width: 899px) {
  /* 输入行左侧「☰」功能入口（桌面端隐藏，按钮仍在头部） */
  body:not(.hall-mode) #btn-func {
    display: inline-block; flex: none; min-height: 40px; padding: 8px 12px; font-size: 16px;
  }
  #func-mask .card { display: flex; flex-direction: column; }
  .func-menu { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; margin-top: 4px; }
  .func-menu .ghost {
    width: auto; margin: 0; min-height: 46px; padding: 10px 8px; font-size: 14px; white-space: nowrap;
    min-width: 0; overflow: hidden; text-overflow: ellipsis;
  }

  /* 侧栏默认只显示页签表头；点页签弹出全屏面板（只读回放保持原侧栏布局） */
  body:not(.hall-mode):not(.wb-readonly) #side:not(.sheet-open) .tabs {
    padding-top: 10px;
    padding-bottom: 12px;
  }
  body:not(.hall-mode):not(.wb-readonly) #side .tab-panes { display: none; }
  /* 互动角色栏：全屏面板内不显示（各页签内容自含），收起态也隐藏；
     仅战斗中（有敌人）在收起态保留，敌人血量不因折叠而看不到 */
  body:not(.hall-mode):not(.wb-readonly) #side #npc-card { display: none; }
  body:not(.hall-mode):not(.wb-readonly) #side:not(.sheet-open).has-enemy #npc-card { display: block; }
  body:not(.hall-mode):not(.wb-readonly) #side.sheet-open {
    position: fixed; inset: 0; z-index: 45; max-height: none;
    padding-top: var(--sat, env(safe-area-inset-top, 0px));
    padding-bottom: var(--sab, env(safe-area-inset-bottom, 0px));
  }
  /* 全屏面板打开时恢复页签内容区（收起态才是隐藏的），高度占满剩余空间内部滚动 */
  body:not(.hall-mode):not(.wb-readonly) #side.sheet-open .tab-panes { display: block; flex: 1; min-height: 0; overflow-y: auto; }
  /* 全屏面板底部横向收起条：占满一行，黄色描边与页签栏自然衔接 */
  body:not(.hall-mode):not(.wb-readonly) #side.sheet-open #side-close {
    display: block; width: 100%; margin: 0; min-height: 46px;
    border-radius: 0; border: 1px solid var(--acc);
    background: var(--bg); color: var(--acc); font-size: 13px;
    letter-spacing: 6px; text-indent: 6px; flex: none;
  }

  /* ---- 剧情选项（手机端）：整句话在窄屏放不下第二个（见 .msg .options 处说明），
     就不再硬挤成小链接了——按整行按钮排：整行可点、左对齐、44px 触摸高度。
     与基础规则同优先级，靠本媒体块在文件更靠后取胜；桌面端不受影响。 ---- */
  .msg .options button.opt-link {
    display: block; width: auto; min-height: 44px;
    margin: 8px 0; padding: 10px 12px;
    font-size: 14px; line-height: 1.55;
    background: var(--panel); border: 1px solid var(--line); border-radius: 8px;
    text-align: left; text-decoration: none;
  }
  .msg .options button.opt-link:active { background: var(--bg2); border-color: var(--acc2); }
}

/* ============================================================
 * 平台积分：侧栏/头部余额、充值弹窗、收支明细（credits.js 注入的 DOM）
 * ============================================================ */
.hall-credits {
  font-size: 13px; color: var(--acc);
  padding: 2px 0;
}
.hall-side-foot { display: flex; flex-direction: column; gap: 6px; align-items: stretch; }

.credit-dlg { width: min(560px, 94vw); max-height: 86vh; overflow: auto; position: relative; }
.credit-dlg h2 { margin-top: 4px; }
.credit-dlg-body { display: flex; flex-direction: column; gap: 12px; }
.credit-balance { color: var(--acc); }
.credit-tiers { display: flex; flex-wrap: wrap; gap: 8px; }
.credit-tier {
  display: flex; flex-direction: column; gap: 2px; align-items: center;
  padding: 10px 14px; border-radius: var(--radius); min-width: 86px;
}
.credit-tier span { font-size: 12px; color: var(--muted); }
.credit-tier.on { border-color: var(--acc); color: var(--acc); background: var(--bg2); }
.credit-tier.on span { color: var(--acc); }
.credit-chans { display: flex; gap: 8px; }
.credit-chan { padding: 8px 16px; border-radius: var(--radius); }
.credit-chan.on { border-color: var(--acc2); color: var(--acc2); background: var(--bg2); }
.credit-actions { display: flex; gap: 8px; }
.credit-qr { display: flex; justify-content: center; padding: 6px;
  background: #fff; border-radius: 8px; width: fit-content; margin: 0 auto; }
.credit-qr img, .credit-qr canvas { display: block; }

.credit-ledger-wrap { max-height: 46vh; overflow: auto; border: 1px solid var(--line); border-radius: 8px; }
.credit-ledger { width: 100%; border-collapse: collapse; font-size: 13px; }
.credit-ledger th, .credit-ledger td { padding: 6px 8px; text-align: left;
  border-bottom: 1px solid var(--line); white-space: nowrap; }
.credit-ledger td.credit-memo { white-space: normal; word-break: break-all; }
.credit-ledger th { color: var(--muted); font-weight: normal; position: sticky; top: 0; background: var(--panel); }
.credit-in { color: var(--ok); }
.credit-out { color: var(--bad); }
.credit-summary b { color: var(--acc); }
/* 流水「来源」小标签：免费/官网充值/Steam（.credit-src） */
.credit-src { color: var(--acc2); font-size: 12px; }

/* 收益提现：额度卡 + 明细表 + 分页 + 申请弹窗表单（me-pane-withdraw / creditDialogShell） */
.credit-pager { display: flex; align-items: center; gap: 10px; }
.wd-field { display: flex; flex-direction: column; gap: 4px; font-size: 13px; color: var(--muted); }
.wd-actions { display: flex; gap: 8px; }

/* 额度区：左边主卡（可提现大数字+申请按钮），右边三格小卡（余额/累计/占用） */
.wd-summary { display: flex; gap: 12px; align-items: stretch; }
.wd-main {
  flex: 1 1 55%; display: flex; flex-direction: column; align-items: flex-start; gap: 4px;
  padding: 14px 16px; border: 1px solid var(--acc); border-radius: var(--radius);
  background: linear-gradient(135deg, var(--bg2), var(--panel));
}
.wd-main-label { font-size: 12px; color: var(--muted); }
.wd-main-val { font-size: 30px; font-weight: 700; line-height: 1.2; color: var(--acc);
  font-variant-numeric: tabular-nums; }
.wd-main-foot { font-size: 12px; }
.wd-main .primary { margin-top: 8px; }
.wd-main .primary:disabled { opacity: .5; cursor: not-allowed; }
.wd-grid { flex: 1 1 45%; display: grid; grid-template-rows: repeat(3, 1fr); gap: 8px; }
.wd-cell {
  display: flex; justify-content: space-between; align-items: center; gap: 8px;
  padding: 6px 12px; border: 1px solid var(--line); border-radius: var(--radius);
}
.wd-cell span { font-size: 12px; color: var(--muted); white-space: nowrap; }
.wd-cell b { font-variant-numeric: tabular-nums; }
.wd-amt { color: var(--acc); font-weight: 600; }

/* 提现状态徽章：待审核=琥珀 / 已打款=绿 / 已驳回=红 */
.wd-badge {
  display: inline-block; padding: 2px 8px; border-radius: 999px;
  font-size: 12px; line-height: 1.5; border: 1px solid var(--line); color: var(--muted);
}
.wd-badge-pending { color: #d97706; border-color: #d97706; background: rgba(217, 119, 6, .08); }
.wd-badge-paid { color: var(--ok); border-color: var(--ok); background: rgba(74, 222, 128, .08); }
.wd-badge-rejected { color: var(--bad); border-color: var(--bad); background: rgba(239, 68, 68, .08); }

/* 非作者兜底：还没发布世界书时的引导块 */
.wd-empty { padding: 28px 12px; text-align: center; }
.wd-empty-ico { font-size: 30px; margin-bottom: 8px; }
.wd-empty-tit { font-weight: 600; margin-bottom: 6px; }

@media (max-width: 640px) {
  .credit-pager { justify-content: center; }
  .wd-summary { flex-direction: column; }
  .wd-main { align-items: center; text-align: center; }
  .wd-main .primary { align-self: stretch; }
  .wd-grid { grid-template-rows: none; grid-template-columns: 1fr; }
}

/* 手机端：面值按钮两列铺满、表格横向可滚（与全站窄屏规则同口径） */
@media (max-width: 640px) {
  .credit-tier { flex: 1 1 calc(50% - 8px); min-width: 0; }
  .credit-ledger th, .credit-ledger td { padding: 8px 6px; }
}

/* ---- 站内邮件（mail.js）：未读红点 + 收件箱弹窗 ---- */
/* 红点通用：挂 data-mail-entry 的按钮有未读时统一亮（大厅侧栏 / 手机 ☰ / 菜单内邮件项） */
.has-unread { position: relative; }
.has-unread::after {
  content: ""; position: absolute; top: 3px; right: 3px;
  width: 8px; height: 8px; border-radius: 50%;
  background: #e5484d; box-shadow: 0 0 0 2px var(--panel);
}
/* 游戏页头部的邮件按钮只服务手机端（手机被搬进 ☰ 菜单，桌面走左侧常驻侧栏） */
.hdr-right #btn-mail { display: none; }

.mail-dlg { width: min(620px, 94vw); max-height: 86vh; overflow: auto; position: relative; }
.mail-dlg h2 { margin-top: 4px; }
.mail-dlg-body { display: flex; flex-direction: column; gap: 10px; }
.mail-list { display: flex; flex-direction: column; gap: 8px; min-height: 120px; }
.mail-item { border: 1px solid var(--line); border-radius: 8px; padding: 8px 10px; }
.mail-item.unread { border-color: var(--acc); }
.mail-head { display: flex; align-items: center; gap: 8px; cursor: pointer; }
.mail-title { flex: 1; font-size: 14px; display: flex; align-items: center; gap: 6px; min-width: 0; }
.mail-item.unread .mail-title { font-weight: 600; }
.mail-dot { flex: none; width: 7px; height: 7px; border-radius: 50%; background: #e5484d; }
.mail-time { flex: none; font-size: 12px; color: var(--muted); }
.mail-content { font-size: 13px; line-height: 1.6; color: var(--txt);
  border-top: 1px dashed var(--line); margin-top: 8px; padding-top: 8px;
  word-break: break-word; white-space: normal; }
.mail-foot { display: flex; justify-content: flex-end; margin-top: 6px; min-height: 0; }
.mail-foot:empty { display: none; }
.mail-att { font-size: 12px; color: var(--muted); padding: 3px 8px;
  border: 1px solid var(--line); border-radius: 999px; }
.mail-att.done { opacity: 0.75; }
button.mail-claim { min-height: 0; }
.mail-pager { display: flex; align-items: center; gap: 10px; justify-content: center; }
.mail-pager:disabled { opacity: 0.5; }

/* ============================================================
 * 键盘遮挡补偿（手机端）：--kb-h 由 common.js 按 visualViewport 求出
 * （键盘遮住布局视口的高度，仅聚焦输入类元素时非 0）。
 * APP 壳 edge-to-edge，键盘弹出不缩小窗口，贴底元素会被输入法盖住 → 手动让位。
 * ============================================================ */
@media (max-width: 899px) {
  /* 游戏页：#app 整体缩到键盘上沿——输入条随网格底行升到键盘上方，剧情流可视高度
     同步缩小（min-height 也要减，否则被 100dvh 兜底顶住缩不下去） */
  #app {
    height: calc(var(--app-vh, 100%) - var(--kb-h, 0px));
    min-height: calc(100dvh - var(--kb-h, 0px));
  }
  /* 弹窗与大厅浮层：改按可视区（而非整屏）居中/贴底——矮卡片不挨着键盘，高卡片
     聚焦其底部输入框时整卡上移让出键盘 */
  #hall-mask, .mask { bottom: var(--kb-h, 0px); }
  /* 全屏侧栏面板（固定定位，不随 #app 缩放）：整体上移到键盘上方 */
  body:not(.hall-mode):not(.wb-readonly) #side.sheet-open {
    transform: translateY(calc(-1 * var(--kb-h, 0px)));
  }
  /* 输入条瘦身：44px 药丸 + 上下 10px 内边距在手机上太墩（真机反馈），
     收成 38px；游戏页专用，其他页面输入框不动 */
  body:not(.hall-mode) #input-bar { padding: 7px 10px 7px; }
  body:not(.hall-mode) #input-bar #input { min-height: 38px; padding: 8px 14px; border-radius: 19px; }
  body:not(.hall-mode) #input-bar .ghost, body:not(.hall-mode) #input-bar [type="submit"] { min-height: 38px; padding: 6px 12px; }
  /* 键盘弹出时，侧栏给系统导航条预留的 --sab 空白正好压在键盘上沿，纯浪费 → 扣掉
     （--kb-h≥--sab 时归零；收起键盘后 --kb-h=0，恢复原样） */
  body:not(.hall-mode) #side {
    padding-bottom: max(0px, calc(var(--sab, env(safe-area-inset-bottom, 0px)) - var(--kb-h, 0px)));
  }
}
