/* ============================================================
 * v7：按参考图重做的全局 UI（Win3.1 标准控件 / 配色 / 标题栏 / 旋转框）
 * ============================================================ */
:root {
  --face: #C7CCD0;
  --face-light: #FFFFFF;
  --face-shadow: #85898C;
  --title-active: #0000A8;
  --title-inactive: #FFFFFF;
  --desktop: #C0C4C8;
  --win-bg: #FFFFFF;
  --text-main: #000000;
}
body { background: var(--desktop); color: var(--text-main); }

/* ---------- 窗口 ---------- */
/* 参考图：外黑线 → 灰色包边 → 内黑线 → 内容；取消白色/灰色斜角高光 */
.win {
  background-color: var(--face) !important;
  /* 抖动色：底色用主色，叠一层 50% 棋盘把另一色混进来（2px 一个棋盘格） */
  background-image: var(--face-dither, none) !important;
  background-size: var(--dither-tile) var(--dither-tile) !important;
  border: 1px solid var(--win-frame, #000) !important;   /* 外侧线：跟随主题的窗口外框颜色 */
  padding: 3px;                                   /* 灰包边 2px + 内侧黑线 1px（后者由 .win::after 画在最里 1px） */
  /* p51：参考图四角剖面里，外框线之后**直接就是面**，没有任何投影 ⇒ 按用户要求删除窗口投影。
     原值 2px 2px 0 rgba(0,0,0,.35)；win31.css 里还有一层 inset 白/灰高光，一并压掉。 */
  box-shadow: none !important;
}
/* 内侧黑线：画在灰包边**最里的 1px**（= padding 3px 的第 3 个像素）上
   ⇒ 可见包边 = 2px（`_dev/ref51.py` 实测四张参考图 4.15 图内 px ÷ ≈2.05 = 2.02 CSS px）。
   ⚠️ p51 关键修复：这条线以前画在 `inset:3px`，而 `inset:3px` 恰好等于**内容区最外 1px**
      （padding-box 内缩 3px = border-box 内缩 4px = 内容区边界）⇒ 线把标题栏第一行盖成黑的，
      最小/最大化键的「上边缘 1px 白高光」永远看不见（参考图里高光就在内黑线的下一行）。
      现在把线退到包边里，内容区完整露出，高光自然出现。 */
.win::after {
  content: '';
  position: absolute;
  inset: 2px;
  box-shadow: inset 0 0 0 1px var(--win-frame, #000);
  pointer-events: none;
  z-index: 40;
}
.win-client {
  background-color: var(--win-bg) !important;
  background-image: var(--winbg-dither, none) !important;
  background-size: var(--dither-tile) var(--dither-tile) !important;
}
/* 活动标题栏：底色 + 抖动层，文字颜色由 JS 按底色亮度算（深底白字 / 浅底黑字） */
.win.focused .titlebar {
  background-color: var(--title-bg, var(--title-active)) !important;
  background-image: var(--title-dither, none) !important;
  background-size: var(--dither-tile) var(--dither-tile) !important;
  color: var(--title-fg, #fff) !important;
}
.win .titlebar { background: var(--title-inactive) !important; color: #000 !important; }
.win .titlebar .tb-title { font-weight: normal; }
.win:not(.focused) .titlebar .tb-title { color: var(--text-main, #000); }
/* 未置前 / 不活跃：标题栏用「窗口背景色 + 对应文字色」成对出现（Win3.1 规范），
   不再写死白底黑字 —— 否则深色主题下非活动窗口会闪出一块白的。 */
.win:not(.focused) .titlebar {
  /* p62：非活动标题栏底色改为「专用变量优先、否则回落窗口背景色」。
     默认（用户没设过「不活动标题栏颜色」）时 `--title2-bg` **不存在**（prefs.js 清空时会
     removeProperty）⇒ 落到 `var(--win-bg)`，与改动前逐像素一致（铁律：标题栏几何/配色不被触碰）。 */
  background-color: var(--title2-bg, var(--win-bg, #ffffff)) !important;
  background-image: var(--title2-dither, var(--winbg-dither, none)) !important;
  background-size: var(--dither-tile) var(--dither-tile) !important;
  color: var(--title2-fg, var(--text-main, #000)) !important;
}
.win:not(.focused) .titlebar .tb-title { color: var(--title2-fg, var(--text-main, #000)) !important; }
/* 标题栏按钮**保持固定的浅灰**：参考图里即使标题栏是青/洋红/黑，右上角三个键也仍是灰方块 ——
   若跟着主题色走，遇深色主题（如全黑高对比）会黑底黑块看不见。
   ⚠️ 这里**不要再加 box-shadow 描边**（p47）：最小化/最大化键自带 1px 黑框，
   再叠一圈描边就成了「两排像素」的粗边（用户报告的「加粗边线」），
   而且只加在非活动窗口上，活动/非活动两态还不一致。 */
.win:not(.focused) .titlebar > .tb-btn { background-color: #C7CCD0 !important; }
.titlebar > .tb-btn { background: var(--face) !important; }

/* ---------- 标题栏 / 三个标题栏按钮的几何（p50 按两张参考图像素级复核）----------
   参考图实测（`_dev/ref50.py` 逐像素；参考图 #1 1px≈1/1.55 CSS px、#2 1px≈1/2.94 CSS px）：
     · #1 关闭键：#000000 外框线 1px → 面色包边 **2px** → 内框线 1px → 关闭键内部
       28×30 参考图 px ≈ 18.1×19.4 CSS px ⇒ 与「标题栏内高」齐平，**正方形**；
     · #2 最小/最大化：键宽 53 参考图 px ≈ 18.0 CSS px，与 #1 的关闭键**同尺寸**；
       键「上 / 右 / 下」三边分别由标题栏黑线、内侧黑线直接界定，键自身**只画 1px 左边框**；
       两键之间只有一条 1px 黑线（黑线两侧是「键内 2px 阴影 / 键内 1px 白高光」，不是双线）；
       两键与标题栏上/下边**无缝隙**（键高 = 标题栏内高）。
     · ⚠️ 标题栏 padding 必须为 0：非 0 时键的上下会露出标题栏底色 ——
       活动窗口下就是关闭键下方那「一排蓝色像素」（用户报告的 bug）。
   ⚠️ 宽度用 `--tb-h`（「标题栏高度」设置项）而不是写死 19px：用户改高度时键仍保持正方形。
   ⚠️ 灰包边 = **2px**（p51 已按用户要求从 3px 改掉：内侧黑线退到包边最里 1px，见 .win::after）。
      参考图看起来「边线更粗」是因为它是 2.05×/1.55×/2.94× 的放大截图，线本身同样是 1px。 */
.win > .titlebar { padding: 0 !important; gap: 0 !important; align-items: stretch !important; }
/* 标题栏现在是 stretch（没有上下 padding），标题文字用等值 line-height 自己垂直居中，
   同时保留 .tb-title 原有的 overflow/ellipsis（改成 flex 会丢掉省略号）。 */
.win > .titlebar > .tb-title { line-height: var(--tb-h, 19px) !important; }
.win > .titlebar > .tb-btn {
  box-sizing: border-box !important;
  width: var(--tb-h, 19px) !important;
  height: auto !important;
  align-self: stretch !important;
  flex: none !important;
  margin: 0 !important;
  padding: 0 !important;
  border: 0 !important;
  border-left: 1px solid var(--win-frame, #000) !important;
  box-shadow: none !important;
  background: #C7CCD0 !important;
  display: flex; align-items: center; justify-content: center;
}
.tb-btn:active { background: #BFC4C8 !important; box-shadow: none !important; }
.tb-btn svg { width: 9px !important; height: 9px !important; }
.tb-btn svg path, .tb-btn svg rect { transform-origin: center; }

/* p50：▼/▲ 位图字形（`js/icons.js` 里 `I.glyph.min/max`）的尺寸与垂直定位。
   尺寸：7×4 CSS px = **真 1:1**（1 用户单位 = 1 CSS px），所以绝不能走上面那条 9×9 的等比缩放
        —— 9px 盒子里 viewBox 会被缩成 0.75 倍，4 行就只剩 3px，台阶全糊。
   定位：参考图 #2 实测（母本 2.94×，换算成 CSS px 后）
        · ▼ 在标题栏内高里**居中**：上 20 参考 px / 下 20 参考 px；
        · ▲ 比 ▼ **高 1 CSS px**：上 18 / 下 23 —— 两键字形并不同高，这是 Win3.1 的既定画法，
          别为了「对称」把它们对齐。
   特异性 `.tb-btn svg[data-bmp]`(0,2,1) 高于两处 `.tb-btn svg`(0,1,1)，无需关心先后。 */
.tb-btn svg[data-bmp] { width: 7px !important; height: 4px !important; }
/* p136③：还原字形是 8x11 位图（上▲ 底边 2 行 + 空 1 行 + 下▼ 顶边 2 行），按 1:1 = 8px x 11px。
   ⚠️ 特异性 (0,3,1) > 上面那条 (0,2,1) ⇒ 不会被 7x4 改坏（min/max 仍是 7x4）。 */
.tb-btn svg[data-bmp][data-bmp-restore] { width: 8px !important; height: 11px !important; }
.win .titlebar > .tb-btn.tb-max > svg[data-bmp] { transform: translateY(-1px); }

/* ---------- 最小化 / 最大化：3D 凸起斜面（p50 按参考图第二张实测）----------
   参考图 #2 逐像素实测（`_dev/ref50.py`，1 参考图 px ≈ 1/2.94 CSS px）：
     · 键内侧「左 / 上」= **1px 白高光**（实测 #FCFCFC）；
     · 「右 / 下」= **2px 阴影**，实测 #84888C；
     · 键底色 = 主题面色（参考图实测 #C0C4C8）。
   ⇒ 阴影值：参考图的 #84888C 恰好等于「面色 × 0.67」= 覆盖 33% 黑（192×0.67=129≈132），
      所以这里用 `rgba(0,0,0,.33)` 而不是固定的 #85898C / --face-shadow（后者在经典主题下被
      prefs.js 的 mixc(face,#000,.42) 重算成偏暗的 #737679，比参考图暗一档）。
      用 alpha 还顺带满足用户「淡淡的投影」的描述，并且任何主题下都自动保持同样的淡度。
   键自身的左框由上方 `.tb-btn` 规则给出 ⇒ 相邻两键**共享同一条** 1px 黑线，不会出现双重边线。 */
.win .titlebar > .tb-min,
.win .titlebar > .tb-max {
  box-shadow: inset 1px 1px 0 var(--white, #fff),
              inset -2px -2px 0 rgba(0, 0, 0, .33) !important;
}
.win .titlebar > .tb-min:active,
.win .titlebar > .tb-max:active {
  background: #BFC4C8 !important;
  box-shadow: inset -1px -1px 0 var(--white, #fff),
              inset 1px 1px 0 rgba(0, 0, 0, .33) !important;
}

/* ---------- 窗口四角「」包角 ----------
   上面两角：外黑线内 1px 起算 → 21px 宽、22px 高。
     · 右侧竖线 x=21 与标题栏按钮右沿卡齐
     · 底边横线 y=22 同时是「包角下缘 / 系统菜单盒下缘 / 标题栏蓝底下缘」⇒ 三者平齐
     包角压在标题栏蓝底之上（z-index 低于内侧黑线 40、高于标题栏），系统菜单盒
     「上 / 左 / 下」三边不再露出蓝色缝隙；按钮抬到包角之上，字形不受影响。
   下面两角：不再画额外边线（见下方规则）。 */
.win .cnr {
  display: block !important;
  position: absolute;
  box-sizing: border-box;
  background: var(--face);
  pointer-events: none;          /* 绝不能拦事件，否则盖住 wm.js 的缩放手柄 */
  z-index: 35;                   /* 标题栏蓝底之上、.win::after 内侧黑线(40)之下 */
}
/* 高度跟随「标题栏高度」设置（--tb-h，默认 19px）：3px 包边 + 标题栏高 = 包角下缘
   永远压在标题栏最后一行上 ⇒ 用户改高度时「包角下缘 = 蓝底下缘」依然成立。 */
/* ⚠️ p48：上两角包角不再画任何线。
   关闭键现在是一个充满标题栏高度的灰方块（下缘就是标题栏黑线），
   原来靠「包角右下两条边」去界定关闭键下缘的做法会与标题栏黑线叠成双重线。
   元素本身保留：effects.js 仍按 .cnr-* 设置四角鼠标指针。 */
.win .cnr-nw, .win .cnr-ne { background: transparent !important; border: 0 !important; }
/* ⚠️ p51：.cnr-* 四个元素继续只当「鼠标指针载体」（effects.js 按 .cnr-* 设指针），不画线。
   真正的「L 形包角」改由下面 .win::before 统一画：8 段线用一个伪元素 + 8 层渐变最省事，
   也不会多出 4 个参与布局/裁剪的盒子，而且偏移全部能用 calc 跟随 --tb-h。 */
.win .cnr-sw, .win .cnr-se {
  width: 4px; height: 4px;
  bottom: 0;
  background: transparent;
  border: 0;
}

/* ---------- 四角「L 形包角」（p51，按用户给的四张参考图逐像素实测）----------
   `_dev/ref51.py` 实测：每个角都有**两段 1px 黑线跨过 2px 灰包边**，把内侧黑线搭到外框黑线上；
   两段距窗口外缘都是 ≈47 图内 px ÷ ≈2.05 = **23 CSS px**（四张图高度一致：
   TL 46.6 / TR 47.2 / BL 47.0 / BR 46.7 图内 px）⇒ 恰好 = `--tb-h + 4px`
   （= 外框线 1 + 包边 2 + 内黑线 1 + 按钮净宽 19）。所以在**上两角**，包角的竖段正好落在
   按键的外框线上（左 = 关闭键右框、右 = 最大化键左框）——这正是用户要的
   「上方包角与按键边缘对齐」；下两角同样距离、独立存在（BL/BR 实测同样 47px）。
   画法：一个伪元素 + 8 层 linear-gradient（1px×3px 短线），偏移全部 calc 跟随 --tb-h
        ⇒ 用户改「标题栏高度」时，包角自动跟着按键跑，不会错位。
   ⚠️ 左右竖段偏移差 1px（左 23 / 右 22）：左侧按钮的「自带框」是它的**最后一列像素**
      （box 右边界），右侧按钮的自带框是它的**第一列像素**（box 左边界）——
      只有照这个 1px 差值放，两段才能各自与按钮边框**像素级重合**。
   ⚠️ `inset:-1px` 是故意的：伪元素的包含块是 .win 的 padding-box（已被 1px 边框内缩），
      用 -1px 撑回**外框盒**后，下面所有偏移都能直接按「距窗口外缘多少 px」读，不必再减 1。 */
.win::before {
  content: '';
  position: absolute;
  inset: -1px;
  pointer-events: none;
  z-index: 41;                                   /* 压在外框线与灰包边之上（内黑线是 40） */
  --cap-bg: linear-gradient(var(--win-frame, #000), var(--win-frame, #000));
  --cap-x: calc(var(--tb-h, 19px) + 4px);        /* 距左 / 上 / 下缘 23px */
  --cap-r: calc(var(--tb-h, 19px) + 3px);        /* 距右缘 22px（与右侧按钮自带左框同像素） */
  background-image: var(--cap-bg), var(--cap-bg), var(--cap-bg), var(--cap-bg),
                    var(--cap-bg), var(--cap-bg), var(--cap-bg), var(--cap-bg);
  background-repeat: no-repeat;
  background-size: 1px 3px, 3px 1px, 1px 3px, 3px 1px, 1px 3px, 3px 1px, 1px 3px, 3px 1px;
  background-position:
    left var(--cap-x) top 1px,      /* 左上·竖（= 关闭键右框向上延伸，跨过包边接外框线） */
    left 1px top var(--cap-x),      /* 左上·横（= 标题栏下缘向左延伸，跨过包边接外框线） */
    right var(--cap-r) top 1px,     /* 右上·竖（= 最大化键左框向上延伸） */
    right 1px top var(--cap-x),     /* 右上·横 */
    left var(--cap-x) bottom 1px,   /* 左下·竖 */
    left 1px bottom var(--cap-x),   /* 左下·横 */
    right var(--cap-r) bottom 1px,  /* 右下·竖 */
    right 1px bottom var(--cap-x);  /* 右下·横 */
}
/* 标题栏按钮画在包角之上：灰底/黑框/字形都不被包角盖住 */
.win .titlebar > .tb-btn { position: relative; z-index: 36; }
/* ---------- 左上角关闭键（系统菜单盒）+ 中空横杠（p50 按参考图第一张实测）----------
   参考图 #1 逐像素实测（`_dev/ref50.py`，1 参考图 px ≈ 1/1.55 CSS px）；
   x=61 / y=44~51 竖切，自上而下：
     #C0C4C8 面色 → #A5A8AC(混合) → **#000000 上框** → #979797(混合) → **#FCFCFC 白芯**
     → **#000000 下框** → #262728(混合) → **#84888C 投影** → #B1B5B9(混合) → 面色
   ⇒ 横杠 = 1px 黑框 + 1px 白芯 + 1px 黑框（共 3px 高），右/下各 1px 淡投影；
      横向：左框 53、白芯 54~71、右框 73、投影 75（参考图单位）⇒ 外宽 21px ≈ 13 CSS px、
      白芯 18px ≈ 11 CSS px。
   ⇒ 用伪元素画：content-box 11×1 + 1px 黑框 = 13×3，再叠右/下 1px 淡投影。
      投影用 `rgba(0,0,0,.33)`：参考图实测 #84888C = 面色 #C0C4C8 × 0.67（33% 黑），
      与用户描述的「淡淡的投影」一致，且在任何主题下都保持同样的淡度。
   键底色：参考图实测 #C0C4C8（= 该主题的面色），本站经典主题面色为 #C7CCD0，沿用第 60 行
        「三个键保持固定浅灰」的既有约定，不跟随主题色。
   ⚠️ 必须 `content-box`：全局 `*{box-sizing:border-box}` 只作用于元素，伪元素默认已是 content-box，
      这里显式写明，防止以后有人加 `*,*::before,*::after{box-sizing:border-box}` 把杠压成 1px 高。 */
.win .titlebar > .tb-btn:first-child {
  background: #C7CCD0 !important;
  box-shadow: none !important;
  /* 参考图 #1：关闭键**自带右框**（灰面右侧有一条 1px 黑线，把灰面与标题栏分开）。
     最小/最大化键不需要：它们的右边有窗口内侧黑线收边。
     ⚠️ 宽度要 +1px：`box-sizing:border-box` 下加一条右边框会把净宽挤掉 1px
     （参考图实测净宽 28/1.55 ≈ 18.1 CSS px，正好等于「标题栏内高 − 1」）。 */
  width: calc(var(--tb-h, 19px) + 1px) !important;
  border-right: 1px solid var(--win-frame, #000) !important;
  /* ⚠️ p51：关闭键的**左边框必须去掉**。内侧黑线现在退到包边里（.win::after 的 inset:2px），
     而左侧按钮的左边界本来就由这条内黑线给出（ref#1 实测：内黑线质心距窗口外缘 3.1~4.1 CSS px
     = 正是关闭键左沿）⇒ 再留 1px 左框就会得到「两排黑色像素」的粗边。 */
  border-left: 0 !important;
}
.win .titlebar > .tb-btn:first-child svg { display: none !important; }
.win .titlebar > .tb-btn:first-child::after {
  content: '';
  box-sizing: content-box !important;
  width: 11px; height: 1px;
  border: 1px solid var(--win-frame, #000);
  background: var(--white, #fff);
  box-shadow: 1px 1px 0 rgba(0, 0, 0, .33);
}
/* 按下时的凹陷反馈（仅加深填充，不加描边，避免与黑线叠成两排像素） */
.win .titlebar > .tb-btn:first-child:active { background: #BFC4C8 !important; }

/* ---------- 标题栏下缘的分隔线（p47 修复）----------
   非活动窗口的标题栏底色 = 窗口底色（Win3.1 规范），两者同色时边界就「消失」了 ——
   用户报告的就是这条线不见了。参考图里活动/非活动窗口的标题栏下缘都有一条外框色细线，
   这里用伪元素补上：不占布局（不影响标题栏高度 / 按钮对齐），压在菜单栏首行上。 */
.win > .titlebar { position: relative; }
.win > .titlebar::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 1px;
  background: var(--win-frame, #000);
  pointer-events: none;
  z-index: 37;
}

/* ---------- 右上角：最大化键 ----------
   旧版这里把最大化键做成「透明底、靠包角左边缘 + 内侧黑线界定」，与最小化键规格不一致
   ⇒ 已被上面的统一几何取代（两键同尺寸同边框）。 */

/* ---------- 菜单：File 首字母加下划线 ---------- */
.menu-item { padding: 0 9px 0 8px; }
.menu-item u { text-decoration: underline; }
.menu-bar { background: var(--face) !important; color: #000 !important; }
/* 悬停不标蓝 —— 只有「点开」的菜单标题标蓝（p47 用户要求） */
.menu-bar .menu-item.open { background: var(--title-active) !important; color: #fff !important; }
.menu-dropdown { box-shadow: 2px 2px 0 rgba(0,0,0,.4); }

/* ---------- 按钮：参考图 OK 按钮风格 ---------- */
button, .btn31, .calc-btn, .cp-cat {
  background: #C7CCD0 !important;
  color: #000 !important;
  border: none !important;
  box-shadow: inset 1px 1px 0 #fff, inset -1px -1px 0 #85898C, 0 0 0 1px #000 !important;
  padding: 2px 8px;
  font-weight: normal;
  min-height: 19px;
}
button:hover, .btn31:hover { background: #D3D7DA !important; }
button:active, .btn31:active, .btn31.active {
  box-shadow: inset 1px 1px 0 #85898C, inset -1px -1px 0 #fff, 0 0 0 1px #000 !important;
  background: #BFC4C8 !important;
}
button:disabled, .btn31:disabled { color: #85898C !important; text-shadow: 1px 1px 0 #fff; }
.btn31.default { box-shadow: inset 1px 1px 0 #fff, inset -1px -1px 0 #85898C, 0 0 0 1px #000, 0 0 0 2px #000 !important; }

/* ---------- 输入框 / 下拉框 ---------- */
.input31, input[type="text"], input[type="password"], input[type="date"], input[type="number"], select, textarea {
  background: #fff !important; color: #000 !important;
  border: none !important;
  box-shadow: inset 1px 1px 0 #85898C, inset -1px -1px 0 #fff, 0 0 0 1px #000 !important;
  padding: 2px 4px; font-family: inherit;
}
select.input31 { padding-right: 2px; }

/* p103：MS-DOS Editor 是**自带配色**的全屏层 —— `js/dos.js` 的 `cmdEdit()` 给自己内联了
   `background:#0000a8; color:#d8d8d8`（经典蓝底），但**上面那条全局 `textarea{…!important}`**
   会把它压成白底黑字（`!important` 跨文件无条件取胜 ⇒ 内联样式也输）。实测：编辑器正文区
   打开就是纯白 `(255,255,255)`，蓝底一像素都不剩。
   ⇒ 这里用**更高特异性 + 同样带 `!important`** 把配色还给它（`.dos-edit-shell textarea` 比 `textarea` 高一级）。
   ⚠️ **绝不去动上面那条全局规则** —— 全站对话框/输入框都靠它。 */
.dos-edit-shell textarea {
  background: #0000a8 !important; color: #d8d8d8 !important;
  border: none !important; box-shadow: none !important; padding: 6px !important;
}

/* ---------- Win3.1 组合框（自绘，取代浏览器原生下拉；原生 select 被隐藏） ---------- */
.s31 {
  display: inline-flex; align-items: center; height: 19px; box-sizing: border-box;
  background: #fff; color: #000; vertical-align: middle; padding-left: 3px;
  box-shadow: inset 1px 1px 0 #85898C, inset -1px -1px 0 #fff, 0 0 0 1px #000;
  font-family: inherit; font-size: inherit; cursor: default; user-select: none; outline: none;
  max-width: 100%; overflow: hidden;
}
.s31-val { flex: 1 1 auto; min-width: 0; overflow: hidden; white-space: nowrap; line-height: 15px; padding: 1px 2px 1px 1px; }
.s31-btn {
  flex: 0 0 auto; width: 16px; align-self: stretch; display: flex; align-items: center; justify-content: center;
  background: #C7CCD0; border-left: 1px solid #000;
}
.s31-btn svg { width: 11px; height: 11px; }
.s31:active .s31-btn, .s31.open .s31-btn { box-shadow: inset 1px 1px 0 #85898C, inset -1px -1px 0 #fff; }
/* 聚焦 / 展开：值区蓝底白字 + 虚线焦点框（参考图） */
.s31.open .s31-val, .s31:focus .s31-val { background: #0000A6; color: #fff; outline: 1px dotted #fff; outline-offset: -1px; }
.s31.s31-dis { color: #85898C; }
.s31-pop {
  /* p78：**必须高于所有模态遮罩**，否则列表展开后被遮罩盖在下面 ⇒ 表现为「下拉点不开、
     只有当前那一项」，用户在「边框 → 样式与层次 → 线型」里踩到的正是这个：
     .bxw-ov（边框/阴影对话框遮罩）是 100030，而这里原先是 100000。
     全站最高层是 100060（新闻等级悬浮卡），取 100100 稳压所有对话框，且不会盖住开机画面之后的任何东西。
     顺带修好同一个对话框里其余下拉（纹理 / 填充方式 / 装饰纹样 / 格式 / 分辨率）以及阴影模块。 */
  position: fixed; z-index: 100100; background: #fff; color: #000; border: 1px solid #000;
  box-shadow: 2px 2px 0 rgba(0, 0, 0, .4); padding: 1px; max-height: 320px; overflow-y: auto;
}
.s31-it { padding: 1px 5px; white-space: nowrap; cursor: default; line-height: 15px; }
.s31-it.on { background: #0000A6; color: #fff; }
.s31-grp { padding: 1px 5px; white-space: nowrap; background: #C7CCD0; border-top: 1px solid #85898C; border-bottom: 1px solid #fff; }

/* ---------- 单选 / 复选：全局统一字形 ---------- */
/* p49 参考图 1:1 复刻（用户要求「全局全部的选择框像素级还原，不得有一个像素的偏差」）：
   外框 = 13×13，1px 纯黑描边 + 11×11 白色内芯；
   选中态 = 一枚 1px 宽的对角像素 X（21 个像素：两条对角线各 11 px、中心共用 1 px），
   X 恰好铺满整个 11×11 内芯 —— 四个端点顶到内框，四周不留白边（旧版 9×9 + 2px 线宽 + 1px 白边已作废）。
   背景图按 border-box 原点 (0,0) 贴 13×13 ⇒ 图里那圈 1px 描边与 CSS 黑边逐像素重合，不产生错位。
   ⚠️ 单选（radio）与复选共用同一字形（用户要求全局统一），radio 不再画圆点、不再圆角。 */
input[type="radio"], input[type="checkbox"] {
  appearance: none; -webkit-appearance: none;
  width: 13px; height: 13px; margin: 0 4px 0 0; padding: 0;
  background-color: #fff;
  border: 1px solid #000;
  border-radius: 0;
  box-sizing: border-box;
  position: relative; vertical-align: -2px;
  background-repeat: no-repeat;
  background-position: 0 0;
  background-origin: border-box;
  background-clip: border-box;
  background-size: 13px 13px;
  image-rendering: pixelated;
}
input[type="radio"]::after, input[type="checkbox"]::after { content: none; }
input[type="radio"]:checked, input[type="checkbox"]:checked {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='13' height='13' viewBox='0 0 13 13' shape-rendering='crispEdges'%3E%3Cpath fill='%23000000' d='M1 1h1v1h-1zM11 1h1v1h-1zM2 2h1v1h-1zM10 2h1v1h-1zM3 3h1v1h-1zM9 3h1v1h-1zM4 4h1v1h-1zM8 4h1v1h-1zM5 5h1v1h-1zM7 5h1v1h-1zM6 6h1v1h-1zM5 7h1v1h-1zM7 7h1v1h-1zM4 8h1v1h-1zM8 8h1v1h-1zM3 9h1v1h-1zM9 9h1v1h-1zM2 10h1v1h-1zM10 10h1v1h-1zM1 11h1v1h-1zM11 11h1v1h-1z'/%3E%3C/svg%3E");
}
input[type="radio"]:disabled, input[type="checkbox"]:disabled { background-color: #C7CCD0; }

/* ---------- 旋转框（替代拖动条，参考图 “2 ▲▼ Minutes”） ---------- */
.spin { display: inline-flex; align-items: center; gap: 4px; }
.spin .spin-in {
  width: 62px; text-align: right; background: #fff;
  box-shadow: inset 1px 1px 0 #85898C, inset -1px -1px 0 #fff, 0 0 0 1px #000;
  border: none; padding: 2px 4px; font-family: inherit;
}
.spin .spin-btns { display: flex; flex-direction: column; }
.spin .spin-btns button {
  width: 15px; height: 10px; min-height: 0; padding: 0; font-size: 7px; line-height: 8px;
  box-shadow: inset 1px 1px 0 #fff, inset -1px -1px 0 #85898C, 0 0 0 1px #000 !important;
  background: #C7CCD0 !important;
}

/* 控制面板：对话框式分组（面板底色与窗口外框一致：实色 + 抖动层，
   否则自定义「窗口背景颜色」时会出现「外框抖动、面板却是纯灰」的割裂观感） */
.cp-root, .cp-side, .cp-main {
  background-color: var(--face) !important;
  background-image: var(--face-dither, none) !important;
  background-size: var(--dither-tile) var(--dither-tile) !important;
}
.cp-cat { display: block; width: 100%; text-align: left; margin-bottom: 2px; }
.cp-cat::before { content: '■'; color: var(--title-active); margin-right: 5px; }
.cp-cat.active::before { color: #000; }
/* ⚠️ 这里不能再写 background 简写：会把上面的 --face-dither 覆盖成 none */
.cp-main { padding: 8px !important; }
/* 控制面板（设置）字距：参考图里的 Win3.1 对话框字距明显比本站像素字体松 ⇒ 整个面板窗口
   （左侧类别栏 + 右侧设置区，含下拉/输入框）统一加 1px，保证同一个对话框内字距一致 */
.cp-root, .cp-root * { letter-spacing: 1px; }
.cp-head { background: transparent !important; color: #000 !important; padding: 2px 0 4px !important; text-align: center; font-weight: bold; }
.cp-panel {
  border: 1px solid #85898C; box-shadow: inset 1px 1px 0 #fff;
  padding: 8px 10px; margin: 0 0 8px; position: relative;
}
.cp-panel > legend, .cp-panel-title {
  position: absolute; left: 8px; top: -8px; background: var(--face); padding: 0 4px; font-weight: bold;
}
.cp-set-item { display: flex; align-items: center; gap: 8px; padding: 3px 2px; border: none !important; }
.cp-set-item > span:first-child { flex: 0 0 226px; }
.cp-radio { display: flex; align-items: center; gap: 4px; padding: 2px 0; }
.cp-note { color: #404040; font-size: 11px; }
.cp-actions { display: flex; justify-content: flex-end; gap: 6px; padding-top: 6px; }

/* ---------- 登录 / 对话框 ---------- */
.wd-dlg, .sysmenu, .nd-menu { background: var(--face) !important; }
.wd-dlg .wd-dlg-t { background: var(--title-bg, var(--title-active)) !important; color: #fff !important; font-weight: bold; }

/* ---------- 等宽按钮（新闻顶栏等） ---------- */
.nw-tab, .nw-act .btn31, .nd-toolbar .btn31, .wd-b, .ct-tools .btn31 {
  min-width: 76px; text-align: center; font-weight: normal !important;
}
.nw-tabs { flex-wrap: nowrap; overflow-x: auto; }
.nw-tab.active { font-weight: normal !important; }

/* ---------- 图片 / 视频内嵌查看器 ---------- */
.media-view { display: flex; flex-direction: column; height: 100%; background: var(--face); }
.media-view .mv-bar { display: flex; gap: 3px; padding: 3px; border-bottom: 1px solid #85898C; flex-wrap: wrap; }
.media-view .mv-stage { flex: 1; background: #000; display: flex; align-items: center; justify-content: center; overflow: auto; }
.media-view .mv-stage img { max-width: 100%; max-height: 100%; image-rendering: pixelated; }
.media-view .mv-stage video { max-width: 100%; max-height: 100%; background: #000; }
.media-view .mv-info { border-top: 1px solid #85898C; padding: 3px 6px; background: var(--face); font-size: 11px; }
.mv-gif { border: 1px solid #000; padding: 4px; background: #000; }

/* ---------- 开机画面 ---------- */
#splash {
  position: fixed; inset: 0; z-index: 100020; background: #008080;
  display: flex; align-items: center; justify-content: center;
}
#splash img { width: 100%; height: 100%; object-fit: cover; image-rendering: pixelated; }

/* ---------- 语言相关的输入法状态栏 ---------- */
body.lang-en #ime-left, body.lang-en #ime-right,
body.lang-eo #ime-left, body.lang-eo #ime-right { display: none !important; }

/* ---------- CRT 默认参数（更透明、线更宽、滚动极慢） ---------- */
:root{
  --crt-w: 2px; --crt-gap: 4px; --crt-speed: 45s;
  --crt-shade: .16; --crt-corner: 42px; --crt-vignette: .38;
}
#crt-overlay{ background-image: repeating-linear-gradient(to bottom, rgba(0,0,0,var(--crt-shade)) 0 var(--crt-w), rgba(0,0,0,0) var(--crt-w) var(--crt-gap)); }

/* ---------- 标题栏按钮：尺寸/正方形/贴合已由文件上方的 p48 规则统一（这里只保留字形大小）---------- */
.tb-btn svg { width: 9px !important; height: 9px !important; }

/* ---------- 开机画面：居中并按分辨率等比缩小 ---------- */
#splash { background: #008080; padding: 4vh 4vw; }
#splash img {
  width: auto; height: auto; max-width: 62vw; max-height: 62vh;
  object-fit: contain; image-rendering: pixelated;
  box-shadow: 0 0 0 2px #000, 6px 6px 0 rgba(0,0,0,.35);
}

/* ---------- 新闻标题栏按钮：窗口变窄时自动双排 ---------- */
.nw-tabs { display: flex; flex-wrap: wrap !important; gap: 3px; padding: 3px 4px; }
.nw-tab { flex: 0 0 auto; min-width: 74px; }
.win[data-app="news"] .nw-tabs { max-height: 56px; overflow-y: auto; }

/* ---------- 悬浮管理面板（右下角） ---------- */
.admin-float {
  position: fixed !important; right: 14px !important; bottom: 34px !important;
  width: 380px !important; max-height: 62vh; z-index: 100004 !important;
  box-shadow: 3px 3px 0 rgba(0,0,0,.45) !important;
}
.admin-float .win-client { max-height: 52vh; overflow-y: auto; }

/* ---------- 像素滚动条（与参考图一致：抖动轨道 + 立体滑块 + 箭头） ---------- */
::-webkit-scrollbar { width: 16px; height: 16px; background: #C7CCD0; }
::-webkit-scrollbar-track {
  background-color: #C7CCD0;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='2' height='2'><rect width='1' height='1' fill='%23ffffff'/><rect x='1' y='1' width='1' height='1' fill='%23ffffff'/></svg>");
}
::-webkit-scrollbar-thumb {
  background: #C7CCD0;
  box-shadow: inset 1px 1px 0 #fff, inset -1px -1px 0 #85898C, 0 0 0 1px #000;
}
::-webkit-scrollbar-button:single-button {
  display: block; width: 16px; height: 16px; background-color: #C7CCD0;
  background-repeat: no-repeat; background-position: center;
  box-shadow: inset 1px 1px 0 #fff, inset -1px -1px 0 #85898C, 0 0 0 1px #000;
}

/* ---------- 指针方案（用户提供的 PNG 光标） ---------- */
/* 拖动/移动窗口：四向箭头 */
.titlebar, .tb-title, .wd-dlg-t, .sysmenu .menu-entry { cursor: var(--cur-move, move); }
.titlebar > .tb-btn, .tb-btn { cursor: var(--cur-hand, pointer); }
/* 窗口四角斜向缩放 */
.win .cnr-nw, .win .cnr-se { cursor: var(--cur-nwse, nwse-resize); }
.win .cnr-ne, .win .cnr-sw { cursor: var(--cur-nesw, nesw-resize); }
/* 不可点击（禁用）控件：禁止光标 */
button:disabled, .btn31:disabled, .btn31.dv-dis, input:disabled, select:disabled, textarea:disabled,
.menu-entry.disabled, .menu-item.disabled, [aria-disabled="true"] {
  cursor: var(--cur-no, not-allowed) !important;
}
/* 加载中：沙漏（优先级要压过禁用态） */
body.pf-busy, body.pf-busy *, body.pf-busy button, body.pf-busy .btn31, body.busy, body.busy *, body.busy button, body.busy .btn31 {
  cursor: var(--cur-wait, wait) !important;
}

/* ---------- 楼中楼：按层级区分楼层牌颜色（深底白字，保证对比度） ---------- */
.cm-floor.cm-lv0 { background: #0000A8; color: #fff; }
.cm-floor.cm-lv1 { background: #0B5A0B; color: #fff; }
.cm-floor.cm-lv2 { background: #8A2A00; color: #fff; }
.cm-floor.cm-lv3 { background: #4A2A8A; color: #fff; }
.cm-floor.cm-lv4 { background: #005A5A; color: #fff; }
.cm-floor.cm-lv5 { background: #8A2050; color: #fff; }
.cm-floor.cm-lv6 { background: #2A2E3A; color: #fff; }

/* ---------- 新闻工具栏：网格对齐（换行时第二行与第一行上下左右对齐）+ 高度可拖动 ---------- */
.win[data-app="news"] .nw-tabs, .nw-tabs {
  display: grid !important;
  grid-template-columns: repeat(auto-fill, minmax(78px, 1fr));
  gap: 3px;
  padding: 3px 4px;
  align-content: start;
  overflow-y: auto;
  overflow-x: hidden;
  max-height: none;
}
.nw-tabs > .btn31 { width: 100%; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nw-tabsplit {
  flex: none; height: 6px; cursor: var(--cur-ns, ns-resize);
  background: var(--face, #C7CCD0);
  border-top: 1px solid #fff; border-bottom: 1px solid #85898C;
}
body.nw-tab-drag, body.nw-tab-drag * { cursor: var(--cur-ns, ns-resize) !important; user-select: none; }

/* ---------- 新闻：等级悬浮卡（Windows 3.1 UI） ---------- */
.nw-lvtip {
  position: fixed; z-index: 100060; min-width: 232px; max-width: 320px;
  background: #ffffe1; color: #000;
  border: 2px outset #dfdfdf; box-shadow: 3px 3px 0 rgba(0,0,0,.35);
  padding: 6px 8px; font-size: 12px; line-height: 1.5;
}
.nw-lvtip h5 { margin: 0 0 4px; font-size: 12px; }
.nw-lvtip .nw-lvtip-sec { margin-top: 5px; padding-top: 4px; border-top: 1px dotted #808080; }
.nw-lvtip table { border-collapse: collapse; width: 100%; }
.nw-lvtip td { padding: 0 4px; white-space: nowrap; }
.nw-lvtip tr.me { background: #0000A8; color: #fff; }
.nw-lvtip .lv-name { font-weight: bold; }
.nw-lvtip .lv-exp { text-align: right; }
.nw-lvtip .lv-rank { text-align: right; }

/* ============================================================
 * 窗口工具栏（File / Options）字号 +1
 *   菜单栏本体 13px / 下拉菜单里的条目回到 12px 常规（避免下拉框过粗）
 *   字重已改为常规 —— 与标题栏保持一致（加粗交给字距，见 p44 块）
 * ============================================================ */
.menu-bar { font-size: 13px; font-weight: normal; }
.menu-item { padding: 0 9px 0 8px; }
.menu-dropdown, .menu-entry, .menu-sep { font-size: 12px; font-weight: normal; }

/* ---------- p47：下拉菜单三列（勾选沟槽 / 标签 / 快捷键） ----------
   参考图里快捷键是**左对齐成一列**的（Enter / F7 / F8 / Del / Alt+Enter 起头齐平），
   所以给标签一个固定最小宽度，快捷键接着它排；勾选态在最左侧沟槽里画 √。

   ⚠️ 尺寸按参考图**用行高 R 归一化**后取值（参考图是缩放过的截图，绝对值不可用，
      只有比例可靠；标定脚本 _dev/geom47.js / _dev/bands47.py）：
        File 菜单参考图（376×391）：下拉外框 325×261，行距 R=29.5，标签墨迹距框左 30，
                                  快捷键列距框左 208 ⇒ 标签 1.02R / 快捷键 7.05R / 宽 11.02R
        Options 菜单参考图（283×145）：√ 墨迹距框左 8、标签墨迹距框左 27、行距 R=29
                                  ⇒ √ 0.28R / 标签 0.93R
        菜单栏高度 / R：参考 26/29 = 0.90
      取 checkX=5、labelX=18、keyX=144（R≈20 时即 0.25R / 0.90R / 7.2R），
      与参考最大偏差 <4%。左内边距 4px 即由此而来：
      `1px 黑框 + 4px 条目左内边距` ⇒ √ 沟槽左沿 5px、标签左沿 18px，
      与参考图实测的 5.4 / 18.3（已按比例折算到 1× ）对齐。
      （下拉框本身不留内边距 —— 首项色块要贴死黑框，见 win31.css 的 `.menu-dropdown`。） */
.menu-dropdown .menu-entry { display: flex; align-items: center; padding: 4px 11px 4px 4px; }
.menu-dropdown .menu-check { flex: none; width: 13px; line-height: 1; }
.menu-dropdown .menu-label { flex: 0 0 auto; min-width: 120px; }
.menu-dropdown .menu-key { flex: none; margin-left: 6px; }

/* 程序管理器（主窗口）的工具栏：背景纯白，下方保留原本的单边线 */
.win[data-app="progman"] > .menu-bar { background: #fff !important; }
/* 程序管理器点工具栏弹出的下拉菜单：背景同样纯白（条目 hover 仍是蓝底白字）；
   并按参考图加宽（比默认长出一截，标签与快捷键两列各自成列）。 */
.win[data-app="progman"] .menu-dropdown { background: #fff !important; min-width: 196px; }
.win[data-app="progman"] .menu-dropdown .menu-sep { background: #808080; border-bottom: 1px solid #fff; }

/* 登录对话框 / 对话框式窗口（WM.create 的 dialog:true —— 关于 / 扫雷）：
   它们的左上角就是系统菜单盒。p48 起**所有**窗口的关闭键统一是「灰底平的 + 中空横杠」，
   所以这里不再需要额外补灰底/描边 —— 补了反而会与内侧黑线叠成「两排像素」。 */
.win[data-app="login"] .titlebar > .tb-btn:first-child:active,
.win.dlg-win .titlebar > .tb-btn:first-child:active { background: #BFC4C8 !important; }

/* ============================================================
 * 图标自由拖动 / 重叠（Windows 3.1 手感）
 *   · 拖动超过阈值后：隐藏文字标签、图标变黑白（Win3.1 的拖动反馈）
 *   · 松手后恢复原样，并可与其他图标任意重叠
 *   · 「排列图标」会把 .free 全部清除，回到对齐的网格排列
 * ============================================================ */
.icon-item, .tray-icon { touch-action: none; }
.icon-item.free, .tray-icon.free { position: absolute !important; margin: 0 !important; }
.icon-item.dragging, .tray-icon.dragging { z-index: 60; }
.icon-item.dragging .icon-label, .tray-icon.dragging .icon-label { visibility: hidden; }
.icon-item.dragging .icon-img, .tray-icon.dragging .icon-img { filter: grayscale(1) contrast(1.4); }
body.icondrag, body.icondrag * { cursor: var(--cur-move, move) !important; user-select: none; }

/* ============================================================
 * Win3.1 滚动条（照参考图 1:1 复刻，用于程序管理器）
 *   轨道：纯灰（无网点）；箭头键 / 滑块 / 角块：1px 黑框 + 左上白高光 + 右下深灰阴影
 *   相邻部件共用同一条 1px 黑线（黑线由「容器左边 / 相邻部件的交界边」各画一次，坐标重合）
 * ============================================================ */
.sb31 { position: absolute; background: var(--face); z-index: 8; box-sizing: border-box; }
.sb31-v {
  top: 0; right: 0; bottom: var(--sbw, 16px); width: var(--sbw, 16px);
  display: flex; flex-direction: column;
  border-left: 1px solid #000; border-top: 1px solid #000;
}
.sb31-h {
  left: 0; right: var(--sbw, 16px); bottom: 0; height: var(--sbw, 16px);
  display: flex; flex-direction: row;
  border-left: 1px solid #000; border-top: 1px solid #000;
}
.sb31-corner {
  right: 0; bottom: 0; width: var(--sbw, 16px); height: var(--sbw, 16px);
  border-left: 1px solid #000; border-top: 1px solid #000;
}
.sb31-btn {
  flex: 0 0 auto; padding: 0; margin: 0; border: 0; box-sizing: border-box;
  /* 必须清零：全局皮肤 button{min-height:19px} 会把 16px 的箭头键顶高，撑破条框 */
  min-width: 0; min-height: 0; max-height: none; font-weight: normal;
  background: var(--face);
  display: flex; align-items: center; justify-content: center;
  box-shadow: inset 1px 1px 0 #fff, inset -1px -1px 0 #84888C !important;
}
/* 箭头键：长轴 = 条宽；跨轴用 align-self:stretch 吃满。
 * 别用 height/width:100% —— body 上有 zoom，百分比尺寸会被二次缩放，按钮会高出条框。 */
.sb31-h > .sb31-btn { width: var(--sbw, 16px); align-self: stretch; }
.sb31-v > .sb31-btn { height: var(--sbw, 16px); align-self: stretch; }
.sb31-track { position: relative; flex: 1 1 auto; background: var(--face); box-sizing: border-box; }
/* 滑块：跨轴吃满轨道（含条自身那条黑线），长轴由 JS 设 position/length */
.sb31-thumb {
  position: absolute; box-sizing: border-box;
  background: var(--face); border: 1px solid #000;
  box-shadow: inset 1px 1px 0 #fff, inset -1px -1px 0 #84888C;
}
.sb31-h .sb31-thumb { top: -1px; bottom: 0; }
.sb31-v .sb31-thumb { left: -1px; right: 0; }
/* 部件之间的分隔黑线：只由右侧（下侧）那个部件的 border 画一次，全条等高 */
.sb31-h > .sb31-track, .sb31-h > .sb31-btn.b { border-left: 1px solid #000; }
.sb31-v > .sb31-track, .sb31-v > .sb31-btn.b { border-top: 1px solid #000; }
.sb31-glyph { display: block; }
/* 滚动条粗细：跟随设置项「滚动条宽度」（--sb-w，默认 16px） */
:root { --sbw: var(--sb-w, 16px); }
/* 真正的滚动容器：占满客户区，让出右侧与下方滚动条；原生滚动条隐藏 */
/* ⚠️ p74：宿主自身必须**既是定位祖先、又自己裁剪**。
   ① `position:relative` ⇒ .sb31-sc（绝对定位）的包含块恒为宿主本身。
      这一点很关键：绝对定位元素只被「包含块链上」的祖先裁剪 —— 宿主一旦退回 static，
      .sb31-sc 的包含块就会跳到 .win-client，`.cp-main` 那层 overflow:hidden 立刻失去裁剪权。
   ② 宿主自己再兜一层 overflow:hidden ⇒ 即使内层 .sb31-sc 的裁剪因任何原因失效
      （变量非法导致盒高塌陷、合成器把 clip 矩形算错……），内容也不可能画到宿主之外
      —— 也就是不可能再压到状态栏、画出窗口。
   宿主里除了 .sb31-sc 与三条滚动条没有别的在流内容，而它们是绝对定位在宿主盒内的，
   所以这一层裁剪对既有观感是**恒等变换**（已用整屏像素 diff 复核）。 */
.sb31-host { position: relative; overflow: hidden; }
.sb31-sc {
  position: absolute; top: 0; left: 0;
  right: var(--sbw, 16px); bottom: var(--sbw, 16px);
  overflow: auto;
  /* ⚠️ p74：再补一道**硬裁剪**。
     用户实拍截图取证结论：`.sb31-sc` 的盒子尺寸是**正确**的（底边与水平条、状态栏齐平），
     但它的内容没有被裁剪 —— 也就是「overflow 裁剪矩形在渲染时被丢掉了」，
     于是列表从状态栏一路画到窗口外、画出窗口框（且 .cp-main / .win-client 那两道
     overflow:hidden 也没拦住）。这属于绘制阶段的问题，不是布局问题。
     `contain: paint` 把裁剪变成**元素自身的绘制包含**（绘制阶段硬边界），
     与 `overflow` 那条裁剪走的是不同实现路径 ⇒ 即便 overflow 的裁剪矩形丢了，这一道仍在。
     安全性：本站在 .sb31-sc **内部**不放任何 fixed/absolute 浮层 —— 实测
     `select31.js` / `datepick31.js` / `chat.js` 的气泡 / `__popAt` 全部挂 `document.body`，
     窗口菜单 `.menu-dropdown` 挂 `.menu-item`（在 .win-client 里，不在滚动容器里）；
     所以 containment 的「包含块上提 / 剪掉浮层」副作用在本站没有受力点。
     js/scroll31.js 另有几何钉死 + 长胖自愈兜底，这一条只负责「裁剪」。 */
  contain: paint;
  scrollbar-width: none; -ms-overflow-style: none;
}
.sb31-sc::-webkit-scrollbar { display: none; width: 0; height: 0; }
/* 拖不动 / 已到头的箭头键：字形变灰（Win3.1 的禁用外观） */
.sb31-btn.off .sb31-glyph rect { fill: #84888C; }
.sb31-btn.active { box-shadow: inset 1px 1px 0 #84888C, inset -1px -1px 0 #fff !important; }
.sb31-thumb { cursor: var(--cur-arrow, default); }
body.sb31-drag, body.sb31-drag * { user-select: none; }

/* ============================================================
 * Win3.1 轮廓拖动：中空「抖动灰点」框
 * ------------------------------------------------------------
 * 拖动窗口时窗口本体留在原地，只有一个中空点阵框跟手移动。
 * 框的尺寸 = 窗口外框尺寸（由 JS 写入 left/top/width/height），
 * 线宽 = 窗口外框厚度（JS 量 border+padding 后写成 --ghost-band）。
 * 点阵用 2×2 只填对角两个像素的 SVG ⇒ 45° 黑点阵，远看即「抖动灰」。
 * ============================================================ */
.wmove-ghost {
  position: fixed; z-index: 99990; pointer-events: none;
  --ghost-band: 4px;
  /* 2×2 棋盘：只有对角两个像素「亮」，即 50% 抖动 */
  --ghost-dither: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='2' height='2'%3E%3Cpath d='M0 0h1v1H0zM1 1h1v1H1z' fill='%23000'/%3E%3C/svg%3E");
  /* Win3.1 的拖动外框用的是 XOR 光栅操作：画出来的点＝它盖住那块地方的反色。
     difference 混合＝逐通道 |背板-源|，源取纯白 ⇒ 结果恰好是 1-背板，即反色。
     之所以不用 backdrop-filter:invert(1)：body 上有 zoom(UI 缩放)，Chromium 的
     backdrop-filter 在 zoom 子树里采样区域会错位；混合模式没有这个问题。 */
  mix-blend-mode: difference;
}
.wmove-ghost > i {
  position: absolute; display: block;
  background: #FFFFFF;
  -webkit-mask-image: var(--ghost-dither);
  mask-image: var(--ghost-dither);
  -webkit-mask-size: 2px 2px;
  mask-size: 2px 2px;
  -webkit-mask-repeat: repeat;
  mask-repeat: repeat;
  image-rendering: pixelated;
}
/* 兜底：万一 mask 不被支持，退回实心白色散点（配合 difference 仍是反色点阵） */
@supports not ((mask-image: none) or (-webkit-mask-image: none)) {
  .wmove-ghost > i { background-image: var(--ghost-dither); background-size: calc(2px / var(--ui-scale, 1)) calc(2px / var(--ui-scale, 1)); background-repeat: repeat; }
}
.wmove-ghost > i.t { left: 0; right: 0; top: 0; height: var(--ghost-band); }
.wmove-ghost > i.b { left: 0; right: 0; bottom: 0; height: var(--ghost-band); }
.wmove-ghost > i.l { left: 0; top: 0; bottom: 0; width: var(--ghost-band); }
.wmove-ghost > i.r { right: 0; top: 0; bottom: 0; width: var(--ghost-band); }
/* 拖动中整屏用移动光标 */
body.win-move, body.win-move * { cursor: var(--cur-move, move) !important; user-select: none !important; }

/* ---- p43: 分享卡片可点 + 附加内容 ---- */
.sh-clickable { cursor: var(--cur-hand, pointer); }
.sh-clickable:hover { box-shadow: 0 0 0 1px var(--title-active, #0000A8); }
.sh-card-extra { border-left: 3px solid #808080; padding-left: 6px; }

/* ============================================================
 * p44：字距 / 弹层统一 / 图标文字字体 / 日期选择器 / 聊天
 * ============================================================ */

/* ---------- 1. 标题栏与工具栏：去加粗 + 加字距 ----------
   参考图里标题与工具栏文字是「常规字重 + 明显的字距」，不是靠加粗撑起来的。
   只加在标题栏与各工具栏的按钮/菜单项上，不动下拉菜单条目与正文。 */
.titlebar .tb-title,
.menu-bar, .menu-bar .menu-item,
.wd-bars .wd-b, .wd-bar label,
.dv-toolbar button, .dv-toolbar .dv-bt,
.mv-bar button,
.ct-tools button,
.nd-toolbar button, .nd-toolbar .btn31,
.nw-toolbar button, .nw-act button, .nw-tab,
.rdr-srow .btn31, .rdr-srow .rdr-tab, .rdr-mid-top .btn31 {
  letter-spacing: 1px;
}
.titlebar .tb-title { font-weight: normal !important; }

/* ---------- 2. 系统菜单（关闭键下拉）统一：白底 + 与工具欄 File 下拉**逐项同规格** ----------
   .sysmenu 原先跟 .nd-menu 一样是灰底（--face），和程序管理器/文件管理器的白底下拉菜单
   不一致；字体也走回 12px 常规。
   ⚠️ p138①：用户要求系统菜单下拉的**字体大小 / 字体 / 选中颜色**与工具欄 File 下拉一致。
      光靠 `.sysmenu .menu-entry` 那条规则做不到 —— 工具欄下拉的条目在 `.menu-dropdown`
      里，会命中 `.menu-dropdown .menu-entry { display:flex; padding:4px 11px 4px 4px }`
      以及 `.menu-dropdown .menu-label { min-width:120px }`；而系统菜单不在
      `.menu-dropdown` 里 ⇒ 拿到的是**另一套**内距（2px 18px 2px 20px），且新加的
      `.menu-label` 没有 flex 约束 ⇒ 列宽对不上。
      这里把系统菜单的条目**提升到与 File 下拉完全相同的规格**，并把选中态补上
      （鼠标悬停 + 打开即预选第一项，两者都用 File 下拉的同一对颜色变量）。
   ⚠️ 系统菜单的**外框更窄**是刻意的（只有 6 项、标签短），所以 min-width 保持 132px，
      但条目内部的三列几何与 File 完全一致。 */
.sysmenu {
  background: #fff !important;
  border: 1px solid #000 !important;
  box-shadow: 2px 2px 0 rgba(0, 0, 0, .4) !important;
  padding: 1px !important;
  min-width: 132px;
  font-family: inherit;
  font-size: 12px;
  font-weight: normal;
}
/* 与 `.menu-dropdown .menu-entry` 同规格（display/padding/字号/字重/字族） */
.sysmenu .menu-entry {
  display: flex;
  align-items: center;
  font-family: inherit;
  font-size: 12px;
  font-weight: normal;
  padding: 4px 11px 4px 4px;
  color: #000;
}
/* 三列骨架与 File 下拉同规格（沟槽 13px / 标签最小宽 / 快捷键留白） */
.sysmenu .menu-check { flex: none; width: 13px; line-height: 1; }
.sysmenu .menu-label { flex: 0 0 auto; min-width: 120px; }
.sysmenu .menu-key { flex: none; margin-left: 6px; }
.sysmenu .menu-entry.disabled { color: #9aa0a6; }
/* 选中色：必须**升特异性 + 同带 !important** 才能压过上面的 `.sysmenu .menu-entry { color:#000 }`
   （两条都是 (0,2,0)，而 v7.css 排在 win31.css 之后 ⇒ 不加这一条则 .sel 的黑字取胜 =
   打开系统菜单「没有任何选中色」）。颜色取全站同一对 --sel-bg/--sel-fg，
   与工具欄 File 下拉的 `.menu-entry:hover,.menu-entry.sel` 一字不差。 */
.sysmenu .menu-entry:hover,
.sysmenu .menu-entry.sel { background: #0000a8 !important; color: #fff !important; }
.sysmenu .menu-entry.disabled:hover,
.sysmenu .menu-entry.disabled.sel { background: transparent !important; color: #9aa0a6 !important; }
.sysmenu .menu-sep { margin: 2px 0; background: #808080; border-bottom: 1px solid #fff; }

/* 文件管理器的右键菜单同样统一为白底（原来也是灰底） */
.nd-menu { background: #fff !important; }

/* ---------- 3. 管理器与桌面图标下的文字：恢复原来的字体（停用 Win31System） ----------
   Win31System 只有 204 个字形、且笔画偏细，图标下的中文+英文混排不好看；
   这里显式回到引入该字体之前的点阵字体栈。 */
.icon-item .icon-label,
.tray-icon .icon-label,
.icon-tray .icon-label {
  font-family: 'SimSun31', 'MSSansPixel', 'F31Latin', 'ZpixCJK', 'F31Hans', 'F31Hant', monospace !important;
  letter-spacing: 0;
}

/* ---------- 4. Win3.1 消息框（Exit Windows 确认框）----------
   全部数字来自参考图逐像素实测（`_dev/_an6.py`~`_an10.py`），
   参考图 1 参考像素 = 1/2.05 CSS px（标定见 js/main.js msgBox31 注释）。
   参考图换算：客户区 292×104 ／ 图标 32×32 @ 左上各 10px ／ 正文左边距 56px、
   行心距客户区上 26px ／ 按钮 72×23、水平居中、间距 38px、距底 9px。
   ⚠️ 窗口本体走本站标准 WM 对话框（.win.dlg-win），所以标题栏 / 系统菜单盒 /
   三键几何一律沿用既有实现，这里**只排客户区内容**，不要再画一套边框。 */
.msg31 { height: 100%; display: flex; flex-direction: column; overflow: hidden; }
/* 上块 flex:1 ⇒ 把按钮行顶到客户区底部；图标/正文按 center 垂直对齐（正文 line-height
   撑到 32px，于是它的行心正好落在图标中线上，与参考图一致）。 */
/* ⚠️ 三个数字都是对着参考图**同时**解出来的（`_dev/_an50.py` + `_dev/_zoom.py` 放大对照）：
   · padding-top 8（原 10）—— 参考图图标盒顶在 CSS y 34.2，我的在 36 ⇒ 整块上移 2px；
   · gap 12（原 14）—— 参考图正文墨迹左沿 CSS x 61.1，我的 63.0 ⇒ 左移 2px；
   · .msg31-t 再 margin-top:-2px —— 参考图**正文墨迹顶**在 y 43.5，图标顶 34.2，两者只差 9.3px；
     我的差 11px（12px 字号在 32px 行盒里居中就是这个位置）⇒ 正文要相对图标单独上抬 2px。
   · letter-spacing .45px —— 参考图正文墨迹宽 211.1px，Win31System@12 只有 198（`_dev/_inkprobe.js`
     实测）。参考图用的 Win3.1 原版 System 点阵比 win31-system.otf **宽约 7%**，本机没有那一款；
     逐字符补 0.45px 后墨迹 = **213×12**，与参考图的 211.1×11.7 **宽高同时贴合**。
     （试过 13px：墨迹 214×**13**，宽对了但高多 1.3px ⇒ 否决。） */
.msg31-top {
  flex: 1 1 auto; min-height: 0;
  display: flex; align-items: flex-start; gap: 12px;
  padding: 8px 16px 0 10px; box-sizing: border-box;
}
.msg31-i { flex: 0 0 auto; width: 32px; height: 32px; }
.msg31-i svg { display: block; width: 32px; height: 32px; image-rendering: pixelated; }
.msg31-t {
  flex: 1 1 auto; min-width: 0;
  font-size: 12px; line-height: 32px;
  margin-top: -.5px; letter-spacing: .45px;
}
/* 参考图标题「Exit Windows」墨迹 = CSS 115.33..205.73（宽 **90.89**）× 高 10.26、中心 x 160.53。
   本站全局 `.tb-title` 是 13px + letter-spacing 1px ⇒ 墨迹 113.00..207.00（宽 **95.00**）× 10.00、中心 160.00。
   中心与高度都对得上（差 0.5px / 0.26px），只有**宽度多 4.1px**（12 个字符 × 0.35px）。
   ⇒ 只在消息框里把字符间距收到 0.65px；**不动全局**，免得把其它窗口的标题栏（早先批次已按别的参考图定过）改坏。 */
.win[data-app="msgbox31"] .tb-title { letter-spacing: .65px; }
.msg31-f {
  flex: 0 0 auto; display: flex; justify-content: center; gap: 38px;
  padding: 0 0 9px; box-sizing: border-box;
}
/* 参考图实测按钮 72×23（比本站通用 .btn31 的 19px 高 4px —— 直接照参考图给死） */
.msg31-f .btn31 {
  width: 72px; min-width: 72px; min-height: 0; height: 23px;
  padding: 0; flex: 0 0 auto; line-height: 21px; text-align: center;
  outline: none !important;
  display: flex; align-items: center; justify-content: center;
}
/* 参考图实测：默认键（OK）的**黑色外框是 2px**（普通键只有 1px），
   且默认键的**文字**上再套一个 1px 点线焦点框 —— 不是整个按钮套一圈虚线。
   ⚠️ 焦点框尺寸也是实测的（`_dev/_an42.py`）：参考图里点线段是 (132,136,140)，
   列 179..224、行 178..209 ⇒ **22.5 × 15.6 CSS px**，垂直方向偏上（距按钮顶 3.9、
   距底 2.4 参考换算）。所以**必须给 label 一个固定高度**：光靠 flex 居中会让
   line-height:21px 把这个 span 撑到 23px（= 整个按钮高），虚线圈就顶到上下边框上了。 */
.msg31-f .btn31.default { box-shadow: inset 1px 1px 0 #fff, inset -1px -1px 0 #85898C, 0 0 0 2px #000 !important; }
.msg31-f .btn31.default .msg31-bi {
  border: 1px dotted #000; padding: 0 3px;
  height: 15px; line-height: 15px;
  display: flex; align-items: center; justify-content: center;
}

/* ---------- 消息框专用外框（对齐参考图的「深蓝包边 + 内侧 1px 白高光」）----------
   参考图的窗口包边不是灰色，而是**与标题栏同色**（实测 #0000a8，宽 8 参考 px ÷ 2.05 = 3.9 ≈ 4px）。
   包边剖面（`_dev/_an50.py` 第 1 节，参考图 x3..x22）：
       x6 #000000（外黑线）→ x8..x15 #0000a8（海军蓝）→ x16 #c8c8eb(AA) → **x17 #fcfcfc（白高光）** → 内容
   纵向同理（第 3 节，参考图 y10..y40）：y14 #000000 → y16..y21 蓝 → y23 **#fcfcfc** → 内容。
   ⇒ 包边 4px（原 3px）+ **内侧 1px 白线**，客户区仍是 292×104，窗口 302×114。
   ⚠️ 之前这里把 `.win::after`（内侧线）直接关掉了 —— 参考图确实没有内侧**黑**线，但有一条内侧**白**线；
      现在改成白线画在包边最里 1px（inset:3px ≡ border-box 内缩 4px，见上面 .win::after 的注释）。 */
.win[data-app="msgbox31"] {
  background-color: var(--title-active) !important;
  background-image: none !important;
  padding: 4px !important;
}
.win[data-app="msgbox31"]::after {
  inset: 3px;
  box-shadow: inset 0 0 0 1px #ffffff !important;
}
/* 客户区：参考图标题栏下面**直接就是白底内容**，没有 .win-client 自带的
   face-shadow 灰边（上/左 #85898C）和 `margin-top:1px`。
   `_dev/_an50.py` 第 2 节实测：参考图正文区左侧剖面是 蓝 → 白 → 白，
   我原来多出 x5 的 #737679 灰竖条（= 客户区左灰边）与 y25 的灰横条（= 客户区上灰边）。 */
.win[data-app="msgbox31"] .win-client {
  border-color: #ffffff !important;
  margin-top: 0 !important;
}

/* ---------- 5. Win3.1 日期选择器（替代浏览器原生 <input type=date>） ---------- */
.d31 {
  display: inline-flex; align-items: center; height: 19px; box-sizing: border-box;
  background: #fff; color: #000; vertical-align: middle; padding-left: 3px;
  box-shadow: inset 1px 1px 0 #85898C, inset -1px -1px 0 #fff, 0 0 0 1px #000;
  font-family: inherit; font-size: inherit; cursor: default; user-select: none; outline: none;
  max-width: 100%; overflow: hidden;
}
.d31-val { flex: 1 1 auto; min-width: 0; overflow: hidden; white-space: nowrap; line-height: 15px; padding: 1px 2px 1px 1px; }
.d31-val.ph { color: #85898C; }
.d31-btn {
  flex: 0 0 auto; width: 16px; align-self: stretch; display: flex; align-items: center; justify-content: center;
  background: #C7CCD0; border-left: 1px solid #000;
}
.d31-btn svg { width: 12px; height: 11px; }
.d31:active .d31-btn, .d31.open .d31-btn { box-shadow: inset 1px 1px 0 #85898C, inset -1px -1px 0 #fff; }
.d31.open .d31-val, .d31:focus .d31-val { background: #0000A6; color: #fff; }
.d31.d31-dis { color: #85898C; }
.d31-pop {
  position: fixed; z-index: 100002; background: #C7CCD0; color: #000;
  border: 1px solid #000; box-shadow: 2px 2px 0 rgba(0, 0, 0, .4); padding: 2px;
  font-family: inherit; font-size: 12px; user-select: none;
}
.d31-head { display: flex; align-items: center; gap: 2px; margin-bottom: 2px; }
.d31-nav, .d31-fbtn {
  width: 17px; height: 17px; display: flex; align-items: center; justify-content: center;
  background: #C7CCD0; box-shadow: inset 1px 1px 0 #fff, inset -1px -1px 0 #85898C, 0 0 0 1px #000;
  font-size: 10px; color: #000;
}
.d31-nav:active, .d31-fbtn:active { box-shadow: inset 1px 1px 0 #85898C, inset -1px -1px 0 #fff, 0 0 0 1px #000; }
.d31-title { flex: 1; text-align: center; background: #0000A6; color: #fff; line-height: 17px; padding: 0 2px; }
.d31-grid { display: grid; grid-template-columns: repeat(7, 20px); background: #fff; box-shadow: inset 1px 1px 0 #85898C, inset -1px -1px 0 #fff; }
.d31-w { text-align: center; line-height: 16px; color: #000080; background: #C7CCD0; border-bottom: 1px solid #85898C; }
.d31-d { text-align: center; line-height: 16px; cursor: default; }
.d31-d.o { color: #9aa0a6; }
.d31-d:hover { background: #000080; color: #fff; }
.d31-d.today { outline: 1px dotted #000; outline-offset: -1px; }
.d31-d.sel { background: #0000A6; color: #fff; }
.d31-foot { display: flex; justify-content: space-between; margin-top: 2px; }
.d31-today { padding: 0 6px; line-height: 17px; }

/* ---------- 5. 聊天：消息菜单 / 引用块 / 转发 / 翻译 ---------- */
.ct-menu {
  position: fixed; z-index: 100030; background: #fff; color: #000;
  border: 1px solid #000; box-shadow: 2px 2px 0 rgba(0, 0, 0, .4); padding: 1px; min-width: 132px;
  font-family: inherit; font-size: 12px; font-weight: normal;
}
.ct-menu .mi { padding: 2px 18px 2px 20px; white-space: nowrap; }
.ct-menu .mi:hover { background: #000080; color: #fff; }
.ct-menu .sep { height: 1px; margin: 2px 0; background: #808080; border-bottom: 1px solid #fff; }
.ct-msg.ct-hit .ct-bubble { outline: 2px dotted #0000A6; outline-offset: 1px; }
.ct-quote { border: 1px solid #0000A6; background: #cfe0ff; padding: 2px 5px; margin-bottom: 3px; cursor: pointer; }
.ct-quote-h { font-size: 11px; color: #000080; }
.ct-quote-b { font-size: 12px; color: #000; max-height: 48px; overflow: hidden; white-space: pre-wrap; word-break: break-word; }
.ct-quote:hover { background: #b9d2ff; }
.ct-qbar { display: flex; align-items: center; gap: 6px; border: 1px solid #0000A6; background: #cfe0ff; padding: 2px 5px; margin: 3px; }
.ct-qbar .ct-qb-t { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ct-fav { color: #a80000; margin-left: 4px; }
.ct-empty { padding: 14px; }

/* ---------- 6. 视频播放器工具栏：所有控件等宽等高、行列对齐 ----------
   原来 .mv-bar 是纯 flex-wrap：按钮 77~96px 不等、spin 框 147~182px、
   自绘下拉更被 .input31{width:100%} 撑到 898px（独占整行）。
   这里把**每个直接子元素**锁成同一列宽 + 同一行高（!important 才压得住
   .s31 的 inline width 与 .input31 的 width:100%），于是自动换行后行列都对齐。
   注意：选择器只作用于直接子元素，spin 里的 ▲▼ 小按钮不受影响。 */
.media-view .mv-bar {
  --mv-col: 118px;
  display: flex; flex-wrap: wrap; gap: 3px; padding: 3px;
  border-bottom: 1px solid #85898C; align-items: center;
}
.media-view .mv-bar > * {
  flex: 0 0 var(--mv-col) !important;
  width: var(--mv-col) !important;
  min-width: 0 !important;
  max-width: none !important;
  height: 22px !important;
  margin: 0 !important;
  box-sizing: border-box;
  /* 不折行：列宽已按最长标签算好（见 video.js 的 fitBar），折行会被 22px 高度裁掉 */
  white-space: nowrap;
}
.media-view .mv-bar .s31 { height: 22px !important; }
.media-view .mv-bar .s31 .s31-val { line-height: 18px; }
.media-view .mv-bar .spin {
  display: flex; align-items: center; gap: 2px; padding: 0 2px 0 4px;
  border: 1px solid #000; background: #C7CCD0;
  box-shadow: inset 1px 1px 0 #fff, inset -1px -1px 0 #85898C;
}
.media-view .mv-bar .spin .cp-note {
  flex: 1 1 auto; min-width: 0; color: #000; font-size: 11px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  /* p82：同 css/v6.css 里 .wd-bar > .cp-note.wd-glab 的注释 —— 字面盒 14px 塞进 11px 行盒，
     用「padding 2px + margin 4px（合计仍是原来的 6px）」把裁剪盒上下各外扩 2px，
     margin 盒尺寸不变 ⇒ .spin(flex+align-items:center) 居中结果与文字位置都不动。 */
  padding: 2px 0; margin: 4px 0;
}
.media-view .mv-bar .spin .spin-in {
  flex: 0 0 32px; width: 32px; height: 16px; padding: 0 2px;
  font-family: inherit; font-size: 12px; text-align: right;
  background: #fff; border: 1px solid #000; box-shadow: inset 1px 1px 0 #85898C;
}
.media-view .mv-bar .spin-btns { flex: 0 0 auto; display: flex; flex-direction: column; gap: 1px; }
.media-view .mv-bar .spin-btns button {
  width: 13px; height: 8px; min-width: 0; padding: 0; font-size: 6px; line-height: 7px;
  border: 1px solid #000; background: #C7CCD0;
  box-shadow: inset 1px 1px 0 #fff, inset -1px -1px 0 #85898C;
}
.media-view .mv-bar .spin-btns button:active { box-shadow: inset 1px 1px 0 #85898C, inset -1px -1px 0 #fff; }

/* ============================================================
 * p45 · 世界语界面：全局回退到「旧字体」
 * ------------------------------------------------------------
 * Win31System（p44 起用于标题栏/工具栏的「新字体」）只有 204 个字形，
 * 完全没有 ĉ ĝ ĥ ĵ ŝ ŭ 这些带帽字母 ⇒ 世界语文案会按**字**回退到
 * 中文点阵/宋体，一行里混出两三种字形（见用户反馈截图）。
 * 所以 body.lang-eo 下整站改用旧的 Microsoft Sans 像素栈，并停用 Win31System。
 * 用 --font-31 / --app-font 双变量 + 通配 !important
 * （!important 才能压过 settings.js 往 body 写的行内 font-family / --app-font）。
 * ============================================================ */
body.lang-eo {
  --font-31: 'SimSun31', 'MSSansPixel', 'F31Latin', 'ZpixCJK', 'F31Hans', 'F31Hant', monospace !important;
  --app-font: 'SimSun31', 'MSSansPixel', 'F31Latin', 'ZpixCJK', 'F31Hans', 'F31Hant', monospace !important;
}
body.lang-eo,
body.lang-eo *:not(.mines-led):not(.ck-led) {
  font-family: 'SimSun31', 'MSSansPixel', 'F31Latin', 'ZpixCJK', 'F31Hans', 'F31Hant', monospace !important;
}
/* LED 数码管（扫雷 / 时钟）与图标位图字形保持各自字体 */
body.lang-eo .mines-led, body.lang-eo .ck-led { font-family: inherit; }

/* ============================================================
 * p45 · 聊天：Markdown/Wikitext 渲染 · 代码灰框 · 头像 · 信息卡 ·
 *        右侧群成员/群公告栏 · 可拖拽按钮栏
 * ============================================================ */

/* ---------- 版面：消息区 + 右侧栏 ---------- */
.ct-body { flex: 1; min-height: 0; display: flex; align-items: stretch; }
.ct-body > .ct-log { flex: 1; min-width: 0; }
.ct-convs { flex: 1; min-height: 0; overflow-y: auto; }

/* ---------- 气泡内 Markdown 排版 ---------- */
.ct-bubble .ct-text { line-height: 1.45; }
/* p134 ③④：图片消息的缩略图**两个方向都要有上限** —— 只限 max-width 的话，
   竖长图会把气泡拉成一条长龙（inline 的 max-width:220px 保持不变，这里只补高度上限）。 */
.ct-bubble .ct-text .ct-img { max-height: 220px; width: auto; height: auto; }
.ct-bubble .ct-text > *:first-child { margin-top: 0; }
.ct-bubble .ct-text > *:last-child { margin-bottom: 0; }
.ct-bubble .ct-text p { margin: 2px 0; }
.ct-bubble .ct-text h1, .ct-bubble .ct-text h2, .ct-bubble .ct-text h3,
.ct-bubble .ct-text h4, .ct-bubble .ct-text h5, .ct-bubble .ct-text h6 {
  font-size: 13px; font-weight: bold; margin: 5px 0 2px;
  border-bottom: 1px solid #c0c0c0; padding-bottom: 1px;
}
.ct-bubble .ct-text ul, .ct-bubble .ct-text ol { margin: 2px 0 2px 18px; }
.ct-bubble .ct-text li { margin: 1px 0; }
.ct-bubble .ct-text blockquote {
  border-left: 3px solid #85898C; margin: 3px 0; padding: 1px 6px; color: #404040;
}
.ct-bubble .ct-text a { color: #0000A6; text-decoration: underline; }
.ct-bubble .ct-text table { border-collapse: collapse; margin: 3px 0; }
.ct-bubble .ct-text th, .ct-bubble .ct-text td { border: 1px solid #85898C; padding: 1px 5px; }
.ct-bubble .ct-text th { background: #E4E7EA; }
.ct-bubble .ct-text hr { border: 0; border-top: 1px solid #85898C; margin: 4px 0; }
.ct-bubble .ct-text img { max-width: 220px; border: 1px solid #000; }

/* ---------- 代码：气泡内的灰色文本框（``` 代码块 / Code 键 / 行内 `code`） ---------- */
.ct-bubble .ct-text pre,
.ct-bubble pre {
  background: #E4E7EA !important;
  border: 1px solid #85898C;
  box-shadow: inset 1px 1px 0 #fff;
  padding: 4px 6px; margin: 4px 0;
  overflow-x: auto; white-space: pre; max-width: 100%;
  font-family: 'SimSun31', 'F31Latin', 'F31Hans', monospace !important;
  font-size: 12px; line-height: 1.35;
}
.ct-bubble .ct-text code,
.ct-bubble code {
  background: #E4E7EA !important;
  border: 1px solid #85898C;
  padding: 0 3px; font-size: 12px;
  font-family: 'SimSun31', 'F31Latin', 'F31Hans', monospace !important;
}
.ct-bubble .ct-text pre code,
.ct-bubble pre code { background: none !important; border: 0; padding: 0; }

/* ---------- 会话列表头像（v6 里全局 display:none 了 .ct-av，这里显式放出来） ---------- */
.ct-conv .ct-av, .ct-tip .ct-av, .ct-gp-mem .ct-av { display: flex !important; }
/* p134 ①：头像缩略图 —— 光 `display:block` 不够：img 一旦没有尺寸约束就会按**原始尺寸**渲染
   （实测 512×512 的自定义头像放进 20×20 的 .ct-av 里，只露出正中一条 20px 窄带 ⇒
   肉眼看就是一块纯色，用户报「不能正確顯示頭像縮略圖」）。铺满 .ct-av 的内容盒并按 cover 裁切。 */
.ct-conv .ct-av img, .ct-tip .ct-av img, .ct-gp-mem .ct-av img {
  display: block !important; width: 100%; height: 100%; object-fit: cover;
}
.ct-av {
  flex: 0 0 20px; width: 20px; height: 20px; box-sizing: border-box;
  align-items: center; justify-content: center; overflow: hidden;
  border: 1px solid #000; background: #fff; font-size: 11px;
}
.ct-av.grp { background: #DCE6F5; }
.ct-conv-nm { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ct-conv .cp-note { font-size: 11px; flex: 0 0 auto; }
.ct-flame { color: #c04000; font-weight: bold; font-size: 11px; flex: 0 0 auto; }

/* ---------- 会话行悬停信息卡 ---------- */
.ct-tip {
  position: fixed; z-index: 100030; display: flex; gap: 7px; max-width: 250px;
  background: #ffffe1; border: 2px outset #fff; box-shadow: 2px 2px 0 rgba(0,0,0,.35);
  padding: 6px 8px; pointer-events: none;
}
.ct-tip .ct-av { flex: 0 0 34px; width: 34px; height: 34px; font-size: 15px; }
.ct-tip-b { min-width: 0; }
.ct-tip-n { font-weight: bold; color: #000080; margin-bottom: 1px; }
.ct-tip-bio { color: #404040; font-size: 11px; margin-top: 2px; white-space: pre-wrap; }

/* ---------- 右侧栏：群成员 / 群公告 ---------- */
.ct-group-panel {
  width: 172px; min-width: 172px; box-sizing: border-box;
  border-left: 1px solid #85898C; background: #C7CCD0;
  padding: 4px; display: flex; flex-direction: column; gap: 3px; overflow-y: auto;
}
.ct-gp-h {
  background: #0000A6; color: #fff; padding: 2px 5px; font-size: 11px; font-weight: bold;
  flex: 0 0 auto; letter-spacing: 1px;
}
.ct-gp-list, .ct-gp-anns {
  background: #fff; border: 1px solid #85898C; max-height: 190px; overflow-y: auto; flex: 0 1 auto;
}
.ct-gp-mem { display: flex; align-items: center; gap: 4px; padding: 2px 4px; border-bottom: 1px dotted #c0c0c0; }
.ct-gp-nm { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ct-gp-tag { font-size: 10px; color: #fff; background: #0000A6; padding: 0 3px; flex: 0 0 auto; }
.ct-ann-item { border-bottom: 1px dotted #c0c0c0; padding: 4px 5px; text-align: left; }
.ct-ann-h { font-size: 11px; color: #000080; margin-bottom: 2px; }
.ct-ann-body { font-size: 12px; line-height: 1.45; }
.ct-ann-body > *:first-child { margin-top: 0; }
.ct-ann-body p { margin: 2px 0; }
.ct-ann-body h1, .ct-ann-body h2, .ct-ann-body h3, .ct-ann-body h4 {
  font-size: 13px; font-weight: bold; margin: 4px 0 2px; border-bottom: 1px solid #c0c0c0;
}
.ct-ann-body ul, .ct-ann-body ol { margin: 2px 0 2px 18px; }
.ct-ann-body blockquote { border-left: 3px solid #85898C; margin: 3px 0; padding: 1px 6px; color: #404040; }
.ct-ann-body pre {
  background: #E4E7EA; border: 1px solid #85898C; padding: 4px 6px; margin: 3px 0;
  overflow-x: auto; white-space: pre; font-family: 'SimSun31', 'F31Latin', monospace; font-size: 12px;
}
.ct-ann-body code { background: #E4E7EA; border: 1px solid #85898C; padding: 0 3px; font-size: 12px; }
.ct-ann-body pre code { background: none; border: 0; padding: 0; }
.ct-ann-body a { color: #0000A6; text-decoration: underline; }
.ct-ann-body table { border-collapse: collapse; margin: 3px 0; }
.ct-ann-body th, .ct-ann-body td { border: 1px solid #85898C; padding: 1px 5px; }
.ct-ann-pop { width: 440px; max-width: 72vw; max-height: 46vh; overflow-y: auto; text-align: left; }
.ct-ann-preview { border: 1px solid #85898C; background: #fff; padding: 5px 7px; max-height: 150px; overflow-y: auto; margin-top: 3px; }

/* ---------- 按钮栏：可上下拖动调整高度（默认只显示前两行） ---------- */
/* position:relative 是必需的：按钮的 offsetTop 要相对 .ct-tools 计算，
   否则会相对 .ct-root（absolute）——「前两行高度」会算成几百像素被 max-height 截断。 */
.ct-tools { max-height: 300px; position: relative; }
.ct-tools-grip {
  height: 5px; margin: 0 3px; flex: 0 0 5px; cursor: ns-resize;
  background: #C7CCD0; box-shadow: inset 0 1px 0 #fff, inset 0 -1px 0 #85898C;
}
.ct-tools-grip:hover { background: #D3D7DA; }
body.ct-resizing, body.ct-resizing * { cursor: ns-resize !important; user-select: none; }

/* ---------- 管理面板：左对齐 + 表单错误提示 ----------
   注意：这里**不要**把 .cp-level 改成 flex —— 评论 / 置顶两类里用 <br> 分行，
   flex 会把 <br> 变成普通 flex item，两行内容会被挤到同一行。
   只做「文本左对齐 + 按钮靠左内联 + 留白」。 */
.cp-main .cp-level, .cp-main .cp-head, .cp-main .cp-note, .cp-main .login-row { text-align: left !important; }
.cp-main .cp-level { padding: 6px 8px; line-height: 1.6; }
.cp-main .cp-level .btn31 { margin: 4px 6px 0 0; vertical-align: middle; }
.cp-main .login-row { gap: 8px; margin: 6px 0; }
.cp-main .login-row label { text-align: left !important; width: auto !important; min-width: 74px; }
.cp-main .input31, .cp-main input, .cp-main textarea { text-align: left; }
.cp-main .cp-cat { text-align: left !important; }
.adm-err { color: #A80000; margin: 4px 0; min-height: 0; white-space: pre-wrap; text-align: left; }

/* ============================================================
 * p45b · 群管理对话框：成员列表纵向 + 标签不折行 + 高度受控
 * ------------------------------------------------------------
 * 症状（见 p45_10 截图）：① 3 个成员横排、第 3 个的「Kick」被切在对话框外；
 * ② 英文标签「Invite Members」被挤成两行；③ 对话框整体高出一截、下方大片空白。
 * 根因：成员列表误用了 .cp-set-item（v7 里是 flex 行），.wd-row label 固定 92px 不抗换行，
 *       且 .wd-dlg 无高度上限。这里全部纠正。
 * ============================================================ */
.wd-dlg { max-height: 78vh; display: flex; flex-direction: column; }
.wd-dlg .wd-dlg-b { flex: 1 1 auto; min-height: 0; overflow-y: auto; }
.wd-dlg .wd-dlg-f { flex: 0 0 auto; }

.wd-dlg .wd-row { align-items: flex-start; }
.wd-dlg .wd-row > label { flex: 0 0 auto; min-width: 92px; white-space: nowrap; text-align: left; }
.wd-dlg .wd-row > input, .wd-dlg .wd-row > .input31, .wd-dlg .wd-row > textarea { flex: 1 1 auto; min-width: 0; text-align: left; }

.ct-memlist {
  display: flex; flex-direction: column;
  background: #fff; border: 1px solid #85898C;
  max-height: 132px; overflow-y: auto;
}
.ct-memlist .ct-member:last-child { border-bottom: 0; }
.ct-member { display: flex; align-items: center; gap: 6px; }
.ct-member > span:first-child { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ct-member > .cp-note { flex: 0 0 auto; }
.ct-member > .btn31 { flex: 0 0 auto; margin-left: 0; }

/* ============================================================
 * p48：控制面板设置项调整 / 默认壁纸 / 音效配套样式
 * ============================================================ */

/* ---- 1. 控制面板滚动条：与程序管理器一致（Win3.1 自绘滚动条） ----
   cp-main 变成 Scroll31 宿主：原生滚动条隐藏，内容进 .sb31-sc。 */
.cp-main.sb31-host { overflow: hidden !important; padding: 0 !important; }
.cp-main.sb31-host > .sb31-sc { padding: 8px 10px; }
.cp-main.sb31-host > .sb31-sc::-webkit-scrollbar { display: none; width: 0; height: 0; }
.cp-main.sb31-host > .sb31-sc { scrollbar-width: none; -ms-overflow-style: none; }

/* ---- 2. 鼠标悬停在设置项上不高亮 ---- */
.cp-set-item:hover, .cp-line:hover { background: transparent !important; }

/* ---- 3. Centered title text 关闭 ⇒ 标题栏文字左置（默认开启居中） ---- */
body:not(.pf-titlecenter) .tb-title { text-align: left !important; }

/* ---- 4. Underline menu access keys 关闭 ⇒ 菜单/系统菜单的访问键下划线消失 ---- */
body:not(.pf-menuul) .menu-bar u,
body:not(.pf-menuul) .menu-dropdown u,
body:not(.pf-menuul) .sysmenu u { text-decoration: none !important; }

/* ---- 5. Text Under tray icons 关闭 ⇒ 程序管理器图标下方文字不显示（默认开启） ---- */
body:not(.pf-traylabel) .icon-tray .icon-label,
body:not(.pf-traylabel) .win-client .icon-item .icon-label { display: none !important; }

/* ---- 6. 对话框内边距（Dialog padding 设置项，默认 8px） ---- */
.nd31-bd { padding: var(--dlg-pad, 12px) var(--dlg-pad, 12px) 6px !important; }
.wd-dlg .wd-dlg-b { padding: var(--dlg-pad, 8px) !important; }

/* ============================================================
 * p49：色块 / 控制面板侧栏 / 语言列表
 * ============================================================ */

/* ---- 1. 颜色选择框（色块）：Win3.1 凹陷字段，与 .input31 / .spin-in 同一套斜面 ----
   原生 input[type=color] 只保留「点开取色盘」的功能，外观按本站字段皮肤重绘。
   色块本体由 Chrome 的 ::-webkit-color-swatch 按 value 填充 ⇒ 面板里显示的就是该设置项
   「当前实际生效的颜色」（主题色或用户自定义色），不再是恒定的 #c0c0c0 兜底色。 */
input[type="color"] {
  appearance: none; -webkit-appearance: none;
  width: 64px; height: 32px; padding: 2px; box-sizing: border-box;
  border: none !important;
  background: #fff;
  box-shadow: inset 1px 1px 0 #85898C, inset -1px -1px 0 #fff, 0 0 0 1px #000 !important;
  cursor: pointer;
}
input[type="color"]::-webkit-color-swatch-wrapper { padding: 0; }
input[type="color"]::-webkit-color-swatch { border: none; }

/* ---- 2. 控制面板左侧栏：标签一律单行、不折行、不被压扁 ----
   p49 用户反馈：英文标签折行后被截断。实测最长标签 "Social & Information Display" = 179.3px，
   加上行首 ■ 标记（13px）与间距（5px）+ 按钮内边距（16px）⇒ 侧栏内容需 213px。
   作用域限定 .cp-control（控制面板），管理面板窗口只有 560px，沿用旧宽度不被挤窄。 */
.cp-control .cp-side { width: 222px; min-width: 222px; overflow-x: hidden; overflow-y: auto; }
.cp-control .cp-side > .cp-cat { flex: 0 0 auto; white-space: nowrap; }

/* ============================================================
 * p57 · 界面缩放的「保留 / 恢复」确认对话框（js/uiscale.js）
 * ============================================================ */
.usg-body { padding: 10px 12px; }
.usg-head { display: flex; gap: 10px; align-items: flex-start; }
.usg-ico { width: 32px; height: 32px; flex: 0 0 32px; }
.usg-ico svg { width: 32px; height: 32px; display: block; }
.usg-txt { flex: 1; min-width: 0; }
.usg-t { font-size: 12px; line-height: 1.5; }
.usg-s { font-size: 12px; line-height: 1.5; margin-top: 3px; color: #404040; }
.usg-bar {
  height: 13px; margin-top: 10px; box-sizing: border-box; padding: 2px;
  background: var(--white);
  border: 1px solid var(--black);
  box-shadow: inset 1px 1px 0 var(--face-shadow), inset -1px -1px 0 var(--white);
}
.usg-bar > i { display: block; height: 100%; width: 100%; background: var(--sel, #0000a8); transition: width 1s linear; }
.usg-foot {
  margin-top: 11px; padding-top: 8px;
  border-top: 1px solid var(--face-shadow);
  display: flex; gap: 6px; justify-content: flex-end;
}
.usg-foot .btn31 { flex: 0 0 auto; }

/* ============================================================
 * p57 · DOS 页的字体与界面缩放 / 语言彻底解耦
 * ------------------------------------------------------------
 * 问题：body.lang-eo *:not(.mines-led):not(.ck-led) 那条通配 !important
 * （特异性 0,3,1）会盖掉 #dos-screen 的**行内** font-family —— 切成世界语后
 * 连 DOS 页都被换成 Microsoft Sans 像素栈，不再是 DOS 字体。
 * 这里用 id 选择器（特异性 1,0,0）+ !important 锁回 DOSVGA：
 * 优先级高于语言规则；而且 #dos-screen 现在挂在 <html> 上、本就不是 body 的
 * 后代（见 js/dos.js ensure()），是双保险。
 * ============================================================ */
#dos-screen, #dos-screen *, #dos-backdrop,
.dos-edit-shell, .dos-edit-shell * {
  font-family: 'DOSVGA', 'F31Latin', monospace !important;
}

/* ============================================================
 * p60 —— 用户这一批的界面修正（6 条）
 * ============================================================ */

/* ---------- 1. 站内悬浮提示（js/tips.js）：替代浏览器原生 title 浮窗 ----------
   全站 80+ 处都用 el.title = T('…') 写提示。tips.js 在捕获阶段把 title 搬到
   dataset.tip31 并摘掉属性 ⇒ 原生黄框不会再出现，改由本浮窗显示。
   外观按 Win3.1 提示条：淡黄底 + 1px 黑框。
   ⚠️ p76：定位改由 __placeInDesk 处理（÷ `#desktop` 自身缩放），宿主也改成 `#desktop`
   （原来挂 body）⇒ 它现在在 `url(#f-crtcurve)` 的滤镜子树里，跟着窗口一起受弧面畸变。
   `fixed` 随之改 `absolute`（理由同 .sysmenu，见 css/win31.css）。 */
#tip31 {
  position: absolute; left: 0; top: 0;
  z-index: 100010;                    /* 在窗口/菜单之上，在开机画面（100020）之下 */
  max-width: 320px;
  padding: 2px 6px;
  background: #ffffe1; color: #000;
  border: 1px solid #000;
  box-shadow: 1px 1px 0 rgba(0, 0, 0, .35);
  font-family: 'SimSun31', 'Win31System', 'F31Latin', 'F31Hans', 'F31Hant', sans-serif;
  font-size: 11px; line-height: 1.5; letter-spacing: 0;
  white-space: pre-wrap; word-break: break-word;
  pointer-events: none;               /* 不许挡住底下的点击 / 触发 mouseout 抖动 */
}

/* ---------- 2. 新全能阅读器：过滤按钮等长等宽、换行后仍上下左右对齐 ----------
   宽度由 __eqButtons 取「自然最宽值」统一写死；这里只保证不被 flex-shrink 压扁、
   文字不在按钮内部折行（折行会让高度也不齐，用户明确要求等长宽）。 */
.rdr-tabs { display: flex; flex-wrap: wrap; gap: 2px; align-items: stretch; }
.rdr-tab {
  flex: 0 0 auto; min-width: 0;
  white-space: nowrap;
  text-align: center;
  height: auto;
}

/* ---------- 3. 旧全能阅读器：目录跳转只滚正文，不滚整页 ---------- */
/* （代码改动见 js/docui.js buildTOC / js/reader.js 目录；这里不需要样式） */

/* ---------- 4. 阅读设置对话框：字段等宽等长 / 去掉重复的数字箭头 / 色块不越界 ----------
   问题来源（用户截图）：
     ① 「字号/行距/字间距/…」右边同时出现**两组**上下箭头 —— 一组是本站自绘的 ▲▼，
        另一组是 <input type=number> 的原生 spinner，功能重复且难看；
     ② 数字行与下拉行宽度不同（.rdr-snum 是 flex:1 里塞固定 74px 输入框，
        而下拉是 flex:1 撑满）⇒ 右边缘参差，看着没对齐；
     ③ 「主题」行右侧 3 个颜色块用的是全局 input[type=color]{width:64px} 皮肤
        （见本文件 p49 段），3×64 + 间距超出对话框 ⇒ 第 3 个色块被顶到 UI 外面。
   ⚠️ 作用域限定 `.rdr-setdlg`（两个阅读器的「阅读设置」面板都挂了这个类），
      不能直接写 `.rdr-form` —— 添加订阅 / 新建分类等对话框共用 .rdr-form，
      把它们一起改窄会是无谓的回归。 */
.rdr-setdlg .rdr-srow2 { flex-wrap: wrap; }
/* 下拉 / 数字行 / 嵌套行统一同一个宽度，右边缘严格对齐 */
.rdr-setdlg .rdr-srow2 > .input31,
.rdr-setdlg .rdr-srow2 > select.input31,
.rdr-setdlg .rdr-srow2 > .rdr-snum,
.rdr-setdlg .rdr-srow2 > .rdr-srow2 {
  flex: 0 0 var(--rdr-fw, 208px);
  width: var(--rdr-fw, 208px);
  min-width: 0;
  box-sizing: border-box;
}
/* 开关按钮（开 / 关）与字段同宽，整列右边缘对齐 */
.rdr-setdlg .rdr-srow2 > .btn31 { flex: 0 0 var(--rdr-fw, 208px); width: var(--rdr-fw, 208px); }
/* 数字行内部：输入框吃掉剩余宽度（原 74px 固定），两个 ▲▼ 各自固定 */
.rdr-setdlg .rdr-snum { display: flex; align-items: center; gap: 2px; }
.rdr-setdlg .rdr-snum .input31 { flex: 1 1 auto; width: auto; min-width: 0; }
.rdr-setdlg .rdr-snum .btn31 { flex: 0 0 22px; width: 22px; min-width: 22px; height: 20px; padding: 0; }
/* 原生 number spinner：彻底摘掉（免得和自绘 ▲▼ 重复成「两组箭头」） */
.rdr-setdlg input[type="number"] { appearance: textfield; -moz-appearance: textfield; }
.rdr-setdlg input[type="number"]::-webkit-outer-spin-button,
.rdr-setdlg input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none !important; appearance: none !important;
  margin: 0; width: 0; height: 0; display: none;
}
/* 主题行：色块缩回本站小尺寸（覆盖 p49 的全局 64×32），3 个色块 + 下拉不再溢出对话框 */
.rdr-setdlg input.rdr-col,
.rdr-setdlg .rdr-col {
  width: 26px !important; height: 20px !important;
  padding: 0 !important; flex: 0 0 26px !important;
  box-sizing: border-box;
}
/* 主题那一行：下拉可伸缩，色块固定 —— 整行仍不超过 --rdr-fw */
.rdr-setdlg .rdr-srow2 > .rdr-srow2 { flex-wrap: nowrap; }
.rdr-setdlg .rdr-srow2 > .rdr-srow2 > select.input31 { flex: 1 1 84px; width: auto; min-width: 76px; }
.rdr-setdlg .rdr-srow2 > .rdr-srow2 > .btn31 { flex: 0 0 auto; width: auto; }

/* ============================================================
 * p62 · 控制面板色块的「抖动色预览」+ 字体反色导致的禁用态
 * ------------------------------------------------------------
 * 用户要求：勾选「Dithered colors」时，**所有**颜色选择项的预览框也要显示抖动色，
 * 即该色在 16 色 VGA 屏上真实混出来的样子（实色打底 + 有序网点）。
 * 原生 `input[type=color]` 的 `::-webkit-color-swatch` 只能铺纯色 ⇒ 用一个绝对定位的
 * 兄弟层把抖动网点贴图盖在色块上。色块本体是 64×32、padding 2px ⇒ 画布区恰好 inset:2px。
 * 贴图内容由 js/control.js 按 `Prefs.engine.paint(色).image` 下发；「抖动色」关闭时 = none。
 * ⚠️ 贴图层必须 pointer-events:none，否则会拦掉点击取色。
 * ============================================================ */
/* ⚠️ 这层盒子必须**自己钉死 64×32**，色块绝对定位铺满它，不要依赖自动高度：
   `.cp-set-item` 是 flex 行，这层 span 会被行高/对齐规则撑成 **34px**（实测 64×34），
   于是 `inset:2px` 的贴图上下各偏 2px（上边多出 2px、下边压掉 2px）。
   改成「盒子定尺寸 + 色块 absolute 铺满」后，画布区恒等于 (2,2,60,28)，与色块本体严丝合缝。 */
.cp-colorbox { position: relative; display: block; flex: 0 0 64px; align-self: center;
  width: 64px; height: 32px; line-height: 0; }
.cp-colorbox > input[type="color"] { position: absolute; left: 0; top: 0; width: 64px; height: 32px; }
.cp-dither {
  position: absolute; inset: 2px;
  pointer-events: none;
  background-repeat: repeat;
  background-size: var(--dither-tile, 4px) var(--dither-tile, 4px);
}
/* 字体反色打开 ⇒ TEXT COLOR 禁用（用户要求）：标签转灰、色块只作「当前生效色」的展示 */
.cp-set-item.cp-locked > span:first-child { color: #808080; }
.cp-set-item.cp-locked .cp-colorbox { opacity: .75; }
.cp-set-item.cp-locked input[type="color"] { cursor: not-allowed; }

/* ============================================================
 * 6. p63：全局通知窗口（.nd31-box）统一成参考图 #5 的 Win3.1 消息框
 * ------------------------------------------------------------
 * 参考图 = Exit Windows 确认框。标定 **1 参考像素 = 1/3.066 CSS px**，
 * 三把独立尺子交叉验证：
 *   · 窗口外框宽  925 参考 px ÷ 302 CSS = 3.063
 *   · 按钮宽      224 ÷ 72               = 3.111
 *   · 正文墨迹宽  645 ÷ 210.4            = 3.066
 *   （与 p58 用同一款框标出的 2.0464 只差缩放比例，几何结论完全一致。）
 *
 * 逐像素实测（参考 px → CSS px）：
 *   外框剖面 x13.7 #d2d2d2(AA) / x14.5 #000000 / x17.5..28 #0000a8 / x29..31 #e0e0f3 / x31+ 白
 *            ⇒ **1px 黑线 + 4px 海军蓝 + 1px 白高光**
 *   窗口     302 × 115      客户区 290 × 83   （115 = 6 + 20 + 83 + 6）
 *   标题栏   20px（19px 内容 + 1px 黑线），左侧系统菜单盒 19×19（面上白高光 / 右下黑边，
 *            内含一根白横杠 —— Win3.1 对话框的系统菜单盒就是这个「▬」，且**没有 ×**）
 *   标题文字 **在「菜单盒右侧」居中**：实测墨迹中心 160.53，比窗口中心 151 右 9.5 =
 *            菜单盒半宽 ⇒ 用 flex [19px 菜单盒][flex:1 文字区] 自然得到，不要额外 padding
 *   图标     32×32 @ 客户区 (10,10)（实测墨迹盒 x57..161,y116..220 ⇒ 中心 = 客户区 (25.4,24.8)）
 *   正文     墨迹左沿距窗口左 61.7（= 包边 6 + 图标 32 + gap 12 + 首字侧承）
 *   按钮     72×23、行内居中、间距 38、距客户区底 9；默认键黑外框 2px + 文字点线焦点框
 *
 * ⚠️ 按钮文字外面那层 `.msg31-bi` 由 js/nativeui.js 的 MutationObserver 统一注入
 *    （article-share / chat / docui / reader 四个模块也手搭 .nd31-box，所以不走各模块改）。
 * ⚠️ 表单类对话框（.nd31-form .nd31-fbd）的 padding/gap 在 v6.css 里用**两段选择器**
 *    定过，特异性高于这里的 `.nd31-bd`；所以这里**不加 `!important`**，表单排版不受影响。
 * ============================================================ */
.nd31-overlay { align-items: center; justify-content: center; padding: 10px; }

.nd31-box {
  box-sizing: border-box;
  min-width: 302px; max-width: 460px; min-height: 115px;
  display: flex; flex-direction: column;
  background: var(--white, #fff) !important;
  border: 1px solid #000 !important;
  border-radius: 0 !important;
  padding: 5px !important;
  /* 海军蓝包边画在「边框内侧 0..4px」，白高光画在 0..5px（后画的在下面 ⇒ 只剩 4..5px 可见） */
  box-shadow: inset 0 0 0 4px var(--title-active, #0000a8),
              inset 0 0 0 5px var(--white, #fff) !important;
  font-family: 'SimSun31', 'Win31System', 'F31Latin', 'ZpixCJK', 'F31Hans', 'F31Hant', monospace;
}

/* 标题栏：海军蓝 + 底部 1px 黑线；左侧系统菜单盒，右侧（即菜单盒右侧）居中标题 */
.nd31-tb {
  flex: 0 0 auto; box-sizing: border-box;
  height: 20px; display: flex; align-items: stretch;
  background: var(--title-active, #0000a8) !important;
  border-bottom: 1px solid #000;
  color: #fff !important; font-weight: normal;
}
.nd31-tb-t {
  flex: 1 1 auto; min-width: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 13px; letter-spacing: .65px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* Win3.1 对话框没有关闭键（参考图右上角是空的）—— 保留节点（Esc / 点遮罩仍可取消），只是不画 */
.nd31-tb-x { display: none !important; }

/* 系统菜单盒：实心面 + 左上白高光 + 右下黑边 + 中间一根白横杠（下有灰影） */
.nd31-sys {
  flex: 0 0 19px; width: 19px; box-sizing: border-box;
  background: var(--face, #c0c4c8);
  box-shadow: inset 1px 1px 0 #fff, inset -1px -1px 0 #000;
  position: relative;
}
.nd31-sys::after {
  content: ''; position: absolute; left: 2px; top: 7px;
  width: 13px; height: 3px;
  background: #fff;
  box-shadow: 0 0 0 1px #000, 1px 1px 0 1px #808080;
}

/* 客户区：白底、图标 32×32 @ (10,10)、正文墨迹左沿距窗口左 61.7
   ⚠️ p63 踩坑：v7.css 上方有 `.nd31-bd{padding:var(--dlg-pad…) !important}`（L1175），
      `!important` 会**无条件**盖掉下面这条普通声明 —— 实测的结果就是图标左沿 14 而不是 16、
      正文左沿 58 而不是 60（每处正好差 2px）。
      修法：把选择器升到三段 `.nd31-overlay .nd31-bd:not(.nd31-fbd)` 并同样带 `!important`，
      既压过 L1175，又**排除表单对话框**（表单体是 `class="nd31-bd nd31-fbd"`，
      它的 padding 要留给 v6.css 的 `--dlg-pad` 体系）。
   ⚠️ p67 补充：这条规则是给「图标 + 正文」的**消息框**写的（三段 + `!important`），
      而滤镜面板的 `<div class="nd31-bd fx-bd">` 也是 `.nd31-bd` 且不是 `.nd31-fbd`
      ⇒ 会被它一起命中：align-items:flex-start 把 .fx-cmp/.fx-right 压成半宽
      （实测 .fx-grid 只剩 129px，20 个缩略图排成 1 列），padding 也被 `!important` 覆盖。
      修法：把 `.fx-bd` 一并排除掉（特异性升到四段），让滤镜面板回到 .fx-bd 自己的声明。
      **不要再加 !important 去对攻** —— 加在 .fx-bd 上会把消息框和表单框一起带歪。 */
.nd31-overlay .nd31-bd:not(.nd31-fbd):not(.fx-bd) {
  flex: 1 1 auto; min-height: 0;
  display: flex; gap: 12px; align-items: flex-start;
  background: var(--white, #fff);
  padding: 8px 16px 0 10px !important;
  box-sizing: border-box;
}
.nd31-ic { flex: 0 0 auto; width: 32px; height: 32px; }
.nd31-ic svg { display: block; width: 32px; height: 32px; image-rendering: pixelated; }
/* 正文：参考图墨迹 210.4×11.4、行心距客户区上 24（图标中心同为 24）⇒
   padding-top 6 + line-height 18 的 12px 字，墨迹中心正好落在 23.9。 */
.nd31-msg {
  flex: 1 1 auto; min-width: 0;
  font-size: 12px; line-height: 18px; letter-spacing: .45px;
  padding-top: 6px; box-sizing: border-box;
  white-space: pre-wrap; word-break: break-word;
}

/* 按钮行：居中、间距 38、距客户区底 9（顶部 11 ⇒ 客户区 8+32+11+23+9 = 83 ✓） */
.nd31-ft {
  flex: 0 0 auto;
  display: flex; justify-content: center; gap: 38px;
  padding: 11px 16px 9px; box-sizing: border-box;
}
.nd31-ft .btn31 {
  width: 72px; min-width: 72px; min-height: 0; height: 23px;
  padding: 0; flex: 0 0 auto; line-height: 21px; text-align: center;
  outline: none !important;
  display: flex; align-items: center; justify-content: center;
}
.nd31-ft .btn31.default { box-shadow: inset 1px 1px 0 var(--white), inset -1px -1px 0 #85898C, 0 0 0 2px #000 !important; }
.nd31-ft .btn31.default .msg31-bi {
  border: 1px dotted #000; padding: 0 3px;
  height: 15px; line-height: 15px;
  display: flex; align-items: center; justify-content: center;
}


/* ============================================================
 * p64 —— 本批（用户 24 条）：
 *   ① 全站滚动条统一成 Win3.1 皮肤（含像素箭头键）
 *   ② win31 标准数字微调框 .spin31（替掉浏览器原生箭头）
 *   ③ 控制面板动作按钮等宽等高
 *   ④ 文档编辑器工具栏的「分组折叠状态导航条」
 *   ⑤ 批注标蓝 + 悬停浮卡
 *   ⑥ 水印 / 页面背景透明度变量化
 *   ⑦ 表单对话框：数值行、只读统计框、控件不越界
 * ============================================================ */

/* ------------------------------------------------------------
 * ① 全站滚动条 → Win3.1
 * ------------------------------------------------------------
 * 口径（与 js/scroll31.js / css 里那套手绘滚动条逐项对齐）：
 *   轨道 = 纯面色（无网点）；箭头键 / 滑块 = 1px 黑框 + 左上白高光 + 右下深灰阴影；
 *   相邻部件共用一条黑线（由靠右/靠下的那个部件单边画）；右下角方块同底色。
 * 箭头字形 = 与 js/scroll31.js 的 RECTS **完全同一张表**（7×7 细尖箭头 + 3px 尾杆），
 *   所以手绘滚动条与这里的原生皮肤看起来是同一套东西。
 * 为什么走「原生皮肤」而不是把每个容器都换成 Scroll31：
 *   ① 原生滚动条**占布局空间**，物理上不可能盖住按钮（用户明确要求「不要和按钮重叠」）；
 *      Scroll31 是 absolute 定位，容器一多就容易压到右侧内容。
 *   ② 站内可滚动容器有 30+ 处（聊天/网盘/阅读器/计算器/DOS…），逐个改宿主容器
 *      要重排 DOM 且要求容器有确定高度，回归面极大。
 *   Scroll31 仍然保留在程序管理器 / 控制面板（.sb31-sc 自己把原生条 display:none 藏掉了，
 *   不会出现两条滚动条）。
 */
::-webkit-scrollbar { width: var(--sbw, 16px); height: var(--sbw, 16px); }
::-webkit-scrollbar-track { background: var(--face); }
::-webkit-scrollbar-track:vertical { border-left: 1px solid #000; }
::-webkit-scrollbar-track:horizontal { border-top: 1px solid #000; }
::-webkit-scrollbar-thumb {
  background: var(--face);
  border: 1px solid #000;
  box-shadow: inset 1px 1px 0 #fff, inset -1px -1px 0 #84888C;
}
::-webkit-scrollbar-thumb:active { box-shadow: inset 1px 1px 0 #84888C, inset -1px -1px 0 #fff; }
::-webkit-scrollbar-button {
  display: block;
  background-color: var(--face);
  background-repeat: no-repeat;
  background-position: center center;
  box-shadow: inset 1px 1px 0 #fff, inset -1px -1px 0 #84888C;
}
::-webkit-scrollbar-button:vertical { width: var(--sbw, 16px); height: var(--sbw, 16px); }
::-webkit-scrollbar-button:horizontal { width: var(--sbw, 16px); height: var(--sbw, 16px); }
::-webkit-scrollbar-button:vertical:start:decrement {
  border-bottom: 1px solid #000;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='7' height='7' viewBox='0 0 7 7' shape-rendering='crispEdges'%3E%3Cpath fill='%23000000' d='M3 0h1v1H3zM2 1h3v1H2zM1 2h5v1H1zM0 3h7v1H0zM2 4h3v3H2z'/%3E%3C/svg%3E");
}
::-webkit-scrollbar-button:vertical:end:increment {
  border-top: 1px solid #000;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='7' height='7' viewBox='0 0 7 7' shape-rendering='crispEdges'%3E%3Cpath fill='%23000000' d='M2 0h3v3H2zM0 3h7v1H0zM1 4h5v1H1zM2 5h3v1H2zM3 6h1v1H3z'/%3E%3C/svg%3E");
}
::-webkit-scrollbar-button:horizontal:start:decrement {
  border-right: 1px solid #000;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='7' height='7' viewBox='0 0 7 7' shape-rendering='crispEdges'%3E%3Cpath fill='%23000000' d='M3 0h1v1H3zM2 1h2v1H2zM1 2h6v1H1zM0 3h7v1H0zM1 4h6v1H1zM2 5h2v1H2zM3 6h1v1H3z'/%3E%3C/svg%3E");
}
::-webkit-scrollbar-button:horizontal:end:increment {
  border-left: 1px solid #000;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='7' height='7' viewBox='0 0 7 7' shape-rendering='crispEdges'%3E%3Cpath fill='%23000000' d='M3 0h1v1H3zM3 1h2v1H3zM0 2h6v1H0zM0 3h7v1H0zM0 4h6v1H0zM3 5h2v1H3zM3 6h1v1H3z'/%3E%3C/svg%3E");
}
::-webkit-scrollbar-corner { background: var(--face); border-left: 1px solid #000; border-top: 1px solid #000; }
/* 滚动条自带一点内边距更耐看；同时保证「内容与滚动条」之间有一条黑线分隔 */
.wd-bars { padding-right: 0 !important; }

/* ------------------------------------------------------------
 * ② win31 标准数字微调框（Spin31）
 * ------------------------------------------------------------
 * 先在**全局**摘掉浏览器原生数字箭头（p60 只在 .rdr-setdlg 局部摘过，
 * 导致裁剪图片等对话框仍是原生箭头）。摘掉之后由 .spin31 提供 Win3.1 箭头。
 */
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none !important; appearance: none !important; margin: 0;
}
input[type="number"] { -moz-appearance: textfield; appearance: textfield; }

.spin31 { display: inline-flex; align-items: center; flex: 0 0 auto; max-width: 100%; }
.spin31 > .spin31-in {
  width: 62px; min-width: 0; text-align: right;
  background: var(--white); border: none; padding: 2px 4px;
  font-family: inherit; font-size: 12px;
  box-shadow: inset 1px 1px 0 #84888C, inset -1px -1px 0 #fff, 0 0 0 1px #000;
  outline: none;
}
.spin31 > .spin31-in:focus { background: var(--white); }
.spin31-btns { display: flex; flex-direction: column; gap: 1px; margin-left: 3px; flex: 0 0 auto; }
/* ⚠️ 全局皮肤 button{min-height:19px} + button{box-shadow:…!important} 会顶高并盖掉这两个小键
   ⇒ 必须显式清零并用 !important 反压（与 .sb31-btn 同一套规矩）。 */
.spin31-btns > button {
  width: 15px; height: 10px; min-width: 0; min-height: 0; max-height: none;
  padding: 0; margin: 0; display: flex; align-items: center; justify-content: center;
  background: var(--face);
  box-shadow: inset 1px 1px 0 #fff, inset -1px -1px 0 #84888C, 0 0 0 1px #000 !important;
}
.spin31-btns > button:active { box-shadow: inset 1px 1px 0 #84888C, inset -1px -1px 0 #fff, 0 0 0 1px #000 !important; }
.spin31-btns > button svg { width: 7px; height: 7px; display: block; }
.spin31-btns > button.off svg rect { fill: #84888C; }

/* 表单对话框里的数值行：标签 / 微调框 / 单位 三段对齐，且整体不越出对话框 */
.nd31-frow.nd31-fnum > .spin31 { flex: 0 0 auto; }
.nd31-frow.nd31-fnum > .cp-note { flex: 0 0 auto; }
/* 值很长时（如文件管理路径）允许中间那段收缩，而不是把对话框撑宽 */
.nd31-frow > .spin31 > .spin31-in { flex: 1 1 auto; }

/* ------------------------------------------------------------
 * ③ 控制面板「动作按钮」等宽等高 + 上下左右对齐
 * ------------------------------------------------------------
 * 用户口径（截图）：导出/导入/登出/重置这几个按钮必须大小长宽相等、四边对齐。
 * 宽度由 JS 按**最长文案**量出后写行内 width（各语言文案长度差很多，写死必然会错）；
 * 这里只负责「盒子怎么摆」：按钮定宽、行内垂直居中、说明文字不参与宽度计算。
 */
.cp-line > .btn31 {
  flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center;
  text-align: center; line-height: 1.25; padding: 2px 6px; box-sizing: border-box;
}
.cp-line { align-items: center; }
.cp-line > .cp-note { flex: 1 1 auto; min-width: 0; }

/* ------------------------------------------------------------
 * ④ 文档编辑器：工具栏「分组折叠状态导航条」
 * ------------------------------------------------------------
 * 工具栏左侧那列「▸/▾ 组名」在窗口收窄时会被挤掉 ⇒ 顶部另起一条**常驻**导航条，
 * 列出全部分组：正在显示 = 黑字；已折叠 = 灰字。点灰字即展开该组。
 * 导航条自己不滚动、不换行挤压按钮（独立一行，放在 .wd-bars 之内、所有 .wd-bar 之前）。
 */
.wd-gnav {
  flex: 0 0 auto; display: flex; align-items: center; flex-wrap: wrap;
  gap: 1px 2px; padding: 2px 3px;
  border-bottom: 1px solid #84888C;
  background: var(--face);
  position: sticky; top: 0; z-index: 3;
}
.wd-gnav-item {
  flex: 0 0 auto; padding: 1px 6px; font-size: 12px; line-height: 15px;
  cursor: var(--cur-hand, pointer); user-select: none;
  border: 1px solid transparent; box-sizing: border-box;
}
/* 该大类正在显示 ⇒ 黑色（实心、可点收起） */
.wd-gnav-item.on { color: #000; }
.wd-gnav-item.on:hover { color: #0000a8; text-decoration: underline; }
/* 未显示（已折叠 / 被空间挤掉）⇒ 灰色，点击可展开 */
.wd-gnav-item.off { color: #84888C; }
.wd-gnav-item.off:hover { color: #0000a8; text-decoration: underline; }
.wd-gnav::before { content: ''; }

/* ------------------------------------------------------------
 * ⑤ 批注：文段标蓝 + 悬停浮卡（作者 / 内容）
 * ------------------------------------------------------------
 * 用户口径：选中文段添加 comment 后文段应**标蓝**，鼠标悬停能看到评论人与内容。
 * 标蓝用 background 而不是 color —— 正文颜色可能是用户自己设的，改 color 会破坏排版。
 */
.wd-cmt {
  background: #B5D4F4;
  border-bottom: 1px solid #378ADD;
  cursor: var(--cur-hand, pointer);
}
.wd-cmt-tip {
  position: fixed; z-index: 100002; max-width: 280px;
  background: #ffffe1; border: 1px solid #000; padding: 5px 7px;
  box-shadow: 2px 2px 0 rgba(0, 0, 0, .4);
  font-size: 12px; line-height: 1.5; color: #000;
  pointer-events: none;
}
.wd-cmt-tip b { display: block; font-weight: normal; color: #000080; margin-bottom: 2px; }

/* 阅读器 / 文章里的批注：与编辑器同一套配色（「同步到文章、阅读器中以相同效果展示」） */
.rdr-content .wd-cmt, .bbs-content .wd-cmt, .dv-content .wd-cmt,
.nw-article .wd-cmt, .art-content .wd-cmt { background: #B5D4F4; border-bottom: 1px solid #378ADD; }

/* ------------------------------------------------------------
 * ⑥ 水印 / 页面背景：透明度变量化
 * ------------------------------------------------------------
 * 原先 css/v6.css 里水印 opacity 写死 .12 ⇒ 用户无法调整。
 * 改为 var(--wm-opacity)，缺省仍 .12（老文档视觉不变）；页面背景同理走 --pagebg-opacity。
 */
.wd-page.watermark::before,
.bbs-content.watermark::before,
.rdr-content.watermark::before,
.dv-content.watermark::before {
  opacity: var(--wm-opacity, .12);
}
.wd-page[data-bgimg], .rdr-content[data-bgimg], .bbs-content[data-bgimg], .dv-content[data-bgimg] {
  background-repeat: repeat; background-position: center center;
}
/* 背景图单独一层，才不会把正文也一起变透明（正文必须保持 100% 不透明） */
.wd-page, .bbs-content, .rdr-content, .dv-content { position: relative; }
.wd-bgimg {
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background-repeat: repeat; background-position: center center;
  opacity: var(--pagebg-opacity, 1);
}
.wd-page > *:not(.wd-bgimg), .bbs-content > *:not(.wd-bgimg),
.rdr-content > *:not(.wd-bgimg), .dv-content > *:not(.wd-bgimg) { position: relative; z-index: 1; }

/* ------------------------------------------------------------
 * ⑦ 对话框收尾：只读统计框 / 数值行不越界
 * ------------------------------------------------------------ */
/* 统计类对话框（拼写 / 语法 / 字数 / 批注列表）：只读框用等宽、可整块选中复制 */
.nd31-ta[readonly] { background: var(--white); color: #000; cursor: text; }
/* 裁剪图片等对话框：标签列窄一点，控件列吃满剩余宽度，避免「选框太小显示不全」 */
.nd31-form .nd31-fbd .nd31-frow > select.input31 { flex: 1 1 auto; min-width: 0; }

/* ------------------------------------------------------------
 * ⑧ p64 补：对话框表单行里的自绘下拉要吃满剩余宽度
 * ------------------------------------------------------------
 * select31.js 会把原生 select 换成 .s31 并 display:none；
 * .s31 是 inline-flex，作为 flex item 的基准尺寸是 max-content ⇒ 不写死宽度时
 * 只占内容那么宽。裁剪位置这类选项文本长一点就被切，必须显式撑满。
 * 注意选择器要落在**可见的 .s31** 上 —— 原先前一轮只写了 select.input31，
 * 而那个 select 已经被 display:none 了，规则等于没生效。 */
.nd31-form .nd31-fbd .nd31-frow > .s31 { flex: 1 1 auto; min-width: 0; }
.nd31-form .nd31-fbd .nd31-frow.nd31-fnum > .cp-note { flex: 0 0 auto; white-space: nowrap; }


/* ============================================================
 * p66：CRT 屏幕曲度 / 色彩滤镜 —— 「滑动页面超出窗口」+ 卡顿 修复
 * ------------------------------------------------------------
 * 用户报：① 开屏幕曲度 + 滤镜后，出现「滑動頁面超出窗口」的漏洞
 *        ② 单绿色 / EL 屏幕(琥珀) / 示波器 太卡
 *        ③ 曲度默认开、数值默认 10%
 * ============================================================ */

/* ---------- 1. 文档级滚动彻底禁死（「滑動頁面」的兜底保证） ----------
   win31.css 给 html/body 的是 `overflow:hidden` —— 它只藏滚动条，**并不禁止
   「程序化滚动」**（`document.scrollingElement.scrollTop = 500` 照样生效）。
   而曲度是 SVG feDisplacementMap 位移滤镜，作用在满屏的 #desktop / #crt-overlay 上；
   滤镜的**输出区域**一旦大于元素盒，结果就画到视口之外，被浏览器算进「可滚动溢出」——
   于是文档多出一段可滚动距离。这时如果有任何东西碰到文档滚动（scrollIntoView /
   锚点 / 浏览器自己），整个 #desktop 会随文档一起滑走，而 position:fixed 的那些层
   （#crt-overlay、托盘提示、弹层）**原地不动** ⇒ 用户看到的就是「滑动页面超出窗口」。
   effects2.js 已把滤镜区域从 120% 收到 0..1（消除溢出源，逐像素等价）；
   这里再用 `overflow:clip` 把「程序化滚动」这条路也堵掉 —— 满屏桌面不允许任何文档级滚动。
   （所有需要滚动的区域都有自己的滚动容器：.sb31-sc / .scroll / .ct-log / #dos-screen …） */
html { overflow: clip; }

/* ---------- 2. 示波器：把「荧光呼吸」从 body 上摘下来 ----------
   p63 写的是 `body.f-scope:not(.f-scope-draw){animation:os-phos …}` ——动的是 **body 的 opacity**。
   body 一变透明，整页（含挂着位移滤镜的 #desktop）每帧都要重新合成、重新跑滤镜：
   实测 3 秒采样的 48 帧里 47 帧超过 33ms（平均 77ms/帧 ≈ 13fps），这就是「示波器太卡」的主因。
   改成一层「纯黑纱」的不透明度动画：视觉等价（原式 = 内容朝黑底按 1−0.94 变暗；
   纱层 opacity 0→0.06 是同一个效果），但它是独立合成层，只动 layer opacity
   ⇒ 底下内容与滤镜都不再逐帧重算。
   ⚠️ 不能用 `body::before` —— prefs.js 的 injectCSS() 已经无条件占用了它（桌面网点贴图层）。 */
@keyframes os-phos-veil { 0%, 100% { opacity: 0; } 47% { opacity: .06; } 49% { opacity: .01; } }
body.f-scope:not(.f-scope-draw) { animation: none; }
#scope-veil {
  position: fixed; inset: 0; pointer-events: none; z-index: 99997;
  background: #000; opacity: 0;
  animation: os-phos-veil 5.5s ease-in-out infinite;
  will-change: opacity;
  /* 纱层自己**不能**被色彩滤镜再滤一遍：示波器滤镜会把「平坦的墨迹」抽成线，
     一块纯黑满屏层被滤完只剩屏幕边缘一圈亮线 —— 那就完全不是「变暗」了。 */
  filter: none !important;
}
body.f-scope.f-scope-draw #scope-veil { animation: none; }

/* ---------- 3. EL 屏幕：暗场呼吸改用合成层 ----------
   `body.f-amber::after` 是满屏 radial-gradient + mix-blend-mode:screen，还在无休止地动 opacity。
   每次不透明度变化都得把背景重新混合一遍 ⇒ 实测平均 63ms/帧（≈16fps）。
   加 will-change 让这层自己缓存成纹理、由合成器改不透明度 —— 画面一个字都不变，只是不再重算。 */
body.f-amber::after { will-change: opacity; }

/* ---------- 4. 被滤镜罩住的 #desktop：明确约束绘制范围 ----------
   `contain: paint` 让 #desktop 成为一个「自足的绘制单元」，把它的绘制（含滤镜输出）
   硬约束在自身盒内 —— 与第 1 节的区域收缩互相印证，从两头堵住「画到视口外」。
   ⚠️ 只给 #desktop 加，**绝不**给 .win-client 加：
      #desktop 本来就有 transform:scale() ⇒ 早就是 fixed 后代的包含块，加不加 containment 都一样；
      而 .win-client 没有 transform ⇒ 一旦加 containment，挂在窗口内部的
      position:fixed 弹层（menu-dropdown / select31 / datepick31 / select31 的浮层）会
      ① 包含块从 #desktop 变成 .win-client ⇒ 定位整体偏掉，② 还会被剪掉。 */
body.pf-warp #desktop,
body.f-c16 #desktop, body.f-mono #desktop, body.f-green #desktop,
body.f-amber #desktop, body.f-scope #desktop, body.f-cga #desktop { contain: paint; }

/* ============================================================
 * p69：文章应用（BBS 博客）= Win3.1 三栏管理器 + 窄信息栏
 *   左 目录树 / 中 文章列表 / 右 正文 / 最右 窄信息栏（贡献日历 + 标签）
 * 只用 Win3.1 的词汇：灰面 + 3D 凸起/凹陷 + 1px 黑线 + 方角 + 小字号；
 * 没有圆角、没有阴影、没有渐变、没有毛玻璃、没有卡片。
 * ============================================================ */
.blog-split {
  display: flex; gap: 3px; padding: 3px; align-items: stretch; min-height: 0;
}
.b31-left, .b31-mid, .b31-side { display: flex; flex-direction: column; gap: 2px; min-height: 0; min-width: 0; }
.b31-left { flex: 0 0 176px; }
.b31-mid { flex: 0 0 232px; }
/* 窄侧栏：整个应用宽度的 18%–24%（默认 21%）⇒ 细长一条，不抢正文 */
.b31-side { flex: 0 0 21%; min-width: 148px; max-width: 280px; overflow: hidden; }
.b31-side[style*="display: none"] { flex-basis: 0; }

/* 三种「面」：凸起面板（灰面）/ 凹陷列表（白底）/ 选中（深蓝反白） */
.b31-colhead, .b31-listhead, .b31-sidehead, .b31-cal {
  flex: none; background: var(--face); color: var(--text-main);
  border: none; box-shadow: inset 1px 1px 0 #fff, inset -1px -1px 0 #85898C, 0 0 0 1px #000;
}
.b31-colhead, .b31-sidehead { display: flex; align-items: center; gap: 4px; padding: 1px 4px; font-size: 11px; }
.b31-colhead-t, .b31-sidehead-t { flex: 1 1 auto; min-width: 0; overflow: hidden; white-space: nowrap; }

/* ---------- 左：文件夹树 ---------- */
.b31-tools { flex: none; display: flex; flex-wrap: wrap; gap: 2px; }
.b31-mini { min-height: 17px !important; padding: 0 4px !important; font-size: 11px !important; line-height: 15px; }
.b31-tree {
  flex: 1 1 auto; min-height: 0; overflow: auto; padding: 1px 0;
  background: #fff; color: #000;
  border: none; box-shadow: inset 1px 1px 0 #85898C, inset -1px -1px 0 #fff, 0 0 0 1px #000;
}
.b31-treehead { font-size: 10px; color: #606060; padding: 2px 4px 1px; border-top: 1px solid #DFDFDF; margin-top: 1px; }
.b31-empty { font-size: 11px; color: #606060; padding: 3px 5px; }
.b31-trow, .b31-sysrow { display: flex; align-items: center; gap: 3px; padding: 1px 4px 1px 2px; font-size: 12px; white-space: nowrap; cursor: default; }
.b31-trow:hover, .b31-sysrow:hover { background: #0000A8; color: #fff; }
.b31-trow.sel, .b31-sysrow.active { background: var(--title-active, #0000A8); color: #fff; }
.b31-trow.sel .bf-n, .b31-sysrow.active .bf-n, .b31-trow:hover .bf-n, .b31-sysrow:hover .bf-n { color: #DFDFDF; }
.b31-exp {
  flex: none; width: 9px; height: 9px; line-height: 7px; text-align: center;
  font-size: 9px; font-family: Win31System, "MS Sans Serif", monospace; color: #000;
  background: #fff; box-shadow: inset 1px 1px 0 #85898C, inset -1px -1px 0 #fff, 0 0 0 1px #000;
  box-sizing: border-box;
}
.b31-ico { flex: none; width: 16px; height: 16px; }
.b31-ico svg { width: 16px; height: 16px; display: block; }
.b31-nm { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.bf-n { flex: none; margin-left: auto; padding-left: 4px; font-size: 11px; color: #606060; }

/* ---------- 中：文章列表头部 + 列表 ---------- */
.b31-listhead { display: flex; flex-direction: column; gap: 2px; padding: 2px; }
.b31-listhead .blog-search { display: flex; gap: 3px; }
.b31-listhead .blog-search .input31 { flex: 1 1 auto; min-width: 0; }
/* p87：「仅看管理员发布」右侧那个「已关闭 / 已开启」状态标签（.b31-adminstate）已删。
   ⚠️ adminrow 原本由那个标签的 line-height:14px 撑到 14px 高；删掉后只剩勾选框(13)+标签(11)
   ⇒ 整行会塌成 13px，连带下面的文章列表上移 1px。这里用 min-height 把行高钉回 14px，
   让「删掉这个标签」成为**唯一**的视觉变化，不牵动其它已验收的像素。 */
.b31-adminrow { display: flex; align-items: center; gap: 4px; font-size: 11px; min-height: 14px; }
.b31-adminlab { flex: 1 1 auto; min-width: 0; }
.b31-chips { display: flex; flex-wrap: wrap; gap: 2px; align-items: center; min-height: 15px; }
.b31-chip {
  display: inline-flex; align-items: center; gap: 2px; font-size: 10px; line-height: 13px; padding: 0 2px;
  background: #C7CCD0; color: #000;
  box-shadow: inset 1px 1px 0 #fff, inset -1px -1px 0 #85898C, 0 0 0 1px #000;
}
.b31-chipx { color: #800000; padding-left: 1px; }
.b31-nofilter { font-size: 10px; color: #606060; }
.b31-clr { min-height: 15px !important; padding: 0 3px !important; font-size: 10px !important; line-height: 13px; }
.b31-left .blog-list, .b31-mid .blog-list, .blog-right {
  flex: 1 1 auto; min-height: 0;
  border: none !important;
  box-shadow: inset 1px 1px 0 #85898C, inset -1px -1px 0 #fff, 0 0 0 1px #000 !important;
  background: #fff;
}

/* ---------- p75：正文栏的左右留白（用户：文字左边和左边栏贴在一起） ----------
   实测（_dev/p75.js）：正文文字左缘 = 正文栏内容盒左缘 = 452，而中栏列表右边框 = 449
   ⇒ 只差 **3px**（正好是 .blog-split 的 gap），文字紧贴左栏像被切掉；右侧同理只剩滚动条 16px。
   根因：win31.css 里老布局留下的 `.blog-right{ padding:0 }`，p69 把它改成「正文栏」之后
   没有跟着给内边距（而独立阅读器窗口的 `.article-view.bbs` 一直有 `padding:10px 14px`）。
   左侧 452、右侧文字 765、栏右缘 781 ⇒ 左右各给 14px（与 .article-view.bbs 同值），
   这样可见间距 = 14（内边距）+ 3（栏间 gap）= 17px，与中栏列表 4px 的内边距拉开一个量级。
   ⚠️ `.bbs-header` 是**本栏的列头**，必须和左栏 `.b31-colhead`「文章目录」、中栏
   `.b31-listhead` 一样**满幅**（三者顶端与左右都对齐同一条栏框线）⇒ 用等值负外边距把它顶回
   栏框左右边；同时把它自身的左右内边距补到 14px，让列头文字与正文文字左对齐。 */
.blog-split > .blog-right { padding: 0 14px 10px !important; }
.blog-split > .blog-right > .bbs-header {
  margin-left: -14px !important; margin-right: -14px !important;
  padding-left: 14px !important; padding-right: 14px !important;
}
/* p121①：标题会换行了 ⇒ 徽章必须跟**首行**对齐（center 在多行标题上会被拉到垂直居中）。
   baseline 在单行 / 多行两种情况下都落在第一行的基线上。 */
/* p121①②：光有 baseline 不够 —— `.bi-title` 在 win31.css 里是 `flex:1`(= `1 1 0%`)，
   而 `0%` 基准在**剩余空间为负**时收缩权重为 0 ⇒ 短標題会被压成「每行一个字」
   （实测 .bi-title 16×36 = 3 行）。让徽章行**自己吃掉**剩余宽度即可。 */
.bi-titlerow { display: flex; align-items: baseline; gap: 3px; flex: 1 1 auto; min-width: 0; }
/* p121②：置顶徽章与管理員徽章**同一套外观**（含选中态反色） */
.bi-admin, .bi-pin { flex: none; font-size: 9px; line-height: 12px; padding: 0 2px; background: #000080; color: #fff; }
.blog-item.selected .bi-admin, .blog-item.selected .bi-pin { background: #fff; color: #000080; }
/* p121①②：元信息列不许把标题挤没 —— 自己不缩、最多占 34%；整行允许换行 ⇒
   带双徽章的長標題**独占一行**（实测 154px / 8 行），短標題那一行不受影响（129px / 1 行）。 */
.blog-item { flex-wrap: wrap; }
.blog-item .bi-meta { flex: 0 0 auto; max-width: 34%; min-width: 0; }
.bi-tags { display: flex; flex-wrap: wrap; gap: 2px; margin-top: 1px; }
.b31-tagmini {
  font-size: 9px; line-height: 12px; padding: 0 2px; background: #DFDFDF; color: #000;
  box-shadow: inset 1px 1px 0 #fff, inset -1px -1px 0 #85898C, 0 0 0 1px #808080;
}
.blog-item.selected .b31-tagmini { background: #C7CCD0; color: #000; }

/* ---------- 最右：窄信息栏 ---------- */
.b31-sidebtn { min-height: 15px !important; padding: 0 4px !important; font-size: 10px !important; line-height: 13px; }
/* p87：工具栏里那个文字版「隐藏侧栏」（.b31-side-toggle）连同它的 .on 态一起删了
   —— 与侧栏表头的 ◀（.b31-sidebtn）功能重复，用户要求只留一个入口。 */

/* 贡献日历：横轴 = 周，纵轴 = 星期；格子 2–6px，整个模块只占几行高 */
.b31-cal { padding: 3px; }
.b31-calhead { display: flex; align-items: center; gap: 3px; font-size: 11px; }
/* p72：窄侧栏里标题常被挤到 30+px，原来只写 overflow:hidden ⇒ 汉字被**从中间切断**（顯示不全）。
   补 text-overflow:ellipsis，退化成一枚省略号，至少不出现「半个字」。 */
.b31-caltitle { flex: 1 1 auto; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.b31-calnav { flex: none; display: flex; align-items: center; gap: 2px; }
.b31-calbtn { min-height: 14px !important; padding: 0 3px !important; font-size: 10px !important; line-height: 12px; }
.b31-calyear { font-size: 10px; }
.b31-calbody { display: flex; flex-direction: column; gap: 1px; margin-top: 2px; min-width: 0; overflow: hidden; }
.b31-calright { display: flex; flex-direction: column; gap: 1px; min-width: 0; overflow: hidden; }
.b31-monthrow { display: grid; }
/* p72：月份标签横跨若干列（跨度由 js/apps.js 按实测字宽算出），这里再兜一道 overflow:hidden，
   保证任何情况下标签都**不会画出自己的格子**（用户铁律：不得重叠、不得超出框）。 */
.b31-month { font-size: 9px; line-height: 11px; color: #000; white-space: nowrap; overflow: hidden; }
.b31-calgrid { display: flex; flex-direction: row; }
.b31-calcol { display: flex; flex-direction: column; }
.b31-day { box-sizing: border-box; background: #E4E4E4; cursor: default; }
.b31-day:hover { outline: 1px solid #fff; box-shadow: 0 0 0 1px #000; }
.b31-day.sel { outline: 1px solid #fff; box-shadow: 0 0 0 1px #000; }
.b31-day.out { visibility: hidden; }
/* p87：删掉「星期 一二三四五六日」图例行（.b31-wdrow / .b31-wdlab / .b31-wd） */
.b31-calfoot { display: flex; align-items: center; gap: 4px; margin-top: 2px; font-size: 10px; }
.b31-legend { display: flex; align-items: center; gap: 1px; }
.b31-legsw { display: inline-block; box-shadow: 0 0 0 1px #808080; }
.b31-legtxt { font-size: 9px; }
.b31-calstat { margin-left: auto; font-size: 10px; color: #000; }
.b31-calclr { margin-top: 2px; }

/* 标签模块：浅蓝底 + 3D 凸起外框，内部是凹陷的可滚动列表 */
.b31-tags {
  flex: 1 1 auto; min-height: 60px; display: flex; flex-direction: column; gap: 2px; padding: 3px;
  background: var(--blog-tag-bg, #BDD7EE); color: var(--text-main);
  border: none; box-shadow: inset 1px 1px 0 #fff, inset -1px -1px 0 #85898C, 0 0 0 1px #000;
}
.b31-taghead { flex: none; display: flex; align-items: center; gap: 4px; flex-wrap: wrap; font-size: 11px; }
.b31-tagtitle { font-weight: normal; }
.b31-tagmodebox { display: flex; align-items: center; gap: 4px; margin-left: auto; }
.b31-radiobox { display: inline-flex; align-items: center; gap: 2px; font-size: 10px; }
.b31-taglist {
  flex: 1 1 auto; min-height: 0; max-height: 168px; overflow: auto;
  display: flex; flex-wrap: wrap; gap: 2px; align-content: flex-start; padding: 2px;
  background: #fff; color: #000;
  box-shadow: inset 1px 1px 0 #85898C, inset -1px -1px 0 #fff, 0 0 0 1px #000;
}
.b31-tag {
  display: inline-flex; align-items: center; gap: 3px; font-size: 11px; line-height: 16px; padding: 0 3px;
  background: #C7CCD0; color: #000; cursor: default;
  box-shadow: inset 1px 1px 0 #fff, inset -1px -1px 0 #85898C, 0 0 0 1px #000;
}
.b31-tag:hover { background: #D3D7DA; }
.b31-tag.on {
  background: #0000A6; color: #fff; padding: 1px 3px 0 4px;
  box-shadow: inset 1px 1px 0 #85898C, inset -1px -1px 0 #fff, 0 0 0 1px #000;
}
.b31-tagc { font-size: 10px; color: #000080; }
.b31-tag.on .b31-tagc { color: #fff; }
.b31-tagfoot { flex: none; display: flex; gap: 2px; }

/* ============================================================
 * p74：文章应用「文章目录 / 信息栏」两栏 —— 中文字形被裁 + 相邻行叠字
 * ------------------------------------------------------------
 * 根因（实测，脚本 _dev/p74-audit.js；度量取自 Canvas 的
 *       fontBoundingBox* / actualBoundingBox*，即 Chrome 排版自己用的那套）：
 *   SimSun31 带 `size-adjust:116.6667%`（win31.css）⇒ 中文字形
 *   **字体内容盒 / 墨迹高 ≈ 1.2–1.3 em**：
 *       11px → 内容盒 14px、墨迹 14px
 *       10px → 内容盒 12px、墨迹 13px
 *        9px → 内容盒 11px、墨迹 12px
 *       12px → 内容盒 15px、墨迹 15px
 *   而全站 `body{line-height:1}` ⇒ 行盒只有 **1 em**，于是：
 *     · 自带 `overflow:hidden` 的单行元素（.b31-colhead-t / .b31-sidehead-t /
 *       .b31-nm / .b31-caltitle）——越出部分被**真的裁掉**：
 *       用户批注图里「文章目录 / 信息栏」底部笔画缺失、正是这个；
 *     · 多行元素（.b31-empty 空状态提示）——相邻两行直接**压字**。
 *   同时还查出：贡献日历头的 ◀ ▶ 两个按钮吃了 `.btn31` 的 `min-width:64px`
 *   （win31.css:255），两个就 128px，而栏头内容盒只有 142px ⇒ 标题被压成「文」。
 * 修法：这两栏里凡放中文的行，**行高一律按墨迹给足**（≥1.3 em，取整到 px），
 *   字号同时降一档（用户要求「再等比例缩小一点」），盒子高度用 height / padding
 *   回补，尽量保持原有版式；日历按钮收成 14px 方钮。
 * ============================================================ */

/* ---------- 栏头「文章目录」/「信息栏」 ---------- */
.b31-colhead, .b31-sidehead { padding: 0 4px; font-size: 10px; line-height: 14px; }
.b31-colhead { height: 14px; }        /* 原 13px（padding 1 + 行高 11）⇒ 只差 1px */
.b31-sidehead { min-height: 17px; }   /* 原 17px（由 ◀ 键撑起）⇒ 保持不变 */
/* ◀ 收侧栏钮（.b31-sidebtn）：原来宽 64px（.btn31 的 min-width:64px），
   侧栏只有 148px 时几乎全被它占掉，标题被压成「文」。
   ⚠️ 原注：「别把它和工具栏里那个竖排的『隐藏侧栏』`.b31-side-toggle` 搞混」——
   p87 起那个工具栏按钮**已删**（用户要求，与这个 ◀ 重复），所以现在侧栏显隐只剩 ◀ 这一个入口。 */
.b31-sidebtn { min-width: 0 !important; width: 15px !important; padding: 0 !important; }

/* ---------- 空状态提示（多行必须给足行高，否则叠字） ---------- */
.b31-empty { font-size: 10px; line-height: 13px; }

/* ---------- 左栏文件夹树 ---------- */
.b31-nm { line-height: 15px; }   /* 行高由 16px 图标撑着 ⇒ 加行高不会让行变高 */
.bf-n { line-height: 13px; }

/* ---------- 右栏贡献日历 ---------- */
.b31-calbtn { min-width: 0 !important; width: 14px !important; padding: 0 !important; }
.b31-caltitle { font-size: 10px; line-height: 13px; }
.b31-calyear { line-height: 13px; }
/* p87：.b31-wdrow 的 line-height 规则随该行一起删除 */
.b31-calfoot { line-height: 13px; }

/* ---------- 右栏标签模块 ---------- */
.b31-taghead { line-height: 14px; }

/* ---------- 编辑器：标签输入 / 自动补全 / 文件夹多选 ---------- */
.wd-tags, .wd-folders { position: relative; display: inline-flex; align-items: center; gap: 3px; flex-wrap: wrap; }
.wd-tagchip {
  display: inline-flex; align-items: center; gap: 2px; font-size: 11px; line-height: 16px; padding: 0 2px 0 3px;
  background: #C7CCD0; color: #000;
  box-shadow: inset 1px 1px 0 #fff, inset -1px -1px 0 #85898C, 0 0 0 1px #000;
}
.wd-tagchip-nm { cursor: default; }
.wd-tagchip-nm:hover { text-decoration: underline; }
.wd-tagx { cursor: default; color: #800000; padding: 0 1px; font-size: 11px; }
.wd-tagin { width: 126px !important; min-width: 0; font-size: 11px !important; }
.wd-tagac {
  position: absolute; left: 0; top: 100%; z-index: 60; min-width: 110px; max-height: 132px; overflow: auto;
  background: #fff; color: #000; border: 1px solid #000;
  box-shadow: inset 1px 1px 0 #fff, inset -1px -1px 0 #85898C, 2px 2px 0 rgba(0, 0, 0, .35);
}
.wd-tagac-i { font-size: 11px; line-height: 15px; padding: 0 4px; white-space: nowrap; cursor: default; }
.wd-tagac-i:hover { background: #0000A8; color: #fff; }

/* ---------- 深色主题（站点支持 body.dark） ---------- */
body.dark .b31-tree, body.dark .b31-taglist { background: #2e2e2e; color: #e0e0e0; }
body.dark .b31-trow:hover, body.dark .b31-sysrow:hover { background: #3a3a55; }
body.dark .b31-cal, body.dark .b31-listhead, body.dark .b31-colhead, body.dark .b31-sidehead { background: #3a3a3a; color: #e0e0e0; }
body.dark .b31-tags { background: #2c3a4a; }
body.dark .b31-month, body.dark .b31-calstat { color: #e0e0e0; }
body.dark .b31-tag { background: #4a4a4a; color: #e0e0e0; }
body.dark .b31-tag.on { background: #0000A6; color: #fff; }
body.dark .b31-tagc { color: #9fc3ff; }
body.dark .b31-tag.on .b31-tagc { color: #fff; }
/* p87：body.dark .b31-adminstate / .b31-adminstate.on 随该元素一起删除 */


/* =====================================================================
 * p67 —— 文档编辑器整改（A4 分页 / 竖排直排 / 文件树清单 / 工具栏门禁 /
 *        正文图片拖拽 / 图片滤镜对话框）
 * ---------------------------------------------------------------------
 * 本文件在 win31.css / v6.css 之后加载 ⇒ 普通声明即可压过基础皮肤；
 * 只有当对手是**跨文件的 `!important`** 时才需要补 `!important`，
 * 而且必须补在**同一个属性**上（跨属性补 `!important` 是无效的 —— p63 踩过）。
 * ===================================================================== */

/* ---------- 1. 工具栏门禁：未选中文字 / 未选中图片时置灰 ----------
   只改文字色与光标，**刻意不碰 box-shadow**：
   全局 `button{box-shadow:… !important}` 来自另一张表，改别的属性压不住。
   ⚠️⚠️ `color` 必须带 `!important`：v7.css 上方有一条
      `button, .btn31, .calc-btn, .cp-cat { color:#000 !important; … }`
      —— **`!important` 的普通声明连 inline style 都能压住**（实测：给按钮写
      `style.color='#84888C'`，computed 仍是 rgb(0,0,0)）。
      两个 `!important` 相遇时比特异性 ⇒ `.wd-bar-btns .wd-b.wd-off`(0,3,0) 胜 `button`(0,0,1)。
   ⚠️ 这里**不写** `pointer-events:none`：让点击照常落到按钮上，
      editor.js 才能用状态栏提示「请先选中文字 / 请先选中一张图片」——
      置灰按钮点下去有解释，比彻底没反应好。 */
.wd-bars .wd-b.wd-off,
.wd-bar-btns .wd-b.wd-off {
  color: #84888C !important;
  -webkit-text-fill-color: #84888C !important;
  cursor: default;
}

/* ---------- 2. A4 分页装饰层（非破坏性） ----------
   `.wd-canvas-wrap` 是滚动容器（v6.css：flex:1; overflow:auto; background:#808080）
   ⇒ 必须补 relative，装饰层才能按纸张的 offsetLeft/offsetTop 定位。 */
.wd-canvas-wrap { position: relative; }
/* 装饰层是 `.wd-page` 的**兄弟**节点：page.innerHTML / 保存 / 导出 / 打印都不会带上它，
   所以分页线永远不会被误当成文档内容保存出去。 */
.wd-pagedeco { position: absolute; pointer-events: none; z-index: 2; }
/* 页与页之间的「缝」：上下各一条虚线 + 浅斜纹。
   ⚠️ 半透明斜纹（不是实心底色）—— 纸是连续的一张，实心底色会把交界处的正文盖掉。 */
/* p93：页缝改成**实心的纸缝**。
   ⚠️ 老版本刻意用「半透明斜纹」，是因为它直接画在 `i×页高` 上、**必然压在正文上**，
      只能靠半透明让底下的字还看得见（用户截图里那条盖着正文的斜纹带）。
      p93 起页缝会吸附到**两行之间的空白**（js/editor.js 的 `snapBreak()`）
      ⇒ 可以放心做成实心，看起来才真是「两张纸之间的缝」。
   ⚠️ 高度由 js 写成 inline（= 上下两条行边界的距离），这里**不再写死 14px**。 */
.wd-pbreak {
  position: absolute; left: 0; right: 0;
  border-top: 1px solid #9a9a9a;
  border-bottom: 1px solid #6b6b6b;
  background: linear-gradient(#dedede, #c9c9c9 48%, #bfbfbf 52%, #dedede);
  box-shadow: inset 0 1px 0 #f4f4f4;
  box-sizing: border-box;
}
/* 每页右下角的「第 N 页 / 共 M 页」 */
.wd-pgno {
  position: absolute; right: 8px; line-height: 20px;
  font-size: 11px; color: #454545; white-space: nowrap;
}

/* ---------- 3. 竖排（直排） ----------
   用户口径里的「豎排」是中文的直排（自上而下、由右向左），走 writing-mode；
   原先「把纸改成横向」只是 Orientation，不是他要的东西（所以他看到「無效」）。 */
.wd-page.wd-vert { writing-mode: vertical-rl; text-orientation: mixed; }
/* 内嵌的「横向矩形」必须强制回横排 —— 否则公式、表格、目录会被逐字竖起来，没法读。 */
.wd-page.wd-vert .lx-wrap,
.wd-page.wd-vert .lx-block,
.wd-page.wd-vert .lx,
.wd-page.wd-vert table,
.wd-page.wd-vert pre,
.wd-page.wd-vert .wd-toc { writing-mode: horizontal-tb; }
/* 直排时图片跟着行高走，别被拉成一张纸条 */
.wd-page.wd-vert img { max-height: 100%; }

/* ---------- 4. 多级清单：文件树（连线）/ 多级编号 / 圆点嵌套 ---------- */
.wd-page .wd-ol { margin: 6px 0; padding-left: 26px; }
.wd-page .wd-ol ol { padding-left: 26px; }
.wd-page .wd-ul { margin: 6px 0; padding-left: 22px; list-style: disc; }
.wd-page .wd-ul ul { padding-left: 22px; list-style: circle; }
.wd-page .wd-ul ul ul { list-style: square; }
.wd-page .wd-ul ul ul ul { list-style: disc; }
.wd-page .wd-ul ul ul ul ul { list-style: circle; }
.wd-page .wd-ul ul ul ul ul ul { list-style: square; }

/* 文件树：├─ / └─ 连线纯靠伪元素画（不打字符，免得被当正文复制出去）。
   · 竖线由 li::before 画，最后一项截断到横杠高度（└ 而不是 ├）；
   · 横杠由 li::after 画，正好落在文字的行中线上；
   · 根节点的 li 不画任何连线。 */
.wd-tree, .wd-tree ul { list-style: none; margin: 0; padding-left: 0; }
.wd-tree li { position: relative; padding-left: 18px; line-height: 1.75; }
.wd-tree > li { padding-left: 0; }
.wd-tree li::before {
  content: ''; position: absolute; left: 5px; top: 0; bottom: 0;
  border-left: 1px dotted #909090;
}
.wd-tree li:last-child::before { bottom: auto; height: .95em; }
.wd-tree li::after {
  content: ''; position: absolute; left: 5px; top: .88em; width: 9px;
  border-top: 1px dotted #909090;
}
.wd-tree > li::before, .wd-tree > li::after { display: none; }

/* ---------- 5. 正文图片：可拖拽 + 松手后文字绕排 ----------
   float 是浏览器原生的「文字绕排」，也就是用户要的「文本為其讓位」；
   单纯 position:absolute 只是把图悬在空中、文字照样被压在下面，不算让位。 */
.wd-page img { cursor: move; }
.wd-page img.wd-imgdrag { cursor: grabbing; outline: 1px dashed #0000a8; outline-offset: 2px; }

/* ---------- 5b. p120④：选中图片后的四角缩放手柄 ----------
   结构见 js/editor.js 的 ensureImgHandles()：.wd-imgh 是 .wd-page 的**兄弟**覆盖层，
   与 .wd-pagedeco 同一套路 ⇒ 保存 / 导出 / 打印都不会带上它。
   手柄 9×9（Win3.1 白底黑框小方块），用 translate(-50%,-50%) 让方块**正对**图片角点。 */
.wd-imgh { position: absolute; pointer-events: none; z-index: 3; }
.wd-imgh-h {
  position: absolute; width: 9px; height: 9px; box-sizing: border-box;
  background: #fff; border: 1px solid #000; transform: translate(-50%, -50%);
  pointer-events: auto;
}
.wd-imgh-h[data-corner="nw"], .wd-imgh-h[data-corner="se"] { cursor: nwse-resize; }
.wd-imgh-h[data-corner="ne"], .wd-imgh-h[data-corner="sw"] { cursor: nesw-resize; }
.wd-imgh-h.wd-imgh-drag { background: #0000a8; }
.wd-page img.wd-imgsel { outline: 1px dashed #0000a8; outline-offset: 2px; }

/* ---------- 5c. p120⑤：编辑器里的 PDF 页（底图 + 批注层） ----------
   结构见 js/editor.js 的 loadPdfSheets()。
   ⚠️ 底图必须 `cursor:default` 并屏蔽编辑器自带的「拖图绕排」（v7 的 `.wd-page img{cursor:move}`
      会给所有 img 生效）—— 纸面不是插图，被拖走就没法编辑了。 */
.wd-pdfsheet { position: relative; margin: 0 auto 13px; max-width: 100%; line-height: 0; }
.wd-pdfsheet > img { display: block; width: 100%; max-width: 100%; height: auto; border: 1px solid #808080; cursor: default; }
.wd-pdfanno {
  position: absolute; inset: 0; box-sizing: border-box; padding: 4px 6px;
  overflow: hidden; line-height: 1.5; font-size: 14px; color: #000;
  background: transparent; outline: none; cursor: text; line-height: 1.5;
}
.wd-pdfanno:focus { background: rgba(255,255,255,.55); }
.wd-pdfanno:empty::before { content: attr(data-ph); color: rgba(0,0,0,.3); }

/* ---------- 6. 图片滤镜对话框 ----------
   结构见 js/editor.js 的 filterDialog()：
   .fx-cmp（原始 / 滤镜后 两联对比） + .fx-right（缩略图网格 + 强度滑杆 + 参数描述）。 */
.fx-box { width: 660px; max-width: 94vw; }
/* 底部 5 个按钮里 "Hold to compare" / "Parameters..." / "Reset" 都比 72px 宽 ⇒ 在滤镜面板内
   放宽度自适应（仍保持 Win31 灰底 + 双色立体 + 23px 高 + 居中排布，只是不强行 72px 定宽）。
   ⚠️ `.nd31-ft .btn31{width:72px}` 在 v7.css:1459，特异性 (0,2,0) ⇒ 这里用 (0,3,0) 压过去，
      **不要**加 !important（v7.css 顶部有 `button{color:#000 !important}` 那类规则，加了会互相打架）。 */
.fx-box .nd31-ft { gap: 16px; }
.fx-box .nd31-ft .btn31 { width: auto; min-width: 72px; padding: 0 12px; white-space: nowrap; }
/* ⚠️ 必须显式写 align-items:stretch：v6.css:366 的 `.nd31-bd{display:flex; align-items:flex-start}`
   会（在 v7.css:1435 那条消息框规则里同样）把 .fx-cmp / .fx-right 缩成半宽 ——
   实测过：.fx-grid 只剩 129px ⇒ 20 个缩略图排成 1 列要滚 10 屏。
   配套改动：v7.css:1435 的消息框规则已加 `:not(.fx-bd)` 把滤镜面板摘出来（否则它的
   align-items / padding `!important` 会无条件压过这里）。 */
.fx-bd { display: flex; flex-direction: column; align-items: stretch; gap: 6px; padding: 8px 12px 0; box-sizing: border-box; }
/* 前后对比：两张图同宽同高，取 contain 保证「同一个视野」便于肉眼比对 */
.fx-cmp { display: flex; gap: 8px; }
.fx-cmp figure { flex: 1 1 0; min-width: 0; margin: 0; display: flex; flex-direction: column; gap: 2px; }
.fx-cmp img {
  width: 100%; height: 128px; object-fit: contain;
  background: #fff; border: 1px solid #808080; image-rendering: pixelated;
}
.fx-cap { font-size: 11px; color: #404040; text-align: center; }
.fx-right { display: flex; flex-direction: column; gap: 5px; }
/* 滤镜缩略图网格：**固定整数列宽 66px**（p71 改）。
   原来写 `minmax(66px,1fr)` ⇒ 列宽是 67.1094px 这种小数，缩略图 img 的内容盒 = 61.11px，
   而示例图是 60×40 的整数像素画 ⇒ 非整数缩放会把像素画糊掉（而且 <1 的缩放最明显）。
   固定 66px 后：按钮内容盒 62、img 内容盒 **60×40**，与 `ImgFX.sampleSrc()` 的原生尺寸
   **完全相等** ⇒ 整数倍 1:1、零重采样。
   9 列 × 66 + 8 × 3 = 618 ≤ 632（面板净宽）⇒ 列数与改前一致（仍是 9 列），
   多出来的 14px 用 `justify-content:center` 左右均分。
   196px = 3 行 × 61（缩略图 42 + 标签 14 + 间隙 1 + 内边距 4）+ 2 × 3 间距 ⇒ 20 个一屏放完不滚动。
   ⚠️ 改这里的列宽/内边距，必须同步改 `js/imgfx.js` 的 SAMPLE_ART/SAMPLE_SCALE（见 _dev/p71.js 断言）。 */
.fx-grid {
  display: grid; grid-template-columns: repeat(auto-fill, 66px); justify-content: center;
  gap: 3px; max-height: 196px; overflow-y: auto; padding: 2px;
}
/* ⚠️ `.fx-th` 是 `<button>` ⇒ 必须自己抹平全局 `button{box-shadow:… !important}`，
   并且补 min-height/min-width/max-height（否则会被全局规则顶高、或被 flex 压扁）。
   **p71 关键**：`<button>` 在 UA 样式里**不继承 font-family**（`button{font:400 13.333px Arial}`），
   所以滤镜名一度渲染成 Arial，而同一面板里的 `.fx-cap`/`.fx-lb`/`.fx-val` 都是
   `SimSun31, Win31System, …` 两套字形（用户截图所示）。照站内惯例补 `font-family: inherit`
   （`.btn31` 也是这么做全站按钮的）⇒ 名字与面板其它文字**统一**为同一套像素字体。
   自检：`_dev/p71.js` 断言 `.fx-th` 与 `.fx-cap` 的 computed fontFamily 完全相同且含 SimSun31。 */
.fx-th {
  display: flex; flex-direction: column; align-items: center; gap: 1px;
  padding: 2px; min-width: 0; min-height: 0; max-height: none;
  font-family: inherit;
  box-shadow: none !important;
}
/* `object-fit: fill`：内容盒 60×40 与示例图原生尺寸相等 ⇒ 等同 1:1 直贴。
   不要写 cover/contain（一旦列宽不是整数就会触发非整数缩放）。 */
.fx-th img { width: 100%; height: 42px; object-fit: fill; background: #fff; border: 1px solid #808080; }
/* 12px = 站内 SimSun31 点阵的原生档（win31.css 里 `size-adjust:116.6667%` ⇒ 12px CSS = 14px 设计）
   ⇒ 笔画最锐利；也是面板其它文字的字号，视觉最统一。
   实测（_dev/p71probe.js 第 6 段）：可用净宽 62px，12px 下 20 个名字里只有
   `High Contrast`(74) / `Teal & Orange`(76) 会省略号，与改前（10px Arial）同为 2 条。
   line-height 14px 给「Original / Soft Glow」的 g 下伸部留出空间，避免被 overflow:hidden 切掉。 */
.fx-th span {
  max-width: 100%; font-size: 12px; line-height: 14px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.fx-th.on { outline: 1px dotted #000 !important; outline-offset: -3px; background: #d8d8d8; }
.fx-ctl { display: flex; align-items: center; gap: 6px; }
.fx-lb { flex: 0 0 auto; white-space: nowrap; }
.fx-slot { flex: 1 1 auto; min-width: 0; display: flex; align-items: center; }
.fx-val { flex: 0 0 46px; text-align: right; }
.fx-desc { min-height: 16px; }

/* 自绘 Win31 trackbar —— 与 Scroll31 / Spin31 同一套视觉（一点立体靠 inset 双色）。
   ⚠️ 几何全部由 JS 用 groove.clientWidth / thumb.offsetWidth 算，
      CSS 只负责外观；**不要**给 .fx-thumb 加 margin-left（JS 已经减过半个滑块）。 */
.fx-track { position: relative; display: block; width: 100%; height: 19px; }
.fx-track:focus { outline: 1px dotted #000; outline-offset: -2px; }
.fx-groove {
  position: absolute; left: 0; right: 0; top: 8px; height: 3px;
  background: #9a9a9a; border-top: 1px solid #6b6b6b; border-bottom: 1px solid #efefef;
}
.fx-fill { position: absolute; left: 0; top: 8px; height: 3px; background: #0000a8; }
.fx-thumb {
  position: absolute; top: 1px; width: 11px; height: 17px; left: 0;
  background: var(--face, #c0c0c0); border: 1px solid #000;
  box-shadow: inset 1px 1px 0 #ffffff, inset -1px -1px 0 #808080;
}

/* ============================================================
 * p79 —— 「属于屏幕画面」的瞬态弹层全部收进 #desktop（收尾 p76）
 * ============================================================
 * 用户：「都修了」= 把 p76 报告里点名的同类缺陷一次做完。
 *
 * 背景：CRT 弧面是 `url(#f-crtcurve)`，**inline 挂在 `#desktop` 上**
 *   （js/effects2.js 的 applyWarp）⇒ 只有它的**滤镜子树**里的元素才跟着屏幕一起弯。
 *   窗口之所以会弯，就是因为 `js/wm.js` 把窗口挂在 `#desktop` 里。
 *   凡是挂在 `document.body` 上的 `position:fixed` 弹层，弧面 10% 时窗口在弯、它们纹丝不动。
 *
 * 三步走（与 p76 对 `.sysmenu` / `#tip31` 的处理完全同构）：
 *   ① 宿主：`document.body.appendChild(x)` → `window.__mountPop(x)`（js/wm.js）；
 *   ② 定位：`__placeFixed(x,…)`          → `window.__placePop(x,…)`（按实际宿主配对坐标系）；
 *   ③ CSS ：源规则的 `position:fixed` 由下面这组 `#desktop > …` 覆盖成 `absolute`。
 *
 * ⚠️ **为什么只在 `#desktop >` 下覆盖，而不是直接改源规则**
 *   `__mountPop` 会判断桌面是否可见：`body.dos-mode #desktop{display:none}`（开机自检 /
 *   DOS 程序全屏）时它**主动退回 `document.body`** —— 否则对话框会被连桌面一起 `display:none`
 *   吞掉（用户会看到「点开没反应」）。退回 body 时这些层必须仍然是 `fixed`，
 *   所以改法只能是「后代选择器覆盖」，不能无条件改掉源声明。
 *   （`.sysmenu` / `#tip31` 是 p76 无条件改的，因为它们永远只挂 `#desktop`；这里一并列出，
 *     让「哪些层已经收进桌面」有一份**单一清单**可查。）
 *
 * ⚠️ **不要给弹层自己也挂一份 `#f-crtcurve`**：`feImage` 是按元素**自己的**
 *   `clientWidth/clientHeight` 铺位移图的（`primitiveUnits="userSpaceOnUse"`）
 *   ⇒ 套在一个贴角落的小盒子上 = 把「屏幕左上角」的位移量贴到它身上，方向全错。
 *   挂进 `#desktop` 才是零坐标数学。
 *
 * ⚠️ 代价（p76 已实测、不是 bug）：搬进来后文字从 **LCD 次像素抗锯齿**变成**灰度抗锯齿**
 *   （合成层的锅，窗口一直如此）。静息位置逐像素不变。
 *
 * 层级：搬进来后 z-index 在 `#desktop` 的层叠上下文里比较。窗口从 101 起递增，
 *   而下面这些层最低也是 9000（`.nd31-overlay`）⇒ 仍然稳压所有窗口；
 *   唯一代价是再也盖不过 `#desktop` 之后的 body 层（`#splash` 开机画面 / `#crt-overlay`），
 *   而那两个本来就应该在上面。
 */
#desktop > .sysmenu,
#desktop > #tip31,
#desktop > .s31-pop,
#desktop > .d31-pop,
#desktop > .nd-menu,
#desktop > .nd-drop,
#desktop > .wd-dlg,
#desktop > .nd31-overlay,
#desktop > .busy-badge,
#desktop > .ct-kao,
#desktop > .ct-tip,
#desktop > .ct-menu,
#desktop > .rdr-selbar,
#desktop > .rdr-menu,
#desktop > .dv-tip,
#desktop > .nw-lvtip,
#desktop > .bxw-ov {
  position: absolute;
}

/* `.wd-dlg` 的居中定位：源规则（js/effects2.js 注入）用的是 `left:50%/top:38%` +
   `translate(-50%,-50%)`，那是相对**包含块**的百分比 ⇒ 搬进 `#desktop` 后
   包含块变成桌面盒；`#desktop` 视觉上恒等于视口（`width:calc(100%/--res-scale)` +
   `scale(--res-scale)`）⇒ 居中位置与从前一致，无需改百分比。这里只是显式记一笔。 */

/* ============================================================
 * p94：文章应用
 *  · 标签区「添加标签」入口（右栏信息栏底部）
 *  · 拖动文章 → 左侧文件夹归档
 *  · 隐藏文件夹在目录树上的标记
 * ------------------------------------------------------------
 * 侧栏内容盒只有 ~148px 宽 ⇒ 新增的行一律 flex + min-width:0，
 * 并**自带 padding 上限**，绝不横向溢出（用户铁律：不得超出框）。
 * ============================================================ */

/* 标签模块底部：上行「新标签输入 + 添加」，下行仍是「重命名 / 删除标签」 */
.b31-tagfoot { flex: none; display: flex; flex-direction: column; gap: 2px; }
.b31-tagaddrow, .b31-tagbtns { display: flex; gap: 2px; min-width: 0; }
/* 输入框走 .input31 的外观，但按侧栏收窄：字号/内边距都降一档，行高与 .b31-mini 齐平 */
.b31-tagaddrow .b31-taginp {
  flex: 1 1 auto; min-width: 0; width: auto;
  font-size: 11px !important; padding: 0 3px !important; height: 17px;
}
.b31-tagbtns > .btn31 { flex: 1 1 auto; min-width: 0; }

/* 拖动文章：被拖的那条半透明；落点文件夹整行反白（与 .sel 同色，用户一眼知道去哪） */
.blog-item.dragging { opacity: .45; }
.b31-trow.drop-on {
  background: #0000A8 !important; color: #fff !important;
  box-shadow: inset 1px 1px 0 #fff, inset -1px -1px 0 #fff;
}
.b31-trow.drop-on .b31-nm, .b31-trow.drop-on .bf-n { color: #fff !important; }

/* 隐藏文件夹：只对**进得去**的隐藏文件夹画（进不去的根本不建节点）。
   图标换成带钥匙孔的灰文件夹（Icons.folderHidden），名字再补一道斜体，
   与普通文件夹一眼可分，同时不改变行高（.b31-nm 的 line-height 由 16px 图标撑着）。 */
.b31-trow.is-hidden .b31-nm { font-style: italic; }

/* 深色主题 */
body.dark .b31-trow.drop-on { background: #2a2a6a !important; }
body.dark .b31-tagaddrow .b31-taginp { background: #4a4a4a; color: #e0e0e0; }

/* ============================================================
 * p93⑩：文档编辑器「字体：」工具栏 —— 一行放得下
 * ------------------------------------------------------------
 * 症状：该行实测 914×69，里面出现 3 种行顶（97 / 116 / 137）= 3 行：
 *        第 1 行「字体：」标签、第 2 行字体下拉、第 3 行字号下拉。
 *        两个自绘下拉的 inline width 都是 **908px**（≈整行宽度）。
 * 根因链（三段，缺一不可）：
 *        ① css/win31.css 有一条全局 `.input31 { width: 100% }`；
 *        ② 这一行的两个 <select> 都带 .input31 ⇒ 布局宽度 = 整行 908px；
 *        ③ js/select31.js 的 enhance() 在增强时把原生 select 的渲染宽度
 *           **只量一次并冻成 inline width**（它是有意这么写的：旧实现每次 sync()
 *           都重算且只增不减，宽度会一路膨胀撑坏面板）⇒ 908px 被永久钉死。
 *           `.input31` 在包装时被有意剔除，所以 wrapper 上只剩 .wd-sel，压不住 inline width。
 * 修法：照抄本文件第 6 节「视频播放器工具栏」的既有做法 —— 把**直接子元素**锁成固定列宽。
 *        必须带 `!important`：inline width（非 important）只有 important 声明的样式能压过；
 *        两个 `!important` 相遇时比特异性 ⇒ `.wd-bar.wd-fbar > .wd-sel` (0,2,0) 稳胜。
 * 结果：标签 104 + 字体下拉（吃满剩余）+ 字号 84，**一行**，行高 ~24px。
 * ⚠️ 选择器只作用于 `.wd-fbar` 的直接子元素，编辑器其余分组行与控制面板下拉不受影响。
 * ============================================================ */
.wd-bar.wd-fbar { flex-wrap: nowrap; }
.wd-bar.wd-fbar > .wd-glab { flex: 0 0 104px !important; width: 104px !important; }
.wd-bar.wd-fbar > .wd-sel {
  flex: 1 1 auto !important; width: auto !important;
  min-width: 0 !important; max-width: none !important;
}
.wd-bar.wd-fbar > .wd-sel.wd-fsize { flex: 0 0 84px !important; width: 84px !important; }

/* ============================================================
 * p107 · 字符控制（字体作用域）· 编辑器字形按钮 · 图形绘制 · 符号面板
 *      · 文章应用工具条网格 · 侧栏恢复按钮
 * ------------------------------------------------------------
 * 本块只做「外观与布局」，字体作用域规则的生成在 js/settings.js 的
 * applyFontScopes()（写进 <style id="p107-fontcss">）—— 默认不生成任何规则，
 * 所以这里也不会顺手改动任何既有像素。
 * ============================================================ */

/* ---------- 1. 字符控制面板 ---------- */
.p107-row {
  display: flex; align-items: center; gap: 4px;
  padding: 3px 4px; border-left: 1px dotted #a0a0a0;
}
.p107-lab { flex: 0 0 auto; font-size: 12px; }
.p107-sel { flex: 0 0 auto; width: 122px; min-width: 0; }
/* 字体下拉吃满整行剩余宽度。
   ⚠️ select31.js 会把原生 select 的渲染宽度**冻成 inline width**（有意为之），
      用 `flex-basis:0%` 让 inline width 彻底失效（flex-basis 非 auto 时 width 被忽略），
      否则一旦它量到的是「插入瞬间还没布局」的 0 宽，下拉就会永久窄成一条。 */
.p107-sel.p107-selwide { flex: 1 1 0%; width: auto; min-width: 0; max-width: none; }
.p107-preview {
  flex: 1 1 auto; min-height: 96px; margin: 3px 4px;
  background: #fff; border: 1px solid #000;
  box-shadow: inset 1px 1px 0 #85898C, inset -1px -1px 0 #fff;
  overflow: auto; padding: 4px;
}
.p107-big { font-size: 20px; line-height: 1.35; margin-bottom: 6px; word-break: break-all; }
.p107-grid { display: flex; flex-wrap: wrap; gap: 1px; }
.p107-cell {
  width: 18px; height: 20px; line-height: 20px; text-align: center;
  font-size: 14px; cursor: pointer; background: #fff;
}
.p107-cell:hover { background: #dcdcdc; }
.p107-cell.sel { background: #0000A6; color: #fff; }
.p107-foot { flex: 0 0 auto; padding: 2px 4px 4px; border-top: 1px solid #85898C; }
.p107-note { font-size: 11px; color: #404040; line-height: 1.5; word-break: break-all; }

/* ---------- 2. 编辑器字形按钮（B / I / U / A / 高亮） ----------
   用户口径：「B按鈕應當粗體、I應該斜體、U應該有下劃線、A應該顯示為藍色、
   高光按鈕應當顯示為黃色」。类名由 editor.js 按**原始 title**（不随语言变）
   打在按钮上 ⇒ 换语言也不会丢。

   ⚠️⚠️ 每条都必须带 `!important`，且靠**升特异性**（`.wd-bars .wd-b.g-x` = 0,3,0）取胜：
      · v7.css:286 `button, .btn31, .calc-btn, .cp-cat { background:#C7CCD0 !important;
        color:#000 !important; border:none !important; box-shadow:… !important }`
      · v7.css:430 `.wd-b { … font-weight: normal !important }`
   跨文件 `!important` 无条件取胜 —— 只升特异性压不住（p107 第一轮「B 不粗 / A 不蓝 /
   高亮不黄」三条红就是这么来的，而 I/U 因为没人抢 font-style/text-decoration 才侥幸对）。
   两个 `!important` 相遇时**比特异性** ⇒ 0,3,0 胜 `button`(0,0,1) / `.wd-b`(0,1,0)。

   ⚠️ I 按钮**只做斜体、不换字体族**：站内约定「标题栏/菜单/工具栏按钮 = Win31System」，
      给按钮塞 Georgia 会破坏这条像素约定；像素字体没有真斜体面时浏览器会合成倾斜，
      视觉上就是斜体（用户要的也是「斜体」而不是「衬线体」）。 */
.wd-bars .wd-b.g-b { font-weight: bold !important; }
.wd-bars .wd-b.g-i { font-style: italic !important; }
.wd-bars .wd-b.g-u { text-decoration: underline !important; }
/* p134 ②：S（删除线）—— p107 时刻意留空；用户口径「S 應當加刪除線（文檔編輯器的也要）」⇒ 补上。 */
.wd-bars .wd-b.g-s { text-decoration: line-through !important; }
.wd-bars .wd-b.g-a {
  color: #0000C0 !important; -webkit-text-fill-color: #0000C0 !important; font-weight: bold !important;
}
/* 高亮：把那个 ▨ 字符涂成黄色 —— 用「实心黄块 + 黑框」比给字符上色更像
   参考图里的「黄色荧光笔」。字符本身仍在（可被读屏/测试取到）。 */
.wd-bars .wd-b.g-hl {
  background: #FFFF00 !important; color: #000 !important; font-weight: bold !important;
  box-shadow: inset 1px 1px 0 #FFFFB0, inset -1px -1px 0 #808000, 0 0 0 1px #000 !important;
}
.wd-bars .wd-b.g-hl:active {
  box-shadow: inset 1px 1px 0 #808000, inset -1px -1px 0 #FFFFB0, 0 0 0 1px #000 !important;
}

/* ---------- p134 ②：聊天工具条字形（与上面文档编辑器的 p107 一套口径） ----------
   ⚠️ 聊天按钮是 `.ct-tools .btn31`（不是 `.wd-b`）⇒ 必须**另写一条选择器**；
      跨文件 `!important` 只比特异性 ⇒ 0,2,0 的 `.ct-tools .btn31.g-b` 足以压过 `button`(0,0,1)。 */
.ct-tools .btn31.g-b { font-weight: bold !important; }
.ct-tools .btn31.g-i { font-style: italic !important; }
.ct-tools .btn31.g-u { text-decoration: underline !important; }
.ct-tools .btn31.g-s { text-decoration: line-through !important; }
.ct-tools .btn31.g-a {
  color: #0000C0 !important; -webkit-text-fill-color: #0000C0 !important; font-weight: bold !important;
}
.ct-tools .btn31.g-hl {
  background: #FFFF00 !important; color: #000 !important; font-weight: bold !important;
  box-shadow: inset 1px 1px 0 #FFFFB0, inset -1px -1px 0 #808000, 0 0 0 1px #000 !important;
}

/* ---------- 3. 图形绘制（选择图形后在页面上拖拽画出来） ---------- */
.wd-page.wd-drawmode { cursor: crosshair; }
.wd-page.wd-drawmode * { cursor: crosshair !important; }
/* 拖拽过程中的橡皮筋框（纸面内的绝对定位覆盖层） */
.wd-drawghost {
  position: absolute; border: 1px dashed #0000A6; background: rgba(0, 0, 166, .12);
  pointer-events: none; z-index: 30;
}
/* 画好的图形：inline-block 保持在正文流里（和旧版 insertShape 的排布一致） */
.wd-shape { display: inline-block; vertical-align: middle; }
.wd-shape-line { height: 0; }
.wd-shape-arrow { position: relative; }
.wd-shape-arrow::after {
  content: ''; position: absolute; top: 50%; right: -1px; transform: translateY(-50%);
  border-left: 7px solid #000; border-top: 5px solid transparent; border-bottom: 5px solid transparent;
}

/* ---------- 4. 符号面板（扩充符号 + Unicode 输入） ---------- */
.p107-symwrap { max-width: 520px; }
.p107-symgrp { font-size: 11px; color: #404040; margin: 6px 0 2px; }
.p107-symgrid { display: flex; flex-wrap: wrap; gap: 1px; }
.p107-sym {
  width: 22px; height: 22px; line-height: 20px; text-align: center; font-size: 14px;
  min-width: 0; min-height: 0; max-height: none; padding: 0;
  border: 1px solid #85898C; background: #C7CCD0;
  box-shadow: inset 1px 1px 0 #fff, inset -1px -1px 0 #85898C;
  cursor: pointer;
}
.p107-sym:hover { background: #dcdcdc; }
.p107-sym:active { box-shadow: inset 1px 1px 0 #85898C, inset -1px -1px 0 #fff; }
.p107-symrow { display: flex; align-items: center; gap: 4px; margin-top: 8px; }
.p107-uni { width: 108px; }

/* ---------- 5. 文章应用：文件夹工具条改成等宽网格（英文界面下不再错位） ----------
   用户口径（附图）：「英語語言下按鈕沒有上下左右對齊且大小長寬一致」。
   旧样式是 `.b31-tools{display:flex;flex-wrap:wrap}` + 按钮按文字自然宽度 ⇒
   英文标签（Subfolder / Move down）一长一短就参差不齐。
   改法：两列等宽网格（New|Subfolder / Rename|Move / …），全部按格子吃满。
   ⚠️ 用 `.b31-left .b31-tools` 升一格特异性，压过 v7.css:1826 的老规则。 */
.b31-left .b31-tools.b31-tools {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 2px; align-content: start;
}
.b31-left .b31-tools.b31-tools > .btn31 {
  width: 100% !important; min-width: 0 !important; max-width: none !important;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ---------- 6. 文章应用：侧栏隐藏/恢复按钮（同一位置，图标对调） ----------
   用户口径：「右側欄目前只有隱藏按鈕，沒有恢復按鈕，應當在隱藏按鈕同樣的位置
   於隱藏後放置恢復按鈕」。按钮本体不变（同一个 DOM 节点、同一位置），
   只把字形 ◀/▶ 与 title 对调 —— 这样「位置」天然一致，不会出现两个按钮。 */
.b31-sidehead .b31-sidebtn { flex: 0 0 auto; }
.b31-sidehead .b31-sidebtn.is-closed {
  background: #C7CCD0;
  box-shadow: inset 1px 1px 0 #fff, inset -1px -1px 0 #85898C;
  font-weight: bold;
}

/* ---------- 7. p107 补充：符号面板的滚动区与 Unicode 行 ---------- */
.p107-symhost { max-height: 268px; overflow: auto; padding-right: 2px; }
.p107-labsm { flex: 0 0 auto; font-size: 12px; }
.p107-uniprev { flex: 0 0 auto; min-width: 54px; font-size: 15px; font-weight: bold; }
.p107-symrow .btn31 { flex: 0 0 auto; }
/* 页眉/页脚的文字载体（p107 修 footer 时新增的节点，本身不需要外观） */
.wd-header-t, .wd-footer-t { }

/* ============================================================
 * p107 补充 · 文章应用：侧栏收起后的「恢复」条 + 视图按钮的按下态
 * ============================================================ */

/* ---------- 8. 侧栏收起：留一条 22px 窄条，按钮留在原地 ----------
   用户口径：「右側欄目前只有隱藏按鈕，沒有恢復按鈕，應當在隱藏按鈕同樣的位置
   於隱藏後放置恢復按鈕」。
   旧实现把 `side` 整块 display:none ⇒ 表头里的按钮跟着消失，无法恢复。
   现在收起 = 换类（`.b31-side-off`），只把非表头的孩子藏起来、宽度压到 22px。
   特异性：`.b31-side.b31-side-off`(0,2,0) > `.b31-side`(0,1,0) ⇒ 不需要 !important。 */
.b31-side.b31-side-off { flex: 0 0 22px; min-width: 22px; max-width: 22px; }
.b31-side.b31-side-off > *:not(.b31-sidehead) { display: none; }
.b31-side.b31-side-off .b31-sidehead-t { display: none; }
.b31-side.b31-side-off .b31-sidehead {
  justify-content: center; padding: 0; gap: 0;
  background: #C7CCD0;
}
.b31-side.b31-side-off .b31-sidehead .b31-sidebtn {
  width: 100%; min-width: 0;
  border-left: none; border-right: none;
}
/* 窄条上给个竖排的「信息栏」提示，鼠标悬停仍能看到 title */
.b31-side.b31-side-off .b31-sidehead::after { content: ''; }

/* ---------- 9. 视图按钮的按下态（三态轮转时用户要能看出当前在哪个态） ---------- */
.btn31.tb-icon.is-on {
  box-shadow: inset 1px 1px 0 #85898C, inset -1px -1px 0 #fff !important;
  background: #b8bcc0 !important;
}

/* ============================================================
 * p109 · 字形样本统一走站内像素字体（符号面板 + 颜文字面板）
 * ============================================================ */
/* 用户口径：「insert symbol 弹窗 和 新闻-聊天 的颜文字选择 内的字体应该使用统一像素字体」。
 *
 * ⚠️⚠️ 真因（两个坑叠加，缺一个都不会出问题）：
 *   ① 这两处的**格子都是 `<button>`**，而 UA 样式表给表单控件**显式**写死了
 *      `font-family`（系统比例字体，Arial 系）⇒ 按钮**不会**从父级继承字体。
 *   ② 本站的像素字体只挂在一条选择器表上（v6.css:54）：
 *        `body, .win, .btn31, .input31, select, textarea, .menu-bar, .titlebar, .cp-root, .cp-root *`
 *      而 `.p107-sym`（符号格）与 `.ct-kao-btn`（颜文字格）**都不带 `btn31`**；
 *      而且这两个浮层是 `__mountPop` 挂到 **`#desktop`** 上的 ⇒ **根本不在 `.win` 里**。
 *      ⇒ 两条路都够不着，格子落到系统字体上，跟周围窗口的像素字格格不入。
 *
 * 修法：**照 p71 已经验证过的站内惯例补 `font-family: inherit`**
 *   （`.fx-th` 当初就是同一个坑、同一条修法；`.btn31` 也是这么把全站按钮统一起来的）。
 *   为什么用 `inherit` 而不是写死 `var(--font-31)`：
 *     · 跟着宿主走 ⇒ 用户若在「字符控制」里给全系统 / 某应用指定了字体（p107 的作用域引擎
 *       会把 `--font-31` 写到 `body` 的行内样式上），这里**自动跟随**，不用两处维护；
 *     · 也不写 `!important` ⇒ p107 那条带 `!important` 的作用域规则仍然优先（用户显式选择 > 兜底默认）。
 *
 * ⚠️ 同类坑的**通用判据**（以后凡是新建 `<button>` 承载文字/字形，都要过这一条）：
 *   `<button>` 在 UA 样式表里是 `button{font:400 13.333px Arial}` ⇒ **不继承 font-family**；
 *   凡是**不在** `body/.win/.btn31/.input31/select/textarea/.menu-bar/.titlebar/.cp-root*`
 *   这条像素字体表里的、又还挂在 `#desktop` 上的浮层，一律要自己补 `font-family: inherit`。
 * 自检：本批 `_dev/p109.js` 断言这两个面板的格子与 `document.body` 的 computed
 *   fontFamily **逐字符相同**，且含 `SimSun31`；并配一条**正对照**（一个不带类的裸 `<button>`
 *   必须拿到系统字体 ⇒ 证明这个坑真实存在，断言不是空的）。 */
.p107-sym, .p107-symgrp, .p107-symhost, .p107-labsm, .p107-uniprev,
.ct-kao, .ct-kao-cat, .ct-kao-btn { font-family: inherit; }


/* ============================================================
 * p111 —— 本批六项界面改动
 * ============================================================ */

/* ---- ① 过大的图片一律**等比例**缩到容器内 ----
   用户口径：「文章應用的預覽以及舊全能閱讀器的閱讀中會出現圖片尺寸超出窗口…
   以後將所有過大的圖片都等比例縮小到窗口內」。
   实测（_dev/p111probe.js）：文章应用预览 .bbs-content 容器 284.8px，内联
   `style="width:1600px"` 的图渲染成 1600×1200（溢出 1315px，且 overflow:visible ⇒
   直接盖到隔壁窗格上）；旧全能阅读器 .dv-content 容器 554px，同一张图溢出 1046px。
   两处都**没有任何 max-width 规则**（.article-view img 有，但预览/阅读器都不在 .article-view 里）。

   ⚠️ 必须带 `height: auto`：只写 max-width 会把带内联 height 的图**压扁**（不是等比例缩小）。
   ⚠️ 只列**阅读容器**，不要写 `.blog-right img` —— 文章列表的缩略图 .bi-thumb 也在 .blog-right
      里，而 `.blog-right img`（0,1,1）特异性高于 `.bi-thumb`（0,1,0），`height:auto` 会
      把缩略图的高宽比改掉。
   ⚠️ 竖排（.dv-content.dv-v）由 css/reader.css 既有规则接管（max-height:76%; max-width:none），
      这里不覆盖它。 */
.bbs-content img, .dv-content img, .rdr-content img,
.article-view img, .cm-body img, .nw-post-body img, .help-body img {
  max-width: 100%; height: auto;
}

/* ---- ② 文章列表里的标签：最多**同时显示六个字**，更长就循环滚动 ----
   用户口径：「文章標籤在文章列表中顯示時最多同時顯示六個字，如果更多則循環滾動」。
   旧行为（实测）：`.bi-tags` 是 flex，chip 默认 `flex-shrink:1` + `white-space:normal`
   ⇒ 15 字的标签被压成 86px 宽、**折成 3 行**（高 36px），把整行列表撑高。
   现在：chip 变成固定宽度的「取景窗」（宽度 = 六个全角字，由 JS 按当前字体量出来写进
   `--tm-w` / `--tm-vw`），内层 .tm-t 承载**完整文字**并做 translateX 循环动画。

   ⚠️ 滚动距离写 `calc(var(--tm-vw) - 100%)`：transform 里的百分比是**元素自身宽度**
      ⇒ 100% == 整段文字宽，减去取景窗宽就是需要平移的量（不需要用 JS 逐个量 px）。 */
.b31-tagmini { flex: 0 0 auto; }
.b31-tagmini .tm-t { display: inline-block; white-space: nowrap; }
.b31-tagmini.tm-scroll {
  width: var(--tm-w, 67px);
  overflow: hidden; white-space: nowrap;
  /* chip 的文字基线要靠底部对齐，否则裁出来的窗会偏上 1px */
  vertical-align: bottom;
}
.b31-tagmini.tm-scroll .tm-t { animation: p111tag 6s linear infinite; }
@keyframes p111tag {
  0%, 12% { transform: translateX(0); }
  88%, 100% { transform: translateX(calc(var(--tm-vw, 63px) - 100%)); }
}

/* ---- ③④ 两组按钮「大小相等、上下左右对齐」 ----
   ①②③④里③④是纯几何口径，真正的等宽在 JS 里用全站既有的 window.__eqButtons 做
   （取自然最宽值统一设宽 ⇒ flex-wrap 换行的每一行左边缘必然对齐；见 js/wm.js）。
   这里只补两件 CSS 管不了的事：
     · `.bbs-act` 原本 gap:4px / `.cm-bar` 原本 gap:3px，且两组的**行距**要一致；
     · 按钮不许再被 flex 压缩（压了就又不等了）。 */
.bbs-act, .cm-bar { align-items: stretch; }
.bbs-act > .btn31, .cm-bar > .btn31 { flex: 0 0 auto; }
.bbs-act { gap: 3px 4px; --eq-gap: 4px; }
.cm-bar { gap: 2px 3px; }

/* p111 ③ 收尾：`.bbs-act` 的网格是「按钮宽 = --eq-col、列间距 = --eq-gap」，但第一行
   左边是 `SPAN.vote-box`（赞同/踩）。它自然宽 = 两个按钮 + 3px 内间距 = 175px，
   比两个按钮位（2×86 + 4 = 176）**少 1px** ⇒ 第 3 列的「收藏」会比下一行的「刪除」
   整体左移 1px（实测 645 vs 646），「上下左右对齐」就差这一格。
   这里把它钉成**恰好两列 + 一个列间距**，网格才是严格 3 列。 */
.bbs-act .vote-box {
  width: calc(var(--eq-col, 86px) * 2 + var(--eq-gap, 4px));
  justify-content: space-between;
}
/* ============================================================
 * p122 · 旧全能阅读器（docview/docui）用户报的 7 件事 + 阅读器浮水印
 * ------------------------------------------------------------
 * ①② 最大化被覆写 / 竖排侧栏开关失效 ⇒ 都在 js/docui.js 里改，这里不需要样式。
 * ③  阅读设置的「选择框」逐行错位 —— 真因：select31.js 把每个 <select> 换成了
 *    `<span class="s31">` 包装器（原生 select 自身 display:none，实测 0×0），
 *    而上面 p35 那一组选择器只写了 `.input31` / `select.input31` / `.rdr-snum`，
 *    **一个都匹配不到 .s31** ⇒ 下拉行退回 `.rdr-wide` 的 196px、高 19px，
 *    比数字行窄 12px、矮 1px，右边缘参差。同时数字行内部是 flex:1 的输入框，
 *    带 px 单位的行少 16px（▲ 在 671）而不带的在 687 ⇒ 逐行错位。
 * ④  夜间/深色/A4 的「桌面」底色：reader.css 用 `#808080 !important` 钉死，
 *    这里用**更高特异性 + 同带 !important** 承接 --dv-desk（docui.applyTheme 下发，
 *    默认值就是 #808080 ⇒ 浅色主题零变化）。
 * ⑩  两个阅读器的浮水印：容器上的 class/data-var 早就写好了（docui.js / reader.js 都做了
 *    `classList.add('watermark')` + `dataset.wm` + `--wm-color/--wm-opacity`），
 *    但这一段原来**只有 opacity、没有 content** —— 真正把字画出来的规则只存在于
 *    `.wd-page`(编辑器) 与 `.bbs-content`(文章应用) ⇒ 编辑器中加的浮水印在阅读器里不显示。
 * ============================================================ */

/* ③-a：下拉包装器进同一套网格（宽 208 / 高 20，与数字行严格同尺寸同左右边） */
.rdr-setdlg .rdr-srow2 > .s31 {
  flex: 0 0 var(--rdr-fw, 208px);
  width: var(--rdr-fw, 208px);
  min-width: 0;
  height: 20px;
  box-sizing: border-box;
}
/* ③-b：数字行内部定宽 —— 输入框固定 144，单位槽固定 14（**空槽也占位**，
   由 docui.js 的 spin() 无条件创建）⇒ 每行 ▼/输入框/▲/单位 四处 x 完全一致 */
.rdr-setdlg .rdr-snum .input31 { flex: 0 0 144px; width: 144px; min-width: 0; }
.rdr-setdlg .rdr-snum .dv-unit { flex: 0 0 14px; width: 14px; overflow: hidden; }
/* ③-c：开关按钮与数字行同高（原来 19 vs 20） */
.rdr-setdlg .rdr-srow2 > .btn31 { height: 20px; box-sizing: border-box; }
/* ③-d：主题那一行 —— 注意它的控件是 `<span class="rdr-themerow">`（**不是** .rdr-srow2，
   所以上面那条 `> .rdr-srow2` 的网格规则压根没作用到它），行内还有 3 个色块 + 2 个按钮
   ⇒ 整行被撑到 373px、溢出对话框右缘（用户截图里第 3 个色块被切掉）。
   把整行钉成 208 宽 + 允许换行，下拉与其它行同为 208×20，色块/按钮换到下一行。 */
.rdr-setdlg .rdr-srow2 > .rdr-themerow {
  flex: 0 0 var(--rdr-fw, 208px);
  width: var(--rdr-fw, 208px);
  flex-wrap: wrap;
}
.rdr-setdlg .rdr-srow2 > .rdr-themerow > .s31 {
  flex: 0 0 var(--rdr-fw, 208px);
  width: var(--rdr-fw, 208px);
  height: 20px;
}

/* ④：A4/PDF 的「桌面」底色跟着主题（浅色/护眼仍 #808080，夜间 #07070b、深色 #141414） */
.dv-root .dv-page.dv-paper { background: var(--dv-desk, #808080) !important; }

/* ⑩：两个阅读器的浮水印正文（与 .bbs-content 同款尺寸；颜色/透明度走容器上的两个变量） */
.rdr-content.watermark::before,
.dv-content.watermark::before {
  content: attr(data-wm);
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 52px;
  color: var(--wm-color, #000000);
  transform: rotate(-24deg);
  pointer-events: none;
  white-space: nowrap;
  overflow: hidden;
}

/* ============================================================
 * p124 patch tail —— ⑧ 编辑器图形（js/edshape.js） / ⑩ 批注共享内核（js/anno.js）
 *   ⚠️ 这一段是**追加**的，不改上面任何既有规则（并发线在制品多，少碰为妙）。
 * ============================================================ */

/* ---------- ⑧ 图形：内联 SVG ----------
   `body.pf-square *{border-radius:0 !important}` 之类全站偏好对 SVG 无效
   ⇒ 圆形永远是圆；几何与元素尺寸同为像素（1:1）⇒ 外框粗细就是字面 px。 */
.wd-shape-el {
  position: absolute; box-sizing: border-box; z-index: 5;
  cursor: move; user-select: none; -webkit-user-select: none;
}
.wd-shape-el > .es-svg { display: block; width: 100%; height: 100%; pointer-events: none; }
.wd-shape-el.sel { outline: 1px dashed #0000a8; outline-offset: 2px; }
.wd-shape-el > .es-h {
  position: absolute; width: 7px; height: 7px; display: none;
  background: #ffffff; border: 1px solid #0000a8; box-sizing: border-box;
}
.wd-shape-el.sel > .es-h { display: block; }
.wd-shape-el > .es-h.nw { left: -4px; top: -4px; cursor: nwse-resize; }
.wd-shape-el > .es-h.ne { right: -4px; top: -4px; cursor: nesw-resize; }
.wd-shape-el > .es-h.sw { left: -4px; bottom: -4px; cursor: nesw-resize; }
.wd-shape-el > .es-h.se { right: -4px; bottom: -4px; cursor: nwse-resize; }
.es-ghost > .es-svg { display: block; width: 100%; height: 100%; }

/* ---------- ⑩ 编辑器里的批注 / 高光：**浮层**（正文保持干净） ---------- */
.anno-layer {
  position: absolute; left: 0; top: 0; width: 100%; height: 100%;
  pointer-events: none; z-index: 3; overflow: hidden;
}
.anno-rect { position: absolute; border-radius: 0; opacity: .42; background: #ffe066; }
.anno-rect.cmt { background: transparent; opacity: .95; border-bottom: 2px solid #2b6cb0; }

/* ---------- ⑩ 只读视图里的高光 / 批注标记 ---------- */
mark.anno-hl { color: inherit; padding: 0; background: #ffe066; }
span.anno-cmt { padding: 0; border-bottom: 2px solid #a5d8ff; background: transparent; }

/* ---------- ⑩ 文章应用右栏：批注 · 高光 · 书签 ---------- */
.article-view.anno-split { display: flex; flex-direction: row; overflow: hidden; align-items: stretch; }
.article-view.anno-split > .anno-main { flex: 1 1 auto; min-width: 0; overflow: auto; }

/* p136④：症状 = 「同步高光标注与下方面板偶尔不显示」。
   根因：阅读模式下 Anno.mountArticle 把 `anno-split` 挂在 **.blog-right** 上，
   但 `.blog-right` **不是** `.article-view`，所以上面那条 `.article-view.anno-split`
   永远不命中；容器保持 display:block，`.anno-main`(925px) 与 `.anno-side`
   竖直堆叠 ⇒ 面板被顶到 y≈1049，而可见区只有 434px → 看不见。
   修法：把 `.blog-right.anno-split` 提升为真正的 flex 行，并隐掉左/中/右边栏。 */
.blog-right.anno-split { display: flex !important; flex-direction: row !important; overflow: hidden; align-items: stretch; }
.blog-right.anno-split > .anno-main { flex: 1 1 auto; min-width: 0; overflow: auto; }
.blog-right.anno-split > .anno-side { flex: 0 0 272px; width: 272px; }
/* p143②（用户：读文章时右侧「批注 · 高光 · 书签」侧栏**强行跳出**，并把左侧
   「文章选择栏」一起隐掉 ⇒ 工具栏「只显示文件树 / 只显示文章」按了没反应）。
   根因就是这里原来的三行 `:has()` 强制 `display:none !important`：
   `!important` 压过 applyView() 写在元素上的**行内** display ⇒ 用户怎么切都回不来。
   改为**不再由 CSS 隐栏**：左 / 中 / 侧栏的显隐一律交给 applyView() / applySide() 管，
   侧栏只作为 .blog-right 内部的 flex 列存在（上面那两条 .blog-right.anno-split 规则保留）。
   这样侧栏照常出现，但左侧文章选择栏与三态视图按钮都恢复正常。 */

/* p136①：症状 = 「删除文章按钮无效」。
   根因：阅读模式下 `.anno-main` 是 434px 滚动窗，内容 594px，
   `.bbs-act` 落在 y=491..582 —— 比 `.anno-main` 可见底 (554) 低 28px，
   被窗口自带 `.status-bar`（y=558..576，position:static，后绘）遮住；
   `elementFromPoint(删除按钮中心)` 返回 status-bar ⇒ 真点击到不了 Delete。
   修法：把动作栏吸在 `.anno-main` 底部（sticky），永远可点。 */
.anno-main > .bbs-act {
  position: sticky; bottom: 0; z-index: 5;
  margin: 6px 0 0; padding: 6px 4px;
  background: var(--win-bg, #c0c0c0);
  border-top: 1px solid #808080;
}

.anno-side {
  flex: 0 0 272px; width: 272px; min-width: 0; box-sizing: border-box;
  display: flex; flex-direction: column; min-height: 0;
  border-left: 1px solid #808080; background: #c0c0c0; color: #000000;
  box-shadow: inset 1px 0 0 #ffffff;
}
.anno-hd {
  flex: 0 0 auto; padding: 4px 6px; font-weight: bold;
  background: #000080; color: #ffffff; font-family: Win31System, MSSansPixel, sans-serif;
}
.anno-bar, .anno-tabs { flex: 0 0 auto; display: flex; flex-wrap: wrap; gap: 2px; padding: 3px 4px; }
.anno-tabs { border-top: 1px solid #808080; border-bottom: 1px solid #808080; }
.anno-side .btn31.anno-b, .anno-side .btn31.anno-tab, .anno-side .btn31.anno-mini, .anno-side .btn31.anno-send { height: 20px; padding: 0 6px; box-sizing: border-box; }
.anno-side .btn31.anno-tab.on { background: #ffffff; font-weight: bold; }
.anno-list { flex: 1 1 auto; min-height: 40px; overflow: auto; padding: 3px 4px; background: #ffffff; }
.anno-none { padding: 6px 2px; color: #404040; }
.anno-row {
  display: flex; flex-wrap: wrap; align-items: center; gap: 3px;
  padding: 3px 2px; border-bottom: 1px dotted #a0a0a0;
}
.anno-kind { flex: 0 0 auto; padding: 0 3px; border: 1px solid #808080; background: #dfdfdf; }
.anno-k-hl { background: #ffe066; }
.anno-k-bookmark { background: #ffcccc; }
.anno-k-note { background: #a5d8ff; }
.anno-k-comment { background: #ccffcc; }
.anno-tx { flex: 1 1 120px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.anno-by { flex: 0 0 auto; color: #404040; }
.anno-cmtbox { flex: 0 0 auto; padding: 4px; border-top: 1px solid #808080; }
.anno-ta { display: block; width: 100%; box-sizing: border-box; margin-bottom: 3px; }

/* ===== p128：编辑器正文里的「引用」块 =====
   用户口径：「在文本編輯器中加入選擇文本使其成為一級標題、二級標題、三級標題
             以及引用內容的功能」⇒ 「段落」栏的引用按钮产出真 `<blockquote>`。
   浏览器默认的 blockquote 是「左右各 40px 外边距 + 斜体」，塞进 Win31 这张白纸上
   又宽又飘 ⇒ 收成 Word 那种「左侧竖线 + 缩进」。
   ⚠️ 一律用**逻辑属性**（inline-start / block）：编辑器有竖排（`.wd-vert`，
      `writing-mode:vertical-rl`），写死 `border-left` 在竖排下会跑到文字的上方。
   ⚠️ **只加 blockquote**：h1 / h2 / h3 一个字都不动 —— 模板文档里本来就有 <h1>/<h2>，
      给它们补样式会改动既有文档的渲染结果（像素回归）。 */
.wd-page blockquote {
  margin-block: 8px;
  margin-inline: 6px 0;
  padding-block: 0;
  padding-inline: 8px 0;
  border-inline-start: 3px solid #808080;
  color: #404040;
}

/* ============================================================
 * p133 ⑦：把「桌面」做成真正的裁剪容器（用户报「滾動內容超出容器」）
 * ------------------------------------------------------------
 * 实测（_dev/p133ff.html 探针，Chrome 154 与 Firefox 156 并列跑）：
 *   · 默认缩放（界面缩放 = 分辨率缩放 = 100%）下 #desktop 的 scrollWidth/scrollHeight
 *     **恒等于** clientWidth/clientHeight ⇒ 没有任何内容超出桌面
 *     ⇒ 本规则在默认设置下是**恒等变换**（已用整屏逐像素 diff 复核：0 个像素不同）。
 *   · 但缩放 ≠ 100% 时就不成立了：界面缩放 150% ⇒ 桌面的**布局**尺寸只剩 853×533，
 *     而按布局像素给尺寸的窗口会盖过它。实测 `div.win.rdr-w`（万能阅读器）= 1620×990
 *     布局像素，右溢 400px、下溢 229px。
 *   · `#desktop` 此前**没有任何 overflow 声明**（= visible）⇒ 超出的那一截直接画到
 *     桌面之外（屏幕之外），正是用户说的「滾動內容超出容器」。
 *     两个引擎的几何**完全一致**（.win 559/560、.blog-right 436/436、.rdr-pbody 558/558、
 *     .cp-main 413/413）⇒ 这不是某引擎独有的缺陷，而是一处**一直没有兜底的裁剪缺口**。
 *
 * 为什么这条修法是安全的：
 *   · 桌面在 Windows 3.1 里**就是整块屏幕**，屏幕之外本就不该有可见内容；
 *     真正的 Win3.1 也是把窗口裁在屏幕边缘的。
 *   · `overflow` **不建立包含块**（那是 transform / filter / contain 的事），
 *     所以站内挂在 `#desktop` 里的浮层（.s31-pop / .d31-pop / .sysmenu / #tip31 /
 *     .nd-menu / .wd-dlg / .nd31-overlay，见本文件下方既有规则）定位基准一个字都不变。
 *   · 它只裁掉「本来就在屏幕外」的像素 ⇒ 默认设置下不可见、不可感。
 * ============================================================ */
#desktop { overflow: hidden; }

/* p133 ⑥：新闻应用话题头 —— 话题名 + 一颗「× 退出话题」。
   话题名可能很长，必须能省略号截断；× 固定钉在右端、不参与压缩。 */
.nw-head-topic { display: flex; align-items: center; gap: 6px; }
.nw-head-tx {
  flex: 0 1 auto; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.nw-head-topic .nw-head-x {
  flex: 0 0 auto; margin-left: auto;
  height: 18px; min-width: 20px; padding: 0 5px; line-height: 16px;
}

