/* ============================================================
   深渊债录 · 「深渊层 / ABYSS」
   在 ui-hollow.css 之后加载。做两件事：
   ① 给每个界面铺上对应的像素背景图；
   ② 把过于方正的矩形界面改成斜切角 / 断边 / 弧线 —— 有机形态。

   ★ 全部声明必须带 !important：
     ui-hollow.css 里 .mi / .modal 等早已用 !important 清掉了
     background / box-shadow / border。两层都带 !important 时先比
     specificity，specificity 相同则按出现顺序、后写者胜 —— 本文件
     在其后加载，所以只要我也带 !important 就能压住它。
     （第一版没带，整层改造被静默吃掉。）

   依然是纯覆盖：不动 HTML 结构、不动任何逻辑。删掉本文件即回到上一版。
   ============================================================ */

/* ---------- ① 背景图 --------------------------------------------------
   ★ 已全部换成 AI 底画（非像素风，见 tools/bg_ai.py 的收编流程）。
     素材经「去水印 → 16:9 → 暗部抬升 + 高光封顶 0.82」处理，本身就很暗，
     只提供氛围与景深，不参与信息表达，不会与前景文字抢对比度。
     四张候选都在 assets/bg/v-ai-*.jpg，换主菜单底图只需改下面这一行 url。 */

/* 背景图之上再压一层「左暗右亮」的渐变：
   菜单在左半屏 —— 压暗它，保证像素字的对比度；右半屏留给沉没都市的景深。
   这是唯一能同时保住「背景有内容」与「菜单不失焦」的分工方式：
   可读性交给背景层，而不是给菜单项加底（加底就退回盒子了）。 */
#mainMenu {
  background:
    /* ★ 上下黑边（2026-10-03 用户："上下暗度要高一点、需要看不到页面边缘"）。
       纯竖向的暗带 —— 顶上 17%（约 184px）和底下 17% 从**近纯黑**渐变到透明，
       中间 66% 完全不动。和下面那圈椭圆暗角叠着用：暗角管左右与四角，这条管上下。
       ★ 它同样只是**背景栈里的一层** ⇒ 所有 DOM 文字（标题图 / 条目 / 页脚小字）
         都绘在它上面，因此"看不见边缘"和"不挡文字"可以同时成立，不用算安全区。
       ★ 只压上下、不压左右：右侧留给沉没神殿的景深（左暗右亮那条渐变管左右）。 */
    linear-gradient(180deg,
      rgba(2, 5, 9, .97) 0%,
      rgba(2, 5, 9, .88) 3%,
      rgba(2, 5, 9, .60) 7%,
      rgba(2, 5, 9, .28) 11.5%,
      rgba(2, 5, 9, 0)   17%,
      rgba(2, 5, 9, 0)   83%,
      rgba(2, 5, 9, .28) 88.5%,
      rgba(2, 5, 9, .60) 93%,
      rgba(2, 5, 9, .88) 97%,
      rgba(2, 5, 9, .97) 100%),
    /* ★ 四周暗角（用户要求"四周加一圈黑边、让人看不清边缘、要有淡化效果"）。
       放在**背景栈的最上层**（= 列表里靠前的层先画、压住后面的层）：
       它只压暗底图，仍然在所有内容（标题/条目/小字）之下 ⇒ 天然满足
       "不要挡住文字"，不需要再算安全区。
       ★★ 踩坑：radial-gradient 的椭圆尺寸百分比是**相对整个盒子宽高**，
          不是相对"半宽/半高"。写 `ellipse 116% 110%` 得到 rx=2227、ry=1188，
          半径比画面对角线还大 ⇒ 暗角整个落在画外、肉眼毫无变化（实测
          各区域亮度差 +0.0）。正确写法是 `58% 55%`（= 半宽×1.16 / 半高×1.10）。
       中心 58% 半径内完全不动，到画面边缘约 0.5、四角到 0.95 —— 是渐变，不是硬边框。 */
    radial-gradient(ellipse 58% 55% at 50% 50%,
      rgba(2, 5, 9, 0) 58%,
      rgba(2, 5, 9, .30) 78%,
      rgba(2, 5, 9, .72) 93%,
      rgba(2, 5, 9, .95) 100%),
    linear-gradient(96deg,
      rgba(5, 10, 17, .90) 0%,
      rgba(5, 10, 17, .80) 32%,
      rgba(5, 10, 17, .42) 60%,
      rgba(5, 10, 17, .06) 100%),
    url('../assets/bg/v-ai-2-cathedral.jpg') center center / cover no-repeat !important;
}

/* ★ 内页的 AI 底画要再压一层平铺暗罩：
   地图页左右两栏是「无底板」的纯文字（见 _map_right 实拍），黄铜齿轮那张
   高光太密，不压一层的话小字和背景纹理打起来。压 0.42 之后底画的形状仍读得出。
   ★★ 2026-10-12（用户「地图背景改成一块石板，顶栏和底栏也包括」→「拖动地图时背景要跟着图标动」）：
   整页是**一整块凿出来的石板**，但石纹要跟着地图一起滚：
   · #app 只做固定的「外框」：深色衬底 + vignette 暗晕 + 凿边倒角 + 外阴影，不铺石纹
   · 石纹（floor-tiles 128px 1:1 平铺）铺在**滚动内容 .map-sizer** 上 ⇒ 拖地图时纹路跟着图标动
   · 顶栏/底栏是固定 HUD，垫一层同色深底即可（见下方 #topbar / .map-bar 补底色） */
#app {
  background:
    radial-gradient(ellipse 130% 115% at 50% 40%, rgba(0,0,0,0) 42%, rgba(3,6,10,.55) 100%),
    linear-gradient(#0a0f14, #0a0f14) !important;
  border-radius: 16px;
  border: 2px solid #1c2931;
  box-shadow:
    inset 0 2px 0 rgba(150,180,196,.14),
    inset 0 -4px 0 rgba(0,0,0,.5),
    inset 0 0 52px rgba(2,5,9,.55),
    0 12px 40px rgba(0,0,0,.66),
    0 2px 10px rgba(0,0,0,.5);
}

#battleScreen {
  background:
    linear-gradient(rgba(4, 8, 13, .28), rgba(4, 8, 13, .28)),
    url('../assets/bg/_newQ2.jpg') center bottom / cover no-repeat !important;
}

/* ---------- 战斗地板（2026-10-10 重做 · 用户「战斗背景图重做成有地板形式」） ----------
   ★ 上一版（v-ai-3-rift 虚空裂隙 + CSS 透视纹理层）已整体退役：
     背景图换成 v-ai-5-arena.jpg —— 画面下方 60% 本身画了石板地板，
     上方是深渊裂隙，地板是**画进图里**的，不再是叠上去的纹理。
   ★ background-position 用 `center bottom`：图下边缘贴死视口底，
     不管视口多高，地板那片区域始终从底部往上铺，角色脚底（距底 300px）稳稳落在地板上。
   ★ .bt-floor 这一层只剩「地平线接触阴影」：给角色脚底一条柔和的落地暗影 +
     一条极淡的亮棱线，让立绘「踩在地板上」而不是悬空。 */
.bt-floor {
  position: absolute; left: 0; right: 0;
  top: calc(100% - var(--ground-off, 300px)); bottom: 0;
  overflow: hidden; pointer-events: none;
}
/* ★ 2026-10-12 撤掉 ::before / ::after 两条 34px 横向暗渐变 ——
   它们叠在脚线（距底 300px）处形成一条横贯全宽的分界线，
   与「石板地面画进图里」的新背景冲突（用户截图指出的分界线就是它）。
   落地感已由背景图自身的地板承担，不再需要接触阴影。 */

/* 模态框（难度 / 设置 / 仓库 / 规则）：遮罩透出背景，氛围一致。
   ★ 内页面板只到 rgba(6,12,17,.90)，底图会透出右半边，所以这里再叠一层
     「上暗下更暗」的竖向渐变，避免 AI 底画的高光（裂隙那张 p99 到 0.64）
     把面板里的正文压掉。 */
.modal-mask {
  background-color: rgba(4, 8, 13, .74) !important;
  background-image:
    linear-gradient(180deg, rgba(4, 8, 13, .55) 0%, rgba(4, 8, 13, .78) 100%),
    url('../assets/bg/v-ai-2-cathedral.jpg') !important;
  background-position: center center, center center !important;
  background-size: cover, cover !important;
  background-repeat: no-repeat, no-repeat !important;
}

/* 不同模态换各自的底：用 :has() 认面板特征，不用改 JS
   ★ 设置面板原来靠 `.set-tabs` 认 —— 2026-10-03 撤掉标签页后这条会**静默失配**
     （设置会悄悄退回默认底图），改用 openSettings 显式挂的 `.set-modal` 标记类。 */
body:has(.modal.set-modal) .modal-mask {
  background-image:
    linear-gradient(180deg, rgba(4, 8, 13, .55) 0%, rgba(4, 8, 13, .78) 100%),
    url('../assets/bg/v-ai-4-brass.jpg') !important;
}
body:has(.dl-item)  .modal-mask {
  background-image:
    linear-gradient(180deg, rgba(4, 8, 13, .55) 0%, rgba(4, 8, 13, .78) 100%),
    url('../assets/bg/v-ai-1-heart.jpg') !important;
}
body:has(.wh-grid)  .modal-mask {
  background-image:
    linear-gradient(180deg, rgba(4, 8, 13, .55) 0%, rgba(4, 8, 13, .78) 100%),
    url('../assets/bg/v-ai-4-brass.jpg') !important;
}

/* ---------- ② 去掉方正感：圆角（原为斜切角，2026-10-03 按"ui圆润一点"改） --------
   ★ 斜切角与圆角**不能共存**：clip-path 的优先级高于 border-radius，
     只要还留着一个 polygon 切角，写多少 border-radius 都是空操作
     （仓库那一版就是这么白写的 —— 量四个角的像素，r0 与 r12 一模一样）。
   ★ 所以这里是"换形状"：clip-path 由 polygon 换成 inset(0 round R)，半径与
     border-radius 取同一个变量 ⇒ 两者几何完全重合，等于只把角的形状换掉。
     保留 clip-path 是为了继续裁掉 .modal::before 那个溢出面板的同心圆环。 */

.modal {
  clip-path: inset(0 round var(--ab-r-panel)) !important;
  border-radius: var(--ab-r-panel) !important;
  background-color: rgba(6, 12, 17, .90) !important;
  box-shadow: inset 0 0 0 1px rgba(126, 176, 190, .20) !important;
  backdrop-filter: blur(2px);
}

/* 主菜单项：回到 hollow 的「去盒化」基调 ——
   只有像素图标 + 大字 + 副标题 + 一条发丝下划线，不给它加底、加框、切角。
   ★ 上一版曾在这里叠「对角渐变底 + 28px 切角」，结果菜单项又变回一块块
   "面板条"，与 hollow 的极简语言相冲，已按需求回退：
   形态改造只留给内页的弹窗与卡片（见下方 .modal / .panel / .btn），
   主菜单保持「字 + 线」的干净状态，可读性由 #mainMenu 的背景压暗负责。 */

/* 面板 / 卡片类 */
.panel,
.card,
.dl-item,
.set-sec,
.help-sec {
  clip-path: inset(0 round var(--ab-r)) !important;
  border-radius: var(--ab-r) !important;
}

/* 按钮：下划线式按钮本来就没有盒子，圆角在这里不改变外观 —— 留着是为了让
   hover / focus 时若将来给出底色，边角自动跟着圆（一处开关，不用回来补）。 */
.btn {
  clip-path: inset(0 round var(--ab-r-sm)) !important;
  border-radius: var(--ab-r-sm) !important;
}

/* ★★ 让 Buff 气泡能出框（2026-10-04 用户反馈）
   `.panel` 上有一层 `clip-path: inset(0 round R)`（见本文件顶部 ② —— 为了把角的形状换掉）。
   而 **clip-path 会同时成为 fixed 后代的包含块 + 裁剪框** ⇒ 气泡挂到图标右边后，
   一越过面板右边缘就被切断（实测：气泡 x=156→416，被裁在面板右边 184，只剩 24px 的缝）。
   ⇒ 只给这一块放开 clip-path。**圆角不会丢**：`.panel` 本来就同时写了同值的 `border-radius`
     （文件顶部注释原话「两者几何完全重合」），去掉 clip-path 后由 border-radius 接管。 */
#gearBuffPanel { clip-path: none !important; }

/* ---------- ② 去掉方正感：顶栏与分隔线 ---------------------------------
   把通长的直棍换成"中段亮、两端渐隐"的断边。 */

#topbar::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 1px;
  background: linear-gradient(90deg,
    transparent 0%, rgba(126, 176, 190, .34) 12%,
    rgba(126, 176, 190, .34) 72%, transparent 96%) !important;
  pointer-events: none;
}

.modal h2::after,
.help-sec h4::after {
  content: '';
  display: block;
  height: 1px;
  margin-top: 8px;
  background: linear-gradient(90deg, rgba(126, 176, 190, .40) 0%, rgba(126, 176, 190, .16) 46%, transparent 100%);
}

/* ---------- ② 去掉方正感：有机装饰 ------------------------------------
   ::before 画同心的弧，像深渊的涟漪；不占布局、不吃点击。 */

.modal::before {
  content: '';
  position: absolute;
  right: -60px; top: -60px;
  width: 240px; height: 240px;
  border: 1px solid rgba(126, 176, 190, .10);
  border-radius: 50%;
  box-shadow: 0 0 0 22px rgba(126, 176, 190, .045),
              0 0 0 52px rgba(126, 176, 190, .022);
  pointer-events: none;
}

#mainMenu::after {
  content: '';
  position: absolute;
  left: -90px; bottom: -110px;
  width: 300px; height: 300px;
  border-radius: 50%;
  border: 1px solid rgba(126, 176, 190, .09);
  box-shadow: 0 0 0 30px rgba(126, 176, 190, .035),
              0 0 0 70px rgba(126, 176, 190, .018);
  pointer-events: none;
}

/* ---------- 规则页的速览图解 ---------- */
.rules-diagram {
  margin: 4px 0 22px;
}
.rules-diagram .rd-cap {
  font-size: 12px;
  letter-spacing: 1px;
  color: #7f97a2;
  margin-bottom: 10px;
  padding-left: 10px;
  border-left: 2px solid rgba(126, 176, 190, .5);
}
.rules-diagram img {
  display: block;
  width: 100%;
  height: auto;
  margin-bottom: 10px;
  /* 图解本身已是深色底，这里只加一道发丝边把它和正文分开。
     （原来是这里切了个 16px 的斜角，已按"圆润"改成圆角，见文件末尾的圆角节。） */
  border: 1px solid rgba(126, 176, 190, .14);
  image-rendering: pixelated;
}
.rules-diagram .rd-end {
  margin-top: 20px;
  padding-top: 12px;
  font-size: 12px;
  color: #7f97a2;
  letter-spacing: 1px;
  background: linear-gradient(90deg, rgba(126, 176, 190, .28), transparent 60%) no-repeat top left / 100% 1px;
}

/* ---------- ③ 主菜单排版 ----------------------------------------------
   · 标题：换「像素化宋体」图片（见 tools/gen_title_lock.py）
   · 条目列：左对齐，不再居中；去掉分界线；悬停表现加厚
   · 未解锁的项：拖一截锁链、挂一把锁
   ------------------------------------------------------------------- */

/* 标题：风化蚀刻海报字（用户给的参考图 = 《HUNT: SHOWDOWN》标题）。
   风格拆解（tools/title_hunt.py 里有量色与算法记录）：
     · 字形：**高对比度衬线 + 瘦高** —— 字体取 NotoSerifSC-VF 的 Black 轴
       （思源宋体 Heavy），再纵向拉伸 1.22 倍；
     · 填充：**骨白**（不是纯白），带竖向石纹与稀疏暗斑；
     · 边缘：值噪声沿轮廓崩口（粗啃 + 细啃两级）+ 底缘不规则溶解；
     · 分离感来自**暗背景 + 一点软投影**，没有厚黑描边、也没有硬挤出
       （与上一套《潜渊症》海报字正好相反）。
   ★ 换黑体（NotoSansSC）就没有衬线，读不出这个味道 —— 这是本套与
     title_style.py（潜渊症套）最关键的区别。
   ★ 成品总高恒为 200px ⇒ 与上一套同高，菜单版式**零位移**。
   ★ background-size 用 `auto 200px`：素材本身正好 200 高，这样同目录下
     title-h1..h5.png（宽度各有差异）可以直接换 url，不用再同步宽度数字。
   ★ 参考图《HUNT: SHOWDOWN》的识别度有一半来自下面那行 SHOWDOWN。
     游戏自己的 `.menu-sub` 被皮肤压到 12px（屏幕上只剩一条虚点），撑不起这个
     位置 ⇒ 默认的 h5 把副题画进图里，文字取**游戏官方英文名** `ABYSSAL LEDGER`，
     同时把 DOM 那行 `visibility:hidden`（占位保留 ⇒ 版式零位移；
     visibility 不摘出无障碍树 ⇒ 屏幕阅读器照样读得到）。
     ★ 若换回 h1..h4（不带副题），要把下面那条 .menu-sub 规则一并删掉，
       否则英文名会整行消失。
   ★ 仍然用 background 而不是 DOM 文字：DOM 里保留「深渊债录」四个字并用
     text-indent 移出可视区，语义与无障碍不受影响（同一策略，沿用至今）。
   备选同目录：title-h1（无副题，字最大）/ h2（冷青）/ h3（血锈）/ h4（黄铜）。 */
.menu-title {
  font-size: 96px !important;
  line-height: 200px !important;
  height: 200px !important;
  letter-spacing: 0 !important;
  text-indent: -9999px !important;
  overflow: hidden !important;
  background: url('../assets/ui/title-h5.png') left center / auto 200px no-repeat !important;
}

/* 副题已画进标题图（h5）⇒ 隐去 DOM 那行，避免出现两行英文名。
   ★ 用 visibility 而不是 display:none：占位保留（版式零位移），
     且 elements 仍在无障碍树里。 */
.menu-sub {
  visibility: hidden !important;
}

/* ★ 品牌块下面那行小字（「你的血量即血债，你的债务即护盾」）按需求撤掉。
   原样式在 ui-hollow.css 的 .menu-tag（12px / letter-spacing 4px）。
   用 display:none（不是 visibility）——它没有版式作用，撤掉后整块往上收，
   反而让标题与条目列的间距更干净。 */
.menu-tag {
  display: none !important;
}

/* 条目列：向左收 —— 原来是 auto 居中、起点在 520px，现在贴到容器左边距。
   垂直仍居中，重心落在画面中部。 */
.menu-options {
  margin-left: 0 !important;
  margin-right: auto !important;
  margin-top: auto !important;
  margin-bottom: auto !important;
}

/* ★ 分界线全部撤掉（原来每条底下有 2px 发丝线，hollow 悬停还叠一条青色线）。
   识别靠"悬停时整行亮起"，不靠线。 */
.menu-options .mi {
  border-bottom: 0 !important;
  padding: 14px 4px !important;
  gap: 20px !important;
}
.menu-options .mi:hover { border-bottom-color: transparent !important; }
/* 只关掉"非锁定项"的 ::after（hollow 的悬停下划线用的就是 ::after）。
   ★ 必须带 :not([data-lock]) —— 否则锁定的项悬停时锁会被一起 display:none。 */
.menu-options .mi:not([data-lock]):hover::after { display: none !important; }

/* ★ 悬停 = 选中。做厚：一道自左向右渐隐的冷青光 + 左侧一枚像素光标。 */
.menu-options .mi::before {
  display: block !important;      /* hollow 里被 display:none !important 关掉了 */
  content: '' !important;
  position: absolute !important;
  left: 0 !important; right: 0 !important;
  top: 20% !important; bottom: 20% !important;   /* 竖条不顶天立地，留出呼吸 */
  background: linear-gradient(90deg,
    rgba(40, 207, 194, .17) 0%,
    rgba(40, 207, 194, .07) 30%,
    rgba(40, 207, 194, 0) 62%) !important;
  border-left: 6px solid rgba(40, 207, 194, 0) !important;
  box-shadow: none !important;      /* 原版 .mi-*::before 的残留一律清掉 */
  opacity: 0 !important;
  transition: opacity .14s ease !important;
  pointer-events: none !important;
}
.menu-options .mi:hover::before,
.menu-options .mi.sel::before,
.menu-options .mi.active::before {
  opacity: 1 !important;
  border-left-color: #28cfc2 !important;
}

.mi-ic,
.mi-ic img { width: 48px !important; height: 48px !important; }
.mi-tx { gap: 4px !important; }
.mi-tx b {
  font-size: 24px !important;   /* 12 的整数倍 —— 像素字落非整数倍会踩半像素发虚 */
  line-height: 40px !important;
  letter-spacing: 8px !important;
}
/* 悬停时字更亮更实，并给一点冷青辉光 —— 比原来只换颜色明显得多 */
.menu-options .mi:hover .mi-tx b {
  color: #f2f9fb !important;
  text-shadow: 0 0 14px rgba(40, 207, 194, .55) !important;
}
.menu-options .mi:hover .mi-ic img { filter: none !important; }

/* ★ 条目里那行解释小字（「签下新的契约」等）按需求撤掉 */
/* ★ 选中态右侧的「›」箭头去掉（HTML 里每个 .mi 都有一个 .mi-ar，悬停时淡入）。
   去掉后 .mi-tx 仍是 flex:1，文字左对齐不受影响。 */
.mi-ar { display: none !important; }

.mi-tx i { display: none !important; }

/* ★ 未解锁：一条锁链横向压过整个条目，链子在正中交叉成 X，交叉点上压一把铸铁挂锁。
   ——「把这一条锁死」的读法。
   ★ 旧版是「X 链 + 锁」并排的小徽章挂在行尾（right:0）——离文字有 700px 远，
     屏幕上读成"旁边浮着一个小东西"，跟条目没有关系。现在改成压在条目身上。
   ★ 摆放几何直接取自需求：链带自条目左边缘起、横跨 296px、高 68px（行高 76，上下各留 4px），
     锁落在交叉中心。素材 1:1 显示不缩放（整数倍缩放在这里没必要，见下方注释）。 */
.menu-options .mi[data-lock] {
  cursor: not-allowed !important;
}
.menu-options .mi[data-lock] .mi-tx b { color: #465059 !important; }
.menu-options .mi[data-lock] .mi-ic img { filter: grayscale(1) brightness(.42) !important; }
.menu-options .mi[data-lock]:hover::before {
  opacity: .45 !important;
  border-left-color: rgba(40, 207, 194, .5) !important;
}
.menu-options .mi[data-lock]:hover .mi-tx b {
  color: #6a7783 !important;
  text-shadow: none !important;
}
.menu-options .mi[data-lock]::after { display: none !important; }   /* 已废弃，见 .seal */

/* ★★ 锁链 = 「一张宽图 + 居中裁剪」，结构由 JS 注入（js/ui.js 的 lockItem / sizeSeal）。
   为什么从 ::after 换成真实 DOM：
     · 解锁要播「锁链断裂」——必须让「左臂 / 环+锁 / 右臂」三块**各自**动画，
       单个伪元素做不到（::before 还被 hover 下划线占着）。
   ★ 链长**固定 + 左对齐**（2026-10-03 用户："锁链长短和仓库锁链一样长" → "锁链向左对齐"）：
     所有未解锁条目的链子共用同一个长度 = 「仓库」那条的长度（JS 量出来，见 ui.js
     的 sealWidth()），不再随文字长短伸缩。
     素材 seal-x.png 固定 384×72，容器只改 width，背景 `center center` 居中裁剪
     ⇒ 可见窗口永远取自图片正中，于是**锁/环永远落在窗口正中**。
   ★ 水平位置由 JS 塞进 --seal-x，**恒为 0** ⇒ 各条链的左端全部钉在条目左边缘，
     谁也不比谁更靠右（旧版把窗口正中对准文字正中，4 字条目会整体右移 28px）。
     ★ 注意 .seal 用 `left: var(--seal-x, 0px) !important` —— 内联 style 斗不过
       `!important`，所以这个值必须走 CSS 变量传进来，不能直接写 el.style.left。
   ★ 三块共用同一张图，靠 X 偏移切出来。设图片宽 I=384、窗口宽 w（在图中居中，
     起点 (I-w)/2），各块相对窗口的起点 o 决定 background-position-x = -((I-w)/2 + o)：
       · 左臂  o=0        → bg-x = w/2 - 192   （唯一依赖 --seal-w 的偏移）
       · 环+锁 o=w/2-16   → bg-x = -176        （常数）
       · 右臂  o=w/2+16   → bg-x = -208        （常数）
   ★ 垂直仍是「环心 = 画布正中」（72/2 = 36）⇒ 只写 top:50%，无需补偿。 */
.seal {
  position: absolute !important;
  left: var(--seal-x, 0px) !important; right: auto !important;
  top: 50% !important; bottom: auto !important;
  transform: translateY(-50%) !important;
  width: var(--seal-w, 208px) !important;
  height: 72px !important;
  display: flex !important;
  pointer-events: none !important;
  z-index: 3 !important;
  opacity: .96;
}
.seal > span {
  display: block;
  height: 72px;
  background-image: url('../assets/ui/seal-x.png');
  background-repeat: no-repeat;
  background-size: 384px 72px;
}
.seal .sg-l { flex: 1 1 auto; background-position: calc(var(--seal-w, 208px) / 2 - 192px) center; }
.seal .lk   { flex: 0 0 32px; background-position: -176px center; }
.seal .sg-r { flex: 1 1 auto; background-position: -208px center; }

/* 崩开瞬间的中心闪光（.seal::after 不受 hollow 的 `.mi::after{display:none}` 影响） */
.seal::after {
  content: ''; position: absolute; left: 50%; top: 50%;
  width: 10px; height: 10px; margin: -5px 0 0 -5px; border-radius: 50%;
  background: radial-gradient(circle, rgba(214, 244, 255, .95), rgba(140, 206, 224, 0) 70%);
  opacity: 0; pointer-events: none;
}

/* ---------- 解锁动画：锁先"嘣"一下变亮 → 两段链子朝两侧崩开坠落 → 锁翻滚着掉下去 ---------- */
@keyframes sealFlare {
  0%   { opacity: 0; transform: scale(.6); }
  14%  { opacity: 1; transform: scale(2.6); }
  100% { opacity: 0; transform: scale(10); }
}
@keyframes sealArmL {
  0%   { transform: none; opacity: 1; }
  16%  { transform: translate(3px, -2px) rotate(-1deg); opacity: 1; }
  100% { transform: translate(-52px, 34px) rotate(-26deg); opacity: 0; }
}
@keyframes sealArmR {
  0%   { transform: none; opacity: 1; }
  16%  { transform: translate(-3px, -2px) rotate(1deg); opacity: 1; }
  100% { transform: translate(52px, 34px) rotate(26deg); opacity: 0; }
}
@keyframes sealCore {
  0%   { transform: none; opacity: 1; filter: brightness(1); }
  12%  { transform: translateY(-3px) scale(1.16); filter: brightness(2.8); }
  26%  { transform: translateY(-2px) scale(1.04); filter: brightness(1.5); }
  100% { transform: translateY(40px) rotate(28deg) scale(.74); opacity: 0; filter: brightness(.8); }
}
.seal.is-breaking .sg-l  { animation: sealArmL .62s cubic-bezier(.42, .02, .78, .44) .10s forwards; }
.seal.is-breaking .sg-r  { animation: sealArmR .62s cubic-bezier(.42, .02, .78, .44) .10s forwards; }
.seal.is-breaking .lk    { animation: sealCore .80s cubic-bezier(.36, .03, .72, .45) 0s forwards; }
.seal.is-breaking::after { animation: sealFlare .52s ease-out .06s forwards; }

/* ============================================================
   仓库（2026-10-03 重做）：左「局外格子 + 存货网格」／右「详情」
   ------------------------------------------------------------------
   ★ 为什么单开一节：旧版仓库是 980px 窄模态里竖着堆三段（统计条→已装备→存货网格），
     卡片高度跟着文案长短跑 ⇒ 每行都参差不齐，效果文字还被压成两行小字。
     现在改成「左网格 + 右详情」：方块统一定尺 ⇒ 行行对齐；详情独占一整栏 ⇒ 看得清。
   ★ 这里全部是**新类名（.wh-*）**，和原版/ hollow 的规则零交集，
     只有 .modal 的宽度需要压过 hollow 的 `max-width:1040px !important`（靠特异性更高 + !important）。
   ★ 尺寸一律取 2 的倍数；字号只用 12（正文）与 24（标题）—— 像素字体在这两档最锐利。
   ============================================================ */

.modal.wh-modal {
  max-width: 1720px !important;
  width: min(1720px, 100%) !important;
  height: 88vh !important;
  max-height: 88vh !important;
  padding: 22px 26px 18px !important;
  display: flex !important;
  flex-direction: column !important;
  overflow: hidden !important;
}

/* ---------- 顶部四格统计 ---------- */
.wh-kpi {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  margin: 10px 0 12px;
  border-top: 2px solid var(--hx-rule);
  border-bottom: 2px solid var(--hx-rule);
}
.wh-kpi > div { padding: 8px 16px 10px; border-right: 1px solid var(--hx-rule); }
.wh-kpi > div:last-child { border-right: 0; }
.wh-kpi b { display: block; font-size: 24px; font-weight: 400; line-height: 34px;
  letter-spacing: 2px; color: var(--gold); }
.wh-kpi i { display: block; font-size: 12px; font-style: normal; line-height: 20px; color: #6b7884; }

.wh-warn {
  font-size: 12px; line-height: 24px; color: #e8c37a;
  border-left: 2px solid #8a6a2c; padding: 2px 0 2px 12px; margin: 0 0 12px;
}

/* ---------- 左右分栏 ---------- */
.wh-wrap {
  flex: 1 1 auto; min-height: 0;
  display: grid; grid-template-columns: minmax(0, 1fr) 448px; gap: 0;
}
.wh-main { display: flex; flex-direction: column; min-height: 0; padding-right: 26px; }
.wh-side { display: flex; flex-direction: column; min-height: 0;
  border-left: 2px solid var(--hx-rule); padding-left: 26px; }

/* ---------- 栏内小标题 ---------- */
.wh-head { display: flex; align-items: baseline; gap: 14px;
  padding: 0 0 8px; border-bottom: 2px solid var(--hx-rule); flex: 0 0 auto; }
.wh-head + .wh-slots { margin-bottom: 18px; }
.wh-head .wh-h { font-size: 24px; line-height: 32px; letter-spacing: 6px; color: #e6eef2; }
.wh-head .wh-n { font-size: 12px; color: #6b7884; }
.wh-head .wh-tip { margin-left: auto; font-size: 12px; color: #4e5c66; }

/* ---------- 局外格子 ---------- */
.wh-slots { display: flex; flex-wrap: wrap; gap: 10px; padding: 12px 0 4px; flex: 0 0 auto; }
.wh-slot { width: 88px; height: 88px; padding: 6px 4px; box-sizing: border-box;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
  background: rgba(16, 30, 38, .55); border: 2px solid var(--teal); color: #e6eef2;
  font-family: inherit; font-size: 12px; }
.wh-slot .ic { font-size: 24px; line-height: 28px; }
.wh-slot .nm { font-size: 12px; line-height: 16px; max-width: 76px;
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.wh-slot.on { cursor: pointer; }
.wh-slot.on:hover { border-color: var(--red2); background: rgba(35, 19, 24, .8); }
.wh-slot.empty { border-style: dashed; border-color: #2a3f4a; color: #3f4c56; }

/* ---------- 筛选与排序 ---------- */
.wh-chips { display: flex; flex-wrap: wrap; gap: 8px; padding: 12px 0 2px; flex: 0 0 auto; }
.wh-chip { padding: 6px 14px; font-family: inherit; font-size: 12px; letter-spacing: 2px;
  background: none; border: 2px solid var(--hx-rule); color: #6b7884; cursor: pointer; }
.wh-chip b { font-weight: 400; color: #46545e; }
.wh-chip:hover { color: #e6eef2; border-color: var(--hx-acc2); }
.wh-chip.on { color: #e6eef2; border-color: var(--hx-acc); }
.wh-chip.on b { color: var(--hx-acc); }
.wh-sorts { margin-left: auto; display: flex; align-items: baseline; }
.wh-sort { padding: 2px 10px 4px; font-family: inherit; font-size: 12px; letter-spacing: 2px;
  background: none; border: 0; border-bottom: 2px solid transparent; color: #6b7884; cursor: pointer; }
.wh-sort:hover { color: #e6eef2; }
.wh-sort.on { color: #e6eef2; border-bottom-color: var(--hx-acc); }

/* ---------- 存货网格：定尺方块，行行对齐 ---------- */
.wh-grid {
  flex: 1 1 auto; min-height: 0; overflow: auto;
  /* ★★ 列必须是**定宽 160px**，不能用 `minmax(150px,1fr)`：后者在本栏 1182px 内容宽下
     算出 160.28px/列 ⇒ 相邻列距在 170/171 之间抖动（亚像素取整），
     方块就会"看着差不多、量起来不齐"。定宽 ⇒ 列距恒 170px，行绝对对齐。
     ★ 横向内边距左边为 0：方块左边缘与栏内标题、筛选片对齐（这就是"整齐"的基准线）。 */
  grid-template-columns: repeat(auto-fill, 160px);
  display: grid;
  grid-auto-rows: 122px; gap: 10px;
  padding: 14px 8px 4px 0; align-content: start;
}
.wh-tile { position: relative; box-sizing: border-box; overflow: hidden;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
  padding: 8px 6px 6px; text-align: center; cursor: pointer;
  background: rgba(9, 17, 24, .82); border: 2px solid var(--hx-rule); color: #a6b6c0;
  font-family: inherit; -webkit-appearance: none; }
.wh-tile:hover { border-color: var(--hx-acc2); }
.wh-tile .ic { font-size: 24px; line-height: 30px; }
.wh-tile .nm { font-size: 12px; line-height: 18px; color: #e6eef2; max-width: 100%;
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.wh-tile .ty { font-size: 12px; line-height: 18px; color: #6b7884; }
/* 左上角：占格形状（原始 11px 像素格，不做缩放 —— 非整数缩放会把方块糊掉） */
.wh-tile .sh { position: absolute; left: 7px; top: 7px; opacity: .8; }
.wh-tile .sh .shape-mini i { background: #1b2b34; }
.wh-tile .sh .shape-mini i.on { background: #7d8b95; }
.wh-tile .cnt { position: absolute; right: 7px; top: 5px; font-size: 12px; line-height: 16px; color: var(--gold); }
/* 三个状态各走一路信号，互不遮蔽：
     稀有度 → 描边色 ｜ 已装备 → 青底 + 底边色条 ｜ 选中 → 外圈亮环 + 提亮底色
   ★ 早先「已装备」和「选中」都用了同一族的青色内环，两张图放在一起分不出谁是谁。 */
.wh-tile.r-rare { border-color: #35608f; }
.wh-tile.r-epic { border-color: #6a45a0; }
.wh-tile.r-legend { border-color: #a8802e; }
.wh-tile.on { background: rgba(13, 34, 42, .92); }
.wh-tile.on::after { content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 4px;
  background: var(--teal); }
/* ★★ 选中环必须画在框**内**（inset）。
   早先用的是外环 `box-shadow: 0 0 0 2px`（画在方块盒子之外），而 `.wh-grid` 是
   `overflow:auto` 的滚动容器 —— 它按 **padding box** 裁剪，方块又紧贴 padding box 的
   左边缘（grid 左边距为 0）⇒ **环的左边整段被切掉**，只剩左上角一段断头弧，
   看起来正是"边缘被挡住了"（2026-10-03 用户报的）。
   内环天生不会被祖先裁剪，也不必给 grid 加左边距 —— 加了会让方块列比栏内标题缩进，
   破坏"整齐"。附带好处：稀有度描边在外、选中环在内，两路信号不再抢同一条边。 */
.wh-tile.sel { box-shadow: inset 0 0 0 2px var(--hx-acc); background: rgba(24, 46, 57, .96); }

.wh-none { font-size: 12px; line-height: 24px; color: #4e5c66; padding: 14px 0; }

/* ---------- 右栏：详情 ---------- */
.wh-dt-scroll { flex: 1 1 auto; min-height: 0; overflow: auto; padding-right: 8px; }
.wh-dt-top { display: flex; gap: 16px; align-items: flex-start; padding-bottom: 14px; }
.wh-dt-ic { flex: 0 0 92px; width: 92px; height: 92px; box-sizing: border-box;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
  background: rgba(9, 17, 24, .8); border: 2px solid var(--hx-rule); }
.wh-dt-ic.r-rare { border-color: #35608f; }
.wh-dt-ic.r-epic { border-color: #6a45a0; }
.wh-dt-ic.r-legend { border-color: #a8802e; }
.wh-dt-ic .i { font-size: 36px; line-height: 42px; }
.wh-dt-id { flex: 1 1 auto; min-width: 0; }
.wh-dt-id > b { display: block; font-size: 24px; font-weight: 400; line-height: 34px;
  letter-spacing: 4px; color: #e6eef2; }
.wh-dt-meta { display: flex; flex-wrap: wrap; gap: 6px; font-size: 12px; line-height: 22px; margin-top: 2px; }
.wh-dt-meta.dim { color: #6b7884; }
.wh-dt-meta.gold { color: var(--gold); }

.wh-dt-sec { border-top: 1px solid var(--hx-rule); padding: 12px 0 2px; }
.wh-dt-sec h5 { margin: 0 0 6px; font-size: 12px; font-weight: 400; letter-spacing: 6px; color: #6b7884; }
.wh-dt-sec p { margin: 0; font-size: 12px; line-height: 24px; color: #a6b6c0; }
.wh-dt-sec.curse h5 { color: #b5636e; }
.wh-dt-sec.curse p { color: #e8909a; }
.wh-dt-sec.dim p { color: #4e5c66; }

.wh-dt-note { margin-top: 14px; font-size: 12px; line-height: 22px; color: #6b7884;
  border-left: 2px solid #2a3f4a; padding-left: 10px; }
.wh-dt-note.on { color: #38c8d8; border-left-color: var(--teal); }
.wh-dt-none { font-size: 12px; line-height: 24px; color: #4e5c66; padding: 14px 0; }

.wh-dt-act { flex: 0 0 auto; margin-top: 14px; padding-top: 14px;
  border-top: 2px solid var(--hx-rule); }
.wh-dt-act .btn { width: 100%; }
.wh-dt-warn { font-size: 12px; line-height: 24px; color: #e8c37a; }

/* 细滚动条（--hide-scrollbars 截图时看不到，实机上是需要的） */
.wh-grid::-webkit-scrollbar, .wh-dt-scroll::-webkit-scrollbar { width: 10px; }
.wh-grid::-webkit-scrollbar-track, .wh-dt-scroll::-webkit-scrollbar-track { background: rgba(255, 255, 255, .03); }
.wh-grid::-webkit-scrollbar-thumb, .wh-dt-scroll::-webkit-scrollbar-thumb { background: rgba(126, 176, 190, .3); }

/* ---------- 窄屏回退：先收窄右栏，再整体堆叠 ---------- */
@media (max-width: 1180px) {
  .modal.wh-modal { width: min(980px, 100%) !important; height: auto !important;
    max-height: 88vh !important; overflow: auto !important; }
  .wh-wrap { grid-template-columns: minmax(0, 1fr) 360px; }
  .wh-main { padding-right: 18px; }
  .wh-side { padding-left: 18px; }
  .wh-grid { grid-auto-rows: 112px; }
}
@media (max-width: 760px) {
  .wh-wrap { grid-template-columns: 1fr; }
  .wh-main { padding-right: 0; }
  .wh-side { border-left: 0; border-top: 2px solid var(--hx-rule); padding: 14px 0 0; margin-top: 6px; }
  .wh-kpi { grid-template-columns: 1fr 1fr; }
  .wh-kpi > div:nth-child(2) { border-right: 0; }
  .wh-grid { grid-template-columns: repeat(auto-fill, minmax(122px, 1fr)); grid-auto-rows: 108px; }
  .wh-slot { width: 76px; height: 76px; }
}

/* ============================================================
   圆角化（用户："ui圆润一点"，2026-10-03）
   ------------------------------------------------------------------
   ★ 语言变更史，别绕回去：
       base 本来是有圆角的（modal 16 / card 11 / set-tab 8 / lv-card 9 …）
       → ui-hollow 把整套圆角抹成 0，换成"直角 + 一条底线"的去盒化语言；
       → abyss 又用「斜切角 clip-path」代替直角（34 / 20 / 14 三档）；
       → 现在按需求统一改成 **圆角**：本文件顶部三处 clip-path 已由 polygon 换成 inset(0 round R)。
   ★ 只有一个开关：三个变量。想出对比图只覆盖这三个数
     （tools/shoot_round_variants.py 就是这么做的），不用去翻每条规则。
   ★ 为什么框架层要写 `!important`：hollow 给 `.modal` 写死了
     `border-radius:0 !important`，而特异性一旦打平，**后加载的表胜**——
     ui-abyss.css 在 ui-hollow.css 之后注入，所以同特异性 + !important 就能压过去。
   ★ 取值一律 2 的倍数（项目硬性规范）；12 / 6 / 16 是"圆润一点"的档位，别默认开太大。
   ★ 本次范围：**弹窗族**（难度 / 巅峰 / 设置 / 规则 / 仓库 / 选取 …）。
     不碰主菜单（.mi，已封版 v1.0），也不碰局内 HUD 与地图（.bt-* / .cell / .map-node）——
     那一屏的方块是玩法语义（格子、占位），动它风险大于收益。
   ============================================================ */
:root {
  --ab-r: 12px;        /* 大件：面板内的卡片 / 行 / 方块 / 大图 */
  --ab-r-sm: 6px;      /* 小件：按钮 / 标签页 / 提示条 / 滚动条 */
  --ab-r-panel: 16px;  /* 弹窗外框 */
}

.modal.wh-modal { border-radius: var(--ab-r-panel) !important; }

/* ---------- 仓库内的件：保持原来的档位 ---------- */
/* 方块 / 局外格子 / 详情图标：同一档圆角，看起来才是"一套" */
.wh-tile,
.wh-slot,
.wh-dt-ic { border-radius: var(--ab-r); }

/* 已装备的底边色条：方块一旦收圆，贴边横条的四角会顶出弧线，改成内缩的圆头短条 */
.wh-tile.on::after {
  left: 10px;
  right: 10px;
  bottom: 4px;
  border-radius: 2px;      /* 条高 4px ⇒ 2px 圆角即胶囊 */
}

/* 筛选片 */
.wh-chip { border-radius: var(--ab-r-sm); }

/* 左栏提示条、右栏脚注：方角改小圆头 */
.wh-warn,
.wh-dt-note { border-radius: var(--ab-r-sm); }

/* 滚动条 */
.wh-grid::-webkit-scrollbar-thumb,
.wh-dt-scroll::-webkit-scrollbar-thumb { border-radius: var(--ab-r-sm); }

/* ============================================================
   以下：把圆角从仓库推广到其余弹窗（2026-10-03 第二轮）
   ------------------------------------------------------------------
   ★ 这些块在 hollow 里被"去盒化"了（background:none + border:0，只留一条底线），
     所以它们**根本看不出圆角** —— 想"圆润"必须先把盒子还回来。
     顺带解决了难度页一个真实的可用性问题：hollow 只靠"底线变色"表示当前档位，
     实机上几乎看不出选中了哪一档。
   ============================================================ */

/* ---------- ① 难度 / 巅峰：五个「独立小区域」（2026-10-03 全部重做） ----------
   用户：「难度选项ui 要全部重做 —— 我更喜欢单独小区域来摆放难度选项，
        并且详情放在下面显示，详情区的内容根据选择不同的难度来显示内容」。
   ★ 主风格不变：仍是深渊石面色阶（`--ab-c*`）+ 三阶上色 + 圆角三变量，
     只是把「通栏一行一条」换成「五块并排的小区域 + 下面一整块详情」。
   ★ 弹窗加宽到 **1092**：内容宽 = 1092 − 2×2(border) − 2×20(padding) = **1048**，
     正好 5×200 + 4×12 ⇒ 小区域每块恰 **200×120**、间距 **12**，全是偶数。
     （不用写死列宽：`repeat(5, minmax(0,1fr))` 在 1048 宽下算出来就是 200，
       窗口变窄时还能自己缩，不必再挂媒体查询。）
   ★ 通道分工沿用仓库那套，一屏只讲三件事：
       选中 → inset 内环 + 提亮一档 ｜ 锁定 → 压暗 + 不可点 ｜ 档位 → 底部三阶暗面。 */
.modal.df-modal { max-width: 1092px !important; }

.df-grid {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 12px;
  margin: 4px 0 16px;
}

.modal .lv-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 2px;
  width: 100%;
  height: 120px;
  padding: 14px 16px !important;
  border: 2px solid var(--ab-line) !important;
  border-radius: var(--ab-r) !important;
  background: var(--ab-c1) !important;
  color: inherit;
  font-family: inherit;
  text-align: left;
  cursor: pointer;
  /* 三阶：中间调平涂 + 底部 8px 硬边暗面 + 顶 1px 暖高光 + 落影（与仓库方块同一套配方） */
  box-shadow: inset 0 1px 0 rgba(182, 213, 203, .16),
              inset 0 -8px 0 rgba(0, 0, 0, .30),
              0 2px 0 var(--ab-lo) !important;
}
.modal .lv-card:hover {
  border-color: var(--hx-acc2) !important;
  background: var(--ab-c2) !important;
}
.modal .lv-card.on {
  border-color: var(--hx-acc) !important;
  background: var(--ab-c2) !important;
  box-shadow: inset 0 1px 0 rgba(182, 213, 203, .26),
              inset 0 -8px 0 rgba(0, 0, 0, .30),
              0 2px 0 var(--ab-lo),
              inset 0 0 0 2px var(--hx-acc) !important;
}
/* 锁定：**不用 opacity** —— 整块透明会把「通关 Lv2 解锁」那行提示一起压没，
   而那行是玩家唯一的解锁线索。改成显式压暗配色：底/边/文字各降一档，提示仍读得出来。 */
.modal .lv-card.lock {
  background: rgba(8, 16, 22, .70) !important;
  border-color: rgba(43, 70, 82, .55) !important;
  box-shadow: none !important;
  cursor: not-allowed;
}
.modal .lv-card.lock .lt-code { color: #47606a; }
.modal .lv-card.lock .lt-name { color: #7d8f97; }
.modal .lv-card.lock .lt-sub  { color: #6b7d85; }
.modal .lv-card.lock:hover { border-color: rgba(43, 70, 82, .55) !important; background: rgba(8, 16, 22, .70) !important; }

.modal .lv-card .lt-code { font-size: 36px !important; line-height: 36px !important; letter-spacing: 2px; color: var(--hx-acc); }
.modal .lv-card .lt-name { font-size: 24px !important; line-height: 24px !important; letter-spacing: 6px; color: #e6eef2; }
.modal .lv-card .lt-sub  { font-size: 12px !important; line-height: 24px !important; color: #6b7884; }
.modal .lv-card.on .lt-code { color: #cdf0f6; }
.modal .lv-card.on .lt-sub  { color: #8fa8b2; }

/* ---------- ② 详情区：选谁换谁（整块 innerHTML 只换这里） ---------- */
.df-det {
  margin-bottom: 14px;
  padding: 16px;
  border: 2px solid var(--ab-line);
  border-radius: var(--ab-r);
  background: rgba(8, 18, 24, .74);
  box-shadow: inset 0 1px 0 rgba(182, 213, 203, .12), inset 0 -8px 0 rgba(0, 0, 0, .22);
}
.df-det-h { display: flex; align-items: baseline; gap: 12px; }
.df-det-h b { font-size: 24px !important; font-weight: 400 !important; letter-spacing: 4px; color: #e6eef2; }
.df-det-h span { font-size: 12px; letter-spacing: 2px; color: var(--hx-acc); }
.df-det-desc { margin: 6px 0 14px; font-size: 12px !important; line-height: 24px !important; color: #a6b6c0; }

/* 六格数值：3×2 的网格线靠 2px 缝隙露出底色，不再一条条画边框 */
.df-stats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 2px;
  background: var(--ab-line);
  border-radius: var(--ab-r-sm);
  overflow: hidden;
}
.df-stat { background: rgba(10, 22, 30, .94); padding: 10px 14px; }
.df-stat .k { display: block; font-size: 12px !important; letter-spacing: 2px; color: #6b7884; }
.df-stat .k b { margin-left: 8px; font-weight: 400; color: var(--gold2); }
.df-stat .v { display: block; font-size: 24px !important; line-height: 36px !important; letter-spacing: 2px; color: #dfeaef; }
/* 「比基准更难」的格：底子转暖、数值转金 —— 只有**变了**的格才亮，扫一眼就知道这档多了什么 */
.df-stat.up { background: rgba(24, 21, 14, .94); }
.df-stat.up .v { color: var(--gold2); }

.modal .diff-sum { margin: 0; }

/* ---------- ③ 巅峰：强化条目（勾选行） ---------- */
.modal .diff-row {
  border: 2px solid var(--hx-rule) !important;
  background: rgba(16, 30, 38, .45) !important;
  border-radius: var(--ab-r) !important;
  padding: 10px 14px !important;
}
.modal .diff-row:hover { border-color: var(--hx-acc2) !important; background: rgba(20, 38, 48, .58) !important; }

/* ---------- ④ 设置：开关行 ---------- */
.modal .set-row {
  border: 2px solid var(--hx-rule) !important;
  background: rgba(16, 30, 38, .45) !important;
  border-radius: var(--ab-r) !important;
  padding: 12px 16px !important;
  margin-bottom: 8px !important;
}

/* ---------- ⑤ 设置：标签页 —— 下划线式改成圆角片 ---------- */
.modal .set-tab {
  border: 2px solid var(--hx-rule) !important;
  background: rgba(16, 30, 38, .45) !important;
  border-radius: var(--ab-r-sm) !important;
  padding: 8px 18px !important;
  color: #8b9aa5 !important;
}
.modal .set-tab:hover { color: #e6eef2 !important; border-color: var(--hx-acc2) !important; }
.modal .set-tab.on {
  border-color: var(--hx-acc) !important;
  background: rgba(26, 50, 61, .90) !important;
  color: #e6eef2 !important;
}

/* ---------- ⑥ 规则页的速览大图 ----------
   ★ 图本身也有一个 16px 的两角斜切（`.rules-diagram img`），它同样会压掉 border-radius ⇒
     必须连 clip-path 一起换掉，否则"改了没生效"在这里会重演一次。 */
.modal .rules-diagram img {
  clip-path: inset(0 round var(--ab-r)) !important;
  border-radius: var(--ab-r) !important;
}

/* ---------- ⑦ 小件对齐到同一档 ---------- */
.modal .seg { border-radius: var(--ab-r-sm) !important; }
.toast { border-radius: var(--ab-r-sm) !important; }
.modal ::-webkit-scrollbar-thumb { border-radius: var(--ab-r-sm); }

/* ============================================================
   仓库：层次（明度台阶）与配色（2026-10-03 第三轮）
   ------------------------------------------------------------------
   用户："感觉层次不太凸显 颜色有点单调"。
   先量改前各分区的底色亮度 —— 全挤在一档，这就是"平"的来源：
     弹窗外底 (4,7,9) ｜ KPI 底 (5,12,16) ｜ 主区空白 (6,13,17) ｜ 侧栏底 (6,12,16) ｜ 方块底 (7,16,22)
   除弹窗外底外全在亮度 11~14 之间 ⇒ 分区之间**没有台阶**，只剩一条 2px 线在硬撑。
   做法（像素风惯例：不用渐变，只堆**纯色台阶 + 1px 硬高光/暗边**）：
     ① 明度台阶：弹窗底 < 凹槽（网格）< 方块 < 已装备 < 选中；
     ② 冷暖分区：主区冷青、右栏暖铜 ⇒ 一眼能看出"这是两块不同的板"；
     ③ 用色带说话：方块顶部 2px 走**类型色**、格子边框走类型色、筛选片与图标框也走类型色 ——
        颜色全挂在已有的编码上（类型 / 稀有度 / 状态），不是装饰性乱加。
   ★ 尺寸一律取 2 的倍数；唯一用 1px 的是"高光线"（像素风的倒角本就只有 1px）。
   ============================================================ */

/* ---------- ① 台阶一：网格做成"凹槽"（最暗一档） ----------
   ★★ 几何必须守恒：凹槽**向外扩**、内容盒仍是 1182px，否则列数/列距/方块坐标全会变
      （实测方块 x=128、列距 170、7 列）。
      横向：border 2 + padding-left 10 = 12 ⇒ margin-left:-12px；右边只 border 2 ⇒ margin-right:-2px
      纵向：border 2 + padding-top 12 = 14（原来就是 14）⇒ margin-top:-2px，内容起点不变。 */
.wh-grid {
  background: rgba(2, 5, 8, .72);
  border: 2px solid rgba(96, 116, 128, .34);
  border-radius: var(--ab-r);
  margin: -2px -2px 0 -12px;
  padding: 12px 8px 4px 10px;
  /* ★ 高度**贴合内容**（不 grow）：撑满的话短列表下方会留出一整块空板子，
     看着像"东西没加载出来"。列表变长时仍会撑到上限并出现滚动条（flex-shrink 兜底）。 */
  flex: 0 1 auto;
  max-height: 100%;
}

/* ---------- ② 台阶二：方块浮起（比凹槽亮一档） ---------- */
.wh-tile {
  background: rgba(17, 31, 41, .96);
  box-shadow: inset 0 1px 0 rgba(158, 210, 222, .12), 0 2px 0 rgba(0, 0, 0, .55);
}
.wh-tile:hover { background: rgba(22, 40, 52, .96); }
/* 已装备再亮一档（青底），与顶部类型带、底部青条上下呼应 */
.wh-tile.on { background: rgba(20, 52, 62, .96); }
/* 选中：最亮一档。★★ box-shadow 必须**写全**（高光 + 投影都要带上），
   否则这条会把上面那两条一起冲掉，方块瞬间"瘪"下去。 */
.wh-tile.sel {
  background: rgba(30, 62, 76, .98);
  box-shadow: inset 0 0 0 2px var(--hx-acc), 0 2px 0 rgba(0, 0, 0, .55);
}
/* 顶部 2px 类型色带 —— 方块身上的"颜色"主要来自这一条。
   ★★ 只能画在 **padding box 之内**（top/left/right 取 0）：`.wh-tile` 有 `overflow:hidden`，
     而 overflow 的裁剪区是 **padding box** —— 早先试图把色带盖在 border 那 2px 上（取 -2px），
     结果整条被裁掉，屏幕上只剩一条 `--hx-rule` 的淡灰线（差点误判成"变量没生效"）。
   ★ 与选中环的关系：环也是 padding box 内侧 2px，所以两者在顶部那一条**重叠**，
     绘制顺序是「伪元素 > inset 阴影」⇒ 顶部显示类型色、左右下三边显示青环，
     看着像"顶部贴了封条"，信号不丢。 */
.wh-tile::before {
  content: ''; position: absolute; left: 0; right: 0; top: 0; height: 2px;
  background: var(--ty, var(--hx-rule));
}

/* ---------- ③ 台阶三：右栏换成"另一块板"（暖铜调，与冷青主区对撞） ----------
   ★ 冷暖只由下面两个变量决定 —— 想让它退回"冷青、只是更暗"的版本，只改这两个值：
       --ab-side-bg: rgba(6, 13, 18, .72);   --ab-side-line: rgba(74, 88, 98, .5); */
:root {
  --ab-side-bg: rgba(38, 24, 15, .68);
  --ab-side-line: #8a5c2c;
}
.wh-side {
  background: var(--ab-side-bg);
  border-left: 2px solid var(--ab-side-line);
  border-radius: var(--ab-r);
  padding: 18px 20px 18px 24px;
}

/* ---------- ④ 栏目标题：4px 引导条（局外=青 / 存货=金） ---------- */
.wh-head { position: relative; padding: 0 0 8px 14px; }
.wh-head::before {
  content: ''; position: absolute; left: 0; top: 6px; bottom: 14px; width: 4px;
  background: var(--teal); border-radius: 2px;
}
.wh-head.wh-head-b::before { background: var(--gold); }
.wh-head.wh-head-b { border-bottom-color: rgba(232, 180, 90, .38); }

/* ---------- ⑤ 顶部统计：四个数各给一个色，别全挤在金色上 ---------- */
.wh-kpi > div:nth-child(1) b { color: var(--gold); }
.wh-kpi > div:nth-child(2) b { color: var(--hx-acc); }
.wh-kpi > div:nth-child(3) b { color: var(--teal); }
.wh-kpi > div:nth-child(4) b { color: #e6eef2; }

/* ---------- ⑥ 局外格子：边框走类型色 —— 一眼看出装了哪一类 ---------- */
.wh-slot {
  background: rgba(20, 40, 50, .78);
  border-color: var(--ty, var(--teal));
  box-shadow: inset 0 1px 0 rgba(158, 210, 222, .10);
}
.wh-slot.on:hover { border-color: var(--red2); background: rgba(48, 24, 30, .88); }
.wh-slot.empty { background: rgba(8, 14, 19, .60); border-color: #31505e; box-shadow: none; }

/* ---------- ⑦ 筛选片：也用类型色（和方块上的色带是同一套编码） ---------- */
.wh-chip.on { border-color: var(--ty, var(--hx-acc)); }
.wh-chip.on b { color: var(--ty, var(--hx-acc)); }
.wh-chip:hover { border-color: var(--ty, var(--hx-acc2)); }

/* ---------- ⑧ 右栏详情：小标题引导条 + 图标框走类型色 ---------- */
.wh-dt-sec { position: relative; padding-left: 12px; }
.wh-dt-sec::before {
  content: ''; position: absolute; left: 0; top: 14px; bottom: 4px; width: 2px;
  background: rgba(126, 176, 190, .32);
}
.wh-dt-sec.curse::before { background: #a8323c; }
.wh-dt-ic { border-color: var(--ty, var(--hx-rule)); background: rgba(14, 26, 34, .9); }
.wh-dt-ic.r-rare,
.wh-dt-ic.r-epic,
.wh-dt-ic.r-legend { border-color: var(--ty, var(--hx-rule)); }
.wh-dt-note { border-left-width: 2px; }

/* ---------- 窄屏回退：凹槽的负外边距要让回去，免得顶出面板 ---------- */
@media (max-width: 1180px) {
  .wh-grid { margin-left: -7px; }
  .wh-side { padding: 16px 16px 16px 18px; }
}
@media (max-width: 760px) {
  .wh-grid { margin: 0; }
  .wh-side { border-left: 0; border-top: 2px solid #7a5228; border-radius: 0; padding: 14px 0 0; }
}

/* ============================================================
   美术风格落地 · 仓库：三阶上色 × 按功能上色（2026-10-03 第九轮）
   ------------------------------------------------------------------
   依据：notes/研读-空洞骑士与杀戮尖塔的美术风格.md
     ① 三阶上色   —— 每块材质只用三档明度，中间调整块平涂、硬边、**无过渡**；
     ② 色相偏移   —— 暗部往蓝紫偏、亮部往暖偏（"变亮"不等于"加白"）；
     ③ 按功能上色 —— 不同类型的插画基调不同（杀戮尖塔）⇒ 不读字也知道它是干什么的；
     ④ 描边纪律   —— 不用纯黑，用**比填色深一阶**的颜色；迎光侧浅、背光侧深（选择性描边）；
     ⑤ 图标语言   —— 深一阶描边 + 简洁符号 + 少量重点色（空洞骑士）。
   ★ 主风格不变：仍是深色深渊调（冷青为骨）、纯色台阶 + 1px 硬高光（**不用渐变**）、
     尺寸仍取 2 的倍数；版式几何（方块 160×122 / 列距 170 / 网格左边 x=128）一个字没动。
   ============================================================ */

:root {
  /* ---- 深渊石面：四级明度 + 高光 ----
     ★ 色相刻意**不统一**：暗面偏蓝紫(≈222°) → 中间调偏青蓝(≈203°) → 亮面偏青绿(≈189°)
       → 高光偏暖骨(≈163°)。这就是"色阶要偏色，不是变亮"。
     ★ 落影用 #050b11 而不是纯黑 —— 纯黑会把像素边缘"烧穿"，也不给色相留位置。 */
  --ab-c0: #0a141d;              /* 最深：网格凹槽 */
  --ab-c1: #0f1e29;              /* 暗面 */
  --ab-c2: #172c38;              /* 中间调 */
  --ab-c3: #1e3c47;              /* 亮面 */
  --ab-hi: #b6d5cb;              /* 暖骨高光（只做 1px 线） */
  --ab-lo: #050b11;              /* 落影 */
  --ab-line: #2b4652;            /* 结构线：比中间调深一阶，不用半透明灰 */
}

/* ---------- 按功能上色：五类封印物的三阶基调 ----------
   ★ 每类四个值是"同一色相内的明度台阶"，不是四个不同的颜色。
       --t-d 深（描边 / 暗面 / 落影）｜--t-m 中（块面平涂）｜--t-t 次（次级字）｜--t-h 亮（徽记 / 重点色）
   ★ 顺带把 --ty 一并定义在这里：老的"顶色带 / 筛选片"规则靠它，
     改完之后 JS 不必再内联写颜色，色板只留 CSS 一处（改版只动这一段）。 */
[data-ty="weapon"] { --ty:#ff6b6b; --t-d:#201219; --t-b:#2c1620; --t-m:#381a23; --t-t:#8a4a44; --t-h:#b25c50; }
[data-ty="ward"]   { --ty:#5b9dff; --t-d:#0c1726; --t-b:#112033; --t-m:#16293f; --t-t:#4f7599; --t-h:#7aa8cf; }
[data-ty="charm"]  { --ty:#ffd166; --t-d:#1f1709; --t-b:#2b210d; --t-m:#382a11; --t-t:#98803f; --t-h:#c9a559; }
[data-ty="core"]   { --ty:#7ee787; --t-d:#0a1c18; --t-b:#0e2620; --t-m:#123028; --t-t:#3f8a74; --t-h:#63c2a2; }
[data-ty="rite"]   { --ty:#c792ea; --t-d:#180f21; --t-b:#21162e; --t-m:#2b1d3c; --t-t:#7a63a0; --t-h:#a084cb; }

/* ---------- 徽记：五类各一个可辨认的剪影 ----------
   ★ 形状本身是一条编码通道（杀戮尖塔用图标外框的形状区分类型）：
     凶器=长剑（尖刃+宽护格+窄柄）｜护咒=拱顶盾（宽、尖底）｜咒物=六棱宝石（窄高、上下尖）
     共鸣核=圆环（唯一的圆）｜仪轨=扁六边（上下平、左右尖）
   ★ 剪影自检标准：把它们全部涂成同一个深色，只看轮廓也该分得出谁是谁 ——
     前两版的凶器在 8 格栅格上只能画成"十"字，这一版把栅格细到 16 格才立住。
   ★ 结构 = 外层深色剪影 + 内层亮色剪影。同一份 polygon 作用在两个同心盒上（外 32 / 内 24）
     ⇒ 描边恒为 4px，比"缩放内层"稳（缩放会让长轴两端的描边变粗）。
   ★ 描边色是 --t-d（比填色深一阶），不是黑 —— 深色底上纯黑描边会直接消失。 */
.sg { position: relative; display: inline-block; width: 32px; height: 32px; flex: 0 0 auto;
  background: var(--t-d, #0a141d); clip-path: var(--sgp); }
.sg > i { position: absolute; inset: 4px; background: var(--t-h, #9ed2de); clip-path: var(--sgp); }
/* 10 个顶点全落在 1/16 的栅格上 ⇒ 32px 盒里每格正好 2px，顶点都取整。
   ★ 凶器的刃**必须够宽**：第一版刃只有 8px 宽、护格又短，整体读成"十"字；
     现在刃基 12px、护格 28px×4px、柄 4px，才立得住"剑"这个剪影。 */
.sg-weapon { --sgp: polygon(50% 0%,75% 68.75%,93.75% 75%,93.75% 87.5%,56.25% 87.5%,56.25% 100%,43.75% 100%,43.75% 87.5%,6.25% 87.5%,6.25% 75%,25% 68.75%); }
.sg-ward   { --sgp: polygon(37.5% 0%,62.5% 0%,100% 18.75%,100% 56.25%,50% 100%,0% 56.25%,0% 18.75%); }
.sg-charm  { --sgp: polygon(50% 0%,75% 18.75%,75% 81.25%,50% 100%,25% 81.25%,25% 18.75%); }
.sg-rite   { --sgp: polygon(18.75% 0%,81.25% 0%,100% 31.25%,100% 68.75%,81.25% 100%,18.75% 100%,0% 68.75%,0% 31.25%); }
/* 共鸣核：clip-path 挖不出洞，改用同心圆 —— 外圈深、中环亮、芯部留暗，
   读起来就是一颗"核"，也是五类里唯一的圆形剪影。 */
.sg-core { clip-path: none; border-radius: 50%; }
.sg-core > i { clip-path: none; border-radius: 50%; background: transparent;
  box-shadow: inset 0 0 0 6px var(--t-h, #9ed2de); }
.sg-lg { width: 48px; height: 48px; }
.sg-lg > i { inset: 4px; }
.sg-lg.sg-core > i { box-shadow: inset 0 0 0 9px var(--t-h, #9ed2de); }

/* ---------- 存货方块：整块按类型上色 + 三阶 ---------- */
.wh-tile {
  background: var(--t-m, var(--ab-c2));
  /* 三阶：中间调平涂（background）＋ 底部一档暗面（硬边平涂，不是渐变）＋ 1px 暖高光 + 落影。
     ★ 暗面写成 inset 大位移纯色，宽度即"平涂色块"的宽度 —— 像素风要的是硬边，不是柔光。 */
  box-shadow:
    inset 0 1px 0 rgba(182, 213, 203, .22),
    inset 0 -10px 0 var(--t-b, var(--ab-c1)),
    0 2px 0 var(--ab-lo);
  border-color: var(--ab-line);
}
/* 类型色带取消：整块底色已经在讲"这是哪一类"，再挂一条带子就是同一件事编两遍。
   位置让给 1px 顶高光（迎光侧浅）—— 选择性描边。 */
.wh-tile::before { top: 0; height: 1px; background: rgba(182, 213, 203, .22); }
.wh-tile:hover { background: var(--t-m, var(--ab-c2));
  box-shadow: inset 0 1px 0 rgba(182, 213, 203, .34),
              inset 0 -10px 0 var(--t-b, var(--ab-c1)),
              0 2px 0 var(--ab-lo),
              inset 0 0 0 999px rgba(190, 240, 245, .07); }
/* 已装备：底部内缩青条（唯一表示"状态"的通道）+ 整块提亮一档。
   ★ 提亮用"铺一层半透明纯色"（inset 大 spread）而不是 filter:brightness ——
     filter 会让整块重新栅格化，小字会发糊。 */
.wh-tile.on {
  box-shadow:
    inset 0 1px 0 rgba(182, 213, 203, .30),
    inset 0 -10px 0 var(--t-b, var(--ab-c1)),
    0 2px 0 var(--ab-lo),
    inset 0 0 0 999px rgba(120, 226, 224, .09);
}
.wh-tile.on::after { background: var(--teal); }
/* 选中：内环 + 再提亮一档（两路信号：环＝选中，亮度＝焦点） */
.wh-tile.sel {
  background: var(--t-m, var(--ab-c2));
  box-shadow:
    inset 0 1px 0 rgba(182, 213, 203, .34),
    inset 0 -10px 0 var(--t-b, var(--ab-c1)),
    0 2px 0 var(--ab-lo),
    inset 0 0 0 2px var(--hx-acc),
    inset 0 0 0 999px rgba(150, 236, 240, .15);
}
.wh-tile .ty { color: var(--t-t, #6b7884); }
/* 占格小图：暗格＝挖空的洞（比底色深一阶），亮格＝骨白。
   ★ 这条也是三阶：洞是"背光面"，格是"迎光面"，两档之间没有中间值。
   ★ 详情框里的那份也要一起换色 —— 底图 style.css 给的是 --gold，
     只改方块不改详情，同一张屏上会出现两种"占格色"。 */
.wh-tile .sh .shape-mini i,
.wh-dt-ic .shape-mini i { background: var(--t-d, #16242c); }
.wh-tile .sh .shape-mini i.on,
.wh-dt-ic .shape-mini i.on { background: #c9d8d4; }

/* ---------- 稀有度：外框 = 深一阶 ----------
   ★ 通道分工：稀有度只走"框"这一条路（沿用玩家已有的灰/蓝/紫/金认知），
     类型只走"底色 + 徽记"，状态只走"条 + 环 + 明度" —— 三条互不遮蔽。 */
.wh-tile.r-common { border-color: var(--ab-line); }
.wh-tile.r-rare   { border-color: #2c567e; }
.wh-tile.r-epic   { border-color: #5b3d86; }
.wh-tile.r-legend { border-color: #8f6b24; }

/* ---------- 局外格子：同一条"按功能上色"的规则 ---------- */
.wh-slot { background: var(--t-m, #16293f); border-color: var(--ab-line);
  box-shadow: inset 0 1px 0 rgba(182, 213, 203, .20), inset 0 -8px 0 var(--t-b, var(--ab-c1)); }
.wh-slot.on:hover { background: var(--t-m, #16293f); border-color: var(--red2);
  box-shadow: inset 0 1px 0 rgba(182, 213, 203, .30), inset 0 -8px 0 var(--t-b, var(--ab-c1)),
              inset 0 0 0 999px rgba(200, 60, 70, .16); }
.wh-slot.empty { background: var(--ab-c0); border-color: #26404c; box-shadow: none; }
.wh-slot .ic, .wh-tile .ic { display: flex; align-items: center; justify-content: center; }
.wh-slot .ic { width: 32px; height: 32px; }
.wh-slot .nm { color: #dbe6e9; }

/* ---------- 筛选片：只留"细色点"这一条类型通道 ---------- */
.wh-chip[data-ty]::before { content: ''; display: inline-block; vertical-align: 1px;
  width: 8px; height: 8px; margin-right: 6px; border-radius: 1px;
  background: var(--t-h, var(--hx-acc)); box-shadow: 0 0 0 1px var(--t-d, #0a141d); }
.wh-chip.on { border-color: var(--t-t, var(--hx-acc)); background: var(--ab-c1); }
.wh-chip.on b { color: var(--t-h, var(--hx-acc)); }
.wh-chip:hover { border-color: var(--t-t, var(--hx-acc2)); }

/* ---------- 详情图标框 / 信息条 / 凹槽：统一到同一套色阶 ---------- */
.wh-dt-ic { background: var(--t-m, var(--ab-c2)); border-color: var(--ab-line); gap: 8px;
  box-shadow: inset 0 1px 0 rgba(182, 213, 203, .20), inset 0 -8px 0 var(--t-b, var(--ab-c1)); }
.wh-dt-ic.r-rare, .wh-dt-ic.r-epic, .wh-dt-ic.r-legend { border-color: var(--ab-line); }
.wh-grid { background: var(--ab-c0); border-color: var(--ab-line); }
.wh-side { box-shadow: inset 1px 1px 0 rgba(255, 196, 132, .10), inset -1px -1px 0 rgba(0, 0, 0, .45); }
.wh-kpi, .wh-head, .wh-dt-sec, .wh-dt-act { border-color: var(--ab-line); }
.wh-head.wh-head-b { border-bottom-color: rgba(232, 180, 90, .38); }
.wh-dt-sec::before { background: var(--ab-line); }

/* ============================================================
   玩法规则 · 翻页式（2026-10-03 第十轮 → 第十一轮改版）
   ------------------------------------------------------------
   用户：「玩法规则显示改成翻页形式的 每一页显示不同方面的内容」
    → 再：「完成按键去掉改成一个 X 放到界面的右上角 翻页键放在界面的左右边」
    → 三度改：「页面不要有上下滑动的功能 翻页键简化一下 内容不要紧贴边缘或边框
              文字要清晰可见不要有挡住的情况」。
   6 页，一页一个方面；现在的翻页三路：
     ① 顶上的章节条（点谁跳谁）② **页框左右两侧的 ‹ › 键** ③ ←/→ 方向键
   关闭 = **右上角一个 ×**（底部那条「完成」整条撤掉，面板随之矮一截）。

   ★★ 宽度仍是一条算式，动任何一项都要重算 —— 目的是让图解保持 940px 的 1:1：
        1164（弹窗宽） − 4（弹窗左右各 2px 边框） − 40（弹窗左右各 20px 内边距） = 1120
        1120 − 44×2（左右翻页键） − 12×2（两个间隙） = 1008（中间那一列）
        1008 − 4（页框左右各 2px 边框） − 64（页框左右各 32px 内边距） = 940
      ★ 页框**不再滚动**（第三轮改版的头号要求）⇒ 滚动条问题整条消失，但页框高度必须
        ≥ 「最长页的自然高 + 上下内边距 48 + 边框 4」= 604 + 52 = 656，取 **668** 留 12px 余量。
      ★ 图解原来挂在开边的 img 上（border 1px）——box-sizing 是 border-box，
        1px 边框会把图像内容压到 938 ⇒ 顺手换成 outline（不占布局）。
      ★ 改完必量：img 的 getBoundingClientRect().width 要**正好 940**。
   ★ **不滚动是硬的**：`.rules-view` 与 `.modal.rules-modal` 都是 `overflow:hidden`
     （后者压掉 style.css 里 `.modal{overflow:auto}` 那条）—— 用户明确不要上下滑动。
     代价：内容一旦超出页框高度就是**被裁**，所以「改内容 ⇒ 重量自然高」是每次的收尾动作。
   ★ 翻页键简化（第三轮）：56×88 的实心竖条 → **44×44**；
     第四轮再简（用户：「左右按键和 X 键简化成没有边框形式 左右按键样式改成 <> 形式的」）：
     **三个键全部脱框** —— 无 border、无底色、无圆角，只剩字符本身；箭头由 ← → 改成
     ASCII 的 `<` `>`（HTML 里写 &lt; &gt;，别写 ‹ ›：后者在 zpix 里画不实）。
     ★ 盒子尺寸一个没动（44×44 / 32×32）⇒ 下面的算式与图解 1:1 完全不受影响。
   ★ 内边距全线放松：页框 16/18 → **24/32**；章节条 gap 8→12、内边距 12→16。
     ★ 章节条 6 等分必须是**整数宽**：1008 − 5×12 = 948，948 ÷ 6 = **158**（像素字体
       落在半像素上会发糊，所以 gap 选 12 而不是 8）。
   ★ 主风格不变：深色深渊调 + 2px 实边 + 圆角沿用 --ab-r 一档，全程无渐变。
   ============================================================ */

/* position:relative 是给右上角那个 × 用的；弹窗本来没有定位上下文（.modal::before
   那个涟漪是贴着遮罩算的），只在这一屏补上，别的面板不受影响。
   ★ overflow:hidden 要 !important：style.css 的 `.modal{overflow:auto}` 是同一层
     写下来的，不管住它，滚轮依然能在整块弹窗上滑。 */
.modal.rules-modal {
  max-width: 1164px !important;
  max-height: 94vh !important;
  overflow: hidden !important;
  position: relative !important;
}

/* ---------- 骨架：左键 ｜ 章节条 + 页框 ｜ 右键 ---------- */
.rules-body { display: flex; gap: 0 12px; }
.rules-main { flex: 1 1 auto; min-width: 0; }
.rules-side {
  flex: 0 0 44px; width: 44px;
  display: flex; align-items: center; justify-content: center;
  /* ★ 让键心与**页框**的垂直中心对齐，而不是整列的中心：
     上边留出「章节条 56 + 它下面的外边距 16」= 72，剩下的 668 里居中 ⇒ 正好落在页框腰部。
     （正好：rules-body 高 72+668=740，页框中心 72+334=406，而 [72,740] 的中点也是 406。） */
  padding-top: 72px;
}
/* 翻页键（第四轮简化）：**无边框、无底色、无圆角的裸箭头**。
   ★ 字符用 ASCII 的 < >（U+003C/003E，HTML 里写成 &lt; &gt;）——
     ★★ 别用 ‹ ›（U+2039/203A）：zpix 里这两个单书名号只画得出几个像素点、细得发糊。
     ASCII 尖括号在这套像素字体里是完整点阵，从 12 到 48px 都立得住。
   ★ 盒子仍是 44×44（宽度算式基准之一），**只脱外观、不改尺寸** —— 图解 1:1 不受影响。
     没有 border ⇒ 盒子的 border-box 就是 44，与原来（44 含 2px 边）外沿完全一致。
   ★ 失去边框后，可用状态就只能靠**颜色**说话：默认灰蓝、hover 提到近白、禁用压到 30%
     （★ 禁用别压太狠：22% 在深底上几乎看不见，玩家会以为「这一侧没渲染」。） */
.rules-arrow {
  width: 44px; height: 44px; padding: 0;
  display: flex; align-items: center; justify-content: center;
  font-family: inherit; font-size: 48px; line-height: 48px;
  color: #a9bdc6; cursor: pointer;
  border: 0; background: none;
  clip-path: none !important; border-radius: 0 !important;
  transition: color .12s linear;
}
.rules-arrow:hover:not([disabled]) { color: #f2f9fb; }
.rules-arrow[disabled] { opacity: .30; cursor: not-allowed; }

/* ---------- 右上角：页码 + 关闭 × ---------- */
.rules-head {
  position: absolute; top: 20px; right: 20px; z-index: 2;
  display: flex; align-items: center; gap: 12px;
}
.rules-head .rules-cnt { font-size: 12px; letter-spacing: 2px; color: #7f97a2; }
.rules-head .rules-cnt b { color: var(--hx-acc); }
/* × 与翻页键同一套「裸字符」语言：无边框、无底色、无圆角。
   ★ 盒子仍是 32×32（绝对定位的锚点尺寸），只脱外观 ⇒ 距弹窗右上角仍是 22px。 */
.rules-x {
  width: 32px; height: 32px; padding: 0;
  display: flex; align-items: center; justify-content: center;
  font-family: inherit; font-size: 24px; line-height: 24px;
  color: #93a8b2; cursor: pointer;
  border: 0; background: none;
  clip-path: none !important; border-radius: 0 !important;
  transition: color .12s linear;
}
.rules-x:hover { color: #f2f9fb; }

/* ---------- 章节条：一页一个按钮（2026-10-05：6 格 → 2 格，flex 自适应，CSS 未动） ----------
   ★ gap 必须是 12：1008 − 5×12 = 948，948 ÷ 6 = 158 整数宽。★★ 2026-10-05 章节条砍到 2 格
     （用户「只留下战斗和关卡就行」）：1008 − 12 = 996，996 ÷ 2 = 498 —— 仍是整数宽，规则不变。
     用 8 的话每格 161.33px，像素字落在半像素上就发糊。 */
.rules-nav { display: flex; gap: 12px; margin: 0 0 16px; }
.rules-nav .rn {
  flex: 1 1 0; min-width: 0; height: 56px;
  display: flex; flex-direction: column; align-items: flex-start; justify-content: center; gap: 4px;
  padding: 0 16px; cursor: pointer; text-align: left; font-family: inherit;
  border: 2px solid var(--ab-line); background: var(--ab-c1);
  clip-path: inset(0 round var(--ab-r-sm)) !important;
  border-radius: var(--ab-r-sm) !important;
}
.rules-nav .rn b { font-size: 12px; line-height: 12px; letter-spacing: 2px; color: #5f6f79; }
.rules-nav .rn i { font-style: normal; font-size: 12px; line-height: 16px; letter-spacing: 1px; color: #b9cad1; }
.rules-nav .rn:hover { border-color: var(--hx-acc2); background: var(--ab-c2); }
.rules-nav .rn.on { border-color: var(--hx-acc); background: var(--ab-c3); }
.rules-nav .rn.on b { color: var(--hx-acc); }
.rules-nav .rn.on i { color: #eef6f8; }

/* ---------- 页框：定高 · 不滚动 · 内边距放松 ----------
   ★ 定高取「最长页的自然高 604 + 上下内边距 48 + 边框 4 = 656」，给到 **668**（余 12）。
     可用高 = 668 − 4 − 48 = 616 ⇒ 最长的那页（链条，604）也完整落在一屏里。
   ★ 没有 overflow-y:auto、也没有藏滚动条的补丁了 —— 页框**根本不滚**。
     这正是用户第三条要求：「页面不要有上下滑动的功能」。
     ★ 副作用：以后往任何一页加内容都要重量自然高（隐藏页量不到，要临时 .on + minHeight:0）。 */
.rules-view {
  height: 668px; overflow: hidden;
  padding: 24px 32px;
  border: 2px solid var(--ab-line); background: var(--ab-c0);
  clip-path: inset(0 round var(--ab-r)) !important;
  border-radius: var(--ab-r) !important;
}
.rules-page { display: none; }
.rules-page.on { display: block; }
/* 原来的右下角 96px 页码水印（`01`~`06`）已撤：它压在正文右下角上，
   正是用户说的「文字……有挡住的情况」—— 短页下部留白就让它留着，不再拿装饰去补。 */
.rules-page > .help-sec:first-child > h4 { margin-top: 0; }
.rules-page .rules-diagram { margin: 0 0 16px; }
.rules-page .rules-diagram img {
  border: 0 !important;                                   /* 见上：border 会吃掉 2px 图像内容 */
  outline: 1px solid rgba(126, 176, 190, .16);
  outline-offset: -1px;
}
.rules-page .help-sec { margin-bottom: 12px; }
.rules-page .help-sec p { line-height: 24px !important; }   /* 26 → 24，仍是 12 的倍数，一页多塞一行 */
/* 末节的 margin-bottom 归零。★ 页尾原来还挂着一个页码水印 <i>（已撤），
   当时必须用 div:last-of-type 才躲得开它；现在页尾就是 div，两种写法等价，
   但继续用 last-of-type 更稳（将来再往页尾放行内装饰也不会失效）。 */
.rules-page > div:last-of-type { margin-bottom: 0; }

/* （原「翻页条：与完成同一排」那一整段已随底栏撤掉 —— 翻页键改到左右两侧，
   关闭改到右上角 ×，详见上面 .rules-body / .rules-head。） */

/* ---------- 玩法规则（2026-10-12 换版：上游全文 · 单页长滚动） ----------
   ★ 2026-10-12 用户拍板「玩法规则整块换成上游版」：正文改用上游 20261006dq 的规则全文
     （含新增的「✦ 遗物」节点、怪物「凝视/反召」等改动），版式回到上游的 .help-sec 分段。
   ★★ 上面这一整段 .rules-body / .rules-arrow / .rules-head / .rules-nav / .rules-view /
     .rules-page / .rules-empty 全部变成**死代码**（ui.js 里已不再产生这些元素）——
     留着不影响渲染，等下一轮清理时再删；保留是为了万一要回退翻页版，样式还在。
   ★ 正文容器：上游的规则是**单页长滚动**，所以这里给 .rules-scroll 一个视口内的高度上限，
     超出就由它自己滚（不动 .modal 的 overflow —— 那是给 ::before 涟漪压边用的）。
     高度取 64vh：定高 0.2.2 弹窗在 1080 高下量得约 700+，64vh≈691，留出标题与「完成」两行。 */
.set-pane.rules-scroll {
  max-height: 64vh;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding-right: 10px;      /* 给滚动条留位，免得压住右侧文字 */
}
.set-pane.rules-scroll::-webkit-scrollbar { width: 8px; }
.set-pane.rules-scroll::-webkit-scrollbar-track { background: #070d12; }
.set-pane.rules-scroll::-webkit-scrollbar-thumb { background: #2b4652; border-radius: 4px; }

/* ============================================================
   三整屏（2026-10-03 第十八轮 · 手绘稿实装）
   ── 地图屏 #app ｜ 装备屏 #gearScreen ｜ 市场屏 #shopScreen
   与 proto/ 的静态稿同一套几何：
     HUD 96 ｜ 面板 2px 实边 + 圆角三档（--ab-r / -sm / -panel）
     ｜ 地图节点 96 · 列距 240 · 行距 224（0,224,448 → 底 896）
   ★ 布局仍然是**流式**的（height:100vh + flex），不写死 1920×1080 ——
     写死会把原有的窄屏适配一刀切掉；在 1920×1080 下量出的几何与手绘稿一致。
   ★★ 这一段是「整屏化」的补丁层：只覆盖位置与尺寸，**不碰**玩法语义类
      （.cell / .item / .bench .bitem / .stats-grid 内部结构）。
   ============================================================ */

/* 封印匣在两个屏里各出现一次（装备屏可编辑 / 市场屏只读预览），
   宽度必须钉成同一个值 —— readCellSize() 量的是「当前可见的那个」，
   两边宽度不同就会算出两种格子尺寸，一眼看出不一致。 */
:root { --bag-w: 744px; }

.hidden-screen { display: none !important; }

/* ---------- ① 三屏外壳 ---------- */
#app, #gearScreen, #shopScreen {
  display: flex; flex-direction: column;
  width: auto; max-width: none; height: 100vh;
  margin: 0; padding: 0; gap: 0;
}
#app.hidden-screen, #gearScreen.hidden-screen, #shopScreen.hidden-screen { display: none !important; }

/* ---------- ② 顶部 HUD（三屏共用；手绘稿标「一样」） ---------- */
.hud {
  flex: 0 0 auto; height: 96px; position: relative;
  display: flex; align-items: center; gap: 24px;
  padding: 0 32px;
  border: 0 !important; border-bottom: 2px solid var(--ab-line) !important;
  border-radius: 0 !important; clip-path: none !important;
  background: rgba(6, 12, 17, .86) !important;
}
.hud-face {
  flex: 0 0 auto; width: 80px; height: 80px; display: grid; place-items: center;
  border: 2px solid var(--ab-line); border-radius: var(--ab-r); background: var(--ab-c1);
}
.hud-face img { width: 64px; height: 64px; image-rendering: pixelated; }
.hud-hearts { flex: 0 0 auto; display: flex; gap: 8px; }
.hud-hearts .hh { width: 32px; height: 24px; display: block; color: var(--red); }
.hud-hearts .hh.off { color: #2b4652; }
.hud-hp { flex: 0 0 auto; display: flex; align-items: baseline; gap: 8px; }
.hud-hp b { font-size: 36px; line-height: 36px; letter-spacing: 2px; color: #e6eef2; }
.hud-hp b.rd { color: var(--red2); }
.hud-hp .sl { font-size: 24px; color: #4d6472; }
/* ★ 2026-10-04（用户红圈）：HUD 里那条「血量 X/Y · 债券 Z」进度条（#debtBar）已删 ——
   血量数字就在左边、债券就在右边，条子只是把同一组数字又说了一遍。
   连带 `.hud .bar` / `.hud .bar-text` 两条覆盖规则一并撤掉。 */
.hud-bonds { flex: 0 0 auto; display: flex; align-items: center; gap: 12px; }
.hud-bonds .co {
  width: 32px; height: 32px; border-radius: 50%;
  border: 2px solid var(--gold); box-shadow: inset 0 0 0 4px rgba(232, 180, 90, .28);
}
.hud-bonds b { font-size: 36px; line-height: 36px; letter-spacing: 2px; color: var(--gold2); }
.hud-bonds i { font-style: normal; font-size: 12px; letter-spacing: 2px; color: #6f8b96; }
.hud-r { margin-left: auto; display: flex; align-items: center; gap: 20px; }
.hud-entry { display: flex; flex-direction: column; align-items: center; gap: 8px; }
.hud-entry > i { font-style: normal; font-size: 12px; line-height: 12px; letter-spacing: 2px; color: #6f8b96; }
/* ★ 图标按钮做成 52 + 8 + 12 = 72 的竖排，稳稳落进 96 高的 HUD ——
   用绝对定位的 ::after 挂名字会溢出 HUD 一截。
   ★★ 2026-10-04 用户「右上角图标缩小一点」⇒ 72×72 收到 52×52。
      图内尺寸只能取 UI 图标的**整数倍**：原生 height 28~34 ⇒ 清晰档只有 34(1x) 与 68(2x)。
      这里取 34 —— 即回到图标的原生像素尺寸，比 68 更锐（68 是 2x pad 放大的）。
      想要介于两者之间的 51/56 会落成 1.5x 非整数倍采样，像素画反而碎。 */
.hud-ic {
  width: 52px; height: 52px; padding: 0; cursor: pointer;
  display: grid; place-items: center;
  border: 2px solid var(--ab-line) !important; border-radius: var(--ab-r-sm) !important;
  background: var(--ab-c1) !important; clip-path: inset(0 round var(--ab-r-sm)) !important;
}
.hud-ic img { width: 34px; height: auto; image-rendering: pixelated; }
.hud-ic:hover { border-color: var(--hx-acc2) !important; background: var(--ab-c2) !important; }
.hud-ic.on { border-color: var(--hx-acc) !important; background: var(--ab-c3) !important; }
.hud .menu-back { flex: 0 0 auto; }

/* ---------- ③ 面板/标题条：三屏统一「56 高的头 + 无内边距的身」 ---------- */
#gearScreen .panel, #shopScreen .panel {
  padding: 0 !important;
  border: 2px solid var(--ab-line) !important;
  background: rgba(9, 17, 24, .88) !important;
}
/* 面板自己就是一根竖着的 flex —— 否则里面的 flex:1（buff 列、bag 区）全部失效：
   .panel 在 style.css 里只写了背景/边框/内边距，display 是默认的 block。 */
#gearScreen .panel { display: flex; flex-direction: column; }
#gearScreen .panel-head, #shopScreen .panel-head {
  flex: 0 0 auto; height: 56px; margin: 0 !important;
  display: flex; align-items: center; gap: 12px;
  padding: 0 20px; border-bottom: 2px solid var(--ab-line);
}
#gearScreen .panel-head h3, #shopScreen .panel-head h3 {
  font-size: 24px; line-height: 24px; letter-spacing: 4px; font-weight: 400; color: #cfe0e6;
  flex: 0 0 auto; white-space: nowrap;   /* 面板头 56 高，标题一换行就顶出去 */
}
#gearScreen .panel-head h3::before, #shopScreen .panel-head h3::before {
  content: ''; display: inline-block; width: 4px; height: 20px;
  background: var(--hx-acc2) !important; margin-right: 12px; vertical-align: -3px; border-radius: 0 !important;
}
#gearScreen .panel-head .small, #shopScreen .panel-head .small { margin-left: auto; letter-spacing: 2px; color: #6f8b96; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ============================================================
   屏 ③ 地图（整屏横排节点树）
   ============================================================ */
#app .map-main { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.map-stage { flex: 1; min-height: 0; position: relative; overflow: hidden; }

/* 2026-10-04：从「只横滚」改成**双向可滚** —— 放大到 2x 时画布比视口还高，
   纵向也得能看，否则放大以后只能盯着最上面一行节点。
   滚动条照样藏掉（右下角有倍率控件、底部有「滑动向左看」，拖拽本身也在提示能滑）。
   ★ cursor:grab 是拖拽平移的提示（拖动逻辑见 ui.js 的 bindUI）。 */
.map-wrap {
  width: 100%; height: 100%; padding: 0;
  overflow: auto;
  overscroll-behavior: contain;
  scrollbar-width: none;
  cursor: grab;
}
.map-wrap::-webkit-scrollbar { width: 0; height: 0; }
.map-wrap.grab-on, .map-wrap.grab-on * { cursor: grabbing !important; }

/* ★★ 2026-10-04（用户「下方的滑动条去掉」）：地图区底沿那条 10px 横向滚动条。
   为什么上面 `.map-wrap` 里的 `scrollbar-width:none` 不生效 —— 两条一起踩：
     ① style.css:1038 有一条**带 id** 的
        `#bagWrap,#mapWrap,.bag-panel,.map-panel{scrollbar-width:thin; scrollbar-color:#2a3d47 #070d12}`，
        (1,0,0) 直接压过本层的 (0,1,0)；
     ② 只要 `scrollbar-width` 被设成非 auto 值，Chromium 就**整条忽略**
        `::-webkit-scrollbar` 的样式 ⇒ 本层那句 `width:0` 也一起失效。
   实测（incoming-bd/probe_scroll.py，不藏滚动条的窗口 1906×956）：滚动条正好压在地图底沿
   y 787–796，thumb 取 #2a3d47、track 取 #070d12，与用户截图上那条亮线**逐像素吻合**。
   修法：拿 id 特化 + !important 把 `none` 钉死。
   ★ `none` = 不画也不占位，但**滚动照旧**（滚轮 / 拖拽 / 双指都不受影响）——
     这正是「滑动向左看 →」想要的：能滑，但不要再摆一根条。 */
#mapWrap {
  scrollbar-width: none !important;
  scrollbar-color: transparent transparent !important;
}
#mapWrap::-webkit-scrollbar { width: 0 !important; height: 0 !important; }

/* ★★ 缩放走 transform，而 **transform 不改变布局尺寸** ⇒
   必须有一层 .map-sizer 顶着「放大后的尺寸」把滚动区撑开，
   否则放大以后根本滚不到右边（内容溢出但滚动条认为没东西可滚）。
   .map-canvas 只按 1x 画，缩放时边框和文字一起缩放，不必重画几百个节点。 */
.map-sizer {
  position: relative;
  /* ★★ 2026-10-12：石纹铺在滚动内容上 ⇒ 拖地图时纹理跟着图标一起动。
     128px 原生 1:1 平铺（不缩放保持像素质感），再压一层暗罩让图标更突出。 */
  background:
    linear-gradient(rgba(5,8,12,.30), rgba(5,8,12,.30)),
    url('../assets/bg/floor-tiles.png') 0 0 / 128px 128px repeat;
}
.map-canvas { position: absolute; margin: 0 !important; transform-origin: 0 0; }

.map-svg path { stroke: #21414e; stroke-width: 2; filter: none; }
.map-svg path.avail { stroke: var(--gold); stroke-width: 2; stroke-dasharray: 8 6; filter: none; }
.map-svg path.on { stroke: var(--gold); stroke-width: 2; filter: none; }

/* 节点：38px 圆点 → 96px 方框（手绘稿的做法：一个方块里放一个图标）
   ★ 图尺寸必须是素材原生的整数分之一：怪物 256→64（0.25×）、UI 图标→68 高（2×）。
   ★★ 这里**不能**用 clip-path 做圆角：clip-path 会连子元素一起裁掉，
      而节点下方那行名字（.cap，top:100%+8px）整条都在框外 ⇒ 名字会凭空消失。
      只写 border-radius 就够（它不裁子元素）。 */
.map-node {
  width: 96px; height: 96px; border-radius: var(--ab-r-sm);
  border: 2px solid var(--ab-line); background: var(--ab-c1);
  display: flex; align-items: center; justify-content: center;
  box-shadow: none; font-size: 0; color: #9fb6c0;
  clip-path: none;
}
.map-node img { display: block; width: 64px; height: 64px; image-rendering: pixelated; }
/* ★★ 2026-10-12（用户红绿点标注）：游戏里图标中点比框中点偏上 ~12px（独立环境测 delta=0，
   真机有偏 —— flex 居中在真实环境不可靠）。改**绝对定位强制居中**：
   图标中心永远钉在框中心，与 flex / 字号 / 基线 / cap 是否参与布局全部解耦。 */
.map-node img.map-ic {
  position: absolute !important;
  left: 50% !important; top: 50% !important;
  /* ★★ 2026-10-12 二次修：原来用 transform:translate(-50%,-50%) !important 居中 ——
     但 CSS 里 !important 声明会**压过动画的 transform**，导致选中动效（眨眼/摇晃/旋转）全部失效。
     改用负 margin 居中（64px 图标 -32 / 48px 小图标 -24），transform 完全让给动画。 */
}
.map-node img.map-ic { margin: -32px 0 0 -32px !important; }
.map-node img.map-ic.ic-sm { margin: -24px 0 0 -24px !important; }

/* ============ 节点图标动效（2026-10-12 用户：鼠标放哪个图标哪个就动） ============
   ★ hover 触发：动画绑在 :hover 上，鼠标离开即停；未悬停保持静止，避免满屏都在动。
   ★ 居中已改为负 margin，动画的 transform 不再与居中冲突。
   ★★ 2026-10-12 统一：各类型的花式动效（眨眼/摇晃/旋转…）用户觉得不好看，
      全部改成与「遭遇」同款的发光呼吸（一闪一闪）。所有节点共用同一个 keyframes。 */
@keyframes nodeblade { 0%,100%{filter:drop-shadow(0 0 0 rgba(232,180,90,0)) brightness(1)} 50%{filter:drop-shadow(0 0 5px rgba(232,180,90,.75)) brightness(1.22)} }
.map-node:hover img.map-ic { animation-name: nodeblade; animation-duration: 1.4s; animation-iteration-count: infinite; animation-timing-function: ease-in-out; }

/* ============ 过关态 .done：灰化 + 一道斜划刀痕（对勾徽章已按用户要求去掉） ============ */
/* style.css 基线的 .map-node.done::after 还画着一枚 ✓，一并关掉 */
.map-node.done::after { content: none !important; }
/* ★★ 2026-10-12 优化（用户「两边有从大到小的感觉、要有刀化的感觉」）：
   原来是一根等宽 3px 的渐变条，太像"画笔横杠"。改成刀刃形：
   · clip-path 六边形 → 两端收成尖，中段最宽（刀锋下刀重、起刀轻的收势）
   · 主体是深色划痕，叠一条错位的高光细边（刀刃反光），一刀过去两道痕
   · 斜角 -26°，宽度拉长到 130%，划过整个图标 */
.map-node .scratch {
  position: absolute; left: 50%; top: 50%;
  width: 130%; height: 9px;
  /* 刀刃形：左端尖(0) → 中段最宽(50% 满宽) → 右端尖(100%)，从大到小 */
  clip-path: polygon(0 44%, 14% 16%, 50% 12%, 86% 20%, 100% 56%, 72% 86%, 46% 88%, 12% 78%);
  background: linear-gradient(90deg, rgba(20,26,33,.28), rgba(10,14,19,.95) 30%, rgba(10,14,19,.92) 60%, rgba(20,26,33,.35));
  transform: translate(-50%,-50%) rotate(-26deg);
  pointer-events: none; z-index: 3;
}
/* 刀刃高光：一条细亮边，略微错位，模拟金属反光划过 */
.map-node .scratch::after {
  content: '';
  position: absolute; left: 10%; top: 20%;
  width: 80%; height: 1.5px;
  background: linear-gradient(90deg, transparent, rgba(180,205,218,.55) 35%, rgba(180,205,218,.2) 70%, transparent);
  transform: rotate(0deg);
}
.map-node.done img.map-ic { filter: grayscale(.7) brightness(.82); }

/* ============ 悬停：不再用框高亮，改为**图标发光呼吸（一闪一闪）** ============ */
/* 框已彻底去掉：hover 不改背景、不改边框；「一闪一闪」由上方 nodeblade 动画承担，
   无需再单独写静态 filter（会被动画的 filter 覆盖）。 */
#app .map-node.avail:hover,
#app .map-node.cur:hover {
  background: none !important;
  border-color: transparent !important;
  box-shadow: none !important;
}
/* ★ 2026-10-05：AI 节点图标是 **64×64**，这里给 1:1。
   原来写 `width:auto; height:68px` 是为了把原版 34×32 的图标拉到 68px ——
   那是 **2.125 倍非整数缩放**，正是铁律 12 要避免的。 */
.map-node img.map-ic { width: 64px; height: 64px; }
/* ★ 2026-10-12：boss 框尺寸由下方已有的 `.map-node.boss{112×112 + margin:-8px}` 接管
   （大框摊边后中心仍对准节点点），此处不再重复声明；不居中的真因见上面的绝对定位修复。
   用户「遭遇/黑市/祭坛的图标缩小一点」：这三类用小一号的 48px（素材内容居中已实测）。 */
.map-node img.map-ic.ic-sm { width: 48px; height: 48px; }
.map-node:not(.avail):not(.cur):not(.boss):not(.done) { opacity: .62; }
/* ★★ 2026-10-12（用户「框你没去掉」三处都要去）：金框/红框/悬停框全部取消。
   节点彻底不带边框，状态只靠图标本身表达 —— 可走=全亮、当前=微光、过关=灰化+划痕。 */
.map-node.avail { cursor: pointer; }
/* ★★ 2026-10-04（用户「地图上添加鼠标放在所选按键上会高亮」）：
   原来这条 hover 内环**根本没有生效** —— ui-hollow.css:286 写着
   `.map-node { box-shadow: none !important; }`，而 !important 只能被 !important 打败，
   本层这条没带 !important ⇒ 内环被整条吞掉，悬停只剩下 ui-hollow 给的
   `rgba(158,210,222,.12)` 那一点冷色底（实测：hover 时 computed box-shadow 是 `none`），
   一眼看不出来，所以用户说「没有高亮」。
   ★ 修法两条一起上：① 补 !important；② 把特异性抬到 `#app .map-node.avail:hover`
     （1 id + 3 class），压过 ui-hollow 的 `.map-node.avail:hover`（0,3,0，同样 !important）。
   ★ 手法仍是像素感：**暖金内环 + 同色淡底**，不用 transform / 渐变
     （老基线 style.css 的 `scale(1.14)` 早已被 ui-hollow 的 `transform:none !important` 按住）。
   ★★ 同一个坑把 `.map-node.cur`（当前所在节点）的内环也吞了 —— 顺手一起补，
     否则「已站在哪个点」和「哪些点能走」只靠边框色差，几乎分不出来。 */
/* ★★ 2026-10-05（构建 rz）：`.cur`（当前所站、还没办完的节点）现在**可点**了 ——
   读档 / 刷新后点它就能把没办完的事接着办（病灶与修法见 ui.js 的 renderMap 点击绑定）。
   于是悬停描边跟可走节点共用同一套：都是「点下去会有反应」的东西，长得不该不一样。
   ★ 2026-10-12（用户「框你没去掉」）：旧版 hover 金框金底整块删除（新的图标发光 hover 见上方
     1535 区块）；.cur 的金边框 + inset 金内环也删 —— 状态全部由图标本身表达
     （动效 + 常驻微光），不再画框。 */
/* .cur 常驻一层柔和的金色微光（区别于 hover 的亮光），图标即状态 */
#app .map-node.cur img.map-ic {
  filter: drop-shadow(0 0 2px rgba(232, 180, 90, .55)) brightness(1.08);
}
/* 基线的 `.map-node` 是 cursor:grab（暗示「按住能拖地图」）⇒ 可点的 .cur 要换回手。 */
#app .map-node.cur { cursor: pointer !important; }
.map-node.cur::after { content: none; }
/* ★★ 2026-10-10（用户「闯过的关卡表现修改」）：旧版只把整节点压到 30% 透明度，
   和「还没走到」的节点几乎分不出来。新版：图标压灰但保持 55% 可辨，
   右上角挂一枚金色对勾徽章（.donetag，JS 在 nodeHtml / boss 节点里输出），
   边框转暗金 —— 一眼是「走过的」，不再是「消失的」。 */
.map-node.done { opacity: .55; }
.map-node.done { border-color: transparent; }
.map-node .donetag {
  position: absolute; right: -9px; top: -9px;
  width: 22px; height: 22px; border-radius: 50%;
  background: #1c2a20; border: 2px solid var(--gold);
  color: var(--gold); font-size: 13px; line-height: 18px; text-align: center;
  box-shadow: 0 0 0 2px rgba(4, 8, 13, .85);
  pointer-events: none;
}
/* ★★ 2026-10-04：ui-hollow 里还留着老基底那条 `.map-node.boss{width:46px!important;height:46px!important}`
   （那时候地图节点是 38px 小圆点，关底只大一圈）。本层是 96px 方框，关底本该 112 ⇒ 那条 !important
   把这里压掉，关底就成了一个 46px 的**空红框**（80px 的图直接溢出框外）。
   本层加载在后 ⇒ 同级 !important 取后者，写死 112 即可。 */
.map-node.boss {
  width: 112px !important; height: 112px !important;
  margin: -8px 0 0 -8px;   /* 大出来的 16px 摊到两边 */
}
/* ★ 2026-10-05：关底原来放 80×80 的怪物立绘 —— 现在换成 64×64 的 AI 图标，
   必须改回 **64**（80 就是 1.25 倍非整数缩放）。关底框仍是 112，四周留白多一点。 */
.map-node.boss img { width: 64px; height: 64px; }
.map-node .cap {
  position: absolute; left: 50%; top: calc(100% + 8px); transform: translateX(-50%);
  font-size: 12px; line-height: 12px; letter-spacing: 2px; color: #7f97a2; white-space: nowrap;
}
.map-node.boss .cap { top: calc(100% + 8px); }

/* ★ 2026-10-04（用户红圈 + 箭头）：利息行原本挂在页底工具条右端，搬到**地图上沿正中**。
   绝对定位挂在 `.map-stage`（overflow:hidden + position:relative）上，而 **不是** .map-wrap
   ⇒ 拖地图 / 缩放时它纹丝不动（否则会跟着画布一起滚走）。
   ★ pointer-events:none：地图要能拖拽平移，浮标压在上沿绝不能把指针吃掉。
   ★ 高度 32 / 内边距 16 / gap 8 全是偶数，字号 12 与站内规范一致。 */
.map-interest {
  position: absolute; left: 50%; top: 8px; transform: translateX(-50%);
  z-index: 3; pointer-events: none;
  display: flex; align-items: center; gap: 8px;
  height: 32px; padding: 0 16px;
  border: 2px solid var(--ab-line) !important; border-radius: var(--ab-r-sm);
  background: rgba(6, 12, 17, .78) !important;
  font-size: 12px; line-height: 12px; letter-spacing: 2px; color: #6f8b96;
  white-space: nowrap;
}
.map-interest b { color: var(--red2); }

/* 底部信息条：关卡块 ｜ 提示 ｜ 当前节点 ｜ 滑动提示 */
.map-bar {
  flex: 0 0 auto; height: 88px; display: flex; align-items: center; gap: 24px;
  padding: 0 32px; border-top: 2px solid var(--ab-line);
  background: rgba(6, 12, 17, .70);
}
.map-act { flex: 0 0 auto; display: flex; align-items: center; gap: 16px; }
.map-act .fl-ic {
  width: 56px; height: 56px; display: grid; place-items: center;
  border: 2px solid var(--ab-line); border-radius: var(--ab-r-sm); background: var(--ab-c1);
}
.map-act .fl-ic img { height: 40px; width: auto; image-rendering: pixelated; }
.map-act .fl-tx b { display: block; font-size: 24px; line-height: 24px; letter-spacing: 2px; color: var(--gold2); }
.map-act .fl-tx b .dim { font-size: 12px; letter-spacing: 2px; }
.map-act .fl-tx i { font-style: normal; font-size: 12px; line-height: 16px; letter-spacing: 2px; color: #7f97a2; }
.map-hint { flex: 1 1 auto; min-width: 0; font-size: 12px; line-height: 18px; letter-spacing: 1px; color: #9fb6c0; }
.map-node-now { flex: 0 0 auto; display: flex; align-items: baseline; gap: 8px; font-size: 12px; letter-spacing: 2px; color: #6f8b96; }
.map-node-now b { font-size: 24px; letter-spacing: 2px; color: var(--red2); }
.map-tip { flex: 0 0 auto; font-size: 24px; letter-spacing: 4px; color: #9fb6c0; }

/* 敌物预览浮层（旧版在右栏，整屏化之后挪到地图右上角）
   ★★ 2026-10-04 用户「右上角图标缩小一点」：面板 340 → 280；
      里面的怪物立绘 .enemy-art 104 → **64**（= 怪物原生 256 的 1/4）。
      顺带把旧版 104 的毛病一并修了：256/104 = 2.46 是非整数倍，缩到 64 才是整数分之一。 */
/* ★ 2026-10-04（用户红圈）：「此处的敌物」浮层（.map-intel）整块删除 ⇒ 这四条规则一并撤掉。
   浮层**内部**元素的样式（.enemy-* / .noreson / .trait / .intel-btn）仍留在 style.css，
   renderEnemy 的数据逻辑也还在 —— 将来若要把敌情挪到别处，样式与逻辑都是现成的。 */

/* ★ 2026-10-04（用户红圈）：右下角那组缩放按钮（`.map-zoom`）已删 —— 控件与样式一并撤掉。
   缩放能力本身保留：滚轮 / 双指仍然生效（ui.js 的 setMapZoom / applyMapZoom 未动，
   只是不再有可见的档位标签与 +/-）。 */

/* ============================================================
   屏 ② 装备
   Buff 竖列 ｜ 封印匣 ｜ 详情 + 当前属性 ｜ 局外装备栏 ｜ 底 装备暂存
   ============================================================ */
.gear-main { flex: 1; min-height: 0; display: flex; gap: 24px; padding: 24px 32px 0; }

/* 左一：Buff 竖列（原来是封印袋下面一条横排） */
.gear-buff { flex: 0 0 152px; }
.gear-buff .buff-bar {
  flex: 1; min-height: 0; display: flex; flex-direction: column;
  align-items: center; gap: 12px; padding: 20px;
  margin: 0 !important; border: 0 !important; background: none !important;
  overflow-y: auto; overflow-x: hidden;
}
/* ★ .buff 在 style.css 里是 42×42，我上一版写 width:100% 把它拉成了横条。
   竖列里要的是「固定方格子居中」—— 尺寸与 HUD 的图标按钮对齐（72）。 */
.gear-buff .buff {
  width: 72px; height: 72px; margin: 0 auto; flex: 0 0 auto;
  border-radius: var(--ab-r-sm) !important;
}
.gear-buff .buff .buff-ic img { width: 48px; height: 48px; }
/* 空态在 152 宽的竖列里：必须允许断行 + 居中，否则会挤成一条竖着的窄杠 */
.gear-buff .buff-empty {
  display: block; font-size: 12px; line-height: 20px; letter-spacing: 1px;
  color: #6f8b96; text-align: center; word-break: break-all; white-space: normal;
}

/* ★★ Buff 效果气泡（2026-10-04 用户反馈）
   原样式在 style.css：`.buff-tip` 挂在图标**上方居中**（bottom:calc(100%+8px); left:50%;
   translateX(-50%)）。而 Buff 列就在屏幕最左 ⇒ 气泡左半截整个溢出屏幕，
   又被 `.buff-bar` 的 `overflow-x:hidden` 按 padding box 裁掉
   —— 用户看到的就是「被边框挡住」。
   改成挂图标**右侧**：这里用 `position:fixed` 逃出 `.buff-bar` 的裁剪区
   （fixed 的包含块是视口，不受祖先 overflow 影响；祖上不能有 transform —— 装备屏没有）。
   坐标由 JS `placeBuffTip()` 在 hover 时写 left/top。
   ★ 这两条**不能加 `!important`**：`!important` 会压过 JS 写的 inline 样式，气泡就动不了了。 */
#gearScreen .gear-buff .buff-tip {
  position: fixed;
  left: 0; top: 0;                 /* 占位，实际由 JS 覆盖 */
  right: auto; bottom: auto;
  transform: none;
  width: 260px;
  z-index: 200;
}
#gearScreen .gear-buff .buff-tip::after { display: none; }   /* 原箭头朝下，挂右边后不再适用 */
/* ★ 光有上面这段还不够：祖先 `.panel` 的 clip-path 会把 fixed 气泡一起裁掉
   （clip-path 建包含块 + 裁剪）⇒ 必须配合下面这条 `#gearBuffPanel{clip-path:none}`。 */

/* 左二：封印匣 —— 格子居中，宽度由 --bag-w 钉死（= 市场屏那一份）
   ★ 居中交给外面那层 .bag-body（flex:1 + place-items:center），不要用 margin:auto 硬撑：
     面板里还有 .bag-hint / .bag-size 两个兄弟，auto margin 会把它们顶出面板下沿
     （实测上留 131 / 下留 202 且整体溢出 52px）。 */
.gear-main .bag-panel { flex: 0 0 var(--bag-w); }
.gear-main .bag-panel .bag-body {
  flex: 1 1 auto; min-height: 0;
  display: flex; align-items: center; justify-content: center;
}
.gear-main .bag-panel #bagWrap { margin: 0; align-self: auto; max-height: 100%; }
/* ★ style.css 给 #bagItems 写了 inset:6px（配 #bagWrap 的 padding:6px），
   但 ui-hollow 把 #bagWrap 的 padding 改成 0 之后 inset 没跟着改 —— 物品层整体
   右下偏 6px。这里把它归零，让「格子 / 物品 / 市场屏那份预览」三者严丝合缝。 */
#bagItems { inset: 0 !important; }
/* ============================================================
   ★★ 封印匣格子：未解锁 / 已解锁 必须一眼可分（2026-10-04 用户红圈）
   ── 为什么原来「长得一样」：ui-hollow 给 `.cell` 写了
      `background / border: ... !important`。`!important` 会压过**一切**非 important 的
      声明，于是 style.css 里 `.cell.locked`（透明底 + 透明边）、`.cell.buyable`（金虚线框）、
      `.cell.r-o / .r-a / .r-q`（三区染色）的**底色与边框全部失效**，
      只剩 box-shadow 那一圈内环还看得见 ⇒ 所有格子看上去一模一样。
      这里用更高特异性（#id + .cell + 修饰类）把它们拿回来，并刻意拉开四档：
          已解锁  = 有填充（按区染色）+ 实线边 + 区色内环   ← 「这里可以放」
          可刻格  = 无填充 + 金色虚线边 + 「+N」标价        ← 「花债券能刻开」
          未解锁  = 完全透明 + 极暗虚线边                   ← 「这里还没有」
          禁置    = 暗红填充 + 暗红实边 + ✕                 ← 「永远开不了」
   ★ 边框统一 1px（与原版同宽）：格子是 border-box，但 #bagItems 的物品层
     按 step() = --cell + gap 绝对定位，动边框宽度会让物品与格线错开。
   ============================================================ */
#gearScreen .cell.r-o, #shopScreen .cell.r-o {
  background: rgba(255, 209, 102, .22) !important;
  border: 1px solid rgba(255, 209, 102, .55) !important;
}
#gearScreen .cell.r-a, #shopScreen .cell.r-a {
  background: rgba(94, 200, 176, .18) !important;
  border: 1px solid rgba(94, 200, 176, .45) !important;
}
#gearScreen .cell.r-q, #shopScreen .cell.r-q {
  background: rgba(96, 118, 146, .22) !important;
  border: 1px solid #2c4453 !important;
}
#gearScreen .cell.buyable, #shopScreen .cell.buyable {
  background: none !important;
  border: 1px dashed rgba(232, 180, 90, .55) !important;
}
#gearScreen .cell.locked, #shopScreen .cell.locked {
  background: none !important;
  /* 暗但要看得见：比 ui-hollow 的默认格边（#17262f）略亮一档，
     靠「虚线 + 无填充」和已解锁的「实线 + 有填充」拉开，不靠亮度硬压。 */
  border: 1px dashed #1f313b !important;
}
#gearScreen .cell.sealed, #shopScreen .cell.sealed {
  background: rgba(58, 31, 36, .55) !important;
  border: 1px solid #4a2530 !important;
  color: #7a4a58 !important;
}

/* ★★ 2026-10-05（新版基底新增「入袋即锁」）：把 `.item.locked` 的整件描边**抢回来**。
   上面那批 `.cell.*` 只管「格子」，这里管**格子里的那件封印物本身**。
   坑：ui-hollow.css:348 有一条
       `.card, .buff, .item { box-shadow: none !important; }`
   —— 它是给旧版「卡片族」去盒子用的，但 `!important` 会连 style.css:297 的
       `.item.locked{ box-shadow: inset 0 0 0 2px var(--gold2) … }` **一起吃掉**
   （style.css 那条不带 !important ⇒ 必败）⇒ 被封住的封印物在皮肤下与普通件长得一样，
   玩家根本不知道该拿钥匙解哪一件。
   修法：同优先级（也带 !important）+ **更高特异性**（`.item.locked` 0,2,0 > `.item` 0,1,0）。
   不做 `#id` 前缀：封印匣在装备屏 `#bagWrap` 与市场屏 `#shopBagGrid` 各有一份，
   战斗中还有 `.bt-bag-layer` 一份 —— 用类选择器一次覆盖三处，不会漏。 */
.item.locked {
  box-shadow: inset 0 0 0 2px var(--gold2), 0 0 10px rgba(232, 180, 90, .30) !important;
}
.item.locked:hover {
  box-shadow: inset 0 0 0 2px var(--gold2), 0 0 14px rgba(232, 180, 90, .45) !important;
}
/* 角标 🔒 在 hollow 下是 9px 小字 + 1px 金边，本来就压得住；这里只把行高与内边距
   钉死，防止 zpix 行高把它撑成 2 行、盖住 1×1 件的名字。 */
.item .lock-dot { line-height: 1 !important; padding: 1px 2px !important; }

/* ★★ 2026-10-04（用户）：把底部统计条**定高**，让 `.bag-body` 的高度彻底不受内容影响。
   `.bag-meta` 里是若干 `.stat` 小卡（难度分 / 派系专精 / 三区统计 / 收容物），
   件数一变张数就变、还可能换行 ⇒ 它天生就会抖；更狠的是 style.css 的
   `.bag-meta:empty{display:none}`，背包一空**整块塌成 0**（实测 29 → 0）。
   封印匣面板高度是固定的 ⇒ 省下来的高度全归 `.bag-body`，里面的格阵就跟着上下跳
   （实测 18.5px，正是「拆下一件，格子位置就变」的另一半原因，前一半是格子尺寸）。
   这里定高 29（= 单行实测值）+ 空态照常占位。 */
#gearScreen #bagMeta, #shopScreen #bagMeta {
  flex: 0 0 auto; height: 29px; margin-top: 8px; overflow: hidden;
}
#gearScreen .bag-meta:empty, #shopScreen .bag-meta:empty {
  display: flex;   /* 空态也要占住这 29px（style.css 原本把它 display:none 掉） */
}

.bag-hint { padding: 0 20px 8px; font-size: 12px; line-height: 18px; letter-spacing: 1px; color: #6f8b96; }
.bag-size { padding: 0 20px 16px; font-size: 12px; line-height: 18px; letter-spacing: 1px; color: #6f8b96; }

/* 左三：详情（上，占满）+ 当前属性（下，随内容） */
.gear-right { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 24px; }
.gear-right #itemPanel { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.gear-right #itemInfo { flex: 1; min-height: 0; padding: 20px; overflow: auto; }
.gear-right #statsPanel { flex: 0 0 auto; }
.gear-right #statsGrid { padding: 20px; }

/* 左四：收容物（原「局外装备栏」）
   ★ 2026-10-04（用户）：删掉「留置」虚线块（原 #gearKeep）——它只是手绘稿里的
     一块示意装饰，ui.js 从未引用过 id，去掉后不牵连任何交互。
   ★★ 2026-10-04（用户「背包挡住丢弃区域了」）—— 真根因在这里，不在背包高度：
     `#gearLoadout` 的固有高是 488（面板头 56 + 槽区 4×88+3×12+内边距 40 + 边框 4），
     而 flex 项目的收缩下限默认是 `min-height:auto` = min-content = 488 ⇒ **它压不下去**。
     列高 = .gear-main 的高 = 窗口高 − 顶栏 96 − main 上留白 24 − 背包(24+224+32) − …
     窗口高 ≲ 1000px 时列高 < 488+24+88 = 600 ⇒ 整列内容顶出列外，
     `#discardZone`（margin-top:auto + flex:0 0 auto）被顺水推舟推到列**下方**，
     正好落在下面那条通长的背包面板上 —— 背包在 DOM 里排在 .gear-main 之后，
     同层绘制**画在上层**，于是「背包挡住了丢弃区」。
     修法：给这条链上每一层都开 `min-height:0` 并让**槽列表自己滚**（收容物板本身仍定住），
     丢弃区就永远待在列内、贴着列底。窗口再矮也只是槽列表出滚动条，不会外溢。 */
.gear-side { flex: 0 0 300px; display: flex; flex-direction: column; gap: 24px; min-height: 0; }
#gearScreen #gearLoadout { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
#gearOutSlots { flex: 1 1 auto; min-height: 0; overflow-y: auto; display: flex; flex-direction: column; gap: 12px; padding: 20px; }
#gearOutSlots .sl {
  flex: 0 0 auto;                  /* 槽恒定 88，窄了让 #gearOutSlots 出滚动条，别把槽压扁 */
  height: 88px; display: flex; align-items: center; gap: 12px; padding: 0 12px;
  border: 2px solid var(--ab-line); border-radius: var(--ab-r); background: var(--ab-c1);
  clip-path: inset(0 round var(--ab-r));
}
#gearOutSlots .sl.empty { border-style: dashed; background: none; }
#gearOutSlots .sl img { width: 64px; height: 64px; object-fit: contain; image-rendering: pixelated; }
#gearOutSlots .sl b { font-size: 24px; line-height: 24px; letter-spacing: 2px; color: #dfeaef; }

/* 右列底部：常驻的「丢弃」区（2026-10-04 用户）
   ★ 原来 #discardZone 是 body 级 fixed 浮层（style.css：right:24 / bottom:80 / 150×150），
     只在拖拽时才 remove('hidden') 浮现 —— 玩家平时根本看不见它。现在挪进本屏常驻。
   ★ 定位改 static 回到文档流：高 88 与局外装备栏的槽同高，margin-top:auto 贴底。
   ★ 圆角只写 border-radius，不用 clip-path（别给以后可能的内部缩放留坑）。 */
#gearScreen .discard-zone {
  position: static; left: auto; right: auto; top: auto; bottom: auto;
  width: auto; height: 88px; margin-top: auto; flex: 0 0 auto; z-index: auto;
  border: 2px dashed var(--red); border-radius: var(--ab-r);
  background: rgba(255, 77, 94, .10); color: var(--red2);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center; font-weight: 400; font-size: 12px; line-height: 18px; letter-spacing: 2px;
}
#gearScreen .discard-zone.hot {
  border-color: var(--red2); background: rgba(255, 77, 94, .28);
  transform: none;                 /* 文档流里不缩放 —— 免得盖住上面的面板 */
}
#gearScreen .discard-zone .small { font-size: 12px; line-height: 18px; letter-spacing: 1px; }

/* 底：背包（原「装备暂存」）
   ★★ 2026-10-04（用户）：**定高**，不再让它随内容长高。
   原来是 flex:0 0 auto + style.css 的 .bench-panel{max-height:260px} ——
   里一有东西面板就从 146 涨到 260，把上面的 .gear-main 压矮 114，
   封印匣面板跟着矮 ⇒ readCellSize() 每次重绘都算出一个不同的格子边长
   （用户原话：「拆下一个封印物，格子大小突然变大，放上又变小了」）。
   定高之后 gear-main 恒定，格子的**尺寸与位置**都不再随内容动。
   （ui.js 那边也同步把高度基准换成了 #gearScreen 自身高度，两条一起才是真稳。）
   ★ 2026-10-04（用户「背包区域向下缩小一点」）：240 → **224**，并把卡面图收到 64
   （沿用 style.css 窄屏那一档的尺寸）+ 内部边距 12→8 + 标题/提示各收 2px，
   保证「面板头 56 + 一行 3 张卡 + 底部提示」仍然**完整放得下、不出滚动条**。
   ★★ 高度一旦再动，必须同步改 ui.js 的 SCREEN_CHROME_H（= 180 + 本面板高，
   这边 224 ⇒ 404），否则封印匣格子会被算错尺寸。 */
#gearBench { flex: 0 0 auto; margin: 24px 32px 32px; height: 224px; max-height: 224px; }
#gearBench .bench { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 6px 20px; gap: 4px; }
#gearBench .bench-empty { padding: 12px 4px; }
/* 卡面与行距收紧 —— 只作用于背包面板这一份。
   ★ 数值是**量出来的**：224 高 ⇒ .bench 可用 164；
     满 3 件时的内容 = 面板头 14 + 4 + 卡 108 + 4 + 提示 16 + 内边距 12 = 158（余 6）。
     改任何一条都要重跑 verify_rename.py 的「装满 3 张卡不出滚动条」那条。 */
#gearBench .pack-art { height: 56px; }
#gearBench .pack-head { padding: 0 2px; }
#gearBench .pack-list { padding-top: 0; }
#gearBench .pack-tip { padding: 0 2px; }

/* ============================================================
   屏 ① 市场（原「黑市弹窗」整屏化）
   左 封印匣（只读预览）｜ 中 商品两位 ｜ 右 货架 2×2
   ============================================================ */
.shop-top {
  flex: 0 0 auto; height: 72px; display: flex; align-items: center; gap: 24px;
  padding: 0 32px; border: 0 !important; border-bottom: 2px solid var(--ab-line) !important;
  border-radius: 0 !important; background: rgba(11, 22, 29, .90) !important;
}
.shop-top .brand { font-size: 24px; line-height: 24px; letter-spacing: 4px; color: #9ed2de; }
.shop-top .brand i { font-style: normal; font-size: 12px; letter-spacing: 4px; color: #6f8b96; margin-left: 12px; }
.shop-top .kv { flex: 0 0 auto; display: flex; align-items: baseline; gap: 8px; font-size: 12px; letter-spacing: 2px; color: #7f97a2; }
.shop-top .kv b { font-size: 24px; line-height: 24px; color: var(--gold2); }
.shop-top .kv b.rd { color: var(--red2); }
.shop-top .kv b.gold { color: var(--gold); }
.shop-top .sbar {
  flex: 1 1 auto; max-width: 420px; height: 20px; overflow: hidden;
  border: 2px solid var(--ab-line); border-radius: var(--ab-r-sm); background: #070d12;
}
.shop-top .sbar i { display: block; height: 100%; width: 0; background: #b8414e; }
.shop-top .ttl { margin-left: auto; font-size: 36px; line-height: 36px; letter-spacing: 8px; color: #e6eef2; }

.shop-main { flex: 1; min-height: 0; display: flex; gap: 32px; padding: 24px 32px; }
.shop-bag { flex: 0 0 var(--bag-w); display: flex; flex-direction: column; }
.shop-bag-body { flex: 1; min-height: 0; display: grid; place-items: center; padding: 20px; }
.shop-plate { position: relative; }
.shop-grid { display: grid; gap: var(--gap); }
.shop-items { position: absolute; inset: 0; pointer-events: none; }
.shop-items .item { pointer-events: none; }
.shop-items .item .nm { font-size: 10px !important; }

.shop-goods { flex: 0 0 420px; display: flex; flex-direction: column; }
.shop-goods-body { flex: 1; min-height: 0; display: flex; flex-direction: column; gap: 16px; padding: 20px; }
.shop-shelf { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
/* ★ 2026-10-04：货架改成承载**全部** slots（5 件 ⇒ 3 行），行数不再写死 `1fr 1fr`；
   改 grid-auto-rows + 纵向可滚，件数再多也不会把卡片压扁。 */
.shop-shelf-body {
  flex: 1; min-height: 0; display: grid;
  grid-template-columns: 1fr 1fr; grid-auto-rows: minmax(180px, 1fr);
  gap: 16px; padding: 20px; overflow-y: auto;
}

.sh-card {
  position: relative; min-height: 0; overflow: hidden;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px;
  padding: 16px; border: 2px solid var(--ab-line); border-radius: var(--ab-r); background: var(--ab-c1);
  clip-path: inset(0 round var(--ab-r));
}
.sh-card.big { flex: 1 1 auto; }
.sh-card .sh-art img { display: block; width: 128px; height: 128px; object-fit: contain; image-rendering: pixelated; }
.sh-card:not(.big) .sh-art img { width: 64px; height: 64px; object-fit: contain; }
.sh-card .sh-tx { text-align: center; }
.sh-card .sh-tx b { display: block; font-size: 24px; line-height: 24px; letter-spacing: 2px; color: #e6eef2; }
.sh-card .sh-tx i { display: block; margin-top: 4px; font-style: normal; font-size: 12px; line-height: 12px; letter-spacing: 2px; color: #7f97a2; }
.sh-card .sh-tx p { margin-top: 8px; font-size: 12px; line-height: 18px; letter-spacing: 1px; color: #9fb6c0; }
.sh-card .sh-buy { display: flex; align-items: center; gap: 12px; }
.sh-card .price { font-size: 24px; line-height: 24px; color: var(--gold); }
.sh-card .price small { font-size: 12px; color: #7f97a2; margin-left: 4px; }
.sh-card .buybtn {
  height: 40px; padding: 0 20px; cursor: pointer; font-family: inherit;
  font-size: 24px; line-height: 24px; letter-spacing: 2px; color: #cfe0e6;
  border: 2px solid var(--ab-line); border-radius: var(--ab-r-sm); background: var(--ab-c1);
}
.sh-card .buybtn:hover { border-color: var(--hx-acc2); background: var(--ab-c2); }
.sh-card .buybtn[disabled] { cursor: not-allowed; color: #5f6f79; border-color: #24404c; }
.sh-card.sold { opacity: .45; }
.sh-card.r-rare { border-color: #35608f; }
.sh-card.r-epic { border-color: #6a45a0; }
.sh-card.r-legend { border-color: #a8802e; }
.sh-empty { font-size: 24px; line-height: 36px; letter-spacing: 2px; color: #7f97a2; }

/* ---------- 黑市「钥匙」栏（2026-10-05 · 随新版基底新增） ----------
   ── 新版基底加了两样东西：①「入袋即锁」——封印物一进封印匣就被固定，要**一把钥匙**才解得开；
      ② 黑市多了一栏钥匙（`.shop-key`，写在 style.css:560，落在**弹窗版**黑市里）。
      皮肤是三整屏黑市，没有那个弹窗 ⇒ 改钉在货架面板**底部独立一条**（index.html 的 `#shopKey`）。
   ── 为什么钉在面板底、不塞进货架：货架只列「还有名额的封印物」，会随买卖变长变短、还要滚；
      钥匙是跨节点的常驻资源 + 常驻标价（每买一把 +25），跟着滚就会「想买的时候找不到」。
      `.shop-shelf` 是 flex 列 ⇒ 上面 `.shop-shelf-body` 取 flex:1（内部自滚），
      这一条 flex:0 0 auto —— 件数再多也挤不掉它，也不会被挤出面板。
   ── 类名不复用新版那份：`#shopKey` 里是 `.sh-key / .sk-ic / .sk-tx / .sh-buy`（见 ui.js renderShop），
      与 `.sh-card` 的 `.sh-buy` 同名但被 `.sh-key` 前缀圈住，两处不会互相串味。 */
.shop-key-bar { flex: 0 0 auto !important; padding: 0 20px 20px !important; }
/* 空态（比如还没有 st）整条收起，不留一条空底框 */
.shop-key-bar:empty { display: none !important; }
.sh-key {
  display: flex !important; align-items: center !important; gap: 16px !important;
  padding: 14px 16px !important;
  border: 2px solid var(--ab-line) !important;
  border-radius: var(--ab-r) !important;
  background: var(--ab-c1) !important;
}
.sh-key .sk-ic { flex: 0 0 auto !important; display: block !important; }
/* ⚠️ 只锁高度，宽度 auto —— 这里原先是 `width:48px; height:48px` 双轴写死，
   而 key.png 是 15x34 的竖长像素画 ⇒ 被横向撑成 1:1，钥匙看着像块砖（2026-10-10 实拍）。
   68 是原高 34 的整数倍（像素格不踩半像素），也正好与右侧文字块（24+4+18+2+18=66）齐平。
   同目录其它图标（chest/tablet/dice/gear）几乎方形，双轴拉不会被看出来；
   key/obelisk 是 15x34 / 17x34 这类细长件，凡双轴写死都会变形 —— 新增图标一律照这条写。 */
.sh-key .sk-ic img {
  display: block !important; height: 68px !important; width: auto !important;
  image-rendering: pixelated !important;
}
.sh-key .sk-tx { flex: 1 1 auto !important; min-width: 0 !important; }
/* 标题：与面板头 h3 同一套语言（4px 竖标 + 24px 字 + 4px 字距），换行即顶高 ⇒ 不换行 */
.sh-key .sk-tx > b {
  display: block !important; font-weight: 400 !important;
  font-size: 24px !important; line-height: 24px !important; letter-spacing: 4px !important;
  color: #e6eef2 !important; white-space: nowrap !important;
}
.sh-key .sk-tx > b::before {
  content: ''; display: inline-block; width: 4px; height: 20px;
  background: var(--hx-acc2) !important; margin-right: 12px; vertical-align: -3px;
}
.sh-key .sk-tx i {
  display: block !important; margin-top: 4px !important; font-style: normal !important;
  font-size: 12px !important; line-height: 18px !important; letter-spacing: 1px !important;
  color: #7f97a2 !important;
}
.sh-key .sk-tx p {
  margin-top: 2px !important; font-size: 12px !important; line-height: 18px !important;
  letter-spacing: 1px !important; color: #9fb6c0 !important;
}
/* 正文里的数字走金色：注意必须写 display:inline 压回行内（标题那条 `> b` 是 block） */
.sh-key .sk-tx p b {
  display: inline !important; font-weight: 400 !important;
  font-size: 12px !important; line-height: 18px !important; color: var(--gold) !important;
}
.sh-key .sh-buy { flex: 0 0 auto !important; display: flex !important; align-items: center !important; gap: 16px !important; }
.sh-key .sh-buy .price { font-size: 24px !important; line-height: 24px !important; }
.sh-key .sh-buy .buybtn {
  height: 40px !important; padding: 0 20px !important; cursor: pointer !important;
  font-family: inherit !important; font-size: 24px !important; line-height: 24px !important;
  letter-spacing: 2px !important; border-radius: var(--ab-r-sm) !important;
}
.sh-key .sh-buy .buybtn[disabled] { cursor: not-allowed !important; }

/* ---------- 中栏「选中物品的详情」（2026-10-04 改版） ----------
   ★ 中栏不再摆「两件特价」，改成点货架后在这里看完整详情 + 买下。 */
.sh-detail { flex: 1; min-height: 0; display: flex; flex-direction: column; gap: 16px; }
.sh-detail .sh-hero {
  flex: 0 0 auto; display: grid; place-items: center; padding: 16px;
  border: 2px solid var(--ab-line); border-radius: var(--ab-r); background: var(--ab-c1);
}
.sh-detail .sh-hero img { display: block; width: 128px; height: 128px; object-fit: contain; image-rendering: pixelated; }
.sh-detail .sh-hero .sh-emoji { font-size: 96px; line-height: 1; }
.sh-detail .sh-info { flex: 1 1 auto; min-height: 0; overflow: auto; }
.sh-detail .sh-name { font-size: 36px; line-height: 36px; letter-spacing: 2px; color: #e6eef2; }
.sh-detail .sh-sub { margin-top: 6px; font-size: 12px; line-height: 12px; letter-spacing: 2px; color: #7f97a2; }
.sh-detail .detail-effect { margin-top: 12px; line-height: 20px; }
.sh-detail .sh-lore {
  margin-top: 8px; font-size: 12px; line-height: 20px; letter-spacing: 1px;
  color: var(--teal); font-style: italic;
}
.sh-detail .sh-buy { flex: 0 0 auto; display: flex; align-items: center; gap: 16px; }
.sh-detail .price { font-size: 36px; line-height: 36px; color: var(--gold); }
.sh-detail .price small { font-size: 12px; color: #7f97a2; margin-left: 4px; }
.sh-detail .buybtn {
  height: 48px; padding: 0 24px; cursor: pointer; font-family: inherit;
  font-size: 24px; line-height: 24px; letter-spacing: 2px; color: #cfe0e6;
  border: 2px solid var(--ab-line); border-radius: var(--ab-r-sm); background: var(--ab-c1);
}
.sh-detail .buybtn:hover { border-color: var(--hx-acc2); background: var(--ab-c2); }
.sh-detail .buybtn[disabled] { cursor: not-allowed; color: #5f6f79; border-color: #24404c; }

/* 货架格 = 可点选的小卡（不直接买）；选中态只靠 border + **inset 内环**
   —— `.sh-card` 有 overflow:hidden + clip-path，外扩的 box-shadow 会被裁掉。 */
.sh-card.sh-tile { cursor: pointer; }
.sh-card.sh-tile:hover { border-color: var(--hx-acc2); background: var(--ab-c2); }
.sh-card.sh-sel {
  border-color: var(--hx-acc) !important;
  background: var(--ab-c2) !important;
  box-shadow: inset 0 0 0 2px var(--hx-acc) !important;
}
.sh-card .sh-state { font-size: 12px; line-height: 12px; letter-spacing: 2px; color: #7f97a2; }
.sh-card .sh-emoji { font-size: 48px; line-height: 1; }

.shop-foot {
  flex: 0 0 auto; height: 88px; display: flex; align-items: center; gap: 24px;
  padding: 0 32px; border-top: 2px solid var(--ab-line);
}
.shop-foot .hint { flex: 1 1 auto; min-width: 0; font-size: 24px; line-height: 24px; letter-spacing: 4px; color: #9fb6c0; }
.shop-foot .hint em { font-style: normal; color: var(--hx-acc); }

/* ★★ 2026-10-04（用户红圈「画圈内容去掉」）：地图屏底栏 `#actions`（72px 那条工具条）
   连同 DOM **整条删除** ⇒ 上面那组 `#actions{…}` / `#actions .int-line{…}` 规则一并撤掉。
   底栏一没，`.map-main` 里的 `.map-stage`（flex:1）自动长高 72px；
   地图纵向居中由 ui.js 现算 `wrap.clientHeight`（见 renderMap 的 oy = sh/2 − CONTENT_CY·z），
   所以**不需要**动任何 JS 常数。
   ★ 别顺手把 `.map-bar`（88px「关卡块 ｜ 提示 ｜ 当前节点 ｜ 滑动提示」）也删了 ——
     它是地图屏**唯一**的底部信息条，用户红圈圈的是更下面那条工具条。
   ★ style.css 的媒体查询里还有 `#actions{…}` 几条窄屏回退规则，选择器匹配不到 DOM 就静默失效，
     留着不碍事（也免得动基线样式表）。 */

/* 「一键收纳」从底栏搬到了封印匣面板标题行最右（index.html 装备屏）。
   面板头定高 56、`.small` 带 margin-left:auto 会把剩余宽度全吃掉 ⇒
   按钮必须 flex:0 0 auto，否则会被压扁成一条。高度 32 与 .map-interest 同档。 */
#gearScreen .panel-head .btn {
  flex: 0 0 auto; height: 32px; padding: 0 16px;
  font-size: 12px; letter-spacing: 2px;
}

/* ---------- 窄屏回退：先纵向堆叠，再谈细节 ---------- */
@media (max-width: 1500px) {
  :root { --bag-w: 560px; }
  .hud { gap: 16px; padding: 0 20px; }
  .gear-main, .shop-main { flex-wrap: wrap; overflow: auto; }
  .gear-right, .gear-side, .shop-goods, .shop-shelf { flex: 1 1 320px; }
}

/* ══════════════════════════════════════════════════════════════════════════
   ★★ 2026-10-05 构建 rs（用户：「图标的边框去掉，鼠标停在上面时要有描边的效果」）
   —— 同一批的另两条在 js/ui.js：连线加弧度（edge 的 bow）、
      节点位置加稳定偏移（nodePos 的 jitter）。
   ══════════════════════════════════════════════════════════════════════════ */

/* 节点常驻**无框、无底、无内环** —— 图标直接浮在地图石壁上，
   只有鼠标悬停在可走节点上时才出现描边（细则见下方 hover）。
   ★★ 边框写 `2px solid transparent` 而**不是** `border:0`：
      96px 是**含边框**的盒模型，真删掉盒子就变 92px、框内图标跟着跳 2px；
      留 2px 透明占位，hover 只换颜色，几何纹丝不动。
   ★ 特异性 `#app .map-node`（1,1,0）压过 style.css 的 `.map-node.avail`
     与 `.map-node.boss` 的红框暗底（都是 0,2,0）；带 !important 是铁律。 */
#app .map-node {
  border: 2px solid transparent !important;
  background: transparent !important;
  box-shadow: none !important;
}
/* 可走节点常驻只留指针，不给框（原来是金框 + 淡底，现在整条让给 hover）。 */
.map-node.avail { cursor: pointer; }
/* 当前所在节点（.cur）**不动** —— 它那圈 inset 金内环（ui-abyss.css 1475 行）
   特异性 1,2,0 > 本层 1,1,0，照样生效；去了框之后反而更需要它标「我在哪」。 */

/* ★★ 2026-10-05：上面那条 `#app .map-node`（1,1,0 + !important）把关底的红框与暗底
   也一起压掉了 —— 关底于是和普通节点长得一模一样（只剩 112 vs 96 的尺寸差，看不出来）。
   ★ 2026-10-12（用户「框你没去掉」）：红框暗底不再恢复 —— 关底靠 **112 大尺寸 + 魔眼图标**
   本身辨识，与全局「去框、图标即状态」一致。 */

/* ============================================================
   第四十轮（2026-10-05 · 构建 20261005ru）：设置面板三件事
   ------------------------------------------------------------
   ① 分段标题「画面 / 进度 / 导航」被圆角切掉字头  ← 病灶在本节第一块
   ② 两套设置的标题统一成「设置」、去掉副标题     ← 纯 JS，见 ui.js
   ③ 新增「音量」段（音乐 / 音效两条滑杆）        ← 见本节第二块
   ============================================================ */

/* ---------- ① 放开 .set-sec / .help-sec 的圆角裁剪 ----------
   ★★ 病灶：本文件上面（② 去掉方正感）把 `.set-sec` 也写进了
        `.panel, .card, .dl-item, .set-sec, .help-sec { clip-path: inset(0 round 12px) }`
      —— 那条的本意是「把方角换成圆角」，对**有底有框**的 .panel / .card 成立。
      但 `.set-sec` 只是个分组容器：**没有背景、没有边框、没有内边距**
      （看得见的盒子是它里面的 `.set-row`）。
      于是这条命令在它身上唯一的作用变成了：**以 12px 为半径，把四个角各挖掉一个四分之一圆盘。**
   ★ 而 `.set-sec > h4`（「画面」「进度」「导航」）正是它的第一枚子元素，
      顶端与容器顶边齐平、左端与容器左边齐平 ⇒ **字头正好落在左上那个 90° 扇里**。
      实测（4x 抓图）：「画」的左上、「进」的左上都被切出一道斜口，
      12px 的小字切掉一角就整枚读不出来了 —— 这正是用户圈出来说的「文字显示不完全被挡住了」。
   ★ .help-sec 同病（规则面板里每一段的 h4 也在容器左上角），一并放开。
   ★★ 圆角一个都不会丢：真正可见的 `.set-row` 自己写着
      `border-radius: var(--ab-r)`（见本文件「④ 设置：开关行」），不受这里影响。 */
.set-sec,
.help-sec { clip-path: none !important; }

/* ---------- ③ 设置：音量滑杆 ----------
   ★ 像素风三件套，通体没有一处渐变：
       凹槽 = 2px 的 inset 硬环（用 box-shadow 而不是 border ——
              border 会把 8px 的槽撑成 12px，还得回头改高度）
       已填 = 4px 实条，取 var(--hx-acc)
       旋钮 = 16×20 的方柱，2px inset 环；悬停 / 拖动时转金
   ★★ 旋钮靠 `left: 中心x` + `margin-left: -6px`（半个旋钮宽）定位 ——
      与 ui.js 的 paintSlider 是一对约定：**改旋钮宽必须两边一起改**
      （JS 里那个常量名叫 SLD_KNOB，值也是 16）。
   ★ `.sld-tr` 高 32px 是**命中区**（点哪儿都能跳档），视觉上的槽只有中间那 8px。
   ★ 尺寸一律取偶数：168 / 32 / 16 / 20 / 8 / 4 / 2 —— 合项目硬性规范。 */
.modal .sld {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 12px;
  height: 32px;
  cursor: pointer;
  outline: none;
  touch-action: none;       /* 触屏上别让浏览器把拖动抢去滚页面 */
  user-select: none;
}
.modal .sld-tr {
  position: relative;
  flex: 0 0 auto;
  width: 168px;
  height: 32px;
}
/* 凹槽：左右通长、2px 内环 —— 不用外扩阴影（会被 .set-row 的 overflow 裁掉） */
.modal .sld-tr::before {
  content: '';
  position: absolute;
  left: 0; right: 0; top: 12px;
  height: 8px;
  background: rgba(6, 14, 20, .95);
  box-shadow: inset 0 0 0 2px var(--hx-rule);
}
.modal .sld-fl {
  position: absolute;
  left: 2px; top: 14px;
  width: 0;                 /* 由 JS 按档位写 */
  height: 4px;
  background: var(--hx-acc);
  pointer-events: none;
}
.modal .sld-kn {
  position: absolute;
  top: 6px;
  left: 8px;                /* 初始值，开面板时立刻被 JS 覆盖 */
  width: 16px;
  height: 20px;
  margin-left: -8px;        /* ← 让 left 直接等于「旋钮中心 x」 */
  background: rgba(12, 24, 32, .96);
  box-shadow: inset 0 0 0 2px var(--hx-acc);
  pointer-events: none;
}
.modal .sld:hover .sld-kn,
.modal .sld:focus-visible .sld-kn,
.modal .sld.on .sld-kn { box-shadow: inset 0 0 0 2px var(--gold); }
.modal .sld-v {
  flex: 0 0 auto;
  width: 44px;
  text-align: right;
  font-size: 12px !important;
  font-weight: 400;
  letter-spacing: 0;
  color: #8b9aa5;
}
.modal .sld:hover .sld-v,
.modal .sld:focus-visible .sld-v,
.modal .sld.on .sld-v { color: #e6eef2; }

/* 音量段底部那行小字（说明音频尚未接入）—— 比正文再退一档，别抢戏 */
.modal .set-note {
  margin: 6px 0 0 !important;
  font-size: 12px !important;
  line-height: 24px !important;
  letter-spacing: 0;
  color: #5f6d78 !important;
}

/* ---------- 规则页占位（2026-10-05 · 构建 20261005rv） ----------
   ★★ 用户「玩法规则里的内容都去掉」：六页的正文段落与 4 张图解全清，只留面板骨架
      （★ 2026-10-05 第二轮再砍到 **2 页**——战斗 / 关卡，见 ui.js 的 RULES_PAGES）。
      页框仍是定高 668（见上 .rules-view）⇒ 占位块直接撑满可用高
        668 − 4（上下边框 2×2） − 48（上下内边距 24×2） = 616，
      这样翻页时页框高度纹丝不动，左右翻页键的垂直基准（padding-top:72 那条算式）也不受影响。
   ★ 只放一句灰字，不加装饰、不冒充正文 —— 这是空状态提示，不是内容。
     将来往页面里填回正文时，这个 .rules-empty 会被 body 顶掉（ui.js 里是 `p.body || RULES_EMPTY`）。 */
.rules-page .rules-empty {
  height: 616px;
  display: flex; align-items: center; justify-content: center;
  color: #5f6f79; font-size: 12px; line-height: 24px; letter-spacing: 2px;
}

/* ============================================================
   ★★ 第五十一轮（2026-10-05 · 构建 20261005sb → 20261005sc）
   战斗整屏排版五连改 —— 逐条对应用户的 5 张红圈截图：
     ① 封印袋里「封印物 ≠ 格线」（物品层右下偏 6px）
     ② 6 条血条 + 怪名挤在右上角面板里，与下面那排立绘毫无对应关系
     ③ 播放控制条（⏸ ▶ ▶▶）竖着堆在屏幕正中
     ④「回合 N」贴顶，比左边那排信息高一截
     ⑤ 玩家牌占着左上角（那里要留给之后要做的玩家立绘）
   ⚠️ 本段全部写在 ui-abyss.css（它排在 ui-hollow.css 之后加载）⇒ 同特异性时
      天然压过 hollow；只有 hollow 带 !important 的声明才需要自己补 !important。
   ============================================================ */

/* ---------- ① 封印袋：物品层与格线对齐 ----------
   style.css 给 `.bt-bagwrap` 写了 padding:6px、给 `.bt-bag-layer` 写了 inset:6px，
   两者本来就严丝合缝；但 ui-hollow 把 padding 归零之后 inset 没跟着改 ⇒ 物品层
   整体右下偏 6px，画面就是「格子在这、封印物在那」。
   ★ 这与装备屏 `#bagItems` 是**同一个坑**（见本文件上文那段注释），当时只补了
     装备屏，漏了战斗中这一份。这里补上，三处（装备 / 市场 / 战斗）从此一致。 */
.bt-bagwrap .bt-bag-layer { inset: 0 !important; }

/* ---------- ⑤ 玩家牌：搬到「左中偏上」，左上角整块腾给玩家立绘 ----------
   位置取自用户标记图的椭圆中心 ≈ 屏宽 29.3% / 屏高 39.7%；本牌约 340×58，
   取左上角 (20%, 37%)。写百分比而不是 px —— 窗口换尺寸时也跟着走。
   ★ 非绝对定位不可：只有脱离 `.bt-top`（DOM 已改，见 ui.js 的 bt.innerHTML）才能
     按**整屏**算百分比；留在顶栏里时 top:% 是拿 84px 顶栏算的，几乎不动。 */
/* ★ 2026-10-06（第五十七轮 · 用户「玩家角色要和敌方怪物横向对齐，血条也是」）：
   两处对齐 —— ①垂直于立绘居中（left / transform），②血条与怪血条同一条线（top）。
   ① 为什么居中：立绘落回地平线之后，这块玩家牌的角色变成「角色头顶的名牌」；
      怪那排的每条血条块是**居中**于各自立绘的（.bt-mobslot 宽 = 立绘宽），
      玩家侧若仍左对齐，绿血条会向右偏出角色半个身位（实测血条 x442..722 vs 角色 x382..622）。
      写法：left 落在「立绘中心」那条线上，再用 translateX(-50%) 自身居中 ——
      卡片将来变宽（比如 bt-res 里多挂几个流派 chip）也不会再偏。
   ② 为什么 top 要算：原来写 top:37%，是**视口高度**的百分比；怪血条却由
      地平线（固定 300px）推出 ⇒ 只有 948 高时两者才凑巧同高（实测都是 y370..384），
      换成 900 高就错开 30px（实测：我方 352..366 / 怪 322..336）。
      改成与怪共用 --np-h / --ground-off 两个基准后，任何视口高度都同线。
      算式：100%(视口高) − 300(地平线) − 262(名条块底边距地平线) − 35 = 卡片顶边；
      其中 35 = 16（名条块底边 → 怪血条顶边）+ 19（本卡片顶边 → 本卡片血条顶边）。
      这两段内部间距由 `.fb-nm` 行高、`.bt-me .nm` 行高与 `.bt-me-col` 的 gap 决定，
      动那三个值时要同步改 35（注释见 style.css 的 .bt-me / .bt-foebar 两段）。
      ★ 948×1912 下新式给出 948−300−262−35 = 351，与原 top:37%（=350.8）一致，版式不动。
   ⚠️ --hero-left / --hero-w 不写死在两处：统一走 #battleScreen 上的变量
      （见下方立绘那段的长注释），矮屏 / 窄屏只改一处，立绘与玩家牌一起跟。 */
.bt-me {
  position: absolute !important;
  left: calc(var(--hero-left) + var(--hero-w) / 2) !important;
  transform: translateX(-50%) !important;
  top: calc(100% - var(--ground-off) - var(--np-h) - 35px) !important;
  z-index: 4 !important;
}
/* 玩家牌搬走之后，`.bt-top` 里只剩两个绝对定位的兄弟 ⇒ 高度会塌成 padding(24px)，
   顶栏那条横线（hollow 给的 border-bottom）会跟着窜到屏幕上沿。
   钉住原高度 84 = 58(玩家牌高) + 12×2(顶栏上下内边距) + 2(横线)，横线位置一行不动。 */
.bt-top { height: 84px !important; }

/* ---- 战斗吸顶 HUD（2026-10-12，用户「地图顶栏复制给战斗界面」）----
   复用 .hud 组件，但绝对定位叠在战斗屏顶部：不挤占战斗布局，立绘/名条/地平线各不动。
   ★ .bt-round 原本是绝对定位挂 .bt-top 里（top:30px 居中），现在改成 HUD 内正常流。 */
.bt-hud {
  position: absolute !important;
  top: 0; left: 0; right: 0;
  z-index: 30;                 /* 压在背景/立绘之上，低于浮层(.fb-qtip z-60) */
  pointer-events: auto;
}
.bt-hud .bt-round { position: static !important; top: auto !important;
  left: auto !important; transform: none !important;
  flex: 0 0 auto; margin: 0 8px; }
.bt-hud .hud-face { width: 72px; height: 72px; }
.bt-hud .hud-face img { width: 56px; height: 56px; }
.bt-hud .hud-hp b { font-size: 30px; line-height: 30px; }
.bt-hud .hud-hp .sl { font-size: 20px; }
.bt-hud .hud-bonds b { font-size: 30px; line-height: 30px; }

/* ============================================================
   ★★ 第五十五轮（2026-10-06 · 玩家角色「塔罗占卜师」入场）
   ★★ 第五十六轮（2026-10-06 · 用户标注图）：--s 288 → 240、bottom 63% → 54.5%
   ★★ 第五十七轮（2026-10-06 · 用户「玩家角色要和敌方怪物横向对齐，血条也是」）：
        立绘定位从「比例（bottom:54.5%）」换成「**与怪共用同一条地平线**」，
        并把三个几何量提到 #battleScreen 上共享（立绘与玩家牌必须读同一份）。
   ------------------------------------------------------------
   ① 地平线怎么算（为什么不是照抄 300px）
      怪的立足线来自 style.css 的 `.bt-mob{bottom:300px}` ⇒ 元素底边 y = 视口高 − 300。
      但两张图自带的**透明下边距**不一样，元素底对齐 ≠ 脚底对齐：
        · 角色 240 原生图：内容底边在第 225 行 ⇒ 15 原生 px（1:1 显示）= **15px**
        · 怪 256 原生图（实测 a1_1=2 / a1_b=4 / a1_e=6 / a1_4=6 / a1_2=7 / a1_3=8）
          ⇒ 底边留白 2–8px，中位 ≈ **5px**
      两者元素底对齐时，角色的可见脚底会比怪高 15 − 5 = 10px。
      ⇒ 严格算 --ground 应是 300 − 10 = **290px**；这里仍沿用第五十七轮的 292.5px，
        原因：240 版与 96 版（留白 6px × 2.5 = 15px）口径完全一致 ⇒ 已验证的版式
        一行不动，差的 2.5px 在 900 高的视口里肉眼不可辨。要精确贴地平线时改 290。
      ★ 只补偿一个有实测依据的量：怪图逐张那 2–8px 的差异保留原样 ——
        那是原画自己的留白，不该由 CSS 逐张去凑（怪物一换补偿值就失效）。
      ★ 为什么用 px 而非 %：怪那排的地平线本身就是固定 300px，
        这里若写 %，视口高度一变两者又会分开。
   ② 为什么三个量要提到 #battleScreen
      玩家牌（.bt-me）要**居中于立绘**，就得知道立绘的 left 与宽。
      原先 --s 写在 .bt-hero 自己身上，兄弟节点读不到 ⇒ 矮屏（立绘降到 192）时
      居中量会算错、绿血条又一次偏出角色。改挂在共同父级 #battleScreen 上，
      矮屏 / 窄屏各改一处，立绘 + 玩家牌 + 护盾一起跟。
   --- 尺寸（第五十六轮定 240；2026-10-09 升到 240 原生）----------
   --hero-w 240：原先是「96 原生 ×2.5」的放大显示（像素块 2/3px 交替、观感糊），
   2026-10-09 改为**入库 240 原生图 ⇒ 1:1**，与怪物立绘（256²，同样 1:1）同级。
   矮屏 192 是 240 的 0.8 倍，只在 max-height:660 的极端尺寸下生效。
   ★ 尺寸链只靠 --hero-w 一个变量：护盾按 150% 跟着缩放。
   ============================================================ */
#battleScreen {
  --hero-left: 20%;     /* 立绘左缘（窄屏 10%） */
  --hero-w: 240px;      /* 立绘边长 = 240 原生图 1:1（矮屏 192） */
  --ground: 292.5px;    /* 立绘元素底边距视口底：与 .bt-mob 的 300px 是同一条地平线，已扣透明下边距 */
  --ground-off: 300px;  /* 怪立足线距视口底 = .bt-mob 的 bottom（窄屏 320 → 见文件末尾媒体查询） */
  --np-h: 262px;        /* 名条块底边距地平线 —— ★ 玩家名条与怪名条共用它，两边才在同一条线 */
}
.bt-hero {
  position: absolute;
  left: var(--hero-left); bottom: var(--ground);
  width: var(--hero-w); height: var(--hero-w);
  z-index: 1; pointer-events: none;
}
.bt-hero-art {
  position: absolute; inset: 0; width: 100%; height: 100%;
  image-rendering: pixelated;
  filter: drop-shadow(0 16px 34px rgba(0, 0, 0, .72));
}
/* 占卜护盾：亮点由战斗日志的 psh 快照驱动（ui.js 的 renderHeroGuard）。
   ★ 2026-10-09 重算（用户：「角色图标没有在护盾中央」）
     旧值由「护盾图 128² 里球心在 (77,63.5)」反推，但那是目测值；
     用最外轮廓做最小二乘圆拟合，实测真实圆心是 **(74.3, 60.7)**、半径 48.9
     ⇒ 护盾整体偏左上约 7px，角色看着「贴不到球心」。
     处理：把 guard_orb.png 整幅**平移 (−10, +3)** 让圆心落到图心 (64,64)
     （tools/p17_install240.py 自动做，附带校验），CSS 就能用对称值。
     ★ 尺寸 133.33% → 150%：原来球环直径只有 244px，而立绘本体 216px ——
     上下只剩 14px 余量，角色几乎顶到环沿，视觉上就是「没居中」。
     150% ⇒ 球环直径 275px，上下余量 29.5px，角色才真正「坐在球心」。
     ★ 2026-10-09 二次重算（高分辨率重绘版）：
     立绘改由 2048² 底画降采样而来，本体高 203px（仍以脚底 y=225 贴地平线）
     ⇒ 本体占 y22..225、**中心 y=123.5**（旧版是 216 高、y9..225、中心 117）。
     ★ 2026-10-09 三次重算（护盾也重做）：用户「护盾也需要重做」。
     旧护盾是 128×128 的位图，被这里 150% 拉到 360px 显示 —— **2.81× 插值放大**，
     比旧立绘的 2.5× 还糊；且实测环带 r44–52 上只有 0°–105° 有像素（其余 250° 全空）、
     连通域 276 个 —— 环本身断裂，是底图的问题，只能重画。
     新版由 tools/p23_orb360.py **程序化重绘**：几何精确正圆、360×360 原生
     ⇒ 150%×240 = 360 ⇒ **1:1**，与立绘 240 原生同级口径。
     圆心从旧的 (50.23%, 49.73%) 变成**正图心 (50%, 50%)**，偏移跟着重算：
       left = 120   − 180 = −60.0px = −25.00%
       top  = 123.5 − 180 = −56.5px = −23.54%
     （护盾是几何特效，用程序化而非 AI 出图：正圆 AI 画不准、中心镂空不保证、
     抠底还会污染半透明能量边。详见 tools/p23_orb360.py 的文件头。）
     ★ 横向锚点不是本体 bbox 中心，而是**头轴**（礼帽中心）。
       底画里四个姿态的礼帽横向位置各不相同（实测差最多 35px），
       所以入库时已按头轴把每个变体对齐到 x=120（tools/p20_hires240.py 自检）。
     ★ 不做 pointer-events：整个 .bt-hero 已经 none，护盾跟着 none。 */
     /* ★ 2026-10-09 第四次（用户：「护盾不要全部显示 / 放大一点 / 有一点虚化 /
       从色块到空白要有过渡」）：
       · 护盾是**光**，不是像素画 ⇒ 这里**去掉 `image-rendering: pixelated`**。
         它会把柔化过的渐变重新量化成硬边色块 —— 用户看到的「色块」就是它造成的。
         立绘（.bt-hero-art）保留 pixelated 不变，那是真·像素画。
       · 放大 1.30×、外侧辉光铺到 r=195（画布半宽 180）⇒ 出画布被裁，
         护盾外缘「延伸到画面之外」；RGB 收尾做 σ=1.4 高斯虚化。
     ★ 2026-10-09 第五次（用户：「泛光超出画布了，要不就扩大画布要不就用别的办法
       让其显示 / 护盾画圈的部分不要显示」）：
       实测 v5 画布边缘 alpha=57 —— 外金光在**上/下/左/右四个正方向各被切出一道平口**
       （四角 alpha=0，所以不是方形残留，纯粹是圆被方画布切了）。
       · 用户选定「金环 + 泛光都去掉」⇒ v6 由 tools/p27_orb512.py 重绘为
         **纯紫色能量场**（无金色主环、无环外金辉光；星芒/刻度保留但改成紫白）。
       · 扩大画布：**360² → 512²**，元素同步放大到 1:1，环体视觉尺寸不变，
         泛光有 60px 余量在自己渐隐到 0（v6 实测画布边缘 alpha=0，不再被裁）。
         尺寸链：512 / 240 = 213.3333% ⇒ left = 50% − 106.6667% = −56.6667%
                                       top  = 51.4583% − 106.6667% = −55.2083%
         （50% / 51.4583% = 立绘中心 x120 / 本体中心 y123.5，全走百分比 ⇒ 矮屏自动等比缩） */
.bt-hero-guard {
  position: absolute; width: 213.3333%; height: 213.3333%;
  left: -56.6667%; top: -55.2083%;
  /* 不加 image-rendering: pixelated —— 会把辉光渐变切成色块 */
  opacity: 0; transition: opacity .35s ease;
}
.bt-hero-guard.on { will-change: opacity; }
/* 矮屏：立绘降一档（192 = 96 ×2）。
   ★ 2026-10-06（第五十七轮）阈值从 940 → 660：940 是**旧版**（bottom:54.5% 按视口高算）
     推出的数；现在立绘贴地平线（bottom 固定 292.5px），头顶 y = 视口高 − 532.5，
     要撞上 84px 顶栏得矮到约 624 以下。还按 940 缩的话，1366×768 / 1600×900 这些
     常见尺寸会白白缩一档，而名条的行是贴地平线的（不跟着缩）——
     实测 900 高时名条会离头顶 110px，飘。改 660 后 768/900/1080 全部保持 240，名条距头顶恒 46px。 */
@media (max-height: 660px) { #battleScreen { --hero-w: 192px; } }
/* 窄屏：style.css 给怪那排另写了 `.bt-mob{width:82%;right:-14%;bottom:320px}`，
   所以立绘要跟着左移 + 抬高 20px（320 − 300），否则地平线又对不上；
   --ground-off 同步改成 320（玩家名条那条 top 算式吃它）。 */
@media (max-width: 760px) {
  #battleScreen { --hero-w: 192px; --hero-left: 10%; --ground: 312.5px; --ground-off: 320px; }
}

/* ---------- 玩家名牌：与怪名字牌**同构**（2026-10-06 第五十七轮） ----------
   怪那边：`[怪名] / [血条，宽 = 槽位宽 − 44 padding] / [特性]`，全部**居中于立绘**。
   玩家这边原来是横排 `[56×56 头像][你 / 血条 280px / chips]` ——
   头像把血条整体往右顶 60px（实测血条 x442..722，而立绘是 x382..622），
   于是「居中于角色」这条就永远对不上。
   改成与怪一致：名字居中在上、血条**满宽**在下，整块宽 = 立绘宽（--hero-w）。
   换算：`--hero-w` 240 ⇒ 血条 x382..622，与立绘左右缘严丝合缝，也和怪的
   「血条宽 = 立绘宽」同一套规则。
   ★ `.hbar` 基础规则是 `width:280px` 定宽（style.css，超窄屏还有一条 180px），
     这里必须显式改 100%，否则块宽改小了血条会**溢出去**（实测 240 的块里伸到 280）。
   ★ 头像（face_*.png）：整块**去掉**。理由：立绘就在名牌正下方，脸已经完整可见，
     这个小头像只是重复；而怪那边根本没有头像 —— 留着它两边就不成一套。
     （若要恢复，把 display:none 换成 position:absolute; right:100% 让它挂在名牌左侧，
       这样既不占宽也不把血条顶偏 —— 但两边仍不同构。见日志 2026-10-06。 */
.bt-me {
  flex-direction: column !important; align-items: center !important;
  width: var(--hero-w) !important;
}
.bt-me .ava { display: none !important; }
.bt-me .bt-me-col { width: 100% !important; align-items: center !important; }
.bt-me .nm { text-align: center !important; }
.bt-me .hbar { width: 100% !important; }
.bt-me .bt-res { justify-content: center !important; }

/* ---------- ③ 播放控制条：横排 + 上移 ----------
   原来 flex-direction:column，40 宽 134 高，正堵在屏幕正中央（top:50%）。
   改成横排（134×40），并整体抬到「顶栏横线(84) 与立绘头顶」之间那块空白带里：
   30% ⇒ 控条自身中心落在 y≈344。 */
.bt-ctl {
  top: 30% !important;
  transform: translateX(-50%) !important;
  flex-direction: row !important;
  gap: 10px !important;
}

/* ---------- ④「回合 N」下移居中 ----------
   原来 top:10 贴着屏幕上沿，比左边的玩家牌（y 12..70）高一截；下移到 30 ⇒
   23 高的小牌正好落在顶栏内容区（12..70）的垂直中线上（中心 41）。 */
.bt-round { top: 30px !important; }

/* ---------- ② 逐怪名条：跟着立绘走（怪名 → 血条 → 护盾 → 特性 → debuff） ----------
   ★★ 2026-10-06（第五十七轮 · 用户「怪物名称显示在怪物血条上方 怪物特性显示在血条下方」）：
      行序定死为 **怪名 / 血条 / 护盾 / 特性 / debuff**，与 ui.js 的 foeBarHtml 一一对应。
      本轮新增的是 `.fb-tr`（特性）—— 从右上角 `.bt-foe` 面板搬来的，见 ui.js 那段注释。
   现在每只怪一个 `.bt-mobslot`，槽位宽度 = 立绘宽度 ⇒ 名条天然「均匀分配」，
   逐条对号入座（原来 6 条挤在面板里，名字还被截成「菌丝傀儡 2·裂殖…」）。
   ★ 名条用**绝对定位挂在 bottom:100%** —— 它完全不参与槽位尺寸计算，
     立绘的大小 / 位置 / 相互重叠一格不变，只是头顶多了一块名牌。
     若改成常规流内布局，名条的最宽内容（怪名 / 血条）会把槽位撑宽，
     反而把立绘挤小、把整排怪推歪。 */
.bt-mob .bt-mobslot { position: relative !important; flex-direction: column !important;
  justify-content: flex-end !important; align-items: center !important; }
.bt-mob .bt-mobslot > .bt-foebar {
  position: absolute !important;
  left: 0 !important; right: 0 !important;
  /* ★★ 2026-10-06（第五十七轮）：锚点从「立绘头顶 −6px」改成「地平线 −262px」。
     原来是 `bottom: calc(100% + 6px)` —— 相对槽位顶算，而槽位高 = 视口缩小时**会被压小的
     立绘高度**（.bt-art 有 max-width:100% + object-fit:contain）⇒ 视口一变，这排水条
     就跟着立绘一起上下漂。
     「血条也要对齐」要求两边同一条线：地平线（= .bt-mob 的 bottom）是这块屏里唯一
     与立绘尺寸无关的固定基准，改挂它。
     ★ 262 是**从 1912×948 实测反解**的：块底边 y=386、地平线 y=648 ⇒ 648 − 386 = 262。
       948 下与原式结果完全一致（386），换算到别的视口高度也稳定。
     ⚠️ 约束：262 必须 > 立绘高 256 + 6（否则名条会压到满尺寸怪物的头顶）——
       所以这个值不能再往小调；视口高 < 约 680 时名条会顶到 84px 顶栏，
       那是「256 的怪 + 名条 + 顶栏」本身装不下，不是这条规则的问题。 */
  bottom: var(--np-h) !important;
  /* ★ 左右各留 22px：相邻槽位是**叠着**的（`.bt-mobslot + .bt-mobslot{margin-left:-4%}`，
     4% × 883 = 35px）。名条若贴着槽位两边，相邻两条血条就会连成一条红色长带
     （4 只怪全都接近满血时尤其明显，实测就是这样）——看不出是「四条」。
     留 22 ⇒ 相邻两条之间恒有 2×22 − 35 = 9px 缝，跟怪数多少无关。 */
  padding: 0 22px !important;
  /* 面板里那套是「怪名 + 血条」同一行（血条 flex:1 吃余宽）＋徽章另起一行；
     立绘头顶这块只有百来 px 宽，必须改成竖着摞、每层居中吃满宽度。 */
  flex-direction: column !important;
  align-items: center !important;
  gap: 2px !important;
}
.bt-mob .bt-mobslot .fb-nm { max-width: 100% !important; text-align: center !important; }

/* ---- 名条首行的「?」信息点（2026-10-12，用户圈选怪名右侧）----
   悬停显示当前预测攻击（#cbIntent 实时内容），浮层 .fb-qtip 全局唯一。 */
.fb-nmrow { display: inline-flex !important; align-items: center !important;
  gap: 5px !important; max-width: 100% !important; justify-content: center !important; }
.fb-q {
  flex: 0 0 auto !important;
  width: 15px; height: 15px; line-height: 13px;
  border: 1px solid rgba(126, 176, 190, .55); border-radius: 50%;
  color: rgba(160, 200, 214, .85); background: rgba(9, 17, 24, .72);
  font-size: 10px; text-align: center; cursor: help; user-select: none;
  transition: border-color .15s, color .15s, background .15s;
}
.fb-q:hover { border-color: rgba(160, 206, 224, .95); color: #d9edf5; background: rgba(24, 46, 57, .9); }
.fb-qtip {
  position: fixed; z-index: 60; pointer-events: none;
  transform: translate(-50%, -100%);
  max-width: 320px; padding: 8px 12px;
  background: rgba(9, 17, 24, .94); border: 1px solid rgba(126, 176, 190, .45);
  border-radius: 6px; color: #c8d8e0; font-size: 12px; line-height: 1.55;
  box-shadow: 0 4px 14px rgba(0, 0, 0, .5);
  opacity: 0; visibility: hidden; transition: opacity .12s;
}
.fb-qtip.on { opacity: 1; visibility: visible; }
.fb-qtip b { color: #eaf4f8; }
.bt-mob .bt-mobslot .bt-foebar .hbar { flex: 0 0 auto !important; width: 100% !important; }
/* `.fb-dbf` 在面板里靠 `flex:0 0 100%` 强制换行；这里已经是竖排，回退成自动高，
   否则 flex-basis:100% 会按「容器高度的 100%」算，徽章行会被撑开。 */
.bt-mob .bt-mobslot .fb-dbf { flex: 0 0 auto !important; justify-content: center !important; }

/* ---- 怪特性行 .fb-tr（2026-10-06 第五十七轮新增）----
   从右上角面板搬来的 traits chips，位置在**血条下方**（用户原话）。
   ★★ 为什么必须 position:absolute（本轮踩到的坑，别改回常规流）：
      `.bt-foebar` 是 **底部锚定** 的（`bottom: calc(100% + 6px)` ⇒ 块底 = 怪物头顶 − 6px）。
      特性行若进流，整块高度 +18px，块会**向上**长 ⇒ 血条从 y370..384 跳到 y351..365，
      与玩家血条（370..384）当场错开 18px —— 而「血条也要对齐」正是本轮的另一半要求。
      脱流挂在块底之下（top:100%），块高不变 ⇒ 血条位置一格不动。
   ★ 代价（已知）：特性行落进怪物立绘的**顶部留白区**（怪图 256²，实测内容顶边在
     第 7–24 行 ⇒ 头顶普遍有 7–24px 透明边距）。单行特性（绝大多数怪）完全落在留白里；
     4 个以上特性换行到两行时会压到头顶 10 来 px，chips 自带描边+底色，仍读得出。
   槽位只有 212px 可用宽（256 − 两侧各 22 padding），所以 chip 比面板里小一号：
   面板 12px 字 / 18px 图标 → 这里 10.5px 字 / 13px 图标，多特性自动换行居中。
   ★ `.bt-mob` 整棵是 pointer-events:none（立绘不吃指针），chips 的 tooltip 靠 hover
     ⇒ 必须在这一层把指针事件**收回来**。只收名条块，立绘那层照旧 none。 */
.bt-mob .bt-mobslot > .bt-foebar { pointer-events: auto !important; }
.bt-mob .bt-mobslot .fb-tr {
  position: absolute !important;
  left: 0 !important; right: 0 !important; top: 100% !important;
  margin-top: 2px !important;
  display: flex !important; flex-wrap: wrap !important;
  justify-content: center !important; align-items: center !important;
  gap: 3px !important;
}
.bt-mob .bt-mobslot .fb-tr:empty { display: none !important; }
.bt-mob .bt-mobslot .fb-tr .bt-chip { padding: 1px 6px !important; font-size: 10.5px !important; gap: 3px !important; }
.bt-mob .bt-mobslot .fb-tr .bt-chip .ic { width: 13px !important; height: 13px !important; }
/* tooltip 方向翻转：`.bt-chip .buff-tip` 默认朝**下**弹（给贴屏顶的 chips 用）。
   名条块下面是怪物立绘，朝下弹会糊在怪脸上；这里改朝**上**弹 —— 名条上方是空的。 */
.bt-mob .bt-mobslot .fb-tr .buff-tip {
  top: auto !important; bottom: calc(100% + 8px) !important;
}
.bt-mob .bt-mobslot .fb-tr .buff-tip::after {
  bottom: auto !important; top: 100% !important;
  border-bottom-color: transparent !important;
  border-top-color: var(--bc, rgba(200, 184, 154, .5)) !important;
}
/* 死亡态：原来 `.bt-mobslot.dead` 用 transform 让整槽「倒下」，现在名条也在槽位里，
   会被一起搬走 14px。改成只动立绘本身（压灰/变暗仍留在槽位上 ⇒ 名条一起灰，正好）。 */
.bt-mob .bt-mobslot.dead { transform: none !important; }
.bt-mob .bt-mobslot.dead .bt-art { transform: translateY(14px) scale(.92) !important; }

/* ============================================================
   ★★ 攻击 / 受击动画（2026-10-10）
   战斗是日志回放：ui.js 的 actAnim() 按每行日志判定「谁出手、谁挨打」，
   给对应立绘容器挂 .atk / .hit 类，动画播完自动移除。
   · 攻击方 = 向前突进（.atk）：朝目标方向冲一小段再弹回，带轻微前倾。
   · 受击方 = 抖动 + 闪色（.hit）：身体抖 + filter 闪红/闪白，模拟吃痛。
   ★ 动画作用在**容器**（.bt-mobslot / .bt-hero）而非 .bt-art 本体 ——
     死亡态已经用 .bt-art 的 transform 表达「倒下」，两者不能打架。
   ★ 怪物是像素画，filter 闪色会糊掉像素边缘？不会：只改亮度/色相，不重采样。
   ============================================================ */

/* —— 怪物槽位：攻击前冲（向右，朝玩家方向）—— */
@keyframes btAtkFoe {
  0%   { transform: translateX(0) translateY(0); }
  32%  { transform: translateX(26px) translateY(-6px); }   /* 前扑：向右下压 */
  62%  { transform: translateX(40px) translateY(-2px); }   /* 冲到位 */
  100% { transform: translateX(0) translateY(0); }         /* 弹回 */
}
.bt-mob .bt-mobslot.atk { animation: btAtkFoe .26s cubic-bezier(.3,.7,.3,1); will-change: transform; }

/* —— 玩家立绘：攻击前冲（向左，朝怪物方向）—— */
@keyframes btAtkHero {
  0%   { transform: translateX(0) translateY(0); }
  32%  { transform: translateX(-28px) translateY(-6px); }
  62%  { transform: translateX(-44px) translateY(-2px); }
  100% { transform: translateX(0) translateY(0); }
}
.bt-hero.atk { animation: btAtkHero .26s cubic-bezier(.3,.7,.3,1); will-change: transform; }

/* —— 受击抖动 + 闪红（怪物，向右被击退：远离左侧的玩家）—— */
@keyframes btHitFoe {
  0%   { transform: translateX(0); }
  15%  { transform: translateX(16px); }
  30%  { transform: translateX(-8px); }
  45%  { transform: translateX(9px); }
  62%  { transform: translateX(-4px); }
  80%  { transform: translateX(2px); }
  100% { transform: translateX(0); }
}
.bt-mob .bt-mobslot.hit { animation: btHitFoe .34s ease-out; will-change: transform; }
.bt-mob .bt-mobslot.hit .bt-art { animation: btFlashRed .34s ease-out; }

/* —— 受击抖动 + 闪红（玩家立绘，向左被击退：远离右侧的怪物）—— */
@keyframes btHitHero {
  0%   { transform: translateX(0); }
  15%  { transform: translateX(-18px); }
  30%  { transform: translateX(8px); }
  45%  { transform: translateX(-10px); }
  62%  { transform: translateX(4px); }
  80%  { transform: translateX(-2px); }
  100% { transform: translateX(0); }
}
.bt-hero.hit { animation: btHitHero .34s ease-out; will-change: transform; }
.bt-hero.hit .bt-hero-art { animation: btFlashRed .34s ease-out; }

/* 受击闪色：压暗 + 染红 + 提亮，一记短促的「吃痛」闪（作用于立绘本体） */
@keyframes btFlashRed {
  0%   { filter: none; }
  20%  { filter: brightness(2.1) saturate(1.4) sepia(.9) hue-rotate(-38deg); }
  55%  { filter: brightness(.7) saturate(1.2) sepia(.6) hue-rotate(-30deg); }
  100% { filter: none; }
}

/* 玩家牌小头像同步抖一下（不闪色，太小看不清） */
@keyframes btHitAva { 0%{transform:translateX(0)} 30%{transform:translateX(6px)} 60%{transform:translateX(-3px)} 100%{transform:translateX(0)} }
.bt-me.hit .ava { animation: btHitAva .3s ease-out; }

/* 尊重「减少动态」设置：整组动画关闭，只保留功能性位移（护盾等） */
@media (prefers-reduced-motion: reduce) {
  .bt-mob .bt-mobslot.atk, .bt-mob .bt-mobslot.hit,
  .bt-hero.atk, .bt-hero.hit { animation: none !important; }
  .bt-mob .bt-mobslot.hit .bt-art, .bt-hero.hit .bt-hero-art,
  .bt-me.hit .ava { animation: none !important; }
}

/* ============================================================
   ★★ 死亡动画（2026-10-10）
   怪物：致命一击时播「崩解倒地」——先被顶起震一下，再向后翻倒 + 缩小 +
        闪白淡出，最后落到 .dead 的静止压灰态（原样式不变，只是过程多了动作）。
   玩家：败北时「后仰倒下」——立绘向后退一步、重心后仰、滑落淡出。
   ⚠️ 动画作用在**槽位容器 / .bt-hero** 上，终点 transform 与 .dead 的
     translateY(14px) scale(.92) 分离：动画播完由 JS 摘 .dying，.dead 接管静止态，
     两者不在同一帧叠 transform，不会打架。
   ============================================================ */

/* 怪物死亡：被顶起 → 崩落 → 缩小压灰（.dying 由 renderFoeBars 在 alive 翻转瞬间挂上） */
@keyframes btDieFoe {
  0%   { transform: translateY(0) scale(1); }
  14%  { transform: translateY(-16px) scale(1.03); }        /* 致命一击顶起 */
  30%  { transform: translateY(6px) scale(1.05); }
  52%  { transform: translateY(2px) scale(.96) rotate(1deg); }
  78%  { transform: translateY(14px) scale(.9); }           /* 塌向地面 */
  100% { transform: translateY(14px) scale(.92); }          /* 与 .dead 静止位一致 */
}
.bt-mob .bt-mobslot.dying { animation: btDieFoe .62s cubic-bezier(.4,.1,.5,1) forwards; will-change: transform; }
/* 死亡动画期间，位移由**槽位**承担；.dead 会把 .bt-art 也下移 14px ⇒ 必须压掉，
   否则槽位(14) + 立绘(14) 叠成 28px。动画结束摘 .dying 后，.dead 的 .bt-art 再接管静止位。 */
.bt-mob .bt-mobslot.dying .bt-art { transform: none !important; }
/* 同样：.dead 立即把槽位压到 28% 透明度 + 灰度，会让「顶起崩落」的动作几乎看不见。
   动画期间先别压灰，等 .dying 摘掉后再由 .dead 的 opacity/.filter 落到静止态。 */
.bt-mob .bt-mobslot.dying.dead { opacity: 1 !important; filter: none !important; }

/* 怪物死亡闪白：本体在崩塌同时闪一下（与受击的闪红区分：死亡是白光） */
@keyframes btDieFlash {
  0%   { filter: none; }
  18%  { filter: brightness(2.4) saturate(.4); }
  45%  { filter: brightness(1.2) grayscale(.5); }
  100% { filter: none; }
}
.bt-mob .bt-mobslot.dying .bt-art { animation: btDieFlash .62s ease-out; }

/* 玩家死亡：后仰倒下（向左后方退 + 重心后倾 + 滑落淡出） */
@keyframes btDieHero {
  0%   { transform: translate(0, 0) rotate(0deg); opacity: 1; }
  22%  { transform: translate(-10px, -4px) rotate(-3deg); opacity: 1; }
  55%  { transform: translate(-26px, 14px) rotate(-14deg); opacity: .9; }
  100% { transform: translate(-38px, 46px) rotate(-24deg); opacity: 0; }
}
.bt-hero.dying { animation: btDieHero .9s ease-in forwards; will-change: transform, opacity; }

/* 玩家死亡闪白（护盾/立绘一起闪） */
.bt-hero.dying .bt-hero-art { animation: btDieFlash .9s ease-out; }

/* 玩家死亡时头像同步抖一下 */
.bt-me.dying .ava { animation: btHitAva .5s ease-out; }

/* 尊重减少动态：死亡动画降级为「直接到静止压灰态」 */
@media (prefers-reduced-motion: reduce) {
  .bt-mob .bt-mobslot.dying { animation: none !important; }
  .bt-mob .bt-mobslot.dying .bt-art { animation: none !important; }
  .bt-hero.dying { animation: none !important; opacity: .4 !important; }
  .bt-hero.dying .bt-hero-art { animation: none !important; }
}

/* ---------- 收容物卡片的「图形位」（2026-10-06 · 修仓库面板打不开） ----------
   收容物不占格 ⇒ 没有形状（`CONTAINMENT` 里没有 shape 字段）。
   皮肤版 itemCard 原来无条件拼 shapeMini(def.id)，而 bag.getShape 只在
   `D.ITEMS` 里找 def ⇒ 收容物 id 进去就是 undefined.shape 抛错，
   「仓库 · 收容物」整个面板起不来。改成 ui.js 的 cardArt()：
   封印物仍画形状小图，收容物画类型图标（与仓库里 mini-eq 的 ICON 口径一致）。
   这里把图标位撑到和 `.card-img` 同样的 44×44，卡片左缘才对齐。 */
.card .card-ic {
  flex: 0 0 auto !important;
  display: flex !important; align-items: center !important; justify-content: center !important;
  width: 44px !important; height: 44px !important;
  font-size: 24px !important; line-height: 24px !important;
}

/* ============================================================
   ★★ 设置面板「角色」段：玩家外观四选一（2026-10-06）
   选项直接用**头像图**（face_*.png，64×64）当图标 —— 立绘是竖条，缩进按钮里
   认不出是谁；头像是方图，一眼能认。
   ★ 图标按 64px **原生尺寸**显示（1:1）⇒ 不用缩放，也就不会糊。
   ============================================================ */
.hero-pick { flex: 0 0 auto; display: flex; gap: 10px; }
.hero-pick .hp {
  width: 88px; padding: 8px 6px 7px; cursor: pointer; font-family: inherit;
  display: flex; flex-direction: column; align-items: center; gap: 7px;
  border: 2px solid var(--ab-line); border-radius: var(--ab-r);
  background: var(--ab-c1); color: var(--dim);
  transition: border-color .14s, background .14s, color .14s, transform .14s;
}
.hero-pick .hp img { width: 64px; height: 64px; display: block; image-rendering: pixelated; }
.hero-pick .hp span { font-size: 12px; line-height: 1; letter-spacing: 1px; }
.hero-pick .hp:hover { border-color: var(--gold); color: var(--text); transform: translateY(-2px); }
.hero-pick .hp.on {
  border-color: var(--gold); color: var(--gold2);
  background: rgba(232, 180, 90, .14);
  box-shadow: inset 0 0 0 2px rgba(232, 180, 90, .22);
}

/* ============================================================
   ★★ 第五十六轮（2026-10-06 · 用户标注图）封印袋搬到屏幕左下角
   ------------------------------------------------------------
   原来：style.css 的 `.bt-bag{left:24px;bottom:300px}` —— 贴在左边缘、离地 300px，
         正好落在立绘与战斗日志之间那块腰部位置（实测截图里袋框 y≈385..650）。
   现在：left/bottom 都取 24px，与「左边缘」保持同一条内边距，袋框整体沉到左下角。
   ★ 为什么只在桌面生效：style.css 的 @media(max-width:760px) 里给窄屏另写了一套
       `.bt-bag{left:12px;bottom:auto;top:150px}`（袋框缩到 .78、日志也挪到页面底部），
       窄屏照旧更合理 —— 用 @media(min-width:761px) 把改动圈在桌面，不动窄屏那套。
   ★ 本文件排在 style.css / ui-hollow.css 之后 ⇒ 同特异性天然压过；
     仍然写 !important，是因为 style.css 里那条窄屏规则带媒体查询，加了更稳。
   ============================================================ */
@media (min-width: 761px) {
  .bt-bag { left: 24px !important; bottom: 24px !important; top: auto !important; }
}
