/* ==================================================================
   新版式组件（照用户截图复刻排版）
   ==================================================================

   ⚠️ 文件分工：
     tokens.css   ← 颜色/圆角/阴影/图标尺寸，**换美术只改那个文件**
     ui.css       ← 组件外观（本文件），一律用 var(--xx)，不写死颜色
     style.css    ← 旧样式 + 布局骨架（逐步淘汰中）

   ⚠️ 类名用 `m-` 前缀（mock 的 m），和旧类名区分开，
      方便一眼看出"这条是新版式"。
   ================================================================== */

/* ── 顶部按钮区：**上下两层** ────────────────────────────────
   ⚠️ 不做横向滚动：所有按钮一次全看得见，放不下就折成第二行。
      列数固定 5 列（11 个按钮 → 5+5+1），窄屏降到 4 / 3 列。

   ⚠️ `container-type: inline-size` 是"图标等比放大"的关键：
      它把 .topbar 声明成一个**容器**，里面的 cqw 就按这个宽度算。
      不加的话 cqw 会退回视口宽度，等比效果就不成立了。 */
.topbar {
  display: block;
  /**
   * ⚠️ 宽度 = 页面的 **40%**（居中，左右各留 30%）。
   *    和 `.town-body` 用**同一个变量**，所以两者左右边界天然对齐。
   *    ⚠️ 这里**不加左右 padding**，否则内容比 role 卡缩进一圈（踩过）。
   */
  width: min(var(--ui-w), 100%);
  margin-inline: auto;
  padding: 10px 0 6px;
  background: transparent;
  /**
   * ⚠️ 容器查询：`.m-tabs` 里的 cqw 按**这个宽度**算，
   *    所以按钮与图标会跟着顶部区域等比放大。
   *    不声明的话 cqw 会退回视口宽度，等比就变成"跟屏幕走"了。
   */
  container-type: inline-size;
  container-name: topbar;
}

.m-tabs {
  display: grid;
  /**
   * ⚠️ **固定 5 列**，不要用 `auto-fit / minmax`。
   *
   *    auto-fit 的行为是"能塞几列塞几列，然后把剩下的空间分给列"——
   *    当算出的最小列宽偏大时，它只留很少的列，
   *    结果按钮**挤在中间一小坨**、左右空出一大片（用户截图里就是这样）。
   *
   *    改成固定列数：11 个按钮 → 5 + 5 + 1，
   *    每一行都铺满整个顶部区域，左右边界和用户画的红框对齐。
   *    手机（≤560px）降到 3 列，否则每格只有 54px、字会溢出。
   */
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 4px;
  background: var(--panel);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: .55cqw;
  /**
   * ⚠️ 字号用 **cqw**（容器宽度百分比），并从这里**继承**给按钮 ——
   *    这样"按钮与图标随宽度等比放大"一行搞定，
   *    不用给每个按钮分别设字号。
   *
   * ⚠️ 外面套 `max(12px, …)` 是**必要的下限**：
   *    纯等比时小屏会掉到 5px，根本读不清。
   *    等比是为了"大屏更大气"，不该把小屏压到不可读。
   */
  font-size: max(12px, 1.6cqw);
}
.m-tab {
  padding: 9px 6px;
  /* 字号继承自 .m-tabs（cqw），不写死 —— 见上面 */
  font-family: inherit;
  color: var(--text-dim);
  background: none;
  border: 0;
  border-radius: var(--radius-sm);
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* 选中项：淡紫底 + 紫字（截图里那格） */
.m-tab.active {
  background: var(--primary-soft);
  color: var(--primary);
  font-weight: 600;
}

/**
 * ⚠️ 移动端的覆盖规则**全部集中在文件末尾**（见「移动端适配」那一段）。
 *
 *    这里原来有一组 `@media (max-width: 700px) { .topbar, .town-body { width:100% } }`
 *    —— 它**被后面第 270 行的 `.town-body { width: min(...) }` 反杀了**
 *    （同优先级，后写的赢），于是手机上界面永远只有 40vw 宽。
 *    实测：内容挤成中间一条、角色卡溢出屏幕。
 *
 *    现在统一挪到末尾。**以后新增移动端规则也请加在那里**，
 *    别散在文件各处 —— 这类"覆盖被反杀"的问题极难靠肉眼发现。
 */

/* 顶栏右侧那一小撮（模型标识 / 离开）挪到标签栏下面一行 */
.topbar-right {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  justify-content: flex-end;
  padding: 6px 2px 0;
}

/* ── 区块标题：左侧紫蓝竖条（照截图）──────────────────────────── */
.m-section {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  margin: var(--sp-5) 0 var(--sp-3);
  padding: 0 2px;
}
.m-section::before {
  content: "";
  width: 4px;
  height: 18px;
  background: var(--primary);
  border-radius: 2px;
}
.m-section h2 {
  margin: 0;
  font-size: var(--fs-lg);
  font-weight: 700;
  color: var(--text-strong);
}
.m-section .m-right {
  margin-left: auto;
  font-size: var(--fs-sm);
  color: var(--text-dim);
}

/* ── 三围条：粗圆头 + 文字嵌在条里（照截图）──────────────────────
   ⚠️ 文字用绝对定位压在条上，所以**条必须有确定高度**（--bar-h）。
      换美术时如果条的切图有固定高度，改 --bar-h 即可。 */
.m-bar {
  position: relative;
  height: var(--bar-h);
  border-radius: var(--radius-pill);
  margin-bottom: var(--sp-2);
  overflow: hidden;
}
.m-bar i {
  position: absolute;
  left: 0; top: 0; bottom: 0;
  border-radius: var(--radius-pill);
  transition: width .25s ease;
}
.m-bar.hp      { background: var(--hp-track); }
.m-bar.hp i    { background: linear-gradient(90deg, var(--hp), var(--hp-2)); }
.m-bar.stamina { background: var(--stamina-track); }
.m-bar.stamina i { background: linear-gradient(90deg, var(--stamina), var(--stamina-2)); }
.m-bar.mp      { background: var(--mp-track); }
.m-bar.mp i    { background: linear-gradient(90deg, var(--mp), var(--mp-2)); }

.m-bar span {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: #fff;
  /* ⚠️ 条填充少时白字会压在浅色轨道上，看不清 ——
     描边比"加暗罩"更稳：加暗罩会让整条变脏。 */
  text-shadow: 0 1px 2px rgba(0, 0, 0, .45);
}

/* ── 三围：**上下三层**（用户要求：不用横向铺满画面）────────────
   ⚠️ 用 flex column 而不是 grid 分列。
      分列会让每条变短，文字嵌在条里就挤成一团；
      上下叠起来每条都是满宽，"❤ 88/94" 这种读起来才顺。 */
.cs-bars {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}
.cs-bars .m-bar { margin-bottom: 0; }
.cs-hint {
  margin: var(--sp-2) 0 0;
  font-size: var(--fs-xs);
  color: var(--text-dim);
}

/* ── 折叠区（技能 / 冒险日记 / 仓库）──────────────────────────────
   ⚠️ 用 <details>/<summary> 原生折叠，不自己写 JS 开关：
      键盘操作、读屏、无 JS 降级全都免费拿到。
      这里只把默认那个三角换成自己的箭头，并美化一下。 */
.cs-sec {
  border-top: 1px solid var(--line);
  margin-top: var(--sp-2);
}
.cs-sec > summary {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 10px 2px;
  font-size: var(--fs-md);
  font-weight: 600;
  color: var(--text);
  cursor: pointer;
  list-style: none;            /* 去掉默认三角 */
  user-select: none;
}
.cs-sec > summary::-webkit-details-marker { display: none; }
/* 自己的箭头：收起时朝右，展开时朝下 */
.cs-sec > summary::before {
  content: "▸";
  color: var(--primary);
  font-size: 12px;
}
.cs-sec[open] > summary::before { content: "▾"; }
.cs-sec > summary:hover { color: var(--primary); }
.cs-sec > div { padding-bottom: var(--sp-3); }

/* ── 宽度：角色卡收成居中竖列，但**顶部按钮区不受这个限制** ──────
   ⚠️ 这里踩过一个坑，值得记下来：

   原来把 `max-width: 620px`（角色卡的宽度）加在 **`#view-town`** 上。
   而 `#view-town` 是 `.topbar` 的**祖先** —— 祖先的 max-width 会把
   子元素一起裁掉。于是不管我把 `--bar-max` 调到 70vw 还是更大，
   顶部按钮区**永远最多 620px**，看起来就是"缩在中间一小坨"。
   （用户连发两张截图指出这一点。）

   正确做法：**容器层不加宽度限制**，宽度给到具体的那几个块上 ——
   这样顶部可以比角色卡宽，两者互不影响。 */
/**
 * ⚠️ `#view-town` 只负责居中，**不设宽度、不设左右 padding**。
 *
 *    踩过两次坑：
 *    ① 在这里设 max-width → 把子元素（顶部按钮区）一起裁掉
 *    ② 在这里设左右 padding → 子元素整体缩进一圈，
 *       于是角色卡比顶部按钮缩进 12px，看着"没对齐"
 *       （用户截图指出："没有对齐"）
 *
 *    宽度只由 `--ui-w` 决定，左右留白交给 `margin-inline: auto`。
 */
#view-town {
  margin: 0 auto;
}

/**
 * ⚠️ `.town-body` 是**统一的宽度容器**（用户定稿）：
 *    顶部按钮区、角色卡+动态那两栏、冒险者页、设施页 —— 全部用它，
 *    所以左右边界天然对齐。
 *
 *    ⚠️ 这里**不能加左右 padding** ——
 *       加了之后内容比顶部按钮缩进一圈，就是"没对齐"。
 *       内边距由各自的卡片负责（`.charstrip` / `.m-feed-wrap` 自己有）。
 */
.town-body {
  width: min(var(--ui-w), 100%);
  margin-inline: auto;
}

/**
 * 「我的」两栏：左角色卡、右最近动态。
 *
 * ⚠️ 用**比例**而不是固定宽度：固定宽度在中等屏幕上会把动态栏挤没。
 * ⚠️ 但纯比例会让角色卡在大屏上依然偏窄（用户反馈"太小"），
 *    所以给左栏一个**下限** 420px（够放下三围条与四维两行），
 *    并给右栏一个**下限** 300px（够放下动态列表标题与一行）。
 *    两者同时生效时，`minmax` 会按内容需要分配，不会互相挤没。
 */
#mine-body {
  display: grid;
  grid-template-columns: minmax(0, 4fr) minmax(0, 5fr);
  gap: var(--sp-4);
  align-items: start;
}
/* 窄屏（手机）堆成一列 */
@media (max-width: 700px) {
  #mine-body { grid-template-columns: 1fr; }
}

/* 桌面宽屏时，两侧留白稍微大一点，卡片更"浮"得起来 */
@media (min-width: 1100px) {
  :root { --app-pad: 20px; }
}

/* ── 等级 / 四维 / 金币 一行（照截图）────────────────────────── */
.cs-stats {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2) var(--sp-4);
  padding: 8px 10px;
  margin: var(--sp-3) 0;
  background: var(--primary-soft);
  border-radius: var(--radius-sm);
  font-size: var(--fs-md);
}
.m-stat {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-weight: 600;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.m-stat-name { color: var(--text-dim); font-weight: 400; font-size: var(--fs-sm); }
/* 属性图标：彩色小方块（每个属性一色，扫一眼能分辨）*/
.m-stat-ico {
  width: var(--icon-size-lg);
  height: var(--icon-size-lg);
  border-radius: 6px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  background: var(--line);
  color: var(--text);
  flex: 0 0 auto;
}
.m-stat-ico.constitution { background: var(--attr-constitution); color: #fff; }
.m-stat-ico.agility      { background: var(--attr-agility); color: #fff; }
.m-stat-ico.intellect    { background: var(--attr-pink); color: #fff; }
.m-stat-ico.luck         { background: var(--attr-luck); color: #fff; }
.m-stat-ico.lv-ico       { background: var(--primary); color: #fff; }
.m-stat.lv b             { color: var(--primary); }
.m-stat-ico.gold-ico     { background: var(--gold-soft); }
.m-stat.gold b           { color: var(--gold); }

/* ── 胶囊（特质 / 装备）──────────────────────────────────────────
   ⚠️ 装备用**暖橙底**，和"人物见闻"那类冷色胶囊一眼分开（照截图）。 */
.m-chips { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.m-chip {
  padding: 3px 10px;
  font-size: var(--fs-sm);
  background: var(--primary-soft);
  border: 1px solid var(--primary-line);
  border-radius: var(--radius-pill);
  color: #4a4463;
}
.m-chip.gear {
  background: var(--gold-soft);
  border-color: var(--gold-line);
  color: #9a5f25;
}
.m-chip.more { color: var(--primary); }

/* ── 卡片容器 ──────────────────────────────────────────────────── */
.m-card {
  background: var(--panel);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: var(--sp-4);
}

/* ── 动态列表（照截图）──────────────────────────────────────────
   ⚠️ 同样只写上下 margin —— 左右留给 `margin-inline: auto` 居中，
      写成 `margin: 0 10px 24px` 会把它覆盖掉、整块贴左。 */
.m-feed-wrap { margin-top: 0; margin-bottom: 0; }
.m-toolbar { display: flex; gap: var(--sp-3); margin-bottom: var(--sp-3); }
.m-select, .m-btn {
  padding: 7px 12px;
  font-size: var(--fs-md);
  font-family: inherit;
  background: var(--panel);
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.m-select { flex: 1; }

.m-feed {
  background: var(--panel);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow: hidden;
}
.m-feed-row {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: 11px var(--sp-4);
  border-bottom: 1px solid var(--line);
  font-size: var(--fs-md);
}
.m-feed-row:last-child { border-bottom: 0; }
.m-feed-ico {
  width: 26px; height: 26px;
  border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 13px;
  flex: 0 0 auto;
  background: var(--line);
}
.m-feed-ico.good { background: #e6f5ec; color: var(--ok); }
.m-feed-ico.bad  { background: var(--hp-track); color: var(--hp); }
.m-feed-ico.live { background: var(--gold-soft); color: var(--gold); }
.m-feed-ico.book { background: var(--primary-soft); color: var(--primary); }
.m-feed-amt { font-weight: 700; color: var(--gold); font-variant-numeric: tabular-nums; }

/* ── 治疗所 ─────────────────────────────────────────────────────
   伤势卡片：名字 + 轻重 + 描述 + 费用/时间 + 治疗按钮。
   颜色读 --hp / --gold，和现有状态条一致。 */
.heal-list { display: grid; gap: var(--sp-3); margin-top: var(--sp-3); }
.heal-card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-left: 3px solid var(--hp);
  border-radius: var(--radius-sm);
  padding: var(--sp-3) var(--sp-4);
}
.heal-head { display: flex; align-items: center; gap: var(--sp-2); }
.heal-name { font-size: var(--fs-md); color: var(--text); }
.heal-stage {
  font-size: var(--fs-xs);
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--hp-track);
  color: var(--hp);
}
.heal-stage.medium { background: var(--gold-soft); color: var(--gold); }
.heal-stage.deep { background: rgba(160, 80, 180, 0.16); color: #a050b4; }
.heal-desc { margin: 6px 0 10px; color: var(--text-dim); font-size: var(--fs-sm); line-height: 1.65; }
.heal-actions { display: flex; align-items: center; gap: var(--sp-3); }
.heal-actions .muted { margin-right: auto; }
.heal-card.chapel { border-left-color: #a050b4; }

/* ── 余烬灶坊 ───────────────────────────────────────────────── */
.cook-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: var(--sp-2);
  margin: var(--sp-3) 0;
}
.cook-item {
  display: flex;
  flex-direction: column;
  gap: 2px;
  text-align: left;
  padding: 9px 11px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  color: var(--text);
  cursor: pointer;
}
.cook-item:hover { border-color: var(--gold); }
.cook-item.on { border-color: var(--gold); background: var(--gold-soft); }
.cook-name { font-size: var(--fs-md); }
.cook-qty { font-size: var(--fs-xs); color: var(--gold); }
.cook-tags { font-size: var(--fs-xs); color: var(--text-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ── 酒馆常驻猫：雾团 ─────────────────────────────────────────
   用户 2026-10-21：给酒馆加一只会睡觉的猫。
   纯装饰 + 点击互动，不参与数值；灰蓝长毛、白袜、尾巴尖浅色。
   放在「最近动态」下方，跟 feed 同一个面板语言。 */
.cat-nap {
  --cat-fur: #7f8fa6;
  --cat-fur-dark: #5f7088;
  --cat-cream: #f0ece1;
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  margin-top: var(--sp-4);
  padding: var(--sp-4);
  background:
    radial-gradient(circle at 14% 20%, rgba(255, 245, 220, 0.55), transparent 34%),
    linear-gradient(135deg, rgba(127, 143, 166, 0.12), transparent 58%),
    var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  cursor: pointer;
  overflow: hidden;
  transition: transform 0.25s ease, border-color 0.25s ease;
}
.cat-nap:hover { transform: translateY(-2px); border-color: rgba(127, 143, 166, 0.55); }
.cat-nap:focus-visible { outline: 2px solid var(--primary); outline-offset: 3px; }
.cat-art { flex: 0 0 148px; width: 148px; }
.cat-art svg { display: block; width: 100%; height: auto; overflow: visible; }
.cat-shadow { fill: rgba(30, 25, 20, 0.16); }
.cat-body { fill: var(--cat-fur); }
.cat-back { fill: var(--cat-fur-dark); opacity: 0.55; }
.cat-head { fill: var(--cat-fur); }
.cat-ear { fill: var(--cat-fur); }
.cat-ear-inner { fill: #b7a99e; }
.cat-paw { fill: var(--cat-cream); }
.cat-tail { fill: none; stroke: var(--cat-fur-dark); stroke-width: 10; stroke-linecap: round; }
.cat-stripe { fill: none; stroke: var(--cat-fur-dark); stroke-width: 3; stroke-linecap: round; opacity: 0.55; }
.cat-eye { fill: none; stroke: #2f2a28; stroke-width: 2.4; stroke-linecap: round; }
.cat-nose { fill: #b78b86; }
.cat-mouth, .cat-whisker { fill: none; stroke: #4b3f3a; stroke-width: 1.4; stroke-linecap: round; opacity: 0.7; }
.cat-body, .cat-head { transform-box: fill-box; transform-origin: center; animation: cat-breathe 4.8s ease-in-out infinite; }
.cat-tail { transform-box: fill-box; transform-origin: 10% 90%; animation: cat-tail 7s ease-in-out infinite; }
.cat-zzz {
  position: absolute;
  top: 16px;
  right: 22px;
  font-family: Georgia, serif;
  font-size: 17px;
  letter-spacing: 4px;
  color: var(--cat-fur-dark, #5f7088);
  opacity: 0.55;
  animation: cat-zzz 3.6s ease-in-out infinite;
}
.cat-copy { min-width: 0; }
.cat-kicker {
  display: inline-block;
  margin-bottom: 2px;
  font-size: var(--fs-xs);
  letter-spacing: 0.12em;
  color: var(--text-dim);
}
.cat-copy h3 {
  margin: 0 0 6px;
  font-size: calc(var(--fs-lg) + 2px);
  color: var(--text);
  font-weight: 700;
}
.cat-copy p {
  margin: 0;
  max-width: 58ch;
  font-size: var(--fs-sm);
  line-height: 1.75;
  color: var(--text-dim);
}
.cat-sign {
  display: inline-block;
  margin-top: 8px;
  font-size: var(--fs-xs);
  color: var(--cat-fur-dark, #5f7088);
  font-style: italic;
}
.cat-nap.awake .cat-body,
.cat-nap.awake .cat-head { animation-duration: 1.1s; }
.cat-nap.awake .cat-eye { stroke-width: 3.4; }
.cat-nap.awake .cat-zzz { opacity: 0; animation: none; }
@keyframes cat-breathe {
  0%, 100% { transform: scaleY(1); }
  50% { transform: scaleY(0.965); }
}
@keyframes cat-tail {
  0%, 84%, 100% { transform: rotate(0deg); }
  88% { transform: rotate(5deg); }
  92% { transform: rotate(-3deg); }
}
@keyframes cat-zzz {
  0%, 100% { transform: translateY(0); opacity: 0.35; }
  50% { transform: translateY(-4px); opacity: 0.7; }
}
@media (max-width: 720px) {
  .cat-nap { align-items: flex-start; padding: var(--sp-3); gap: var(--sp-3); }
  .cat-art { flex-basis: 104px; width: 104px; }
  .cat-copy p { font-size: var(--fs-xs); line-height: 1.65; }
}

/**
 * ⚠️ `.m-feed-what` 必须读 `--r` —— 锻造记录里的成品名要按稀有度上色。
 *    不写 `color: var(--r)` 的话，JS 加的 `r-*` 类完全不生效，
 *    而界面看起来"有颜色"（继承来的灰），很难发现。
 *    （这个坑已经踩过三次：`.item-name`、`.equip-name`、现在这里）
 */
.m-feed-what {
  color: var(--r, var(--text-dim));
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.m-feed-when {
  margin-left: auto;
  font-size: var(--fs-xs);
  color: var(--text-dim);
  white-space: nowrap;
  flex: 0 0 auto;
}

/* ── 角色横条：新版式覆盖 ──────────────────────────────────────── */
.charstrip {
  /**
   * ⚠️ 这里**不能**写 `margin: 0 10px …`。
   *
   *    `margin` 是简写，会把左右一起重置成 10px ——
   *    而上面那条 `.charstrip, .m-feed-wrap { margin-inline: auto }`
   *    就是靠左右 auto 来**居中**的，被这条简写覆盖之后
   *    角色卡就贴到左边去了（用户截图里正是这样）。
   *
   *    只写上下 margin，左右交给上面的 auto。
   */
  /* ⚠️ 只写上下 margin —— 宽度由父级 .town-body 统一给，
     左右不要再设（写成 margin 简写会覆盖父级布局意图）。 */
  margin-top: 0;
  margin-bottom: 0;
  padding: var(--sp-4);
  background: linear-gradient(165deg, #f6f4fe 0%, #ffffff 42%, #fdfbff 100%);
  border: 1px solid var(--primary-line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.cs-top {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  flex-wrap: wrap;
  margin-bottom: var(--sp-4);
}
.cs-name { font-size: var(--fs-xl); font-weight: 700; color: var(--text-strong); }
.cs-sub { font-size: var(--fs-sm); color: var(--text-dim); }
.cs-tags { display: inline-flex; gap: var(--sp-2); flex-wrap: wrap; }
.cs-spacer { flex: 1 1 auto; }
.cs-rest { color: var(--primary) !important; border-color: var(--primary-line) !important; }

.cs-line { display: flex; align-items: baseline; gap: var(--sp-3); margin-top: var(--sp-3); }
.cs-label { font-size: var(--fs-sm); color: var(--text-dim); flex: 0 0 auto; min-width: 46px; }
.cs-traits, .cs-equip { display: flex; flex-wrap: wrap; gap: var(--sp-2); }

/**
 * ⚠️ `.layout` 已经**不再使用**（HTML 里换成了 `.town-body`）。
 *    删掉它以免留下两条互相打架的"布局规则" —— 这类死规则最坑，
 *    下次改宽度时很难判断是哪一条在生效。
 */
.hall { background: none; border: 0; box-shadow: none; padding: 0; }

/**
 * ⚠️ 这块原来是 `margin-left: 0; margin-right: 0`（把旧样式的
 *    `margin: 0 10px` 归零）。现在不能这么写了 ——
 *    角色卡要靠 `margin-inline: auto` **居中**，
 *    归零会把它顶到左边去。
 *    改法：只把 margin 的**上下**交给我们，左右由上面的 auto 负责。
 */
/* ⚠️ 这两块现在是 #mine-body 网格的格子，间距由 grid gap 负责，不再各自设 margin。 */
.charstrip,
.m-feed-wrap { margin-top: 0; margin-bottom: 0; }

/* 镇上的设施格子做成卡片 */
.facility-grid { gap: var(--sp-3); }

/* ── 锻造台容器 ──────────────────────────────────────────────────
   ⚠️ 这个类之前一直没有样式（子元素有，容器没有）。
      查 CSS 一致性时才发现的 —— 容器没样式不会报错，
      只是内边距靠子元素凑，看起来会比别处挤。 */
.forge { padding: 2px 0; }

/* 冒险日记的「展开全部」（常态只显示最近 5 段）*/
.diary-more { margin-top: var(--sp-3); align-self: flex-start; }

/* ==================================================================
   顶部按钮区（用户定案：设施从页面底部拆到最顶端）
   ================================================================== */

/* ⚠️ 设施按钮的容器必须用 `display: contents`。
   否则它在 grid 里会占**一整格** —— 7 个设施会全挤在同一格里，
   而不是各自占一格。`contents` 让它不参与布局，
   子按钮直接成为 .m-tabs 网格的格子。 */
.m-tabs-group { display: contents; }

/* ==================================================================
   冒险者页（用户指定：显示自己 + 其他玩家）
   ================================================================== */
.adventurer-list {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}
.adv-card {
  background: var(--panel);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: var(--sp-4);
  border-left: 3px solid var(--line);
}
/* 自己那张卡用主色标出来，一眼在名单里找到自己 */
.adv-card.me { border-left-color: var(--primary); }
/* 已阵亡的淡一点，但仍看得见（记录要保留）*/
.adv-card.dead { opacity: .62; }

.adv-head { display: flex; align-items: baseline; gap: var(--sp-3); flex-wrap: wrap; }
.adv-name { font-size: var(--fs-lg); font-weight: 700; color: var(--text-strong); }
.adv-lv { font-size: var(--fs-sm); color: var(--primary); font-weight: 600; }
.adv-me {
  font-size: var(--fs-xs); padding: 1px 7px;
  background: var(--primary-soft); color: var(--primary);
  border-radius: var(--radius-pill);
}
.adv-dead { font-size: var(--fs-xs); color: var(--danger); }
.adv-meta { display: flex; flex-wrap: wrap; gap: var(--sp-4); margin-top: var(--sp-2); }
.adv-skill { margin-top: var(--sp-1); }

/* ==================================================================
   用户第 N 轮细节调整
   ================================================================== */

/* 四维图标：**透明底**（用户要求）。
   原来是每个属性一个彩色实心小方块，整行太花；
   去掉底色后靠 emoji 自身的颜色区分就够了。 */
.m-stat-ico.plain {
  background: none;
  width: auto;
  min-width: 16px;
  border-radius: 0;
}

/* 金币 / 职业 / 性格 一行（在四维下面）*/
.cs-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2) var(--sp-5);
  padding: 7px 10px;
  margin: 0 0 var(--sp-3);
  background: var(--bg-2);
  border-radius: var(--radius-sm);
  font-size: var(--fs-sm);
  color: var(--text-dim);
}
.cs-meta .m-stat { font-size: var(--fs-sm); }
.cs-meta .m-stat b { color: var(--text); }
.cs-meta .m-stat.gold b { color: var(--gold); }

/* 日记翻页（用户要求：底部做 1、2、3 这种页码）*/
.pager {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-top: var(--sp-3);
}
.pager:empty { display: none; }
.pager-btn {
  min-width: 30px;
  padding: 4px 9px;
  font-size: var(--fs-sm);
  font-family: inherit;
  color: var(--text-dim);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.pager-btn:hover:not(:disabled) { border-color: var(--primary); color: var(--primary); }
.pager-btn.on {
  background: var(--primary);
  border-color: var(--primary);
  color: #fff;
  font-weight: 600;
}
.pager-btn:disabled { opacity: .4; cursor: not-allowed; }

/* ══════════════════════════════════════════════════════════════════════
   剧情定制相关（2026-10-16）
   · 角色名高亮
   · 名字高亮开关（顶部）
   · 冒险记录列表 + 剧情阅读弹层
   · 世界日志"阅读剧情"入口
   ══════════════════════════════════════════════════════════════════════ */

/**
 * 剧情里的角色名高亮。
 *
 * ⚠️ 颜色由 JS 通过内联的 `--name-color` 传进来（见 name-highlight.js），
 *    这里只负责**怎么显示**。这样两件事分开：
 *      · 选色逻辑改 → 只动 JS
 *      · 显示样式改（加粗/底纹/下划线）→ 只动 CSS
 *
 * ⚠️ 用 `font-weight: 600` 而不是 `background`：长文里高亮底色会显得很花，
 *    加粗+染色既有辨识度，又不破坏阅读节奏。
 */
.story-name {
  color: var(--name-color, var(--primary));
  font-weight: 600;
}

/**
 * 名字高亮开关。
 * ⚠️ 和 `.m-tab.active` 一样用 class 切换，而不是改行内样式 ——
 *    这样"开/关"的视觉完全由 CSS 决定，JS 只管状态。
 *
 * ⚠️ 它在**剧情弹层里**（用户 2026-10-16 从顶部栏挪进来的），
 *    因为它只影响剧情正文，放顶部栏会被当成全局开关。
 */
#story-name-hl.active,
#story-font-btn.active {
  background: var(--primary-soft);
  border-color: var(--primary-line);
  color: var(--primary);
  font-weight: 600;
}

/* ── 剧情弹层的阅读设置条 ─────────────────────────────────────────── */
.story-bar {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin-bottom: var(--sp-2);
  /* 手机上按钮换行也不挤 */
  flex-wrap: wrap;
}
/* 用 spacer 把「阅读设置」推到右边，而不是 margin-left:auto —— 换行时更稳 */
.story-bar-gap { flex: 1 1 auto; }

/* 设置面板：三组，每组一行 */
.story-settings {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding: var(--sp-3);
  margin-bottom: var(--sp-3);
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
}
.ss-group {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  /* 手机上"字号"标签 + 四个按钮会放不下，允许折行 */
  flex-wrap: wrap;
}
.ss-label {
  flex: 0 0 auto;
  font-size: var(--fs-sm);
  color: var(--text-dim);
  min-width: 32px;
}
.ss-opts { display: flex; gap: var(--sp-2); flex-wrap: wrap; }

/**
 * 设置项按钮。
 * ⚠️ 高度给到 34px：手机上这是**用手指点**的，
 *    低于 32px 很容易点偏（原来 `.ghost.small` 只有 24px 左右）。
 */
.ss-opt {
  font: inherit;
  font-size: var(--fs-sm);
  padding: 7px 14px;
  min-height: 34px;
  color: var(--text-dim);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  cursor: pointer;
  white-space: nowrap;
}
.ss-opt:hover { border-color: var(--primary); color: var(--primary); }
.ss-opt.on {
  background: var(--primary);
  border-color: var(--primary);
  color: #fff;
  font-weight: 600;
}

/* ── 角色卡里「探险记录」那个按钮（在 职业 / 性格 那一行）────────────
   ⚠️ 要看起来**像个能点的东西** —— 这个入口的价值全在于被点开，
      做成静态文字的话玩家不会去点。 */
.m-stat-btn {
  cursor: pointer;
  font: inherit;
  font-size: inherit;
  color: var(--primary);
  background: var(--primary-soft);
  border: 1px solid var(--primary-line);
  border-radius: var(--radius-pill);
  padding: 2px 10px;
}
.m-stat-btn:hover { border-color: var(--primary); }
.m-stat-btn:active { transform: translateY(1px); }

/**
 * ⚠️ 这里原来有一套「探险记录列表」的旧版式
 *    （一行灰字用「　·　」把副本名/日期/段数/结局拼起来）。
 *    用户 2026-10-16 给了参照图，改成下面 `.rec-row` 的胶囊版式了，
 *    所以旧的那几个类**已删除**。
 *    留着的话下次改样式会看到两套长得不一样的"记录行"，不知道该改哪一套。
 */

/* ── 世界日志头部：胶囊行 ───────────────────────────────────────── */
.log-pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: var(--fs-sm);
  padding: 4px 12px;
  border-radius: var(--radius-pill);
  background: var(--panel-2);
  border: 1px solid var(--line);
  color: var(--text);
  white-space: nowrap;
}
.log-pill-ico { font-size: var(--fs-sm); }
.log-date { color: var(--text-dim); font-variant-numeric: tabular-nums; }

/* 阅读剧情按钮：做成实心按钮，比一行灰字更像"能点" */
.log-open {
  margin-top: var(--sp-2);
  align-self: flex-start;
  font-size: var(--fs-sm);
  font-weight: 600;
  padding: 6px 14px;
  color: var(--primary);
  background: var(--primary-soft);
  border: 1px solid var(--primary-line);
  border-radius: var(--radius-pill);
  cursor: pointer;
}
.log-open:hover { border-color: var(--primary); }

/**
 * 日志行里嵌的成员结算卡片。
 * ⚠️ 外面已经有一层 .log-row 的边框/底色，这里再加卡片会"框中框"。
 *    所以把卡片自身的外框去掉，只保留内部信息层次。
 */
.log-members { margin-top: var(--sp-2); }
.log-members .stl-card {
  background: var(--bg-2);
  box-shadow: none;
}

/* ══════════════════════════════════════════════════════════════════════
   副本告示板（用户 2026-10-16 要求按参照图重做）
   ══════════════════════════════════════════════════════════════════════

   参照图的设计语言：
     ① 卡片而不是表格行（圆角 + 细边 + 阴影，信息分层）
     ② 胶囊标签承载零散数值（楼层 / 推荐等级 / 精力 / 入场费）
     ③ 图标打头
     ④ 说明弱化、行动按钮在右下

   ⚠️ 电脑端 vs 手机：卡片用 auto-fit 网格 —— 宽屏自动 2~3 列，
      窄屏自动落回一列。**不需要给电脑端单独写一套**。
      一列铺满宽屏的话，一张卡会横跨整个屏幕、说明只占一条，很空。
   ══════════════════════════════════════════════════════════════════════ */

.dg-list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: var(--sp-4);
  align-items: start;
}

.dg-card {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding: var(--sp-4);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
/* 已通关：左边一条绿线，扫一眼就知道哪些打过了 */
.dg-card.cleared { border-left: 3px solid var(--ok); }
/* 进不去：整体压暗，但仍然可读（要看得到"为什么进不去"） */
.dg-card.locked { opacity: .72; }

.dg-head {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex-wrap: wrap;
}
.dg-icon { font-size: var(--fs-lg); }
.dg-name {
  font-size: var(--fs-lg);
  font-weight: 700;
  color: var(--text-strong);
}
/* 「已通关」胶囊：原来拼在名字后面，名字一长就被挤到第二行 */
.dg-badge {
  font-size: var(--fs-xs);
  font-weight: 600;
  padding: 2px 10px;
  border-radius: var(--radius-pill);
}
.dg-badge.ok { color: var(--ok); background: #e8f5ee; }

.dg-chips { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.dg-chip {
  font-size: var(--fs-xs);
  padding: 3px 10px;
  border-radius: var(--radius-pill);
  background: var(--panel-2);
  border: 1px solid var(--line);
  color: var(--text-dim);
  white-space: nowrap;
}
.dg-chip.gold { color: var(--gold); background: var(--gold-soft); border-color: var(--gold-line); }

/* 说明：最多两行 —— 长了会把卡片撑高、网格参差不齐 */
.dg-desc {
  font-size: var(--fs-sm);
  color: var(--text-dim);
  line-height: 1.7;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.dg-foot {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  margin-top: auto;   /* 把按钮压到卡片底部，多张卡片的按钮就能对齐 */
  padding-top: var(--sp-2);
}
/* 不可进入的原因：写在按钮旁边，不藏在 tooltip 里（手机没有 hover） */
.dg-reason { font-size: var(--fs-xs); color: var(--danger); flex: 1 1 auto; }
.dg-enter {
  margin-left: auto;
  font: inherit;
  font-size: var(--fs-md);
  font-weight: 600;
  padding: 8px 22px;
  min-height: 38px;          /* 手机上要能点准 */
  border-radius: var(--radius-pill);
  border: 1px solid var(--line);
  background: var(--panel-2);
  color: var(--text-dim);
  cursor: not-allowed;
}
.dg-enter.ready {
  background: var(--primary);
  border-color: var(--primary);
  color: #fff;
  cursor: pointer;
}
.dg-enter.ready:hover { background: var(--primary-2); }

/**
 * 副本结束后的确认块（用户 2026-10-16 取消了副本页的剧情与结算展示）。
 *
 * ⚠️ 它只有三样东西：一句"已经记入世界日志" + 两个查看入口 + 返回。
 *    不能省 —— 什么都不显示的话，点完结算界面会突然一片空白，
 *    玩家会以为出错了。
 */
.exp-done {
  margin-top: var(--sp-3);
  padding: var(--sp-4);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.exp-done .action-row { flex-wrap: wrap; }

/* ── 冒险记录列表 ─────────────────────────────────────────────────── */
.rec-list { display: flex; flex-direction: column; gap: var(--sp-3); }

/**
 * 一条探险记录（用户 2026-10-16：参照图二那张排版）。
 * ⚠️ 和世界日志的 .log-row 视觉统一 —— 两个列表是同一类东西，
 *    长得不一样会让人觉得是两个功能的临时拼凑。
 */
.rec-row {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.rec-head { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }

/* ── 世界日志：整行可点 ───────────────────────────────────────────── */
/* 可点的日志行给一点反馈，否则玩家不知道能点 */
.log-row { cursor: pointer; transition: border-color .15s; }
.log-row:hover { border-color: var(--primary-line); }

/* 摘要行里那个"显示放弃/出错"按钮和文字之间的间隔 */
.log-filter-gap { flex: 1 1 auto; }

/* ── 剧情弹层里的"小队编码" ───────────────────────────────────────── */
.story-squad {
  color: var(--primary);
  font-weight: 600;
}

/**
 * 组队卡片上的「小队编码」（用户要求组队界面也能看到）。
 * ⚠️ 做得比"队码"低调：队码是入场券（要发给朋友），
 *    编码只是身份标签 —— 两者视觉上要能一眼区分开。
 */
.party-squad {
  font-size: var(--fs-sm);
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
  margin-bottom: 2px;
}

/* ── 剧情弹层里的结算结果块 ───────────────────────────────────────── */
/**
 * ⚠️ 它要看起来**和正文不一样** —— 正文是"故事"，这里是"账"。
 *    所以给一条实心左边框 + 稍深的底色，读到这里能明显感到"结束了"。
 */
.story-settle {
  margin-top: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  background: var(--primary-soft);
  border-left: 3px solid var(--primary);
  border-radius: var(--radius-sm);
  /* 深色底图下 primary-soft 会显得突兀，所以用具名变量兜底 */
  color: var(--story-fg, var(--text));
}
.story-settle-title {
  font-weight: 700;
  font-size: var(--fs-lg);
  margin-bottom: var(--sp-2);
}
.story-settle-line {
  font-size: var(--fs-md);
  line-height: 1.8;
}
.story-settle-line.muted { color: var(--story-muted, var(--text-dim)); }

/* ── 剧情弹层：还在写的时候的提示条（用户 2026-10-16"边写边读"）──── */
.story-partial {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  flex-wrap: wrap;
  padding: var(--sp-3) var(--sp-4);
  margin-bottom: var(--sp-3);
  font-size: var(--fs-sm);
  color: var(--story-fg, var(--text));
  background: var(--gold-soft);
  border: 1px solid var(--gold-line);
  border-radius: var(--radius-sm);
}
.story-partial button { margin-left: auto; }

/* ── 剧情弹层里的冒险日记（结算时才写出来的那一段）───────────────── */
.story-diary-label {
  margin-top: var(--sp-3);
  font-weight: 700;
  font-size: var(--fs-md);
  color: var(--story-muted, var(--text-dim));
}
.story-diary-body {
  padding: var(--sp-3) var(--sp-4);
  border-left: 3px solid var(--story-line, var(--line));
  font-size: var(--story-size, 16px);
  line-height: var(--story-lh, 1.9);
  font-family: var(--story-font, inherit);
  white-space: pre-wrap;
  color: var(--story-fg, var(--text));
}

/* ══════════════════════════════════════════════════════════════════════
   结算卡片（用户 2026-10-16 定版式）
   ══════════════════════════════════════════════════════════════════════

   一名玩家一张卡，竖着堆（队伍上限 6 人）：
     第一层  名字（蓝） + HP 增减（涨=绿 / 掉=红）
     第二层  金币 / 属性点 / 新特质（金）
     第三层  新物品（黑字 + 稀有度后缀，可点击展开描述）

   ⚠️ 为什么竖着堆而不是并排：
      6 人并排在任何手机上都必然溢出。竖着堆两端都成立，
      以后想改成"电脑上两列"也只需要加一条 grid。
   ══════════════════════════════════════════════════════════════════════ */

/**
 * ⚠️ 版式以用户给的**参照图**为准（图三/图四）：
 *    名字（蓝）+ 健康/受伤胶囊 + HP 数值胶囊（琥珀）
 *    第二行是一排浅底小胶囊：HP-15(红) / 💰+5 / 🛡敏+1
 *    第三行是"新装备："前缀 + 蓝字虚线的物品名 + ×N + 稀有度胶囊
 *
 *    所以卡片用**浅色面板 + 胶囊**的调子，而不是表格线。
 */
.stl-list { display: flex; flex-direction: column; gap: var(--sp-3); }

.stl-card {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  padding: var(--sp-4);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
/* 还没结算的队友：弱化，但**要显示**（不显示会被当成没参加） */
.stl-card.pending { opacity: .7; }

/* ── 队友结算：接在同一张卡片里，不另起一张（用户 2026-10-20） ── */
.stl-party-block {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  margin-top: var(--sp-2);
  padding-top: var(--sp-3);
  border-top: 1px solid var(--line);
}
.stl-party-title {
  font-weight: 700;
  font-size: var(--fs-md);
  color: var(--text-dim);
}
.stl-party-member {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding-top: var(--sp-3);
  border-top: 1px dashed var(--line);
}
.stl-party-member:first-of-type {
  padding-top: 0;
  border-top: 0;
}

/* ── 第一行：名字 + 状态胶囊 + 血量 ─────────────────────────────── */
.stl-head {
  display: flex;
  align-items: center;   /* 参照图里名字和胶囊是中线对齐的 */
  gap: var(--sp-3);
  flex-wrap: wrap;
}
.stl-name {
  font-size: var(--fs-xl);
  font-weight: 700;
  /* 用户指定：名字用蓝色 */
  color: var(--primary);
  line-height: 1.2;
}

/** 「健康 / 受伤」胶囊（参照图：健康=绿底绿字，受伤=红底红字）*/
.stl-badge {
  font-size: var(--fs-sm);
  font-weight: 600;
  padding: 3px 12px;
  border-radius: var(--radius-pill);
}
.stl-badge.ok { color: var(--ok); background: #e8f5ee; }
.stl-badge.hurt { color: var(--hp); background: var(--hp-track); }

/** HP 数值胶囊 —— 已废弃
 *  ⚠️ 用户 2026-10-16："第一层健康旁边的生命值显示去掉，这个位置空出来"。
 *     血量已经在第二行用 `HP-7` 表达了（那个更能说明"这趟怎样"），
 *     所以这一层不再重复显示剩余血量。
 *     样式保留成注释而不是删掉，是因为参照图里本来有这个元素 ——
 *     万一以后想加回来，知道它原来是长什么样的。
 */

/* ── 第二行：一排小胶囊 ─────────────────────────────────────────── */
.stl-row {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex-wrap: wrap;
}
.stl-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: var(--fs-sm);
  font-weight: 600;
  padding: 4px 12px;
  border-radius: var(--radius-pill);
  background: var(--panel-2);
  border: 1px solid var(--line);
}
.stl-ico { font-size: var(--fs-sm); }
/* 掉血红（参照图 HP-15 是红字浅红底） */
.stl-chip.hp-hurt { color: var(--hp); background: var(--hp-track); border-color: transparent; }
.stl-chip.hp-heal { color: var(--ok); background: #e8f5ee; border-color: transparent; }
.stl-chip.gold b { color: var(--gold); }
.stl-chip.attr b { color: var(--primary); }

/**
 * 新特质：`✨ 新特质：拾荒直觉` —— **一个**胶囊。
 *
 * ⚠️ 用户 2026-10-16 两次调整后的定版：
 *    "新特质和具体特质合并成一个ui，**并且是透明底**，
 *     新特质前的图标用这个✨️"
 *
 *    所以底色是 transparent（原来那层金色底 + 边框显得很重，
 *    一排胶囊里它最扎眼）。改用"金色文字 + 无色底"来区分身份。
 */
.stl-trait {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: var(--fs-sm);
  color: var(--gold);
  font-weight: 600;
  background: transparent;
  border: 0;
  padding: 4px 2px;
}
/* 「新特质：」这三个字比名字弱一档，让名字当主角 */
.stl-trait-label { color: var(--text-dim); font-weight: 400; }
.stl-trait b { font-weight: 700; }

/* ── 第三行：新装备 / 新物品（前缀 + 蓝字名 + ×N + 稀有度）────────
   ⚠️ 用户 2026-10-16："掉落物显示优先横向铺满再换行"。
      所以容器是 wrap，**每一条掉落是 inline-flex 的整块** ——
      横向排、放不下才换行，而且一条掉落不会被拆到两行。
      之前是 column（一条一行），竖着占很长。
*/
.stl-lines {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2) var(--sp-4);
}

.stl-line {
  display: inline-flex;      /* 整块，不参与拉伸 */
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs-md);
}
/* 「新装备：」这种前缀：灰色小字，不抢物品名 */
.stl-line-label { color: var(--text-dim); font-size: var(--fs-sm); white-space: nowrap; }

/**
 * 物品名：蓝字 + 虚线下划线（参照图就是这样，表示"能点"）。
 *
 * ⚠️ 用 <button> 而不是 <span>：键盘可达、读屏可用。
 *
 * ⚠️⚠️ **`color` 必须显式声明**，不能指望继承。
 *    浏览器给 <button> 的默认样式里有 `color: buttontext`（近黑），
 *    它会盖掉从父级继承来的颜色 —— 这正是用户报的
 *    "掉落物的名称颜色没有改过来"：名字一直是黑的，不是蓝的。
 *    同理 `font: inherit` 也要显式写，否则按钮用自己的默认字体。
 */
.stl-item-name {
  font: inherit;
  font-size: var(--fs-md);
  font-weight: 600;
  color: var(--primary);          /* ← 不能省，见上面的说明 */
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  text-decoration: underline dotted var(--primary-line);
  text-underline-offset: 3px;
  white-space: nowrap;            /* 名字不能被拆行 */
}
.stl-item-name:hover { text-decoration-color: var(--primary); }

.stl-item-qty { color: var(--text-dim); font-variant-numeric: tabular-nums; }
.stl-empty { color: var(--text-dim); font-size: var(--fs-sm); }

/**
 * 稀有度配色（用户 2026-10-16 直接给定色号，见 tokens.css 的 --rarity-*）。
 *
 *   普通 #95949a / 精良 #82ae46 / 稀有 #89c3eb / 史诗 #674598 / 传说 #fcc800
 *
 * ⚠️ 用户报过"物品名称的颜色和稀有度的颜色对不上" ——
 *    根因是**名称写死 var(--primary)，而胶囊用稀有度色**，两者永远不同。
 *
 *    现在两边都取同一个 `--rarity-*` 变量，做法是：
 *      · `.stl-rarity` 上定义 `--r`（该档的颜色）
 *      · 同一个 `.stl-line` 里的 `.stl-item-name` 用 `color: var(--r)`
 *    于是名称和胶囊**必然一致**，不可能再对不上。
 *
 *    代码里的耦合点：`addLine()` 同时给 line 和 rarity 两个元素挂 r-xxx 类。
 *    改这里时别只改一个 —— 注释里写清楚了。
 */
.stl-rarity {
  font-size: var(--fs-xs);
  font-weight: 600;
  padding: 2px 10px;
  border-radius: var(--radius-pill);
  /* 胶囊用该档的颜色描边 + 文字，**不填底色**（参照图就是描边胶囊） */
  color: var(--r, var(--text-dim));
  border: 1px solid currentColor;
  white-space: nowrap;
}

/* 名称与胶囊同色：名称跟着 --r 走（--r 由 .r-* 类挂在同一个 .stl-line 上） */
.stl-line .stl-item-name { color: var(--r, var(--primary)); }
.stl-line .stl-item-name { text-decoration-color: var(--r, var(--primary-line)); }

.r-common { --r: var(--rarity-common); }
.r-uncommon { --r: var(--rarity-uncommon); }
.r-rare { --r: var(--rarity-rare); }
.r-epic { --r: var(--rarity-epic); }
.r-legendary { --r: var(--rarity-legendary); }

/* ══════════════════════════════════════════════════════════════════════
   物品详情浮层（用户 2026-10-16："做成额外的小弹窗，
   不要挤压物品展示栏的字符"）
   ══════════════════════════════════════════════════════════════════════

   ⚠️ `position: absolute` + 挂到 body 上，**完全不占布局空间** ——
      这是"不挤压物品栏"的关键。挂在物品行里面用 relative 的话，
      即使绝对定位也会受祖先的 overflow 裁剪（弹层里就有 overflow-y: auto）。
*/
.item-tip {
  /**
   * ⚠️ **必须是 `position: fixed`，不能是 absolute。**
   *
   *    定位坐标来自 `anchor.getBoundingClientRect()` —— 那是**视口**坐标。
   *    `absolute` 是相对**文档**算的，两者差一个 scrollY：
   *    页面一滚动，浮层就会飞到上方很远的地方
   *    （用户截图里它跑到了弹层顶部，就是这个原因）。
   *
   *    fixed + 挂 body 两个条件一起才成立：
   *      · fixed  → 坐标和 getBoundingClientRect 同一套参考系
   *      · 挂 body → 不被弹层里的 `overflow-y: auto` 裁剪
   */
  position: fixed;
  z-index: 300;                 /* 高于弹层（弹层是 50） */
  max-width: 300px;
  max-height: 46vh;             /* 内容长时不至于顶出屏幕 */
  overflow-y: auto;
  padding: var(--sp-3) var(--sp-4);
  background: var(--panel);
  border: 1px solid var(--r, var(--line));
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-lift);
  pointer-events: none;         /* 浮层自己也点得掉的话会和"点别处关闭"打架 */
}

/* 名称按该物品的稀有度上色（和列表里、胶囊里同一套 --r） */
.item-tip-name {
  font-size: var(--fs-md);
  font-weight: 700;
  color: var(--r, var(--text-strong));
  margin-bottom: 2px;
}
.item-tip-rarity {
  display: inline-block;
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--r, var(--text-dim));
  border: 1px solid currentColor;
  border-radius: var(--radius-pill);
  padding: 1px 8px;
  margin-bottom: var(--sp-2);
}
.item-tip-desc {
  font-size: var(--fs-sm);
  color: var(--text-dim);
  line-height: 1.7;
}

/* 手机：浮层贴在底部当"底部小卡"，比跟着手指跑更稳、更好读 */
@media (max-width: 560px) {
  .item-tip {
    max-width: none;
    left: var(--sp-3) !important;
    right: var(--sp-3);
    width: auto;
  }
}

/* ── 特质详情（用户 2026-10-16："特质需要进行详细描述"）────────────── */
/* 描述：这是什么（世界数据里写死的） */
.trait-desc {
  font-size: var(--fs-sm);
  color: var(--text);
  line-height: 1.7;
  margin-top: 2px;
}
/* 依据：AI 根据**这一段具体剧情**给出的授予理由 */
.trait-why {
  font-size: var(--fs-sm);
  color: var(--text-dim);
  line-height: 1.7;
  margin-top: 4px;
  padding-left: var(--sp-3);
  border-left: 2px solid var(--line);
}

/* 物品描述浮层（原来那里是就地展开的 .stl-item-desc，
   用户 2026-10-16 要求改成浮层 —— 就地展开会挤压物品栏的排版）。
   见文件下方 .item-tip 的定义。 */

/* ── 电脑端：结算卡片排成两列（宽屏才放得下）────────────────────
   ⚠️ 只在 ≥900px 生效。手机上仍然是一列 —— 参照图就是手机版的一列，
      两列会让每张卡太窄、物品名换行。
*/
@media (min-width: 900px) {
  .stl-list {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
    align-items: start;
  }
}

/* 手机：卡片内边距与字号收一档 */
@media (max-width: 560px) {
  .stl-card { padding: var(--sp-3); }
  .stl-name { font-size: var(--fs-lg); }
  .stl-row { gap: var(--sp-1) var(--sp-2); }
  .stl-chip, .stl-badge, .stl-score { padding: 3px 9px; font-size: var(--fs-xs); }
  .stl-line { font-size: var(--fs-sm); }
  .stl-item-name { font-size: var(--fs-sm); }
}

/**
 * 剧情阅读弹层里的正文排版 + **阅读设置的实际效果**。
 *
 * ⚠️ 复用探险面板的 `.exp-seg`（左边一条竖线 + 段号），
 *    这样"读历史剧情"和"正在跑副本"看起来是同一个东西。
 *
 * ⚠️ 所有 `--story-*` 变量都由 app.js 的 applyStoryPrefs() 写在
 *    `#story-modal` 上（**作用域只到这一层**）——
 *    玩家调的是"读剧情时的样子"，不该连带把角色卡和副本面板一起改了。
 *    所以下面这些覆盖都带 `#story-modal` 前缀来提优先级，
 *    而不是去改 style.css 里 `.exp-seg-text` 的原始字号
 *    （那条同时管着正在跑的副本，改了会一起变）。
 */
#story-body {
  display: flex;
  flex-direction: column;
  gap: 14px;
  max-height: 62vh;
  overflow-y: auto;
  padding-right: 6px;
  -webkit-overflow-scrolling: touch;

  /* 底图：整块正文区域的背景，而不是只给每段上色 —— 段与段之间也要连上 */
  background: var(--story-bg, #fff);
  color: var(--story-fg, var(--text));
  border: 1px solid var(--story-line, var(--line));
  border-radius: var(--radius-sm);
  padding: var(--sp-4);
}

/* 正文：字号/行高/字体三项设置都落在这里 */
#story-modal .exp-seg-text {
  font-size: var(--story-size, 16px);
  line-height: var(--story-lh, 1.9);
  font-family: var(--story-font, inherit);
  color: var(--story-fg, var(--text));
}

/**
 * 段号与左侧竖线也要跟着底图走。
 * ⚠️ 蓝灰那一档是深色底，段号原来用的琥珀色在深底上偏暗，
 *    所以这里显式改用 `--story-muted`。
 */
#story-modal .exp-seg-no { color: var(--story-muted, var(--text-dim)); }
#story-modal .exp-seg { border-left-color: var(--story-line, var(--line)); }
#story-modal #story-meta { color: var(--story-muted, var(--text-dim)); }

/* 弹层宽度比角色卡宽：剧情是长文，太窄读起来累 */
#story-modal .modal-card { max-width: 760px; }

/* 手机：弹层占满，正文区尽量高，左右留白收小 */
@media (max-width: 700px) {
  #story-modal .modal-card {
    max-width: 100%;
    /* 竖屏手机上给足高度，否则长剧情只能看到几行 */
    max-height: 92vh;
  }
  #story-body {
    max-height: 68vh;
    padding: var(--sp-3);
  }
  /* 手机上字号档位整体抬一档下限：默认"中"在手机上偏小 */
  #story-modal .exp-seg-text { font-size: var(--story-size, 16px); }
}

/* 特质详情弹层里的每一行 */
.trait-row {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: 9px 11px;
  margin-bottom: var(--sp-2);
  background: var(--bg-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
}
.trait-info { flex: 1 1 auto; min-width: 0; }
.trait-name { font-weight: 600; color: var(--text); }
.trait-drop { color: var(--danger) !important; border-color: var(--danger-3) !important; flex: 0 0 auto; }

/* 装备行：用户要求去掉副手/饰品这类槽位标注，只列名字 */
.cs-equip-item .cs-equip-slot { display: none; }

/* ==================================================================
   冒险者卡片（用户要求：一排 3 个、做小、和顶部边框适配）
   ================================================================== */
/**
 * ⚠️ 宽度**不再在这里设** —— 它的父级 `.town-body` 已经是 `--ui-w`
 *    （和顶部按钮区同一个宽度），所以左右边界天然对齐。
 *    在这里再设一次反而会嵌套两层宽度、算出更窄的结果。
 */
.adventurer-list {
  display: grid;
  /* 一排 3 个（用户指定），窄屏自动降到 2 / 1 列 */
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--sp-3);
  align-items: start;
}
@media (max-width: 720px) { .adventurer-list { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 460px) { .adventurer-list { grid-template-columns: 1fr; } }

/* 卡片做小：内边距、字号、圆角都收一档 */
.adv-card {
  padding: var(--sp-3);
  border-radius: var(--radius-sm);
  min-width: 0;              /* 不加的话长名字会把格子撑破 */
}
.adv-name { font-size: var(--fs-md); }
.adv-lv { font-size: var(--fs-xs); }
.adv-head { gap: var(--sp-2); }
.adv-meta { gap: var(--sp-2) var(--sp-3); font-size: var(--fs-xs); }
.adv-gear { font-size: var(--fs-xs); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* 缩小版三围条：复用 m-bar 的配色，但更薄 */
.adv-bar {
  position: relative;
  height: 14px;
  border-radius: var(--radius-pill);
  margin-bottom: 4px;
  overflow: hidden;
}
.adv-bar i {
  position: absolute; left: 0; top: 0; bottom: 0;
  border-radius: var(--radius-pill);
}
.adv-bar.hp      { background: var(--hp-track); }
.adv-bar.hp i    { background: linear-gradient(90deg, var(--hp), var(--hp-2)); }
.adv-bar.stamina { background: var(--stamina-track); }
.adv-bar.stamina i { background: linear-gradient(90deg, var(--stamina), var(--stamina-2)); }
.adv-bar.mp      { background: var(--mp-track); }
.adv-bar.mp i    { background: linear-gradient(90deg, var(--mp), var(--mp-2)); }
.adv-bar span {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 10px; font-weight: 600; color: #fff;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .45);
}

/* 缩小版四维 */
.adv-attrs {
  display: flex; flex-wrap: wrap;
  gap: 4px var(--sp-3);
  margin: 6px 0;
  font-size: var(--fs-xs);
}
.adv-attr { display: inline-flex; align-items: center; gap: 3px; }
.adv-attr b { color: var(--text); }

/**
 * 设施按钮：**字号必须和「我的/冒险者」完全一致**（用户要求"按钮的字体大小统一"）。
 *
 * ⚠️ 原来这里写了 `font-size: var(--fs-xs)`（11px），
 *    而前两个标签继承的是容器字号（28px）—— 于是同一行里
 *    前两个特别大、后面几个特别小（用户截图里就是这个毛病）。
 *    现在只保留**颜色**差异做区分，字号一律继承。
 */
.m-tab-facility { color: var(--text-dim); }
.m-tab-facility.active { color: var(--primary); }

/* 关注按钮（用户要求：名字旁边的五角星，可关注 / 已关注）*/
.adv-follow {
  margin-left: auto;         /* 推到卡片右上角，不挤名字 */
  padding: 2px 8px;
  font-size: var(--fs-xs);
  font-family: inherit;
  color: var(--text-dim);
  background: none;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  cursor: pointer;
  white-space: nowrap;
  flex: 0 0 auto;
}
.adv-follow:hover { border-color: var(--gold); color: var(--gold); }
/* 已关注：实心金星，一眼看出状态 */
.adv-follow.on {
  color: var(--gold);
  border-color: var(--gold-line);
  background: var(--gold-soft);
  font-weight: 600;
}

/* ══════════════════════════════════════════════════════════════════════
   移动端适配（**必须放在文件最末尾**）
   ══════════════════════════════════════════════════════════════════════

   ⚠️ 踩过的坑，写在这里免得下次再犯：

      原来把 `.topbar, .town-body { width: 100% }` 的媒体查询写在**第 100 行**，
      而 `.town-body { width: min(var(--ui-w), 100%) }` 在**第 270 行** ——
      **同优先级下后写的赢**，于是那条覆盖被反杀，
      手机上界面永远只有 40vw 宽（430px 屏上只剩 172px）。
      实测现象：内容挤在屏幕中间一条，"我的"页角色卡直接溢出到屏幕外。

      结论：**媒体查询必须写在它所覆盖的规则之后**。
      所以这一段放在文件最末尾，并且以后新增的覆盖也加在这里。

   ⚠️ 第二条教训：**不要再按"我以为手机多宽"写一列一列的固定断点**。
      我们从昨天到现在因为断点翻了三次车（70vw → 50% → 40%）。
      现在顶部按钮改用 `auto-fit` —— **列数由浏览器按实际宽度算**，
      不管手机是 360 还是 430 都自己排好。
   ══════════════════════════════════════════════════════════════════════ */

/* ── 手机 / 平板竖屏：界面占满整宽 ────────────────────────────────────
   桌面上 --ui-w 是 40vw（居中留白），窄屏必须放满，
   否则内容被挤在中间一小条（实测截图就是这个现象）。 */
@media (max-width: 860px) {
  :root {
    /* 覆盖 tokens 里的 40vw —— 这里改根变量，所有用到它的地方一起生效 */
    --ui-w: 100%;
  }
  .topbar,
  .town-body {
    width: 100%;
    /* 窄屏不要左右留白（桌面上那圈留白是给"以后填东西"预留的） */
    padding-inline: 0;
  }

  /* ── 顶部按钮：改成**流体网格** ──────────────────────────────────
     ⚠️ 原来是写死的列数（5/4/3 列），要不停加断点。
        改成 auto-fit + minmax：浏览器自己算能放几列，
        放不下的自动折行 —— 360px 到 430px 都能自己排好。 */
  .m-tabs {
    grid-template-columns: repeat(auto-fit, minmax(102px, 1fr));
  }
  /* 按钮内边距收一点，让窄屏每格能放下 4 个字 */
  .m-tab { padding: 10px 4px; }

  /* ── 「我的」两栏 → 堆成一列 ────────────────────────────────────
     ⚠️ 原来只在 ≤700px 生效；改成跟着 860 走，和平板断点一致。
        不堆叠的话角色卡会被压到 172px，直接溢出屏幕（实测）。 */
  #mine-body { grid-template-columns: 1fr; }
}

/* ── 手机（≤560px）：再收一档 ───────────────────────────────────────── */
@media (max-width: 560px) {
  /* 最小列宽降到 96px，让 3 列稳稳放得下 */
  .m-tabs { grid-template-columns: repeat(auto-fit, minmax(96px, 1fr)); }

  /* 卡片内边距收小，把有限的宽度留给内容 */
  .charstrip,
  .m-feed-wrap .m-feed,
  .adv-card {
    padding: var(--sp-3);
  }

  /* 四维那一行：允许换行，别硬挤成一行 */
  .cs-stats { gap: var(--sp-2) var(--sp-3); }

  /* 特质/装备的胶囊：字号降到最小档，长名字允许省略号 */
  .m-chip { font-size: var(--fs-xs); padding: 3px 8px; }

  /* 分页按钮够手指点 */
  .pager-btn { min-width: 34px; padding: 6px 9px; }
}

/* ══════════════════════════════════════════════════════════════════════
   装备制作页（用户 2026-10-17）
   ══════════════════════════════════════════════════════════════════════

   ⚠️ 这些样式放在文件**最末尾**，因为下面有 @media 覆盖 ——
      ui.css 里同优先级的规则靠**源码顺序**决定胜负，
      基础规则写在 media query 后面的话会把它顶掉（这个坑踩过 4 次）。
*/

.craft-body {
  width: min(var(--ui-w), 100%);
  margin: 0 auto;
  padding: var(--app-pad);
}

.craft-head { margin-bottom: var(--sp-3); }
.craft-head h2 { margin: 0 0 4px; font-size: var(--fs-xl); color: var(--text-strong); }
.craft-head p { margin: 0; }

/* ── 五工坊网格 ──────────────────────────────────────────────────
   ⚠️ auto-fit + minmax 而不是固定列数：手机上自动落成一列，
      电脑上两到三列，不用给每个断点单独写。 */
.craft-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--sp-3);
  margin: var(--sp-3) 0;
}

.craft-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  padding: var(--sp-4);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  cursor: pointer;
  text-align: left;
  font: inherit;
  color: var(--text);
  transition: border-color .15s, transform .1s;
}
.craft-card:hover { border-color: var(--primary-line); }
.craft-card:active { transform: translateY(1px); }

/* 未实装的工坊：**不置灰**，但要弱一档 —— 用户要求"壳子也能点开看" */
.craft-card.shell { opacity: .82; border-style: dashed; }
.craft-card.shell:hover { border-color: var(--gold-line); }

.craft-icon { font-size: 26px; line-height: 1; }
.craft-name { font-size: var(--fs-lg); font-weight: 700; color: var(--text-strong); }
.craft-blurb { font-size: var(--fs-sm); color: var(--text-dim); line-height: 1.6; }

.craft-state {
  margin-top: auto;
  padding-top: var(--sp-2);
  font-size: var(--fs-xs);
  font-weight: 600;
}
.craft-state.ok { color: var(--primary); }
.craft-state.soon { color: var(--text-dim); }

.craft-foot { margin-top: var(--sp-4); line-height: 1.7; }

/* ── 壳子工坊的说明 ───────────────────────────────────────────── */
.craft-shell-note {
  padding: var(--sp-3) var(--sp-4);
  background: var(--gold-soft);
  border: 1px solid var(--gold-line);
  border-radius: var(--radius-sm);
  font-size: var(--fs-sm);
  line-height: 1.7;
  margin: var(--sp-3) 0;
}

/* 它认哪些用途标签：一排小胶囊 */
.craft-use-list { display: flex; flex-wrap: wrap; gap: 6px; margin: var(--sp-2) 0; }
.craft-use-tag {
  font-size: var(--fs-xs);
  padding: 3px 10px;
  border-radius: var(--radius-pill);
  background: var(--panel-2);
  border: 1px solid var(--line);
  color: var(--text-dim);
}

/* 跳去别的工坊 */
.craft-jump { display: flex; flex-wrap: wrap; gap: 6px; margin: var(--sp-2) 0; }

/* ── 铁匠铺：类别不符的素材 ─────────────────────────────────────
   ⚠️ 不是隐藏，是置灰 + 说明原因。
      直接藏起来的话玩家会困惑"我明明有铁矿石，为什么这里没有"。 */
.forge-pick.off {
  opacity: .55;
  border-style: dashed;
}
.forge-pick-warn {
  font-size: var(--fs-xs);
  color: var(--hp);
  line-height: 1.5;
}

/* ── 手机：工坊卡单列 ─────────────────────────────────────────── */
@media (max-width: 560px) {
  .craft-grid { grid-template-columns: 1fr; }
  .craft-body { width: 100%; }
}

/**
 * ⚠️ `forge-result` 与 `craft-forge` 是**纯容器** —— 它们的子元素
 *    （`.forge-out` / `.forge-eval` 等）自带样式，容器本身不需要外观。
 *    但仍然要声明一下：不声明的话，如果哪天改了子元素的内边距，
 *    容器就没有任何"兜底间距"，会贴到上一个元素上。
 *
 *    这也是 check-css 报"没样式"的原因 —— 它只看类名有没有规则，
 *    不区分"容器"与"组件"。给个最小声明既满足检查，也不会过度设计。
 */
.craft-forge, .forge-result { margin-top: var(--sp-2); }

/* ══════════════════════════════════════════════════════════════════════
   装备详情弹层（用户 2026-10-17）
   ══════════════════════════════════════════════════════════════════════
*/

/**
 * 角色卡上的装备名现在是 <button>（可点开详情）。
 *
 * ⚠️ 原来的 `.cs-equip-item` 是给 <span> 写的，**没有重置按钮默认样式** ——
 *    换成 button 后会变成浏览器默认的灰底凸起按钮，和旁边一行胶囊不搭。
 *    所以这里补上 font/color/背景/边框的继承与重置。
 *
 * ⚠️ 也不能简单写 `border: none` —— 那一行胶囊的边框是它的一部分，
 *    要保留 `1px solid var(--line)`，只是让 **button 自己的**默认边框消失。
 */
button.cs-equip-item {
  font: inherit;
  color: var(--text);
  cursor: pointer;
  transition: border-color .15s, background .15s;
}
button.cs-equip-item:hover {
  border-color: var(--primary-line);
  background: var(--primary-soft);
}
/* 空装备时的入口按钮：不要胶囊外观，但要是可点的 */
.equip-empty { margin: 2px 0; }

/* ── 弹层里的每一行装备 ───────────────────────────────────────── */
.equip-row {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border-bottom: 1px solid var(--line);
}
/* 最后一行不要多余的分隔线 —— 否则弹层底部会多一道 */
.equip-row:last-child { border-bottom: 0; }

.equip-info { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 3px; }

/**
 * ⚠️ 每行的「卸下 / 穿上」按钮**不许被挤压，也不许竖排**
 *    （用户 2026-10-17 截图报的："字符需要调整一下，不要竖向排版"）。
 *
 *    根因：`.equip-row` 是 flex，`.equip-info` 是 `flex: 1 1 auto`。
 *    描述文字很长时（实测有 90+ 字的），按钮作为另一个 flex 子项
 *    会被压缩 —— 压到只剩一个字的宽度，「卸下」就变成了竖排两行。
 *
 *    两个属性缺一不可：
 *      flex: 0 0 auto   → 不参与收缩，该多宽就多宽
 *      white-space: nowrap → 即使真的被压到很窄，也不换行
 *
 *    ⚠️ 只写 `flex: 0 0 auto` 不够：父级 flex-wrap 允许换行时，
 *       文字仍可能在按钮内部折行。两个一起写才稳。
 */
.equip-row > .ghost {
  flex: 0 0 auto;
  white-space: nowrap;
}

.equip-head { display: flex; align-items: baseline; gap: var(--sp-2); flex-wrap: wrap; }
/**
 * ⚠️ **必须声明 color: var(--r)**（用户 2026-10-17 报"弹层里的装备没有应用
 *    稀有度色号"）。
 *
 *    原因就是我在别的文件里写过的那个坑：
 *    `.r-*` 类**只定义 `--r` 变量**，真正的颜色要在元素自己的规则里读出来。
 *    只加类不写 `color`，颜色就不会出现 ——
 *    而界面看起来"有颜色"（继承来的默认灰），所以很难发现漏了哪一处。
 *
 *    ⚠️ 这个坑已经踩了**第二次**（上次是 `.item-name`）。
 *       以后加任何"按稀有度上色的元素"，两件事必须一起做：
 *         ① JS 里加 r-* 类　② CSS 里写 color: var(--r, 兜底)
 */
.equip-name {
  font-weight: 700;
  font-size: var(--fs-md);
  color: var(--r, var(--text));
}

/**
 * 槽位名（武器 / 武器 2 / 饰品 …）
 * ⚠️ 角色卡上刻意不显示，但弹层里**必须**显示 ——
 *    有三把武器时不写"武器 2"根本分不清卸的是哪一把。
 */
.equip-slot {
  font-size: var(--fs-xs);
  padding: 1px 8px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--line);
  color: var(--text-dim);
}
/* 数量（背包里可穿戴的）：独立一格，不跟着名字变色 */
.equip-qty { font-size: var(--fs-xs); color: var(--text-dim); }

.equip-stats { font-size: var(--fs-sm); color: var(--primary); font-variant-numeric: tabular-nums; }
.equip-desc { font-size: var(--fs-sm); color: var(--text-dim); line-height: 1.7; }
.equip-forged { font-size: var(--fs-xs); color: var(--gold); }
.equip-uses { font-size: var(--fs-xs); color: var(--text-dim); }

/* 手机：按钮换到下一行，别把文字挤成一条 */
@media (max-width: 560px) {
  .equip-row { flex-wrap: wrap; }
  .equip-row .ghost { margin-left: auto; }
}

/* 点具体某件装备打开弹层时，那一行要高亮 —— 否则三把武器分不清点了哪把 */
.equip-row.focus {
  background: var(--primary-soft);
  border-left: 3px solid var(--primary);
}

/**
 * 特质与装备两行的「详情」按钮**同列右对齐**（用户 2026-10-17 给的红框位置）。
 *
 * ⚠️ 两行的内容长度不一样（特质 3 个胶囊 vs 装备 1 件），
 *    光靠 flex 自然排布按钮会在不同水平位置上 —— 看起来不像一列。
 *    给按钮 `margin-left: auto` 把它推到最右，两行就都贴右边了。
 */
#cs-traits-line > #traits-detail-btn,
#cs-equip-line > #equip-detail-btn {
  margin-left: auto;
  flex: 0 0 auto;
}

/**
 * ⚠️ 小按钮统一**禁止折行**（用户 2026-10-17 报"卸下/穿上变成竖排"）。
 *
 *    根因不只是 flex 挤压：这些按钮的文字都是**两三个汉字**
 *    （卸下 / 穿上 / 买入 / 全卖 / 详情 / 关闭 / 返回），
 *    一旦可用宽度小于两个字，浏览器就会**逐字换行** ——
 *    中文没有空格断行点，所以会变成竖排，非常难看。
 *
 *    `white-space: nowrap` 是这类短标签按钮的正确默认值。
 *
 *    ⚠️ 只给 `.ghost.small` 加，不给全部 button 加：
 *       有些按钮（比如工坊卡片里的长说明）本来就该折行。
 */
.ghost.small { white-space: nowrap; }

/* ── 铁匠铺的两个子页：装备锻造 / 材料锻造（用户 2026-10-17）───── */
.craft-subtabs {
  display: flex;
  gap: var(--sp-2);
  margin: var(--sp-3) 0;
  flex-wrap: wrap;
}

.craft-subtab {
  font: inherit;
  font-size: var(--fs-md);
  padding: 8px 16px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--text-dim);
  cursor: pointer;
  white-space: nowrap;
  transition: border-color .15s, background .15s, color .15s;
}
.craft-subtab:hover { border-color: var(--primary-line); }
.craft-subtab.on {
  border-color: var(--primary);
  background: var(--primary-soft);
  color: var(--primary);
  font-weight: 700;
}

.craft-subpane { margin-top: var(--sp-2); }

/* ── 锻造结果弹窗（用户 2026-10-17）────────────────────────────── */
.forge-verdict {
  padding: 12px 16px;
  border-radius: var(--radius-sm);
  font-size: var(--fs-md);
  font-weight: 700;
  margin-bottom: var(--sp-3);
}
.forge-verdict.win {
  background: var(--good-soft, rgba(90, 170, 90, .14));
  color: var(--good, #4e9a4e);
  border: 1px solid var(--good-line, rgba(90, 170, 90, .3));
}
.forge-verdict.lose {
  background: var(--bad-soft, rgba(200, 90, 90, .12));
  color: var(--bad, #b05252);
  border: 1px solid var(--bad-line, rgba(200, 90, 90, .28));
}

.forge-modal-card {
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: var(--sp-3) var(--sp-4);
  margin-bottom: var(--sp-3);
  background: var(--panel);
}

.forge-modal-head {
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  flex-wrap: wrap;
  margin-bottom: 6px;
}

/* ⚠️ 必须读 --r，否则稀有度色号不生效（踩过两次的坑） */
.forge-modal-name {
  font-size: var(--fs-lg);
  font-weight: 700;
  color: var(--r, var(--text));
}

.forge-modal-desc {
  margin: 0;
  font-size: var(--fs-sm);
  line-height: 1.7;
  color: var(--text-dim);
}

.forge-modal-meta {
  display: flex;
  flex-direction: column;
  gap: 5px;
  border-top: 1px dashed var(--line);
  padding-top: var(--sp-3);
}

.forge-modal-row {
  display: flex;
  gap: var(--sp-3);
  font-size: var(--fs-sm);
  align-items: baseline;
}
.forge-modal-row > span:first-child {
  flex: 0 0 64px;
  color: var(--text-dim);
}
/* 素材列表可能很长，允许折行，但按钮类短标签不折 */
.forge-modal-row > span:last-child { flex: 1 1 auto; min-width: 0; }

@media (max-width: 560px) {
  .forge-verdict { font-size: var(--fs-md); }
  .forge-modal-name { font-size: var(--fs-md); }
  .forge-modal-row > span:first-child { flex: 0 0 56px; }
}

/* ── 铁匠铺师徒氛围（用户 2026-10-17 + 人设文档）────────────── */
.smith-ambient {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 10px 14px;
  margin: var(--sp-3) 0;
  border-left: 3px solid var(--primary-line, var(--line));
  background: var(--panel);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}

.smith-ambient-row {
  display: flex;
  gap: var(--sp-2);
  align-items: baseline;
  font-size: var(--fs-sm);
  line-height: 1.6;
}

.smith-ambient-who {
  flex: 0 0 auto;
  font-weight: 700;
  white-space: nowrap;
}
.smith-ambient-who.brant { color: var(--gold, #b8860b); }
.smith-ambient-who.noen  { color: var(--primary); }

.smith-ambient-what { color: var(--text-dim); flex: 1 1 auto; min-width: 0; }

/* ── 锻造弹窗里的师徒对白 ───────────────────────────────────── */
.forge-talk {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: var(--sp-3);
}

.forge-talk-line {
  display: flex;
  gap: var(--sp-2);
  align-items: baseline;
  font-size: var(--fs-md);
  line-height: 1.65;
}

.forge-talk-who {
  flex: 0 0 auto;
  font-weight: 700;
  white-space: nowrap;
}
.forge-talk-line.brant .forge-talk-who { color: var(--gold, #b8860b); }
.forge-talk-line.noen  .forge-talk-who { color: var(--primary); }
/* 炼金公会（2026-10-19）：会长与执业炼金师 */
.forge-talk-line.vera  .forge-talk-who { color: var(--gold, #b8860b); }
.forge-talk-line.mira  .forge-talk-who { color: var(--primary); }

.forge-talk-said { flex: 1 1 auto; min-width: 0; color: var(--text); }

@media (max-width: 560px) {
  .forge-talk-line { font-size: var(--fs-sm); flex-direction: column; gap: 2px; }
  .smith-ambient-row { flex-direction: column; gap: 2px; }
}

/* ── 弹窗标题的成功/失败配色（用户 2026-10-17）────────────────── */
/**
 * ⚠️ `.modal-head h2` 默认是 `color: var(--amber-2)`（琥珀金）。
 *    成功时没问题，但「锻造失败」还金灿灿的很不像话 —— 用户要求改红。
 *
 * ⚠️ 用具体类而不是行内 style：行内 style 优先级最高，
 *    以后想调颜色就调不动了。
 */
#forge-modal-title.is-win  { color: var(--amber-2); }
#forge-modal-title.is-lose { color: var(--bad, #c0392b); }

/* ── 名字变化：锻造前 → 锻造后 ───────────────────────────────── */
.forge-modal-flow {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  /**
   * ⚠️ **紧跟在标题后面**，不要推到最右（用户 2026-10-17）。
   *
   *    第一版写的是 `margin-left: auto` —— 那会把整块推到最右边、
   *    紧贴「关闭」按钮，看起来像另一组独立控件，和标题脱节。
   *    用户要求："居中或者紧跟在锻造成功的字符后大概三个字符的间隔"。
   *
   *    现在：左边留约 3 个字宽的间隔，右边用 `auto` 把关闭按钮顶到最右。
   *    （`.modal-head` 是 `justify-content: space-between`，
   *      中间项的 `margin-right: auto` 会吸走所有剩余空白。）
   *
   *    3 个字 ≈ fs-sm(12px) × 3 = 36px，取 34px 视觉上刚好。
   */
  margin-left: 34px;
  margin-right: auto;
  min-width: 0;
  flex: 0 1 auto;
  font-size: var(--fs-sm);
}

.forge-flow-from {
  color: var(--text-dim);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 22ch;
}

.forge-flow-arrow {
  flex: 0 0 auto;
  color: var(--text-dim);
  opacity: .7;
}

/**
 * ⚠️ 必须读 `--r`，否则稀有度色号不生效。
 *    （这个坑已经踩过四次：.item-name / .equip-name / .m-feed-what / 这里）
 */
.forge-flow-to {
  color: var(--r, var(--text));
  font-weight: 700;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 24ch;
}

.forge-flow-fail {
  color: var(--bad, #c0392b);
  font-weight: 700;
  white-space: nowrap;
}

@media (max-width: 560px) {
  /* 手机上一行放不下：名字变化折到标题下面 */
  .modal-head { flex-wrap: wrap; }
  .forge-modal-flow {
    order: 3;
    flex: 1 1 100%;
    margin: var(--sp-2) 0 0;
    font-size: var(--fs-xs);
  }
  .forge-flow-from { max-width: 14ch; }
  .forge-flow-to { max-width: 16ch; }
}

/* ── 名字变化：字号与标题接近（用户 2026-10-17）────────────────── */
/**
 * ⚠️ 用户："顶部名称的变化字号可以调大一点，和左侧装备锻造成功一样大，
 *    或者略小都OK。"
 *
 *    `.modal-head h2` 是 17px，所以这里取 15px —— 略小一档，
 *    既不抢标题的主次，也不会小到看不清装备名。
 */
.forge-modal-flow { font-size: 15px; }
.forge-flow-from { font-size: 15px; }
.forge-flow-to { font-size: 15px; }

@media (max-width: 560px) {
  /* 手机端仍用 xs —— 一行要装下两个名字，太大就截断了 */
  .forge-modal-flow,
  .forge-flow-from,
  .forge-flow-to { font-size: var(--fs-xs); }
}

/* ── 铁匠铺：素材/装备/方式的选择态（用户 2026-10-17）────────────
 *
 * ⚠️⚠️ 这一块**原来根本不存在**：
 *      只有 `.forge-pick.off`（类别不符置灰），
 *      **没有 `.forge-pick` 基础规则、也没有 `.forge-pick.on`**。
 *    所以选中素材时界面**一点变化都没有** ——
 *    用户报的"素材选择需要 UI 颜色变化"就是这个。
 *
 * ⚠️ 同时 JS 那边还有第二个 bug：`paintMats()` 重建按钮后
 *    `dataset.id` 丢了，`classList.toggle('on', …)` 永远判 false，
 *    所以就算这里写了 `.on` 也不会亮。两处必须一起修。
 */
.forge-pick {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 3px;
  font: inherit;
  text-align: left;
  padding: 9px 13px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--text);
  cursor: pointer;
  transition: border-color .15s, background .15s, box-shadow .15s, transform .08s;
  /* 名字可能长，允许换行，但不要撑破容器 */
  min-width: 0;
  max-width: 100%;
}

.forge-pick:hover:not(.off) {
  border-color: var(--primary-line, var(--line));
  background: var(--panel-2, var(--panel));
}

.forge-pick:active:not(.off) { transform: translateY(1px); }

/**
 * 选中态：**加深**而不是只描个边。
 * ⚠️ 用户特别强调「选择第二件材料的时候第一件被选择的材料
 *    UI 颜色加深效果不变」—— 所以这个效果必须能**同时出现在多个按钮上**，
 *    不能做成"单选高亮"。
 */
.forge-pick.on {
  border-color: var(--primary);
  background: var(--primary-soft, var(--panel-2));
  box-shadow: inset 0 0 0 1px var(--primary);
}

/* 选中态里的名字加粗一点，加深感更明确 */
.forge-pick.on .forge-pick-name { font-weight: 700; }

/**
 * ⚠️ `.off` 的优先级要低于 `.on`：
 *    理论上类别不符的选不上，但万一数据变了（比如换装备后旧选中变成不符），
 *    也不该出现"既选中又置灰"的混乱视觉。
 */
.forge-pick.on.off { opacity: 1; border-style: solid; }

/* ── 消耗品携带栏（用户 2026-10-19）────────────────────────────── */
.belt-row {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) 0 var(--sp-3);
  border-bottom: 1px solid var(--line, rgba(255, 255, 255, 0.08));
  margin-bottom: var(--sp-3);
}

.belt-slot {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--radius-sm);
  border: 1px dashed var(--line, rgba(255, 255, 255, 0.18));
  background: transparent;
  color: var(--text-dim, #8b8b93);
  font: inherit;
  font-size: var(--fs-sm);
  cursor: pointer;
}
.belt-slot.on {
  border-style: solid;
  border-color: var(--primary);
  color: var(--text);
}
.belt-name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

@media (max-width: 560px) {
  .belt-row { flex-wrap: wrap; }
  .belt-name { font-size: var(--fs-xs); }
}