/* ============ 全局 ============ */
/* ============ 公文字体（Web Font 内置，全设备显示一致，与导出 PDF 同源） ============ */
/* 与本地同名时浏览器优先使用 Web 字体，保证手机/电脑/PDF 三端统一。
   ⚠ 每个字体只声明 normal 一个字重：库内字体均无 bold 字形，若声明 bold 变体，
   浏览器会认为"bold 已有专用字形"而放弃合成加粗，导致加粗不可见（历史 bug）。
   加粗一律由下方 .faux-bold / strong 描边方案承担，不依赖字体字重。 */
@font-face {
  font-family: "仿宋";
  src: url("/static/fonts/fangsong.woff2") format("woff2");
  font-weight: normal; font-style: normal; font-display: swap;
}
/* 仿宋_GB2312：公文标准字库（与"仿宋"共用朱雀仿宋字形，开源印刷仿宋风格，接近 Word 中易仿宋） */
@font-face {
  font-family: "仿宋_GB2312";
  src: url("/static/fonts/fangsong.woff2") format("woff2");
  font-weight: normal; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "楷体";
  src: url("/static/fonts/kaiti.woff2") format("woff2");
  font-weight: normal; font-style: normal; font-display: swap;
}
/* 黑体：Noto Sans CJK SC 子集（与 PDF 服务端渲染同源，保证屏幕与导出一致） */
@font-face {
  font-family: "黑体";
  src: url("/static/fonts/hei.woff2") format("woff2");
  font-weight: normal; font-style: normal; font-display: swap;
}
/* 宋体：Noto Serif CJK SC 子集（与 PDF 服务端渲染同源） */
@font-face {
  font-family: "宋体";
  src: url("/static/fonts/song.woff2") format("woff2");
  font-weight: normal; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "方正小标宋简体";
  src: url("/static/fonts/xiaobiaosong.woff2") format("woff2");
  font-weight: normal; font-style: normal; font-display: swap;
}

/* ============ 公文加粗（第四次修正，2026-10-04） ============
   前版"描边+合成"双层叠加过粗失真（墨量 ×2.9）。
   根因修复后（@font-face 假 bold 声明已删、font-synthesis 显式开启），
   浏览器原生合成加粗已完全可用（实测墨量 ×1.8，与 Word 伪加粗相当），
   故本版：仅用 font-weight:bold + font-synthesis:weight，效果自然不失真。
   三级标题（t-h3）与字段加粗同参数。 */
.faux-bold, .faux-bold *,
.doc-body strong, .doc-body b,
.ql-editor strong, .ql-editor b,
.ql-editor > p.t-h3, .doc-body .doc-block.t-h3,
.eb.faux-bold {
  font-weight: bold;
  font-synthesis: weight;
}

/* ========== 基础 ========== */
/* v7.68（用户 2026-10-06 要求）：主题换肤。
   ---------------------------------------------------------------------------
   本系统原有配色已用 CSS 变量组织，但只覆盖了「正红色」这一族
   （--red / --red-deep / --red-soft），另有约 40 处把红色【硬编码】在
   各处规则里（渐变的第二端点 var(--red-2)、阴影 rgba(var(--red-shadow),...) 等）。
   若只换 --red，结果是「按钮底色变了，按钮的阴影/渐变还是红的」——
   比不换更难看。故此处先补齐三个变量把硬编码统一收编，再按主题覆盖。

   收编清单：
     --red-2     渐变第二端点 / 按钮主色（原散落 var(--red-2)、var(--red-deep) 等）
     --red-shadow 品牌色半透明（供 rgba 阴影，原写死 166,27,41）
     --gold      金色点缀。★ 原来就定义了却【从未被引用】—— .cchip:hover
                 / .att-name:focus 等处反而硬编码 var(--gold)，等于定义了个死变量。 */
:root {
  --red: #a61b29; --red-deep: #8a1420; --red-soft: #fdf3f1;
  --red-2: #c0392b; --red-shadow: 166, 27, 41;
  /* 登录页渐变专用三色（v7.68）：原来是三条硬编码，为让登录页跟随主题
     而抽成变量。默认值=系统原有三色，逐字节保留；各主题在末尾覆盖。 */
  --lg-a: #8f1d15; --lg-b: #c0392b; --lg-c: #a83228;
  --ink: #2b2b2b; --muted: #8a8a8a; --line: #eadfd8;
  --bg: #f6f2ec; --card: #ffffff; --gold: #c9a86a;
  --shadow: 0 2px 12px rgba(90, 40, 30, .08);
}
* { margin: 0; padding: 0; box-sizing: border-box; }
/* body 不锁死高度：若 height:100%，内容溢出后 sticky 元素（顶栏/工具条/格式栏）
   的粘性范围被限制在一屏内，长公文滚动约一屏后头部工具栏会跟着内容滚走 */
html { height: auto; }
body { min-height: 100vh; }
body {
  font-family: -apple-system, "PingFang SC", "Microsoft YaHei", "微软雅黑", sans-serif;
  background: var(--bg); color: var(--ink); font-size: 14px;
}
button { font-family: inherit; cursor: pointer; }
input, select, textarea { font-family: inherit; font-size: 14px; color: var(--ink); }
.hidden { display: none !important; }
.muted { color: var(--muted); font-size: 13px; }

/* ============ 顶栏 ============ */
.topbar {
  height: 60px; display: flex; align-items: center; justify-content: space-between;
  padding: 0 20px; background: linear-gradient(120deg, var(--red-deep), var(--red) 55%, var(--red-2));
  color: #fff; position: sticky; top: 0; z-index: 50; box-shadow: 0 2px 10px rgba(120, 20, 20, .25);
}
.topbar-left { display: flex; align-items: center; gap: 12px; }
.logo {
  width: 42px; height: 42px; border-radius: 50%;
  background: linear-gradient(145deg, #ffffff, #f6ede4);
  padding: 2.5px; object-fit: contain;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, .50),
              0 3px 10px rgba(60, 10, 5, .32),
              inset 0 0 0 1px rgba(var(--red-shadow), .08);
}
.brand-name { font-size: 17px; font-weight: 700; letter-spacing: 1px; }
.brand-sub { font-size: 11px; opacity: .85; margin-top: 2px; }
.user-chip {
  background: rgba(255,255,255,.16); border: 1px solid rgba(255,255,255,.35);
  /* ★ v7.74：去掉 cursor:pointer 与 hover 变色——app.js 里的空 onclick 已删，
     胶囊是纯展示元素，手型光标会误导用户以为可点击。 */
  padding: 6px 14px; border-radius: 20px; user-select: none; font-size: 13px;
}
/* v7.41：补上 .topbar-right 的布局定义。
   为什么必须补：这条规则在整个样式表里【一次都没出现过】，浏览器退回 div 默认的
   display:block —— 于是 .user-chip（inline-flex）和 .topbar-more（display:flex）会
   被迫各占一行竖着堆叠。移动端实测 .topbar-right 高达 84px，而 .topbar 只有 52px，
   多出的部分直接压住了第二行的「GB/T 9704—2012 标准公文格式」副标题。
   桌面端因为按钮较多、内容较窄，肉眼看不出错位，所以一直没被发现。 */
.topbar-right { display: flex; align-items: center; gap: 8px; flex: none; }

/* ★ v7.75（体验修复 U3）：顶栏登录剩余时间倒计时。
   低调灰白与顶栏融为一体；剩余 ≤5 分钟变红 + 脉冲动画，给用户明确预警。 */
.sess-timer {
  font-size: 12px; font-variant-numeric: tabular-nums; letter-spacing: .3px;
  padding: 4px 10px; border-radius: 14px; white-space: nowrap; user-select: none;
  background: rgba(255,255,255,.14); border: 1px solid rgba(255,255,255,.28);
  color: rgba(255,255,255,.92);
}
.sess-timer.sess-warn {
  background: #a61b29; border-color: #ffd7d7; color: #fff; font-weight: 700;
  animation: sessPulse 1.4s ease-in-out infinite;
}
@keyframes sessPulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255,120,120,.55); }
  50% { box-shadow: 0 0 0 6px rgba(255,120,120,0); }
}
@media (max-width: 980px) {
  /* 移动端顶栏空间紧张：倒计时只留图标+分钟，字号更小 */
  .sess-timer { font-size: 11px; padding: 3px 7px; }
}

/* ============ 固定工具条 ============ */
.actionbar {
  position: sticky; top: 60px; z-index: 45;
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 8px 18px; background: #fffdf9; border-bottom: 1px solid var(--line);
  box-shadow: 0 2px 8px rgba(120, 40, 30, .06);
}
.ab-tabs { display: flex; gap: 4px; flex-wrap: wrap; }
.ab-tab {
  border: none; background: transparent; color: #6d5a52; font-size: 14px;
  padding: 8px 13px; border-radius: 9px; display: inline-flex; align-items: center; gap: 6px; transition: all .15s;
}
.ab-tab:hover { background: var(--red-soft); color: var(--red); }
.ab-tab.active { background: linear-gradient(120deg, var(--red), var(--red-2)); color: #fff; font-weight: 600; box-shadow: 0 2px 7px rgba(var(--red-shadow),.28); }
.ab-tab.active .nav-badge { background: rgba(255,255,255,.32); }
.nav-icon { font-size: 15px; }
.nav-badge { background: var(--red); color: #fff; font-size: 11px; min-width: 18px; height: 18px; border-radius: 9px; display: none; align-items: center; justify-content: center; padding: 0 5px; }
.ab-ops { display: flex; gap: 7px; align-items: center; flex-wrap: wrap; margin-left: auto; }
.ab-sep { width: 1px; height: 20px; background: var(--line); margin: 0 3px; }

/* ============ 拟文工具条下拉框（文种 / 印章 / 模板）美化 ============ */
.sel {
  --sel-arrow: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23a89a8c' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
  appearance: none; -webkit-appearance: none; -moz-appearance: none;
  border: 1px solid var(--line); border-radius: 9px;
  padding: 8px 30px 8px 14px;
  font-size: 14px; font-weight: 500; color: var(--ink);
  background-color: #fff; outline: none; cursor: pointer; user-select: none;
  box-shadow: 0 1px 3px rgba(90, 40, 30, .06);
  transition: border-color .15s, box-shadow .15s, background-color .15s, color .15s;
  background-image: var(--sel-arrow);
  background-repeat: no-repeat;
  background-position: right 10px center;
  background-size: 12px;
  max-width: 240px; text-overflow: ellipsis;
}
.sel:hover { border-color: #d8c7ba; box-shadow: 0 2px 7px rgba(90, 40, 30, .10); }
/* 三个业务下拉各配主题色锚点：文种=印泥红（发布前必选）、印章=鎏金、模板=黛青 */
#catSelect, #sealType, #tplSelect { padding-left: 17px; }
#catSelect { --sc: var(--red); --sc-soft: rgba(var(--red-shadow), .11); }
#sealType  { --sc: #b8860b;    --sc-soft: rgba(184, 134, 11, .13); }
#tplSelect { --sc: #3c6e71;    --sc-soft: rgba(60, 110, 113, .13); }
#catSelect, #sealType, #tplSelect {
  background-image: linear-gradient(var(--sc), var(--sc)), var(--sel-arrow);
  background-size: 3px 58%, 12px;
  background-position: left center, right 10px center;
  background-repeat: no-repeat;
}
#catSelect:hover, #sealType:hover, #tplSelect:hover { border-color: var(--sc); }
#catSelect:focus, #sealType:focus, #tplSelect:focus {
  border-color: var(--sc); box-shadow: 0 0 0 3px var(--sc-soft);
}
/* 文种未选（发布前必选）：红底红字提醒，选中后由 JS 移除 sel-empty 恢复 */
#catSelect.sel-empty {
  border-color: rgba(var(--red-shadow), .42);
  background-color: var(--red-soft);
  color: var(--red);
}

/* 区块格式工具条 */
.fmtbar {
  position: sticky; top: 116px; z-index: 44;
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  padding: 8px 18px; background: #fff8f4; border-bottom: 1px dashed #e0b4a8;
  box-shadow: 0 2px 8px rgba(120, 40, 30, .05);
}
.fmtbar-label { font-size: 12.5px; color: var(--red); font-weight: 700; margin-right: 4px; }
.fmtbar select { border: 1px solid var(--line); border-radius: 7px; padding: 5px 7px; font-size: 12.5px; background: #fff; outline: none; }
.fmtbar select:focus { border-color: var(--red); }
#fmtColor { width: 32px; height: 28px; border: 1px solid var(--line); border-radius: 7px; background: #fff; padding: 2px; cursor: pointer; }

/* ============ 底部固定操作条（v7.64 移除） ============
   电脑端底部操作条 #dockbar 已随 v7.64 移除（DOM/样式/逻辑同步下线），
   拟文页底部占位随之取消：.paper-stage 回落默认 padding（14px 16px 50px）。
   ≤980px 移动端媒体查询中的相关规则保留未动（对移动端行为无影响）。 */

/* ============ 移动端底部工具栏（小屏时承载功能按钮行 + 格式设置行） ============ */
.mobile-dock { display: none; }
.mobile-dock.hidden { display: none; }
@media (max-width: 980px) {
  .mobile-dock:not(.hidden) { display: block; }
}
.mobile-dock {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 96;
  background: #fffdf9; border-top: 1px solid var(--line);
  box-shadow: 0 -3px 14px rgba(120, 40, 30, .12);
  max-height: 62vh; overflow-y: auto; overscroll-behavior: contain;
  padding-bottom: env(safe-area-inset-bottom, 0);
}
/* 移入后取消原 sticky/宽度设定 */
.mobile-dock #composeOps,
.mobile-dock #fmtbar { position: static !important; top: auto !important; width: auto; }
.mobile-dock #composeOps { margin: 0; padding: 8px 10px; border-bottom: 1px solid var(--line); }
.mobile-dock #fmtbar { border-bottom: none; border-top: none; box-shadow: none; background: #fff8f4; }
/* 移动端隐藏简单底栏（功能已并入底部工具栏） */
@media (max-width: 980px) {
  #dockbar { display: none !important; }
  body.with-dock .paper-stage { padding-bottom: calc(var(--dock-h, 150px)); }
}

/* ============ 布局 ============ */
.layout { min-height: calc(100vh - 120px); }
.main { padding: 0; overflow-x: hidden; }
.view { animation: fadein .18s ease; }
@keyframes fadein { from { opacity: 0; transform: translateY(4px);} to { opacity: 1; } }
.main > .view:not(#view-compose) { padding: 18px 22px; }
.view-head { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 10px; margin-bottom: 16px; }
.view-head h2 { font-size: 20px; color: var(--red-deep); letter-spacing: 1px; }
.view-head-tools { display: flex; gap: 8px; flex-wrap: wrap; }
.search { padding: 9px 14px; border: 1px solid var(--line); border-radius: 20px; outline: none; width: 230px; background: #fff; }
.search:focus { border-color: var(--red); box-shadow: 0 0 0 3px rgba(var(--red-shadow),.08); }

/* ============ 按钮 ============ */
.btn { border: none; border-radius: 9px; padding: 9px 16px; font-size: 14px; transition: all .15s; display: inline-flex; align-items: center; gap: 5px; }
.btn:active { transform: scale(.97); }
.btn-primary { background: linear-gradient(120deg, var(--red), var(--red-2)); color: #fff; box-shadow: 0 3px 8px rgba(var(--red-shadow),.3); }
.btn-primary:hover { filter: brightness(1.08); }
.btn-accent { background: linear-gradient(120deg, #b8860b, #d4a017); color: #fff; box-shadow: 0 3px 8px rgba(180,140,20,.25); }
.btn-accent:hover { filter: brightness(1.08); }
.btn-outline { background: #fff; border: 1px solid var(--red); color: var(--red); }
.btn-outline:hover { background: var(--red-soft); }
.btn-ghost { background: #fff; border: 1px solid var(--line); color: #6d5a52; }
.btn-ghost:hover { border-color: var(--red); color: var(--red); }
.btn-danger { background: #fff; border: 1px solid #d4a0a0; color: #b23b2e; }
.btn-danger:hover { background: #fdf0ee; }
.btn-success { background: linear-gradient(120deg, #1e7e34, #2e9e50); color: #fff; box-shadow: 0 3px 8px rgba(30,126,52,.25); }
.btn-success:hover { filter: brightness(1.08); }
.btn-sm { padding: 5px 10px; font-size: 12.5px; border-radius: 7px; }
.mini-btn { background: #fff; border: 1px solid var(--line); border-radius: 7px; padding: 4px 10px; font-size: 12.5px; color: #6d5a52; }
.mini-btn:hover { border-color: var(--red); color: var(--red); background: var(--red-soft); }
.mini-btn.danger { color: #b23b2e; }

/* ---- 历史记录（撤销 / 重做 / 版本列表） ---- */
.hist-btn { font-size: 14px; line-height: 1; padding: 4px 9px; font-weight: 700; }
.hist-btn.disabled, .hist-btn:disabled { opacity: .35; cursor: not-allowed; }
.hist-btn.disabled:hover, .hist-btn:disabled:hover { border-color: var(--line); color: #6d5a52; background: #fff; }
.hist-open { display: inline-flex; align-items: center; gap: 4px; }
.hist-count {
  background: var(--red); color: #fff; border-radius: 9px; padding: 0 5px;
  font-size: 10.5px; line-height: 15px; min-width: 15px; text-align: center; font-weight: 700;
}
.hist-mask {
  position: fixed; inset: 0; background: rgba(40, 22, 16, .42);
  display: flex; align-items: center; justify-content: center; z-index: 3000;
}
.hist-mask.hidden { display: none; }
.hist-card {
  background: #fff; border-radius: 14px; width: min(460px, 92vw);
  max-height: 76vh; display: flex; flex-direction: column;
  box-shadow: 0 24px 60px rgba(60, 30, 20, .3); overflow: hidden;
}
.hist-head {
  display: flex; align-items: baseline; gap: 8px; padding: 13px 16px;
  border-bottom: 1px solid #f1e7e0; background: #fffaf7;
}
.hist-title { font-size: 14.5px; font-weight: 700; color: var(--red-deep); }
.hist-sub { font-size: 11.5px; color: #a08c84; flex: 1; }
.hist-x {
  border: none; background: transparent; font-size: 15px; color: #a08c84;
  cursor: pointer; padding: 2px 6px; border-radius: 6px;
}
.hist-x:hover { background: var(--red-soft); color: var(--red); }
.hist-list { overflow-y: auto; padding: 6px; flex: 1; }
.hist-item {
  display: flex; align-items: center; gap: 10px; padding: 9px 11px;
  border-radius: 9px; cursor: pointer; font-size: 13px; color: #4a3a33;
}
.hist-item:hover { background: var(--red-soft); }
.hist-item.current { background: #fdf0ea; font-weight: 700; color: var(--red-deep); }
.hist-idx {
  flex: 0 0 22px; height: 22px; line-height: 22px; text-align: center;
  background: #f2e9e4; color: #8a756c; border-radius: 6px; font-size: 11px; font-weight: 700;
}
.hist-item.current .hist-idx { background: var(--red); color: #fff; }
.hist-label { flex: 1; display: flex; align-items: center; gap: 6px; }
.hist-cur { font-size: 10.5px; background: var(--red); color: #fff; border-radius: 5px; padding: 1px 5px; font-weight: 700; }
.hist-time { font-size: 11.5px; color: #a08c84; font-variant-numeric: tabular-nums; }
.hist-empty { padding: 26px 16px; text-align: center; color: #a08c84; font-size: 13px; }
.hist-foot {
  display: flex; gap: 8px; justify-content: flex-end;
  padding: 10px 14px; border-top: 1px solid #f1e7e0; background: #fffaf7;
}

/* ============ 卡片与表单 ============ */
.card { background: var(--card); border-radius: 14px; padding: 16px 18px; box-shadow: var(--shadow); margin-bottom: 14px; border: 1px solid #f1e7e0; }
.card-title { font-size: 14.5px; font-weight: 700; color: var(--red-deep); margin-bottom: 12px; display: flex; align-items: center; justify-content: space-between; }
.card-tools { display: flex; gap: 6px; }
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 14px; }
.f-field { display: flex; flex-direction: column; gap: 5px; margin-bottom: 10px; }
.f-field > span { font-size: 12.5px; color: var(--muted); }
.f-field input, .f-field textarea, .f-field select {
  border: 1px solid var(--line); border-radius: 9px; padding: 9px 12px; outline: none;
  background: #fffdfb; transition: border .15s; width: 100%; resize: vertical;
}
.f-field input:focus, .f-field textarea:focus, .f-field select:focus { border-color: var(--red); box-shadow: 0 0 0 3px rgba(var(--red-shadow),.07); }
.span2 { grid-column: span 2; }

/* ============ 拟文（所见即所得纸张） ============ */
.compose-meta {
  display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 10px;
  padding: 10px 20px 6px; color: #6d5a52; font-size: 12.5px;
}
.cm-left { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.cm-hint { color: #9c8c82; }
.pv-zoom { display: inline-flex; gap: 4px; background: #fff; border: 1px solid var(--line); border-radius: 9px; padding: 3px; }
.pv-zoom button { border: none; background: transparent; font-size: 12px; padding: 4px 10px; border-radius: 7px; color: #7a6a60; }
.pv-zoom button:hover { color: var(--red); background: var(--red-soft); }
.pv-zoom button.on { background: var(--red); color: #fff; font-weight: 600; }
/* v7.41（用户要求「移动端适应区域不需要」）：移动端隐藏缩放栏。
   为什么可以放心隐藏，而不是要留个入口：
     · 移动端「适应」等价于屏宽自适应，而 paper-stage 本身就是按屏宽流式排版的
       （.paper-stage 用 clamp/百分比控制纸宽），不需要手动选比例；
     · 三个固定档位（75%/100%/125%）是为桌面端「纸面按 A4 实际尺寸显示」设计的，
       手机屏本就放不下 A4 实际尺寸，125% 只会更糟；
     · 实测该栏在 390px 屏上占 209×52px，且把 .compose-meta 撑到 150px 高——
       相当于白白吃掉近一行的正文可视高度（.cm-hint 那句提示就为此换行成两行）。
   桌面端不受影响，本规则只在移动端断点内生效。 */
@media (max-width: 768px) {
  .pv-zoom { display: none !important; }
  /* 隐藏后 .cm-right 只剩一个空 div，连带把 compose-meta 的高度收回来 */
  .cm-right { display: none; }
}
.doc-state { font-style: normal; font-size: 11.5px; background: #eee; color: #888; border-radius: 9px; padding: 3px 10px; font-weight: 600; }
.doc-state.saved { background: #e5f5e9; color: #1e7e34; }
.doc-state.dirty { background: #fdf0e0; color: #b8860b; }
.paper-stage {
  overflow: auto; padding: 14px 16px 50px; background: #ece5da;
  min-height: calc(100vh - 210px);
}
.paper-scale { transform-origin: top center; margin: 0 auto; }
.paper-tip { text-align: center; font-size: 12.5px; color: #a89a90; padding: 10px 0 20px; }

/* ============ 纸张（A4，GB/T 9704 页边距） ============ */
.paper {
  position: relative;
  width: 210mm; min-height: 297mm; box-sizing: border-box;
  padding: 37mm 26mm 35mm 28mm; margin: 0 auto;
  background: #fff; box-shadow: 0 6px 26px rgba(80, 40, 30, .18);
  /* 公文字体栈：仿宋_GB2312 优先（公文标准），朱雀仿宋 Web 字体保证三端一致 */
  font-family: "仿宋_GB2312", "仿宋", "仿宋_GB2312", FangSong, STFangsong, "Noto Serif CJK SC", serif;
  /* 纵向 flex：让版记（.doc-version）用 margin-top:auto 推到版心底；
     内容变长时纸随内容撑高、版记自然跟随下移，不再用 absolute 钉死而被正文覆盖 */
  display: flex; flex-direction: column;
}
/* flex 子项默认 min-height:auto 会阻止收缩，正文区需可增长 */
.paper > * { flex: 0 0 auto; }
.paper > .doc-body { flex: 0 0 auto; }

/* ============ 按钮 ============ */
/* ---- 公文元素（编辑预览与打印共用） ---- */
.doc-org {
  font-family: "方正小标宋简体", "方正小标宋_GBK", "华文中宋", STZhongsong, "Noto Serif CJK SC", SimSun, serif;
  color: #d0342c; text-align: center; font-size: 30pt; line-height: 1.25; letter-spacing: 1px;
  font-weight: 700; white-space: nowrap;
  /* GB/T 9704—2012 7.2.5：发文字号编排在发文机关标志下空二行位置
     版心 225mm÷22 行 = 10.227mm/行 → 空二行 = 20.45mm；
     已扣除行盒自身留白，实留 18.71mm ≈ 41.4pt */
  margin-bottom: 41.4pt;
}
.doc-org-file { margin-left: .25em; letter-spacing: 2px; }
.doc-org-sub { text-align: center; color: #d0342c; font-size: 30pt; font-weight: 700; letter-spacing: 14px; text-indent: 14px; margin-bottom: 8pt; }
/* GB/T 9704—2012 7.2.7：发文字号之下 4mm 处印与版心等宽的红色分隔线
   文号行盒自带上下留白，故用 0.8mm 补偿后实留 4mm */
/* 发文字号：中文用仿宋，阿拉伯数字用 Times New Roman（GB/T 9704—2012 惯例）
   Times New Roman 无中日韩字形，汉字/〔〕 自动按回退链落到仿宋，无需手工分词。
   先声明 @font-face 保证无该字体的机器也得到同源字形（与 PDF 端同字体文件）。 */
@font-face {
  font-family: "Times New Roman";
  src: url("/static/fonts/times.ttf") format("truetype");
  font-weight: normal; font-style: normal; font-display: swap;
}
.doc-number { text-align: center; font-size: 16pt; color: #000; line-height: 1.2; margin-bottom: 8.1pt;
  font-family: "Times New Roman", "Liberation Serif", "仿宋", "仿宋_GB2312", FangSong, STFangsong, serif; }
/* ★ v7.91（用户 2026-10-14 要求）：编辑器中的阿拉伯数字一律 Times New Roman。
   与 .doc-number 同一口径：仿宋数字宽度偏窄（"1" 仅 0.354em），公文中成排数字观感不佳。
   做法是渲染时把数字段包进 .tnr（本项目在app.js 的 wrapDigits() 中生成，
   与 PDF 端 pdf_export.py::_num_html 口径一致），不改用户数据本身——
   用户手动设过字体的数字同样只换字体族，字号/加粗/颜色等一概保留。
   覆盖标题/正文/表格/落款/附件说明等全部文字区域。 */
.tnr, .tnr-true,
.doc-body .tnr, .doc-body .tnr-true,
.ql-editor .tnr, .ql-editor .tnr-true,
.doc-table .tnr, .doc-table .tnr-true {
  font-family: "Times New Roman", "Liberation Serif", serif !important;
}
/* 数字本身已由 .tnr 定族；此处防止嵌套在自定义字体 span 里时被外层 font 覆盖 */
.doc-body .tnr span, .doc-body .tnr-true span,
.ql-editor .tnr span, .ql-editor .tnr-true span { font-family: inherit; }
/* 发文字号：前缀可编辑，流水号锁定 */
.doc-number.num-edit { white-space: nowrap; }
.doc-number .num-seq { display: inline-block; background: #f3efec; color: #6d5a52; border-radius: 4px; padding: 0 3px; }
.paper.editable .doc-number .eb.num-prefix { display: inline-block; min-width: 2em; }
/* 红色分隔线：上方紧接文号（文号下 4mm），下方空二行接标题
   GB/T 9704—2012 7.3.2：标题编排于红色分隔线下空二行位置（225mm÷22行×2≈20.45mm）
   已扣除标题行盒上部留白，margin 50.8pt → 实测墨迹 20.45mm（原 58pt 实测 23.0mm 偏大） */
.doc-redline { border: none; border-bottom: 2.4pt solid #d0342c; margin: 0 0 50.8pt; }
.doc-title {
  font-family: "方正小标宋简体", "方正小标宋_GBK", "华文中宋", STZhongsong, "Noto Serif CJK SC", SimSun, serif;
  text-align: center; font-size: 22pt; line-height: 1.45; margin-bottom: 18pt; color: #000; font-weight: 400;
}
.doc-to { font-size: 16pt; margin-bottom: 4pt; }
/* white-space:pre-wrap：保留用户在段首/段中手动输入的空格（半角/Tab/全角）。
   默认 normal 会「折叠连续空格 + 剥除行首空白」，导致编辑页（.ql-editor 为 pre-wrap）
   看得到空格、预览/导出却消失。此处与 .ql-editor 及 PDF 端 .blk 保持取值一致。 */
.doc-block { font-size: 16pt; text-indent: 2em; margin: 0; white-space: pre-wrap; }
.doc-block.t-h1 { font-family: "黑体", SimHei, sans-serif; }
.doc-block.t-h2 { font-family: "楷体", "楷体_GB2312", KaiTi, STKaiti, serif; }
.doc-block.t-h3 { /* 加粗由描边+合成方案接管（.t-h3 已并入统一选择器） */ }
.doc-attach { font-size: 16pt; text-indent: 2em; margin-top: 14pt; }
/* 连续附件说明行（附件：1.xxx / 缩进 2.xxx）为同一说明块的续行，段间不加空 */
.doc-attach + .doc-attach { margin-top: 0; }
/* 行高用正文行距，避免续行行距过大 */
.doc-attach { line-height: 1.6; }
/* 落款（GB/T 9704—2012 §7.3.5）：间距与水平位置由 signLayout() 内联注入
   （margin-top / margin-left），保证与 PDF 导出完全一致；
   此处只保留排版属性，不再用 text-align:right + padding-right 的旧方案。 */
.doc-sign-area { position: relative; margin-top: 22.75pt; min-height: 60pt; margin-bottom: 96px; }
.doc-sign { position: relative; z-index: 3; font-size: 16pt; white-space: nowrap; }
.doc-date { position: relative; z-index: 3; font-size: 16pt; margin-top: 4pt; white-space: nowrap; }
/* 公章：衬于文字下方（骑年盖月），文字压于章上；位置由 sealLayout() 内联注入 */
.doc-seal {
  position: absolute; width: 42mm; height: 42mm; opacity: .9;
  pointer-events: none; z-index: 1;
}
.doc-seal img { width: 100%; height: 100%; }
/* 编辑态不显示印章，避免遮挡落款/日期文字编辑；预览/只读/PDF 仍正常显示 */
.paper.editable .doc-seal { display: none !important; }
/* 版记（GB/T 9704—2012 7.4.4）：置于最后一面最下面，底边对齐版心下边缘。
   配合 .paper 的纵向 flex，用 margin-top:auto 推到版心下边缘（paper 的
   padding-bottom:35mm 即该距离）；内容不足一页时贴底，内容超出一页时
   随文档流自然下移，不再绝对定位钉死而被正文覆盖。 */
.doc-version { position: static; margin-top: auto; }
/* 版记：抄送机关、印发机关一律左对齐；印发日期右对齐；末条分隔线粗 1pt（0.35mm） */
.doc-version .cc-line { font-size: 14pt; border-top: 1pt solid #000; border-bottom: 1pt solid #000; padding: 3pt 0; text-align: left; }
.doc-version .print-line {
  font-size: 14pt; border-bottom: 1pt solid #000; padding: 3pt 0;
  display: flex; align-items: baseline; justify-content: space-between;
}
.doc-version .print-line .print-org { text-align: left; }
.doc-version .print-line .print-date { text-align: right; margin-left: auto; white-space: nowrap; }
/* 非编辑态用纯文本时，保证日期同样靠右 */
.doc-version .print-line > .print-date:last-child { flex: 0 0 auto; }
.doc-blank { text-align: center; color: #c9beb4; font-size: 12pt; padding: 40pt 0; letter-spacing: 2px; }

/* ============ v7.82 正文表格（网页端，与 PDF 导出 .doc-table 视觉对齐） ============ */
/* 只读/预览态：外层包裹（表格与段落同级，不参与 <p> 流） */
.doc-table-wrap { margin: 8pt 0; }
/* 编辑态：表格宿主，内部表格可 contenteditable 单元格 */
/* ★ v7.93 修「表格不能居中」：
   原先水平 auto 外边距写在宿主 .tbl-host 上，但宿主是 display:block 且宽度撑满版心，
   块级元素宽度已满时 margin-left/right:auto 会被解析成 0px —— 居中完全失效
   （实测 align=center 时 computed marginLeft=0px，表格贴左，diff 达 -255px）。
   正确做法：宿主只管上下外边距与整宽，水平对齐交给内层 table。
   display:table 元素在宽度小于容器时 margin-left/right:auto 是标准生效的。 */
.tbl-host { margin: 30px 0 8pt; outline: none; }
.tbl-host .doc-table { margin-left: auto; margin-right: auto; }
.doc-table {
  border-collapse: collapse; table-layout: fixed; width: 100%;
  font-family: "仿宋", "仿宋_GB2312", FangSong, STFangsong, serif;
  font-size: 16pt; line-height: 1.5; background: #fff;
}
.doc-table td, .doc-table th {
  padding: 3pt 6pt; vertical-align: middle; text-align: left; border: none;
  word-break: break-word; overflow-wrap: anywhere;
}
/* 边框样式：全部 / 网格 → 全框线；外框 → 仅表格外框；无 → 无框线 */
.doc-table.dt-all td, .doc-table.dt-all th,
.doc-table.dt-grid td, .doc-table.dt-grid th { border: 1px solid #000; }
.doc-table.dt-outer { border: 1px solid #000; }
.doc-table.dt-outer td, .doc-table.dt-outer th { border: none; }
.doc-table.dt-none td, .doc-table.dt-none th { border: none; }
/* 虚线边框 */
.doc-table.dt-dashed td, .doc-table.dt-dashed th { border-style: dashed; }
.doc-table.dt-dashed.dt-outer { border-style: dashed; }
/* 表头行：加粗 + 浅灰底 */
.doc-table.dt-hd tr:first-child td, .doc-table.dt-hd tr:first-child th {
  font-weight: bold; font-synthesis: weight; background: #f3f3f3;
}
/* 只读/预览态单元格不允许编辑；编辑态由 contenteditable 属性控制 */
.doc-table-wrap .doc-table td, .doc-table-wrap .doc-table th { cursor: default; }
.tbl-host .doc-table td[contenteditable="true"], .tbl-host .doc-table th[contenteditable="true"] { outline: none; cursor: text; }
.tbl-host .doc-table td[contenteditable="true"]:focus, .tbl-host .doc-table th[contenteditable="true"]:focus {
  outline: 1.5px solid var(--red); outline-offset: -1.5px; background: #fff7ec;
}
/* 选中单元格（列宽拖拽 / 合并操作目标） */
.doc-table td.cell-sel, .doc-table th.cell-sel { background-image: linear-gradient(rgba(var(--red-shadow), .12), rgba(var(--red-shadow), .12)); }
/* 空表格单元格占位：保证高度可见 */
.doc-table td:empty::after, .doc-table th:empty::after { content: "\200b"; }
/* 列宽拖拽手柄（编辑态，由 JS 注入 .col-resizer） */
.col-resizer {
  position: absolute; top: 0; width: 7px; cursor: col-resize; z-index: 5;
  transform: translateX(-50%);
}
.col-resizer:hover { background: rgba(var(--red-shadow), .25); }
/* 表格悬浮工具条 */
/* ★ v7.84：表格右下角宽度拖拽手柄（Word 式） */
.tbl-host { position: relative; }

/* ===== ★ v7.86 正文插图（图片块）===== */
/* 编辑态宿主：与 .tbl-host 同级，自身不是 contenteditable（事件由 #paper 委托） */
.img-host { margin: 8pt 0; outline: none; }
.img-host .img-box { display: inline-block; }
.img-host img { max-width: 100%; vertical-align: top; }
.img-host.img-selected .img-box {
  outline: 2px solid var(--red, #c0392b); outline-offset: 2px;
}
/* 四角缩放手柄（选中后出现） */
.img-host .img-h {
  position: absolute; width: 11px; height: 11px; z-index: 6;
  background: #fff; border: 1.5px solid var(--red, #c0392b); border-radius: 2px;
}
.img-host .img-h[data-dir="nw"] { left: -6px; top: -6px; cursor: nwse-resize; }
.img-host .img-h[data-dir="ne"] { right: -6px; top: -6px; cursor: nesw-resize; }
.img-host .img-h[data-dir="sw"] { left: -6px; bottom: -6px; cursor: nesw-resize; }
.img-host .img-h[data-dir="se"] { right: -6px; bottom: -6px; cursor: nwse-resize; }
/* 裁剪模式：遮罩 + 8 手柄 */
.img-host.img-cropping .img-crop { outline: 1px dashed #fff; }
.img-host .img-crop-mask {
  position: absolute; inset: 0; background: rgba(0,0,0,.35); pointer-events: none;
}
.img-host .img-crop-tip {
  position: absolute; left: 50%; bottom: -22px; transform: translateX(-50%);
  background: rgba(0,0,0,.72); color: #fff; font-size: 11px; padding: 2px 8px;
  border-radius: 3px; white-space: nowrap;
}
/* 只读/预览/打印态 */
.doc-figure-wrap { margin: 8pt 0; page-break-inside: avoid; }
.doc-figure-wrap img { max-width: 100%; vertical-align: top; }
.doc-figure-wrap .img-cap, .img-host .img-cap { text-align: center; }

/* 浮动图片工具栏（与 .tbl-toolbar 同视觉，叠加其上） */
.img-toolbar {
  position: absolute; z-index: 132; display: flex; flex-wrap: wrap; align-items: center; gap: 4px;
  background: #fff; border: 1px solid #d0d0d0; border-radius: 6px; padding: 4px 6px;
  box-shadow: 0 3px 12px rgba(0,0,0,.16); max-width: 720px;
}
.img-toolbar button {
  font-size: 12px; padding: 3px 7px; border: 1px solid #ddd; background: #fafafa;
  border-radius: 4px; cursor: pointer; white-space: nowrap;
}
.img-toolbar button:hover { background: #f0f0f0; border-color: #bbb; }
.img-toolbar select { font-size: 12px; padding: 3px 4px; border: 1px solid #ddd; border-radius: 4px; }
.img-toolbar .tb-sep { width: 1px; height: 18px; background: #e2e2e2; margin: 0 2px; }
/* 拖拽入正文时的高亮 */
#paper.img-drag-over { outline: 2px dashed var(--red, #c0392b); outline-offset: -4px; }

/* ★ v7.87 图片块自由拖拽换位
   ★ v7.91：真正接管拖拽的是 .img-box / .img-crop（鼠标按到的那个盒子），
   .img-host 只是事件委托容器。故光标与悬停提示都要挂在承载盒子上，
   否则图片上仍显示文本光标，用户不知道这里可以拖。 */
.img-host[draggable="true"] { cursor: grab; }
.img-host[draggable="true"]:hover { outline: 1px dashed rgba(0,0,0,.28); outline-offset: 3px; }
.img-host .img-box.img-drag-handle,
.img-host .img-crop.img-drag-handle { cursor: grab; }
.img-host .img-box.img-drag-handle:active,
.img-host .img-crop.img-drag-handle:active { cursor: grabbing; }
.img-host.img-dragging { opacity: .4; }
/* 拖拽落点指示线（插入位置） */
.img-drop-mark {
  height: 0; margin: 6pt 0; border-top: 3px dashed var(--red, #c0392b);
  pointer-events: none; position: relative;
}
.img-drop-mark::after {
  content: "放到这里"; position: absolute; left: 50%; top: -18px;
  transform: translateX(-50%); font-size: 10.5pt; color: #fff;
  background: var(--red, #c0392b); padding: 1px 8px; border-radius: 3px;
  white-space: nowrap;
}
/* 换位拖拽进行中：禁用文本选区，避免蓝亮一片 */
#docBody.img-reorder { user-select: none; -webkit-user-select: none; }

/* 裁剪模式：选框 + 手柄 + 四周压暗（box-shadow 大范围外扩即遮罩） */
.crop-overlay { position: relative; display: inline-block; line-height: 0; }
.crop-overlay img { display: block; }
.crop-sel {
  position: absolute; box-sizing: border-box; border: 1.5px solid #fff; cursor: move;
  box-shadow: 0 0 0 9999px rgba(0,0,0,.45); z-index: 3;
}
.crop-sel .crop-h {
  position: absolute; width: 10px; height: 10px; background: #fff; border: 1.5px solid var(--red, #c0392b);
  border-radius: 50%; z-index: 4;
}
.crop-sel .crop-h[data-dir="nw"] { left: -6px; top: -6px; cursor: nwse-resize; }
.crop-sel .crop-h[data-dir="n"]  { left: 50%; top: -6px; margin-left: -5px; cursor: ns-resize; }
.crop-sel .crop-h[data-dir="ne"] { right: -6px; top: -6px; cursor: nesw-resize; }
.crop-sel .crop-h[data-dir="e"]  { right: -6px; top: 50%; margin-top: -5px; cursor: ew-resize; }
.crop-sel .crop-h[data-dir="se"] { right: -6px; bottom: -6px; cursor: nwse-resize; }
.crop-sel .crop-h[data-dir="s"]  { left: 50%; bottom: -6px; margin-left: -5px; cursor: ns-resize; }
.crop-sel .crop-h[data-dir="sw"] { left: -6px; bottom: -6px; cursor: nesw-resize; }
.crop-sel .crop-h[data-dir="w"]  { left: -6px; top: 50%; margin-top: -5px; cursor: ew-resize; }
.crop-ok, .crop-cancel {
  position: absolute; bottom: -34px; z-index: 5; font-size: 12px; padding: 3px 10px;
  border-radius: 4px; cursor: pointer; border: 1px solid #ccc; background: #fff;
}
.crop-ok { left: 0; background: var(--red, #c0392b); color: #fff; border-color: var(--red, #c0392b); }
.crop-cancel { left: 62px; }
/* ★ v7.93：宽度手柄挪到右下角**外侧**，避免与拖动手柄（右下角内侧）重叠 */
.tbl-host .tbl-grip {
  position: absolute; right: -2px; bottom: -2px; width: 14px; height: 14px;
  cursor: nwse-resize; z-index: 5; border-radius: 3px;
  background: linear-gradient(135deg, transparent 0 42%, var(--red, #c0392b) 42% 58%, transparent 58% 70%, var(--red, #c0392b) 70% 86%, transparent 86%);
  opacity: 0; transition: opacity .15s;
}
.tbl-host:hover .tbl-grip, .tbl-host .tbl-grip:active { opacity: .85; }
/* ★ v7.85：多选单元格高亮（box-shadow 不遮挡底色与文字） */
#docBody td.cell-picked, #docBody th.cell-picked {
  box-shadow: inset 0 0 0 2px #1a73e8;
  background-image: linear-gradient(rgba(26, 115, 232, .06), rgba(26, 115, 232, .06));
}
#docBody td.cell-picked::selection, #docBody th.cell-picked::selection { background: rgba(26, 115, 232, .25); }
/* ★ v7.92：表格拖拽手柄。
   ★ v7.93 改到表格右下角内侧（原在左上角外侧）：
   表格上方是各类浮动工具栏的地盘 —— 表格格式工具栏浮在表格正上方，
   图片工具栏也是 absolute 定位挂在 body 上；手柄放左上角时会被它们整块盖住，
   用户按住"手柄"实际命中的是工具栏（实测 elementFromPoint 返回 img-toolbar），
   表现为「表格拖不动」。右下角内侧不与任何工具栏重叠。
   只有按住它才能拖动表格，表格本体与单元格照常可点、可输入文字。
   命中区 30×22，hover 变红加亮，鼠标移出表格即淡出，不干扰阅读。 */
.tbl-drag-grip {
  position: absolute; right: 3px; bottom: 3px; z-index: 6;
  width: 30px; height: 22px; display: flex; align-items: center; justify-content: center;
  border: 1px dashed rgba(0, 0, 0, .3); border-radius: 6px; background: rgba(255, 255, 255, .92);
  color: #9a8878; font-size: 14px; line-height: 1; cursor: grab; user-select: none;
  opacity: .5; transition: opacity .12s, border-color .12s, color .12s;
}
.tbl-host:hover > .tbl-drag-grip { opacity: 1; }
.tbl-drag-grip:hover { opacity: 1; border-color: var(--red); color: var(--red); background: #fff; }
.tbl-drag-grip:active { cursor: grabbing; }
/* 单元格输入时手柄半透明，避免遮挡内容阅读 */
.tbl-host:focus-within > .tbl-drag-grip { opacity: .35; }
/* 只读态（预览/查看）不显示手柄 */
.paper:not(.editable) .tbl-drag-grip { display: none !important; }

/* ★ v7.93 鼠标自研拖拽（弃用 HTML5 DnT 后的配套样式）
   拖拽进行中全局用 grabbing 光标，并禁止选中，视觉上明确"正在拖"。 */
body.block-dragging-cursor,
body.block-dragging-cursor * { cursor: grabbing !important; }
body.block-dragging-cursor .img-host,
body.block-dragging-cursor .tbl-host,
body.block-dragging-cursor .doc-table { user-select: none !important; }
/* 拖拽中的块半透明，让用户看清落点 */
.img-host.img-dragging, .tbl-host.img-dragging { opacity: .55; }
/* 图片本体在可拖状态下的手型光标（.img-drag-handle 由 JS 挂） */
.img-drag-handle { cursor: grab; }
/* 图片盒子触摸可用：移动端没有 hover，手柄需常态可见 */
@media (hover: none) {
  .tbl-drag-grip { opacity: .9; }
  .img-drag-handle { cursor: grab; }
}
/* ★ v7.92（用户反馈「红框框起来的格式栏影响表格的内容输入」）：
   原 .tbl-toolbar 用 flex-wrap: wrap，表格稍宽时按钮换行，工具栏高度暴涨，
   而定位是按固定 46px 上移，结果工具栏整条压在表格首行上，导致无法输入。
   改为：不换行 + 横向可滚动 + 宽度自适应，并按实际高度上移（JS 侧配合）。
   工具栏始终浮在表格上方，不占用表格自身的布局空间。 */
.tbl-toolbar {
  position: absolute; z-index: 60; display: flex; flex-wrap: nowrap; gap: 4px; align-items: center;
  padding: 6px 8px; background: #fff; border: 1px solid #e6d9d0; border-radius: 10px;
  box-shadow: 0 6px 20px rgba(0, 0, 0, .14); font-size: 12.5px;
  max-width: min(1180px, calc(100vw - 24px)); overflow-x: auto; overflow-y: hidden;
  scrollbar-width: thin;
}
.tbl-toolbar::-webkit-scrollbar { height: 6px; }
.tbl-toolbar::-webkit-scrollbar-thumb { background: #e0d2c8; border-radius: 3px; }
.tbl-toolbar button, .tbl-toolbar select { flex: 0 0 auto; }
.tbl-toolbar .tb-sep { width: 1px; height: 18px; background: #ece1d9; margin: 0 3px; }
.tbl-toolbar button {
  border: 1px solid #eadfd7; background: #fffaf7; border-radius: 7px; padding: 3px 8px;
  cursor: pointer; color: var(--ink); font-size: 12.5px; line-height: 1.5;
}
.tbl-toolbar button:hover { background: #fff0e8; border-color: var(--red); color: var(--red); }
.tbl-toolbar select { border: 1px solid #eadfd7; border-radius: 7px; padding: 3px 4px; font-size: 12.5px; background: #fff; }
.tbl-toolbar .tb-color { width: 26px; height: 24px; padding: 0; border-radius: 6px; }
/* 表格网格选择器（插入表格时） */
.tbl-grid-picker { display: grid; gap: 2px; padding: 6px; background: #fffaf7; border-radius: 8px; }
.tbl-grid-picker .gp-cell { width: 18px; height: 18px; border: 1px solid #ddd0c6; background: #fff; border-radius: 3px; }
.tbl-grid-picker .gp-cell.on { background: rgba(var(--red-shadow), .35); border-color: var(--red); }
.tbl-grid-hint { text-align: center; font-size: 12px; color: var(--muted); margin-top: 6px; }

/* ---- 可编辑纸张（WYSIWYG） ---- */
.paper.editable .eb {
  outline: none; border-radius: 3px; cursor: text;
  border-bottom: 1px dashed rgba(var(--red-shadow), .22);
  display: block; max-width: 100%;
}
/* 版头、抄送行保留行内（与"文件"字/前缀同排） */
.paper.editable .doc-org .eb,
.paper.editable .cc-line .eb { display: inline-block; max-width: 100%; }
/* 附件说明行保留行内（「附件：」前缀与内容同排） */
.paper.editable .doc-attach .eb { display: inline-block; max-width: calc(100% - 3.5em); vertical-align: bottom; }
.paper.editable .eb:hover { background: rgba(255, 240, 225, .55); }
.paper.editable .eb:focus { background: #fff7ec; border-bottom: 1px solid var(--red); }
.paper.editable .eb.empty-hint:empty::before,
.paper.editable .eb[data-ph]:empty::before {
  content: attr(data-ph); color: #c4b6ab; font-style: italic; font-size: .82em;
}
.paper.editable .doc-block { position: relative; }
/* ---- 正文：只读/打印态（静态 .doc-block 段落） ---- */
.doc-body { outline: none; }
.doc-body .doc-block { font-family: "仿宋", "仿宋_GB2312", FangSong, STFangsong, serif; font-size: 16pt;
  text-indent: 2em; line-height: 1.75; text-align: justify; margin: 0; min-height: 1.75em; }
.doc-body .doc-block.t-h1 { font-family: "黑体", SimHei, sans-serif; font-weight: normal; }
.doc-body .doc-block.t-h2 { font-family: "楷体", "楷体_GB2312", KaiTi, STKaiti, serif; }
.doc-body .doc-block.t-h3 { font-family: "仿宋", "仿宋_GB2312", FangSong, serif; }  /* 加粗由描边方案接管 */
/* ---- 正文整块编辑区（Quill 2.0 接管）：外观与旧 .doc-body 完全一致 ---- */
.paper #quillHost.ql-container.ql-snow { border: none; font-family: inherit; font-size: inherit; float: none; clear: both; }
.ql-toolbar { display: none !important; }   /* 自带工具栏关闭：统一用页内格式栏 */
.doc-body .ql-editor,
.ql-editor { padding: 0; outline: none; cursor: text; overflow-y: visible; min-height: 1.75em; white-space: pre-wrap;
  font-family: "仿宋", "仿宋_GB2312", FangSong, STFangsong, serif; font-size: 16pt; line-height: 1.75; }
.ql-editor > p { font-size: 16pt; text-indent: 2em; line-height: 1.75; text-align: justify;
  margin: 0; min-height: 1.75em; position: relative; font-family: "仿宋", "仿宋_GB2312", FangSong, STFangsong, serif; }
.ql-editor > p.t-h1 { font-family: "黑体", SimHei, sans-serif; font-weight: normal; }
.ql-editor > p.t-h2 { font-family: "楷体", "楷体_GB2312", KaiTi, STKaiti, serif; }
.ql-editor > p.t-h3 { font-family: "仿宋", "仿宋_GB2312", FangSong, serif; }  /* 加粗由描边方案接管 */
.ql-editor.ql-blank::before { color: #c4b6ab; font-style: italic; font-size: .82em; left: 0; right: 0; }
/* 空段落占位提示（无内容时显示，不占额外高度） */
.doc-body .doc-block:empty::before,
.doc-body .doc-block > br:only-child + .rt-ph { content: ""; }
.doc-body .doc-block:not(:focus):empty::before {
  content: attr(data-ph); color: #c4b6ab; font-style: italic; font-size: .82em;
}
.paper.editable .doc-body { outline: none; cursor: text; }
.paper.editable .doc-body:focus-within { background: transparent; }
.paper.editable .empty-hint { color: #bdb0a6; }

/* ============ 列表 ============ */
.doc-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 14px; }
.doc-card { background: #fff; border-radius: 14px; padding: 16px; box-shadow: var(--shadow); border: 1px solid #f1e7e0; display: flex; flex-direction: column; gap: 9px; }
.doc-card .dc-title { font-size: 15.5px; font-weight: 700; color: var(--ink); line-height: 1.45; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.doc-card .dc-meta { display: flex; flex-wrap: wrap; gap: 6px; font-size: 12px; color: var(--muted); }
.doc-card .dc-no { color: var(--red); font-weight: 600; }
.tag { display: inline-block; padding: 2px 9px; border-radius: 8px; font-size: 11.5px; background: var(--red-soft); color: #9c5a50; }
.tag.pub { background: #e5f5e9; color: #1e7e34; }
.tag.draft { background: #f0ede9; color: #8a8175; }
.dc-ops { display: flex; gap: 6px; flex-wrap: wrap; margin-top: auto; padding-top: 6px; border-top: 1px dashed #f0e6de; }

/* ============ 表格 ============ */
.table-wrap { background: #fff; border-radius: 14px; box-shadow: var(--shadow); border: 1px solid #f1e7e0; padding: 6px; overflow-x: auto; }
.rec-table { width: 100%; border-collapse: collapse; font-size: 13.5px; min-width: 900px; }
.rec-table th {
  background: linear-gradient(120deg, var(--red-deep), var(--red)); color: #fff; padding: 11px 10px;
  text-align: left; font-weight: 600; white-space: nowrap;
}
.rec-table th:first-child { border-radius: 10px 0 0 0; }
.rec-table th:last-child { border-radius: 0 10px 0 0; }
.rec-table td { padding: 10px; border-bottom: 1px solid #f5ece6; vertical-align: middle; }
.rec-table tr:nth-child(even) td { background: #fdf8f5; }
.rec-table tr:hover td { background: var(--red-soft); }
.rec-no { color: var(--red); font-weight: 700; }
.status-pub { color: #1e7e34; font-weight: 700; }
.status-draft { color: #b23b2e; }
.empty { text-align: center; color: var(--muted); padding: 40px 0; }

.logs-panel { margin-top: 14px; background: #fff; border-radius: 14px; box-shadow: var(--shadow); border: 1px solid #f1e7e0; padding: 4px 16px; }
.logs-panel summary { cursor: pointer; padding: 12px 0; font-weight: 700; color: var(--red-deep); font-size: 14px; }
/* v7.29：系统日志恢复 7.24 显示方式（序号 + 日期分组 + 四列/两列栅格），
   div 高度按用户要求在 7.24 的 320px 基础上加 100px → 420px。
   v7.39：用户再次要求加 100px → 520px（沿用同一条规则，便于回溯每次调整的依据）。
   注意：这里只改了 .logs 的 max-height，外层 .card 会自适应撑高，无需同步调整；
   .logs-panel 已无 HTML 引用（v7.17 日志独立成选项卡后废弃），保留仅为兼容旧样式。 */
.logs { max-height: 520px; overflow: auto; font-size: 12.8px; }
.log-item { display: flex; gap: 10px; padding: 7px 2px; border-bottom: 1px dashed #f0e6de; color: #6d5a52; align-items: baseline; }
.log-item .lg-t { color: #b0a49c; white-space: nowrap; }
.log-item .lg-act { color: var(--red); font-weight: 600; white-space: nowrap; }
.log-item .lg-seq { display: inline-flex; align-items: center; justify-content: center; min-width: 26px; height: 20px; padding: 0 6px; background: #efe6df; color: #8a6f5f; border-radius: 10px; font-size: 12px; font-weight: 700; font-variant-numeric: tabular-nums; flex: none; }
.log-item .lg-body { color: #6d5a52; }
.log-day { margin: 14px 0 4px; padding: 6px 10px; background: #f6efe9; border-left: 3px solid var(--red); border-radius: 4px; font-weight: 700; color: #5a4a42; font-size: 13px; position: sticky; top: 0; }
/* v7.66：日志总数徽标（与「刷新 / 一键清除日志」同排右对齐） */
.log-total { display: inline-flex; align-items: center; gap: 2px; padding: 6px 12px; background: #fff6f2; border: 1px solid #f0d9d2; border-radius: 8px; color: #8a6f5f; font-size: 13px; white-space: nowrap; }
.log-total b { color: var(--red); font-size: 15px; font-variant-numeric: tabular-nums; margin: 0 2px; }

/* ============ 模板库 ============ */
.tpl-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 14px; }
.tpl-card { background: #fff; border-radius: 14px; padding: 18px; box-shadow: var(--shadow); border: 1px solid #f1e7e0; transition: all .18s; cursor: pointer; position: relative; overflow: hidden; }
.tpl-card::before { content: ""; position: absolute; top: 0; left: 0; right: 0; height: 4px; background: linear-gradient(90deg, var(--red), #d4a017); }
.tpl-card:hover { transform: translateY(-3px); box-shadow: 0 8px 22px rgba(120, 40, 30, .16); }
.tpl-icon { font-size: 30px; margin-bottom: 8px; }
.tpl-name { font-size: 16px; font-weight: 700; color: var(--red-deep); margin-bottom: 5px; }
.tpl-desc { font-size: 12.5px; color: var(--muted); line-height: 1.55; margin-bottom: 10px; min-height: 38px; }

/* ============ 统计 ============ */
.stat-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 14px; margin-bottom: 14px; }
.stat-card { background: #fff; border-radius: 14px; padding: 18px; box-shadow: var(--shadow); border: 1px solid #f1e7e0; position: relative; overflow: hidden; }
.stat-card::after { content: ""; position: absolute; right: -18px; top: -18px; width: 64px; height: 64px; border-radius: 50%; background: var(--red-soft); }
.stat-num { font-size: 30px; font-weight: 800; color: var(--red); }
.stat-label { font-size: 13px; color: var(--muted); margin-top: 3px; }
.stat-row { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.cat-bar-row { display: flex; align-items: center; gap: 10px; padding: 6px 0; }
.cat-bar-name { width: 70px; font-size: 13px; color: #6d5a52; text-align: right; }
.cat-bar-track { flex: 1; background: #f5ede6; border-radius: 6px; height: 18px; overflow: hidden; }
.cat-bar-fill { height: 100%; background: linear-gradient(90deg, var(--red), #d4604a); border-radius: 6px; transition: width .4s; }
.cat-bar-num { width: 34px; font-size: 13px; font-weight: 700; color: var(--red); }

/* ============ 格式规范 ============ */
.spec-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.spec-grid ul { padding-left: 20px; line-height: 2; color: #5d5049; font-size: 13.5px; }
.spec-grid .span2 { grid-column: span 2; }

/* ============ 弹窗 ============ */
.modal-mask { position: fixed; inset: 0; background: rgba(60, 20, 15, .45); z-index: 1000; display: flex; align-items: center; justify-content: center; backdrop-filter: blur(2px); }
/*v7.43：z-index 由 100 提到 1000 —— 必须高于移动端抽屉的 .m-panel(131)。
   原来抽屉压在上面，把附件弹窗整个盖住（用户报「抽屉挡住了附件」）。
   层级约定（本项目务必遵守，自上而下）：
     9999登录遮罩 > 10000 toast > 3000 历史记录(.hist-mask)
     > 1002 预览(.preview-mask) > 1000 通用弹窗(.modal-mask)
     > 131 抽屉(.m-panel) > 130 抽屉遮罩/标题面板 > 120 移动底栏
   任何全屏弹层的 z-index 都必须 > 131，否则会被抽屉盖住。 */
.modal { background: #fff; border-radius: 16px; padding: 22px 24px; width: min(560px, 92vw); max-height: 86vh; overflow: auto; box-shadow: 0 16px 50px rgba(60,20,15,.35); animation: pop .18s ease; }
@keyframes pop { from { transform: scale(.94); opacity: 0;} to { transform: scale(1); opacity: 1;} }
.modal h3 { color: var(--red-deep); margin-bottom: 14px; font-size: 17px; }
.modal .modal-ops { display: flex; justify-content: flex-end; gap: 8px; margin-top: 18px; }
/* ============ 全屏公文预览（预览 / 查看 共用，按导出 PDF 的真实分页展示） ============ */
.preview-mask { position: fixed; inset: 0; background: #5c4c44; z-index: 1002; overflow-y: auto; overflow-x: hidden; }
.pv-topbar {
  position: sticky; top: 0; z-index: 5; display: flex; align-items: center; justify-content: space-between;
  gap: 10px; padding: 10px 16px; background: rgba(52, 36, 30, .95); color: #fff;
  box-shadow: 0 2px 10px rgba(0,0,0,.3);
}
.pv-title { font-size: 15px; font-weight: 600; }
.pv-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.pv-count { font-size: 12.5px; color: #e6d5cb; background: rgba(255,255,255,.12); border-radius: 20px; padding: 3px 10px; }
.pv-body { padding: 18px 10px 70px; }

/* PDF 分页：每页一张 A4 图，纵向整齐排列 */
.pv-pages { display: flex; flex-direction: column; align-items: center; gap: 18px; }
.pv-page-wrap { display: flex; flex-direction: column; align-items: center; gap: 6px; max-width: 100%; }
.pv-page {
  background: #fff; box-shadow: 0 6px 22px rgba(0,0,0,.35); overflow: hidden;
  border-radius: 2px; line-height: 0;
}
.pv-page img { display: block; width: 100%; height: 100%; }
.pv-pageno { font-size: 12px; color: #cdbab0; letter-spacing: .5px; }
.pv-loading, .pv-error {
  color: #f0e2da; font-size: 14px; padding: 46px 20px; text-align: center; line-height: 2;
  display: flex; align-items: center; justify-content: center; gap: 10px;
}
.pv-spin {
  width: 16px; height: 16px; border-radius: 50%; display: inline-block;
  border: 2px solid rgba(255,255,255,.3); border-top-color: #fff; animation: pvspin .8s linear infinite;
}
@keyframes pvspin { to { transform: rotate(360deg); } }

/* ============ toast ============ */
.toast {
  position: fixed; top: 74px; left: 50%; transform: translateX(-50%) translateY(-12px);
  background: rgba(43, 43, 43, .92); color: #fff; padding: 10px 22px; border-radius: 24px;
  font-size: 13.5px; opacity: 0; pointer-events: none; transition: all .25s; z-index: 10000; max-width: 80vw;
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
.toast.ok { background: rgba(30, 126, 52, .95); }
.toast.err { background: rgba(178, 59, 46, .95); }

/* ============ 移动端 ============ */
.compose-tabs { display: none; }
@media (max-width: 980px) {
  .topbar { padding: 0 12px; }
  .brand-name { font-size: 13.5px; }
  .brand-sub { display: none; }
  .logo { width: 34px; height: 34px; }
  .user-chip { padding: 5px 9px; font-size: 12px; max-width: 104px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .actionbar { top: 56px; padding: 7px 10px; gap: 8px; }
  .ab-tab { padding: 7px 10px; font-size: 13px; }
  .ab-ops { width: 100%; margin-left: 0; gap: 6px; }
  .ab-ops .btn { padding: 8px 11px; font-size: 13px; flex: 1 1 auto; justify-content: center; }
  .ab-ops .sel { flex: 1 1 100%; max-width: none; }
  .fmtbar { top: 148px; padding: 7px 10px; gap: 5px; }
  .fmtbar-label { width: 100%; margin: 0 0 2px; }
  /* 底部固定操作条（手机端） */
  .db-inner { padding: 8px 10px; gap: 6px; }
  .db-label { display: none; }
  .dockbar select { flex: 1 1 30%; min-width: 0; max-width: none; }
  .dockbar .btn { flex: 1 1 auto; justify-content: center; }
  .paper-stage { padding: 8px 6px 40px; min-height: auto; background: #ece5da; }
  .paper-scale { width: 100%; transform: none !important; height: auto !important; }
  .paper { width: 100%; min-height: auto; padding: 34px 18px 30px; }
  /* v7.57：移动端拟文落款/印章修复。桌面端按 GB/T 9704 版心 156mm 硬算 margin-left；
     移动端纸张宽度只有 100%（常见 320~430px），硬算 mm 会大幅溢出并把文字挤成竖条。
     改为：落款区域整体右对齐，印章缩放到 76px 并靠右覆盖，保证署名/日期横向可读。 */
  .doc-sign-area {
    margin-top: 18px !important;
    position: relative;
    text-align: right;
    padding-right: 0;              /* 文字靠右，让印章压在落款与日期之上 */
    margin-bottom: 48px;           /* 减少默认 96px 在移动端的空白 */
    min-height: auto;
  }
  .doc-sign, .doc-date {
    margin-left: 0 !important;     /* 覆盖 signLayout() 注入的 margin-left */
    text-align: right;
    white-space: nowrap !important; /* 避免长落款折行 */
  }
  .doc-seal {
    position: absolute !important;
    width: 80px !important;
    height: 80px !important;
  }
  .stat-row, .spec-grid, .form-grid { grid-template-columns: 1fr; }
  .spec-grid .span2 { grid-column: span 1; }
  .main > .view:not(#view-compose) { padding: 14px 12px; }
  /* v7.56：非拟文页的固定底栏（⋯ 更多功能，约 57px + 安全区）盖住屏幕底部，
     列表末尾的分页条若不预留空间，页码行会被遮挡（用户 2026-10-06 反馈）。
     with-dock 只在拟文页存在，故用 :not(.with-dock) 为其余页面统一让位。 */
  body:not(.with-dock) .main > .view:not(#view-compose) {
    padding-bottom: calc(76px + env(safe-area-inset-bottom, 0px));
  }
  .search { width: 100%; }
  .modal { width: 96vw; padding: 14px 10px; max-height: 94vh; }
  .modal h3 { font-size: 15.5px; }
  .pv-body { padding: 12px 4px 60px; }
}

/* ============ 桌面端：头部三条工具栏改为 fixed 悬浮 ============ */
/* 不依赖 sticky/滚动容器，窗口滚动到任何位置都恒定可见 */
@media (min-width: 981px) {
  .topbar    { position: fixed; top: 0; left: 0; right: 0; }
  .actionbar { position: fixed; top: 60px; left: 0; right: 0; }
  .fmtbar    { position: fixed; top: var(--head-h, 116px); left: 0; right: 0; }
  /* 三条脱离文档流后：用等高内边距补偿，避免内容顶到条下被遮 */
  body { padding-top: var(--head-h, 116px); }
  body.with-dock .layout { padding-top: var(--fmtbar-h, 42px); }
}

/* ============ v7.65：电脑端窄窗口顶栏「防掉行」 ============
   实测窗口宽 1050~1150px（笔记本 + 系统缩放的常见有效宽度）时，
   #composeOps 一行放不下全部控件，「📄 导出 PDF」被单独挤到第二行行首，
   视觉上脱离了「📮 发布」——用户看到的就是这个（提出“把导出 PDF 搬到发布后面”）。
   改法：不挪按钮（顺序本就正确），而是在分组分隔符 .ab-sep 处【主动断行】：
   分隔符变为横贯整行的细分隔线，「👁预览 / 💾保存草稿 / 📮发布 / 📄导出PDF」
   4 键整组落到第二行——导出 PDF 在任何电脑端宽度都紧跟「发布」，
   且“公文设置 | 输出操作”两组分界更清晰（保持美化布局）。
   仅 981~1365px 生效（1366 及以上单行放得下维持原状）；≤980px 移动端另有规则不受影响。 */
@media (min-width: 981px) and (max-width: 1365px) {
  .ab-ops .ab-sep { width: 100%; height: 1px; margin: 3px 0 7px; }
}

/* 模板库页 · 公文字体包下载条 */
.font-pack { display: flex; align-items: center; justify-content: space-between; gap: 14px; flex-wrap: wrap; }
.font-pack-info { display: flex; flex-direction: column; gap: 4px; font-size: 14px; line-height: 1.5; }
.font-pack-info strong { color: var(--red-deep, var(--red-deep)); }
.font-pack-btn { text-decoration: none; white-space: nowrap; }
.font-pack-info a { color: var(--red, var(--red-2)); text-decoration: underline; }

/* 模板库 · 卡片编辑/删除角标与模板编辑弹窗 */
.tpl-card { position: relative; }
.tpl-ops { position: absolute; top: 8px; right: 8px; display: flex; gap: 4px; opacity: 0; transition: opacity .15s; }
.tpl-card:hover .tpl-ops { opacity: 1; }
.tpl-op { border: none; background: #f7f1ec; border-radius: 8px; width: 28px; height: 28px; cursor: pointer; font-size: 13px; line-height: 1; display: inline-flex; align-items: center; justify-content: center; transition: all .15s; }
.tpl-op:hover { background: var(--red-soft, var(--red-soft)); transform: translateY(-1px); }
.tpl-form { display: flex; flex-direction: column; gap: 10px; margin: 14px 0; text-align: left; }
.tpl-form label { display: flex; flex-direction: column; gap: 4px; font-size: 13px; color: #6d5a52; font-weight: 600; }
.tpl-form input, .tpl-form textarea { border: 1px solid #e5d8cf; border-radius: 9px; padding: 9px 12px; font-size: 14px; font-family: inherit; background: #fff; color: #333; }
.tpl-form input:focus, .tpl-form textarea:focus { outline: 2px solid var(--red-soft, var(--red-soft)); border-color: var(--red, var(--red-2)); }
.tpl-form textarea { line-height: 1.7; resize: vertical; font-family: "仿宋", fangsong, serif; }
.tpl-form-row { display: flex; gap: 10px; }
.tpl-form-row label { flex: 1; }
.modal-ops { display: flex; justify-content: flex-end; gap: 10px; margin-top: 6px; }

/* 模板图标（网络下载 Twemoji，与 emoji 同风格）与选择网格 */
.tpl-icon img.tpl-icon-img { width: 34px; height: 34px; display: inline-block; vertical-align: middle; }
.icon-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(42px, 1fr)); gap: 6px; max-height: 158px; overflow-y: auto; padding: 8px; background: #faf6f2; border-radius: 10px; border: 1px solid #f1e7e0; }
.icon-item { border: 2px solid transparent; background: #fff; border-radius: 8px; padding: 4px; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: all .12s; }
.icon-item img { width: 26px; height: 26px; }
.icon-item:hover { background: var(--red-soft, var(--red-soft)); transform: translateY(-1px); }
.icon-item.active { border-color: var(--red, var(--red-2)); background: var(--red-soft, var(--red-soft)); }

/* ---------------- 登录页 ---------------- */
/* v7.38：flex-direction: column —— 登录卡片与卡片下方的版本标记改为【纵向】排列。
   原来默认是 row（水平），版本号移到 </form> 之后就成了卡片的兄弟节点，
   不加这个声明会与卡片并排显示（而不是在下方）。 */
.login-mask { position: fixed; inset: 0; z-index: 9999; background: linear-gradient(160deg, var(--lg-a) 0%, var(--lg-b) 55%, var(--lg-c) 100%); display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 20px; }
.login-card { background: #fff; border-radius: 18px; padding: 38px 36px 28px; width: 380px; max-width: 100%; box-shadow: 0 24px 60px rgba(60,10,5,.45); display: flex; flex-direction: column; gap: 12px; text-align: center; }
.login-title { font-size: 20px; font-weight: 800; color: var(--red-deep, var(--red-deep)); letter-spacing: 1px; }
/* 登录页校徽（2026-10-04）：圆形 + 白色光环 + 柔影 + 轻入场动效 */
.login-logo-wrap {
  position: relative;
  width: 104px; height: 104px;
  margin: 0 auto 18px;
}
.login-logo-wrap::before {          /* 暖色光晕托底 */
  content: ""; position: absolute; inset: -12px; border-radius: 50%;
  background: radial-gradient(circle, rgba(var(--red-shadow), .10), rgba(var(--red-shadow), 0) 68%);
}
.login-logo-wrap::after {           /* 底部呼吸柔影 */
  content: ""; position: absolute; left: 50%; bottom: -9px;
  width: 62px; height: 9px; border-radius: 50%;
  transform: translateX(-50%);
  background: radial-gradient(ellipse, rgba(90, 40, 30, .20), rgba(90, 40, 30, 0) 72%);
  animation: logoShadow 3.6s ease-in-out .7s infinite;
}
.login-logo {
  width: 96px; height: 96px; border-radius: 50%;
  display: block; margin: 0 auto;
  border: 4px solid #fff;
  background: #fff;
  box-shadow: 0 0 0 1px rgba(var(--red-shadow), .22),
              0 10px 26px rgba(90, 40, 30, .28),
              0 2px 6px rgba(90, 40, 30, .16);
  animation: logoIn .55s cubic-bezier(.22, 1.2, .36, 1) both,
             logoFloat 3.6s ease-in-out .7s infinite;
}
@keyframes logoIn {
  from { transform: scale(.82) translateY(-8px); opacity: 0; }
  to   { transform: scale(1) translateY(0);      opacity: 1; }
}
@keyframes logoFloat {              /* 轻柔悬浮 */
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-5px); }
}
@keyframes logoShadow {             /* 影子随悬浮同步呼吸 */
  0%, 100% { transform: translateX(-50%) scale(1);    opacity: 1;  }
  50%      { transform: translateX(-50%) scale(.84);  opacity: .62; }
}
.login-sub { font-size: 12.5px; color: #9a867c; margin-bottom: 12px; }
.login-input { border: 1px solid #e5d8cf; border-radius: 10px; padding: 12px 14px; font-size: 15px; font-family: inherit; background: #faf6f2; }
.login-input:focus { outline: 2px solid var(--red-soft, var(--red-soft)); border-color: var(--red, var(--red-2)); background: #fff; }
.login-err { background: #fdecea; color: var(--red-deep); font-size: 13px; border-radius: 8px; padding: 8px 10px; }
.login-btn { border: none; border-radius: 10px; background: var(--red, var(--red-2)); color: #fff; font-size: 16px; font-weight: 700; letter-spacing: 6px; padding: 12px; cursor: pointer; transition: all .15s; margin-top: 4px; }
.login-btn:hover { background: var(--red-deep, var(--red-deep)); }
/* v7.36：登录防连点期间置灰，让"正在提交"有明确视觉反馈 */
.login-btn:disabled { background: #b8a99a; cursor: not-allowed; letter-spacing: 6px; }
.login-btn:disabled:hover { background: #b8a99a; }
.login-tip { font-size: 12px; color: #b3a099; }

/* 角色徽章与用户管理 */
.role-badge { display: inline-block; font-size: 11px; padding: 1px 7px; border-radius: 20px; background: #eef2ee; color: #3c7a3c; margin-left: 6px; vertical-align: 1px; }
.role-badge.admin { background: #fdecea; color: var(--red-deep); }
.user-ops { white-space: nowrap; }
.user-ops .btn { margin-right: 4px; }

/* 移动端为编辑视图（纸张宽度随屏、高度随内容）：版记改回流式布局，
   紧跟落款之后自然排布，避免 absolute 贴底与流内容重叠；桌面端保持贴底标准 */
@media (max-width: 980px) {
  .doc-version { position: static; margin-top: 14px; }
}

/* 非本人公文标记 */
.tag.own-none { background: #f3efe9; color: #8a7767; border: 1px dashed #d9cbbd; }

/* ---------------- 回收站（v6.1） ---------------- */
.rc-pick { display: flex; align-items: center; gap: 8px; cursor: pointer; min-width: 0; }
.rc-pick input[type="checkbox"] { width: 16px; height: 16px; accent-color: #a61b29; cursor: pointer; flex: none; }
.rc-pick span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tag.rc-tag { background: #f3e3e0; color: #a61b29; border: 1px solid #e5c8c3; }

/* 回收站分区标题（公文 / 模板） */
.rc-section-title { font-weight: 700; color: #6d5a52; font-size: 15px; padding: 14px 2px 4px; }

/* ---------------- 列表分页（v6.5：草稿箱/已发布/发布记录/模板库） ---------------- */
.doc-list .pager-box, .tpl-grid .pager-box { grid-column: 1 / -1; }
.pager-box {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
  gap: 10px 14px; padding: 16px 4px 4px; user-select: none;
}
.pager-info { color: var(--muted); font-size: 13px; white-space: nowrap; }
.pager-box .pg-size {
  padding: 5px 8px; border: 1px solid var(--line); border-radius: 8px;
  background: var(--card); color: #5a4a3d; font-size: 13px; cursor: pointer; outline: none;
}
.pager-box .pg-size:focus { border-color: var(--red); }
.pager-nav { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; justify-content: center; }
.pg-btn {
  min-width: 30px; height: 30px; padding: 0 9px;
  border: 1px solid var(--line); border-radius: 8px; background: var(--card);
  color: #5a4a3d; font-size: 13px; cursor: pointer; line-height: 1;
  transition: border-color .15s, color .15s, background .15s;
}
.pg-btn:hover:not(:disabled):not(.cur) { border-color: var(--red); color: var(--red); }
.pg-btn.cur { background: var(--red); border-color: var(--red); color: #fff; font-weight: 700; cursor: default; }
.pg-btn:disabled { opacity: .35; cursor: default; }
.pg-ellipsis { color: var(--muted); padding: 0 3px; font-size: 13px; }
.pg-jump { display: inline-flex; align-items: center; gap: 6px; color: var(--muted); font-size: 13px; white-space: nowrap; }
.pg-jump .pg-input {
  width: 60px; height: 30px; padding: 0 8px;
  border: 1px solid var(--line); border-radius: 8px;
  font-size: 13px; color: #5a4a3d; outline: none; text-align: center;
  -moz-appearance: textfield; appearance: textfield;
}
.pg-jump .pg-input::-webkit-outer-spin-button,
.pg-jump .pg-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.pg-jump .pg-input:focus { border-color: var(--red); }
/* 发布记录表格内的分页（table-wrap 内） */
.table-wrap .pager-box { border-top: 1px dashed var(--line); margin-top: 10px; }
/* 小屏：间距收紧 */
@media (max-width: 640px) {
  .pager-box { gap: 8px 10px; row-gap: 10px; }
  .pg-jump { display: none; }   /* 手机端隐藏跳转输入（页码按钮已足够） */
  /* v7.56：窄屏放不下全部元素时按固定两行排布，不再随意挤行——
     第一行：共 N 条 · 第 x/y 页 + 每页条数下拉；
     第二行：页码按钮组独占一行居中（width:100% 强制换行，视觉稳定不重叠）。 */
  .pager-nav { width: 100%; }
}

/* ---------------- 用户会话管理（v6.7：启停用 / 在线用户 / 单点在线） ---------------- */
/* 登录页：账户在线占用详情 */
.login-occupied {
  margin-top: 10px; padding: 12px 14px; border-radius: 10px;
  background: #fdf3f1; border: 1px solid #eac5be; text-align: left;
}
.login-occupied .occ-title { font-weight: 700; color: #a61b29; font-size: 13.5px; margin-bottom: 8px; }
.login-occupied .occ-grid { display: grid; grid-template-columns: auto 1fr; gap: 4px 12px; font-size: 12.5px; color: #5a4a3d; }
.login-occupied .occ-k { color: #a08a7a; }
.login-occupied .occ-tip { margin-top: 8px; font-size: 12px; color: #a08a7a; line-height: 1.6; }
/* 用户管理：停用态 / 在线徽标 */
tr.u-disabled td { color: #b8aca0 !important; background: #faf7f4; }
tr.u-disabled td b { text-decoration: line-through; }
.role-badge.u-off { background: #f4f0ec; color: #a08a7a; }
.role-badge.u-on { background: #eef7ee; color: #2e7d32; }
/* 在线用户面板 */
.online-card { margin-bottom: 16px; padding: 12px 14px; }
.online-head { font-weight: 700; color: #5a4a3d; margin-bottom: 8px; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.online-head .online-tip { font-weight: 400; font-size: 12px; }
.online-dot { display: inline-block; width: 9px; height: 9px; border-radius: 50%; background: #34a853; box-shadow: 0 0 0 3px rgba(52,168,83,.15); }

/* 设置页：文种管理（v6.9） */
.cat-add-row { display: flex; gap: 8px; margin-bottom: 12px; }
.cat-add-row .search { flex: 1; max-width: 320px; }
.cat-list { display: flex; flex-wrap: wrap; gap: 8px; }
.cat-chip { display: inline-flex; align-items: center; gap: 6px; padding: 6px 10px; border: 1px solid var(--line);
  border-radius: 10px; background: #fff; }
.cat-name { font-weight: 600; color: #4a3f35; }

/* 列表文种筛选按钮（v7.0：草稿箱/已发布顶部横向排列，点击筛选 + 分页联动） */
.cat-chips { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 0 0 14px; }
.cchip { display: inline-flex; align-items: center; gap: 6px; padding: 5px 12px; border: 1px solid var(--line);
  border-radius: 999px; background: #fff; color: #5a4a3d; font-size: 13px; cursor: pointer;
  transition: background .15s, border-color .15s, color .15s; }
.cchip:hover { border-color: var(--gold); background: #fdf9f2; }
.cchip.on { background: #a67c2e; border-color: #a67c2e; color: #fff; font-weight: 600; }
.cchip .n { display: inline-flex; align-items: center; justify-content: center; min-width: 20px; height: 18px;
  padding: 0 5px; border-radius: 9px; background: #f1ebe2; color: #7a6a58; font-size: 11.5px; font-weight: 600; }
.cchip.on .n { background: rgba(255,255,255,.25); color: #fff; }

/* 品牌署名（2026-10-05 v7.9）：系统名称后附加设计者信息，小一号弱化显示 */
.login-designer { font-size: 13px; font-weight: 600; opacity: .8; letter-spacing: .5px; }
.brand-designer { font-size: 13px; font-weight: 600; opacity: .92; letter-spacing: .5px; margin-left: 2px; }
/* 代码版本标识（v7.35b）：常驻顶栏，让用户一眼确认浏览器加载的是哪一版代码。
   做成胶囊小标签——版本号是排障信息，不该和品牌名抢视觉权重，但必须始终可见。 */
/* 代码版本标识（v7.35b 建立 / v7.38 美化）：常驻顶栏，让用户一眼确认浏览器加载的是哪一版代码。
   设计取舍：版本号是排障信息，不该和品牌名抢视觉权重，但必须始终可见。
   美化要点：
     · 等宽字体（tabular-nums）—— 版本号数字等宽，升级到 v7.38 / v10.0 不会因字宽变化而抖动；
     · 半透明描边胶囊 —— 与顶栏红色底色协调，压得住但不刺眼；
     · "V" 前缀大写、数字略小 —— 视觉上退到品牌名之后，符合"辅助信息"的层级。 */
.brand-ver { display: inline-block; margin-left: 8px; padding: 1px 8px 1px 6px;
  border-radius: 4px; border: 1px solid rgba(255,255,255,.38);
  background: rgba(255,255,255,.12);
  font-family: ui-monospace, "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
  font-size: 10.5px; font-weight: 700; letter-spacing: .6px; color: #fff; opacity: .82;
  vertical-align: 3px; cursor: help; user-select: all;
  transition: opacity .15s, background .15s; }
.brand-ver:hover { opacity: 1; background: rgba(255,255,255,.22); border-color: rgba(255,255,255,.6); }

/* 登录页版本标记（v7.38）：登录前顶栏被遮罩挡住，这里是唯一能看到版本的地方。
   v7.38 位置调整：从登录表单【内部】移到卡片【外下方】，定位为页脚级辅助信息。
   两个随之而来的样式改动，都不是随手调的：
     · margin 由 "-4px 0 14px" 改为 "14px 0 0" —— 原值是为表单内位置设计的
       （负上边距贴住副标题、下边距撑开与用户名框的间距）；
     · 颜色由深棕 #a89880 改为半透明白 —— 原色是给白色卡片内用的，在红底遮罩上
       对比度约 1.6:1，几乎看不见。这里用 rgba(255,255,255,.72)，与顶栏版本
       徽章的白色系保持一致，对比度约 4.5:1。 */
.login-ver { margin: 14px 0 0; text-align: center;
  font-family: ui-monospace, "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
  font-size: 11.5px; letter-spacing: .5px; color: rgba(255, 255, 255, .72);
  text-shadow: 0 1px 2px rgba(60, 10, 5, .35);
  user-select: all; cursor: help; transition: color .15s; }
.login-ver:hover { color: #fff; }

@media (max-width: 768px) {
  .brand-designer { display: none; } /* 手机端顶栏空间有限，署名仅在桌面端顶栏展示 */
  .login-designer { font-size: 11.5px; }
  .brand-ver { display: none; }       /* 顶栏太窄，登录页已有版本号，不会失去可查性 */
}

/* ============ 公文附件（v7.19，2026-10-05） ============ */
.att-list { max-height: 46vh; overflow-y: auto; margin: 8px 0; border: 1px solid var(--line); border-radius: 8px; }
.att-row { display: flex; align-items: center; gap: 8px; padding: 8px 10px; border-bottom: 1px solid #f2ece3; flex-wrap: wrap; }
.att-row:last-child { border-bottom: none; }
.att-seq { font-weight: 700; color: #a67c2e; font-size: 13px; white-space: nowrap; }
.att-icon { font-size: 16px; }
.att-name { flex: 1; min-width: 160px; padding: 5px 9px; border: 1px solid var(--line); border-radius: 6px;
  font-size: 13.5px; color: #4a3f35; background: #fffdf9; }
.att-name:focus { border-color: var(--gold); outline: none; background: #fff; }
.att-meta { font-size: 12px; color: #8a7a68; white-space: nowrap; }
.att-add { display: flex; gap: 8px; align-items: center; margin-top: 6px; }
/* 编辑器正文区附件说明行的可视提示（保持国标排版，仅加浅色底提示可编辑） */
.doc-attach[data-field="attachment"] .eb { min-width: 60px; }
/* 附件说明前缀（「附件：」/续行缩进）为静态文本，不可编辑，仅作所见即所得提示 */
.doc-attach .att-prefix { user-select: none; pointer-events: none; }
@media (max-width: 768px) {
  .att-row { gap: 6px; }
  .att-name { min-width: 100px; flex-basis: 100%; }
  .att-meta { display: none; }
}

/* ==========================================================================
   v7.25 移动端拟文极简模式（2026-10-05）
   需求：去掉固定的上下端工具栏，只固定「一级/二级/三级/正文/历史/存稿/发布」7 键。
   做法：移动端隐藏原 fmtbar/mobile-dock/顶栏工具条，改用极简底栏 #mMini；
        其余全部控件（#composeOps / #fmtbar）移入上滑抽屉 #mPanel，按需展开。
   ========================================================================== */
.m-mini, .m-panel, .m-panel-mask { display: none; }

@media (max-width: 980px) {
  /* 隐藏原上/下端工具栏（草稿箱等非拟文页不受影响，body.with-dock 仍受控） */
  body.with-dock .actionbar { display: none; }
  /* 格式栏已移入抽屉（带 .in-panel 标记），故只隐藏未入抽屉的情形 */
  body.with-dock #fmtbar:not(.in-panel) { display: none !important; }
  body.with-dock .mobile-dock,
  body.with-dock #dockbar { display: none !important; }
  /* 抽屉内格式栏必须正常显示（覆盖 .hidden 与上面的规则） */
  .m-panel #fmtbar { display: flex !important; }

  /* 顶栏改为单行紧凑（品牌 + 用户 + 更多） */
  .topbar { height: 52px; }
  .actionbar { top: 52px; }
  /* 极简底栏（v7.26：两行 = 文种选择 + 常用 7 键/更多） */
  .m-mini {
    display: block; position: fixed; left: 0; right: 0; bottom: 0; z-index: 120;
    background: #fffdf9; border-top: 1px solid var(--line);
    box-shadow: 0 -2px 12px rgba(120, 40, 30, .12);
    padding-bottom: env(safe-area-inset-bottom, 0);
  }
  .m-mini.hidden { display: none; }
  /* 第一行：文种选择 */
  .m-mini-row1 {
    display: flex; align-items: center; gap: 6px;
    padding: 6px 8px 0;
  }
  .m-mini-cat-lb {
    flex: none; font-size: 12.5px; font-weight: 700; color: #9a8a7c; line-height: 1;
  }
  .m-mini-cat-host { flex: 1 1 auto; min-width: 0; display: flex; }
  .m-mini-cat-host #catSelect {
    flex: 1 1 auto; width: 100%; min-width: 0;
    height: 40px; min-height: 44px; padding: 0 10px;
    font-size: 16px; font-weight: 600;      /* 16px 避免 iOS 聚焦自动放大 */
    border: 1px solid #d9b8ab; border-radius: 10px; background: #fff;
    color: #4a3f35; cursor: pointer;
  }
  .m-mini-cat-host #catSelect.sel-empty { border-color: var(--red); background: #fdf1ee; color: var(--red); }
  /* 第二行：常用 7 键 + 更多 */
  .m-mini-inner { display: flex; align-items: center; gap: 4px; padding: 5px 6px 6px; }
  /* v7.39：字号 13.5px → 12.5px。
     「一级/二级/三级/正文」这类 2 字键在 360px 屏上按 13.5px 需占 ~39px/键，
     8 键合计超出可用宽度，导致末尾「⋯ 更多功能」被压缩溢出。
     12.5px 在中文短词上的可读性仍足够（正文 UI 常用的下限档），却能省下约 5px/键。 */
  .m-mini .mm-btn {
    flex: 1 1 0; min-width: 0; min-height: 46px; padding: 4px 2px;
    display: inline-flex; align-items: center; justify-content: center; gap: 2px;
    font-size: 12.5px; font-weight: 600; color: #4a3f35;
    background: #fff; border: 1px solid var(--line); border-radius: 10px; cursor: pointer;
  }
  .m-mini .mm-btn:active { background: #fdf3ee; }
  .m-mini .mm-save { color: var(--red); border-color: #e0b4a8; }
  .m-mini .mm-pub { color: #fff; background: var(--red); border-color: var(--red); font-weight: 700; }
  /* 「📮 发布」图标+文字较宽，单独放宽并禁止换行。
     v7.39：字号 13px → 12px。原 13px 在 360px 窄屏实测 client 40px / scroll 43px，
     溢出 3px（emoji 💾/📮 比同等字号的汉字宽）。降到 12px 后正好放下。 */
  .m-mini .mm-pub { flex: 1.3 1 0; white-space: nowrap; font-size: 12px; }
  .m-mini .mm-save { white-space: nowrap; font-size: 12px; }
  /* v7.39：「⋯」后面补上「更多功能」文字。
     为什么不能只加文字、必须重排宽度：
     拟文页这一行有 8 个键挤在 360~390px 屏上（扣掉 padding/gap 后可用约 336~366px），
     「更多功能」4 个字 + 三点实测需要 48+19+6(间距)+4(内边距) ≈ 77px。
     沿用原来的 flex:0 0 46px 必然被压缩，「更多功能」挤成两行反而更丑。
     实测（v7.40 验证）：仅把 flex 调到 1.8 仍会内容溢出（scrollWidth > clientWidth），
     因为固定 13.5px 的字体让前 6 个汉字键（一级/二级/三级/正文）也各占 ~39px。
     故此处同时做两件事：
       1) 汉字类按键（.mm-btn 基类）字号 13.5px → 12.5px，让出约 5px/键；
       2) 「更多功能」字号 12px → 11.5px，三点 19px → 16px，并给足 flex: 2.4。
     二者叠加后 360px 窄屏实测可容纳且不换行。 */
  .m-mini .mm-more { flex: 2.4 1 0; white-space: nowrap; line-height: 1.15; }
  .m-mini .mm-more .mm-more-dots { font-size: 16px; font-weight: 700; }
  .m-mini .mm-more .mm-more-txt { font-size: 11.5px; font-weight: 600; }
  .m-mini .hist-count { margin-left: 1px; }
  /* 非拟文页：底栏只留「⋯ 更多功能」一个键（草稿箱/日志等也能打开抽屉导航） */
  .m-mini.mini-only-more .mm-btn:not(.mm-more) { display: none; }
  .m-mini.mini-only-more .mm-more { flex: 1 1 auto; }
  .m-mini.mini-only-more .mm-more .mm-more-txt { font-size: 14px; }
  .m-mini.mini-only-more .m-mini-inner { padding: 5px 8px; }
  .m-mini.mini-only-more .m-mini-row1 { display: none; }

  /* 抽屉：上滑面板。停在极简底栏「之上」，保证抽屉打开时底栏 7 键依然可点 */
  .m-panel-mask {
    display: block; position: fixed; left: 0; right: 0; top: 0;
    bottom: var(--mini-h, 0px); z-index: 130;
    background: rgba(40, 12, 6, .42);
  }
  .m-panel-mask.hidden { display: none; }
  .m-panel {
    display: flex; flex-direction: column;
    position: fixed; left: 0; right: 0; bottom: var(--mini-h, 0px); z-index: 131;
    max-height: calc(74vh - var(--mini-h, 0px)); background: #fffdf9;
    border-radius: 18px 18px 0 0; box-shadow: 0 -8px 30px rgba(80, 20, 10, .30);
    animation: mPanelUp .22s ease-out;
  }
  .m-panel.hidden { display: none; }
  @keyframes mPanelUp { from { transform: translateY(22%); opacity: .4; } to { transform: none; opacity: 1; } }
  .m-panel-grab { display: flex; justify-content: center; padding: 8px 0 2px; }
  .m-panel-grab span { width: 40px; height: 4px; border-radius: 3px; background: #d8cabd; }
  .m-panel-head {
    display: flex; align-items: center; justify-content: space-between;
    padding: 6px 14px 8px; border-bottom: 1px solid var(--line);
  }
  .m-panel-head b { color: var(--red-deep, var(--red-deep)); font-size: 15px; }
  .m-panel-close {
    width: 40px; height: 40px; border-radius: 10px; border: 1px solid var(--line);
    background: #fff; font-size: 17px; color: #6d5a52; cursor: pointer;
  }
  .m-panel-body { overflow-y: auto; -webkit-overflow-scrolling: touch; padding: 10px 12px calc(14px + env(safe-area-inset-bottom, 0)); }
  .mp-sec { margin-bottom: 12px; }
  .mp-sec-t { font-size: 12.5px; font-weight: 700; color: #9a8a7c; margin-bottom: 6px; }
  /* 抽屉内的两个宿主还原成常规纵向流，去掉 sticky/fixed */
  .m-panel #composeOps, .m-panel #fmtbar {
    position: static !important; top: auto !important; width: auto;
    display: flex; flex-wrap: wrap; gap: 6px; padding: 0; margin: 0;
    border: none; box-shadow: none; background: transparent;
  }
  .m-panel #composeOps .sel { flex: 1 1 100%; }
  .m-panel #fmtbar .fmtbar-label { width: 100%; margin: 0 0 2px; }
  /* 「文种 / 保存草稿 / 发布 / 历史」已由底部两行栏常驻提供，抽屉内不再重复，避免误触与视觉冗余 */
  .m-panel #btnSaveDraft, .m-panel #btnPublish,
  .m-panel #btnHistory, .m-panel #catSelect { display: none !important; }
  .m-panel #composeOps .ab-sep { display: none; }
  /* 抽屉内的导航区：与顶栏一致的 tab 外观 */
  .m-panel .ab-tabs { display: flex; flex-wrap: wrap; gap: 6px; }
  .m-panel .ab-tab {
    min-height: 44px; padding: 8px 12px; font-size: 13.5px;
    border: 1px solid var(--line); border-radius: 10px; background: #fff;
  }
  .m-panel .ab-tab.active {
    background: linear-gradient(120deg, var(--red), var(--red-2)); color: #fff;
    border-color: transparent; font-weight: 600;
  }
  .m-panel .ab-tab.active .nav-badge { background: rgba(255,255,255,.32); }
  /* 抽屉打开时底栏上浮，避免被面板压住 */
  body.m-panel-open .m-mini { box-shadow: 0 -2px 18px rgba(120, 40, 30, .22); }
}

/* ==========================================================================
   v7.23 移动端优化（2026-10-05，源自全链路审计 P2–P6）
   - P2 触控目标 ≥44px（Apple/Google 规范）
   - P3 用户管理表格窄屏卡片化
   - P4 拟文底部工具栏可折叠，格式栏默认收起
   - P5 顶栏「更多」下拉，标题独占一行
   - P6 系统日志长文本两列栅格
   ========================================================================== */

/* ---- P5 顶栏：按钮收进「更多」，标题不被挤压 ---- */
.topbar-more {
  display: none; width: 40px; height: 40px; flex: none;
  align-items: center; justify-content: center;
  font-size: 22px; line-height: 1; color: #fff; cursor: pointer;
  background: rgba(255,255,255,.18); border: 1px solid rgba(255,255,255,.34);
  border-radius: 10px; padding: 0;
}
.topbar-more:active { background: rgba(255,255,255,.32); }
.topbar-menu {
  position: absolute; right: 12px; top: calc(100% - 4px); z-index: 120;
  min-width: 152px; background: #fff; border: 1px solid var(--line);
  border-radius: 12px; box-shadow: 0 10px 30px rgba(80,20,10,.24); overflow: hidden;
}
.topbar-menu .tm-item {
  display: block; width: 100%; text-align: left;
  padding: 13px 15px; font-size: 14.5px; color: #4a3f35;
  background: none; border: none; border-bottom: 1px solid #f3ece3; cursor: pointer;
}
.topbar-menu .tm-item:last-child { border-bottom: none; }
.topbar-menu .tm-item:active { background: #fdf6f0; }

@media (max-width: 980px) {
  .topbar { position: relative; }                 /* 让下拉相对顶栏定位 */
  #btnChangePw, #btnLogout { display: none; }      /* 移动端隐藏，露出「更多」 */
  .topbar-more { display: flex; }
  .topbar-left { flex: 1 1 auto; min-width: 0; }
  .brand-name {                                    /* 标题独占空间，不再被按钮挤压 */
    font-size: 14.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  /* v7.41：用户胶囊改为弹性宽度。
     原来这里写死 max-width:92px，实测 scrollWidth > clientWidth（内容被截断溢出）——
     「用户名 + 管理员」徽标本就塞不进 92px，长的用户名（如 4~5 个汉字）会被硬切。
     改为 flex 容器 + min-width:0 + ellipsis：能显示多少显示多少，
     放不下时按 CSS 规范在省略号处截断，而不是撑破布局或压住副标题。 */
  .user-chip {
    max-width: 30vw; min-width: 0; flex: 0 1 auto;
    display: inline-flex; align-items: center; gap: 4px;
    padding: 5px 10px; font-size: 12px; white-space: nowrap;
    overflow: hidden; text-overflow: ellipsis;
  }
  /* 角色徽标在窄屏独立占位，不与用户名抢横向空间（长用户名时省略号落在用户名上） */
  .user-chip #userName { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
  .user-chip .role-badge { flex: none; margin-left: 0; font-size: 10px; padding: 1px 5px; }
}

/* ---- P4 移动端底部：紧凑网格，工具区更矮 ---- */
@media (max-width: 980px) {
  .mobile-dock #composeOps { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; padding: 8px 8px; }
  /* 文种/印章信息量大，各占满一行；模板下拉与按钮同排 */
  .mobile-dock #composeOps > #catSelect,
  .mobile-dock #composeOps > #sealType { grid-column: 1 / -1; }
  .mobile-dock #composeOps > .sel { min-height: 44px; font-size: 13.5px; }
  .mobile-dock #composeOps .ab-sep { display: none; }
  .mobile-dock #composeOps .btn { min-height: 44px; padding: 8px 6px; font-size: 13px; }
/* 印章上传按钮：宽屏只显图标，窄屏补文字（避免出现空按钮） */
.seal-up-txt { display: inline; margin-left: 3px; }
}
/* ★ v7.74（死规则修复）：v7.73 及之前这个 @media (min-width:981px) 被误嵌在上面
   @media (max-width:980px) 块内部——CSS 不支持嵌套，实际等价于
   (max-width:980px) and (min-width:981px)，永远不成立，导致桌面端「换印章」
   文字从未隐藏过。现移出嵌套，与外层块平级，恢复设计意图。 */
@media (min-width: 981px) {
  .seal-up-txt { display: none; }   /* 桌面端导航条紧凑，只留 🔄 图标 */
}

/* ★ v7.74（移动端功能修复）：模板卡片的「编辑/删除」按钮（.tpl-ops）此前只靠
   :hover 显示（opacity:0 → hover 才 1）。触摸屏没有 hover——手机上这两个按钮
   永久不可见，模板管理功能形同虚设；且 opacity:0 不脱离点击流，看不见却能误触。
   @media (hover:none) 精准命中触摸设备（PC 鼠标环境不受影响，仍保持 hover 显隐）。 */
@media (hover: none) {
  .tpl-ops { opacity: 1; transition: none; }
}

/* ★ v7.74（移动端可用性修复）：发布记录表（#recTable）此前固定 min-width:900px，
   375px 手机屏只能看到约 1/3 列，「删除/撤回」按钮在屏幕外且无任何滚动提示。
   参照 #userTable 已验证的卡片化方案（td::before 显示字段名），≤980px 转卡片。 */
@media (max-width: 980px) {
  #recTable { min-width: 0; }
  #recTable thead { display: none; }   /* 表头隐藏，字段名由 td::before 承担 */
  #recTable, #recTable tbody, #recTable tr, #recTable td { display: block; width: 100%; }
  #recTable tr {
    border: 1px solid var(--line); border-radius: 12px;
    background: #fff; margin-bottom: 10px; padding: 10px 12px;
  }
  #recTable td {
    display: flex; align-items: flex-start; gap: 10px;
    padding: 5px 0; border: none; text-align: left; font-size: 14px;
    max-width: none !important; white-space: normal !important;  /* 覆盖原先内联的 max-width/nowrap */
  }
  #recTable td::before {
    content: attr(data-label); flex: none; width: 68px;
    color: #9a8a7c; font-size: 12.5px; font-weight: 600;
  }
  #recTable td.rec-ops {
    flex-wrap: wrap; gap: 8px; padding-top: 9px; margin-top: 5px;
    border-top: 1px dashed var(--line);
  }
  #recTable td.rec-ops::before { width: 100%; }
}

/* ---- P2 触控目标 ≥44px（移动端） ---- */
@media (max-width: 980px) {
  /* 导航 tab */
  .ab-tab { min-height: 44px; padding: 10px 12px; display: inline-flex; align-items: center; }
  /* 通用按钮（下拉菜单、列表操作、弹窗内按钮一并覆盖） */
  button, .btn, .ab-ops .btn, .db-inner .btn, .mobile-dock .btn {
    min-height: 44px;
  }
  .btn-sm { min-height: 44px; padding: 10px 13px; }
  /* 下拉选择 */
  select, .fmtbar select, .dockbar select, .mobile-dock select {
    min-height: 44px; font-size: 14px; padding: 8px 9px;
  }
  /* 搜索框 / 文本输入 */
  input[type="text"], input[type="password"], input:not([type]), .search {
    min-height: 44px; font-size: 16px; /* 16px 可避免 iOS 聚焦时自动放大页面 */
  }
  /* 格式工具栏里的方形小按钮（B / 一级 / 二级…） */
  .fmtbar button, .fmtbar .btn { min-width: 44px; min-height: 44px; }
  /* 色块与撤销/重做/历史 */
  #fmtColor { width: 44px; height: 44px; }
  /* 列表里的操作按钮 */
  .user-ops .btn, .att-add .btn, .view-head-tools .btn { min-height: 44px; }
  /* 顶栏 chip 可点 */
  .user-chip { min-height: 40px; display: inline-flex; align-items: center; }
}

/* ---- P3 用户管理表格：窄屏改卡片式 ---- */
@media (max-width: 980px) {
  .tbl-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  #userTable { min-width: 0; }
  /* 其他记录类表格保持横向滚动（.rec-table 默认 min-width:900px） */
  .rec-wrap, .tbl-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  /* 该表用首行 <th> 作表头（无 thead），移动端隐藏并由 td::before 显示字段名 */
  #userTable tr:first-child th { display: none; }
  #userTable, #userTable tbody, #userTable tr, #userTable td { display: block; width: 100%; }
  #userTable tr {
    border: 1px solid var(--line); border-radius: 12px;
    background: #fff; margin-bottom: 10px; padding: 10px 12px;
  }
  #userTable td {
    display: flex; align-items: flex-start; gap: 10px;
    padding: 5px 0; border: none; text-align: left; font-size: 14px;
  }
  #userTable td::before {
    content: attr(data-label); flex: none; width: 68px;
    color: #9a8a7c; font-size: 12.5px; font-weight: 600;
  }
  #userTable td.user-ops { flex-wrap: wrap; gap: 8px; padding-top: 9px; margin-top: 5px; border-top: 1px dashed var(--line); }
  #userTable td.user-ops::before { width: 100%; }
  #userTable td .role-badge { white-space: nowrap; }  /* 角色徽标不竖排 */
}

/* ---- P4 拟文底部工具栏：格式栏默认折叠，点「Aa」展开 ---- */
.dock-fmt-toggle {
  display: none; width: 100%; align-items: center; justify-content: center; gap: 6px;
  min-height: 44px; padding: 9px 12px; margin: 0;
  background: #fff8f4; border: none; border-top: 1px dashed #e0b4a8;
  color: var(--red); font-size: 14px; font-weight: 700; cursor: pointer;
}
@media (max-width: 980px) {
  .dock-fmt-toggle { display: flex; }
  /* 折叠态：#fmtbar 自身就是 .fmtbar，故用 .fmt-collapsed 直接作用其子元素 */
  .fmt-collapsed select,
  .fmt-collapsed button,
  .fmt-collapsed #fmtColor,
  .fmt-collapsed .fmtbar-label { display: none; }
  .fmt-collapsed { padding: 0 !important; border: none !important; background: transparent !important; box-shadow: none !important; min-height: 0; }
}

/* ---- P6 系统日志：长文本两列栅格，窄屏单列（v7.29 随 7.24 显示方式一并恢复） ---- */
.log-item .lg-body {
  min-width: 0; overflow-wrap: anywhere; word-break: break-word;
  line-height: 1.55;
}
@media (min-width: 981px) {
  .log-item { display: grid; grid-template-columns: 58px 74px 132px 1fr; gap: 10px; align-items: baseline; }
  .log-item .lg-body { line-height: 1.55; }
}
@media (max-width: 980px) {
  .log-item { display: grid; grid-template-columns: 42px 1fr; gap: 4px 8px; }
  .log-item .lg-t { grid-column: 1; font-size: 12px; }
  .log-item .lg-act { grid-column: 2; justify-self: start; }
  .log-item .lg-body { grid-column: 1 / -1; font-size: 13px; padding-left: 50px; }
}

/* ---- 登录页标题（P7）：<br> 强制两行，不再断词 ---- */
.login-title { line-height: 1.35; }

/* ==========================================================================
   v7.41 移动端顶栏/拟文头部优化（2026-10-06）
   ---------------------------------------------------------------------------
   本块刻意放在文件【最末尾】：因为前面的 @media (max-width:980px) 块里已有多处
   .user-chip 规则（如 1153 行的 min-height:40px），CSS 按源码顺序层叠，
   放在中间会被后面的规则覆盖部分属性。集中收口在末尾，避免逐处打补丁。
   ========================================================================== */
@media (max-width: 980px) {
  /* ---- 1. 顶栏右侧：横向排列，不再把副标题挤出屏幕 ---- */
  /* .topbar-right 的 display:flex 已在基础样式（第 101 行）定义，
     此处只补移动端专属的尺寸收敛。 */
  .topbar-right { gap: 6px; }

  /* ---- 2. 用户胶囊：不撑破、不硬切、也不压住系统名 ---- */
  /* 两轮踩坑记录（都是截图+几何实测才发现的，肉眼极易漏）：
       第1 轮 max-width:34vw（133px）→ 胶囊盖住标题「公文管理系统」后半段；
       第 2 轮 26vw（101px）      → 仍与标题文字重叠 34px。
     根因不在胶囊宽度，而在 .brand-name：它是 flex 子项且
     white-space:nowrap，却【没有】overflow/text-overflow，
     于是文字按完整宽度参与布局，把相邻的胶囊挤出可视区之外再叠上来。
     修法（两者都要）：
       ·.brand-name 允许截断（min-width:0 + ellipsis）——窄屏下标题
         完整显示本就不现实（15 个汉字需要约 200px），让它按需省略；
       · .user-chip 继续收窄，保证标题至少能显示到「小雅镇中心小学·公文…」这类
         可辨识的程度，降级顺序是「标题优先于用户名」。 */
  .topbar-left { flex: 1 1 auto; min-width: 0; }
  /* ★ 关键补丁：.brand 必须显式 min-width:0。
     flex 子项的 min-width 默认值是 auto，等于「不许缩到内容宽度以下」——
     于是 .brand（211px）即使父级 .topbar-left 已被压到 230px 也纹丝不动，
     直接把右边的胶囊挤出可视区再叠上来。
     实测证据：.topbar-left scrollW=257 / clientW=230（已被压缩），
     而 .brand scrollW=211 / clientW=211（完全没缩），说明 .brand-name 上的
     overflow:hidden|text-overflow:ellipsis 根本没触发（宽度没被压缩就没有省略对象）。
     加上 min-width:0 后，.brand 可收缩，标题才会在省略号处截断。 */
  .brand { min-width: 0; flex: 1 1 auto; }
  .brand-name {
    min-width: 0; max-width: 100%;
    overflow: hidden; text-overflow: ellipsis;
  }
  .user-chip {
    max-width: 24vw; min-width: 0; flex: 0 1 auto;
    display: inline-flex; align-items: center; gap: 4px;
    padding: 0 9px; min-height: 34px;
    font-size: 11.5px; line-height: 1.2;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .user-chip #userName { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .user-chip .role-badge { flex: none; margin-left: 0; font-size: 10px; padding: 1px 5px; }

  /* ---- 3. 「⋯」更多按钮：与胶囊视觉对齐 ---- */
  .topbar-more {
    width: 36px; height: 36px; min-height: 36px; flex: none;
    font-size: 20px; border-radius: 9px;
  }

  /* ---- 4. 拟文头部：隐藏缩放栏后回收高度 ---- */
  /* 具体隐藏规则见第 320 行附近的 .pv-zoom / .cm-right，
     这里只补充让 .compose-meta 收得更紧：隐藏后不再需要 space-between 分栏。 */
  .compose-meta { padding: 8px 12px 4px; gap: 6px; }
  .cm-left { gap: 8px; }
  /* 提示语在窄屏过长且信息价值低（正文区已有引导），收成一行并允许截断 */
  .cm-hint {
    font-size: 11.5px; white-space: nowrap; overflow: hidden;
    text-overflow: ellipsis; max-width: 62vw; display: block;
  }
}

/* ==========================================================================
   v7.42 移动端底栏优化（2026-10-06）
   ---------------------------------------------------------------------------
   改前实测问题（390px 屏）：
     · 8 键挤一行，6/8 个键宽度仅 37px —— 低于 44px 触控标准（Apple/Google
       规范），误触风险高；按钮被压成 37x46 的细长条，宽高比 0.8 视觉失衡；
     · 底栏占屏 12.8%（108px）；
     · 文种下拉宽 240px，却只显示「文种：请选择文种」7 个字，两侧大量留白；
     · 「🕘 历史」键只有图标无文字，与相邻「💾 存」「📮 发布」风格不统一。

   改法：8 键 → 5 键（标题/历史/存/发布/更多），每个键宽约翻倍。
   四个标题级别功能并未丢失 —— 抽屉里的 #fmtbar 本就完整包含它们，
   底栏这两处分别是「快捷方式」与「完整入口」。
   ========================================================================== */
@media (max-width: 980px) {
  /* ---- 1. 文种行：标签并入下拉，省出独立标签的横向空间 ----
     原来「文种」标签(26px) + 下拉(240px) 并排，标签形同虚设（重复下拉里的文字）。
     改为标签绝对定位到下拉左侧内侧，下拉吃掉整行宽度。 */
  .m-mini-row1 { padding: 6px 8px 2px; gap: 0; position: relative; }
  .m-mini-cat-lb {
    position: absolute; left: 16px; top: 50%; transform: translateY(-50%);
    z-index: 1; pointer-events: none;   /* 点不到，避免与下拉抢事件 */
    font-size: 11.5px; color: #9a8a7c;
  }
  .m-mini-cat-host #catSelect {
    /* 覆盖第 141 行的通用 max-width:240px（那是桌面端排版上限）。
       移动端底栏宽度紧张，文种下拉应吃满整行，实测宿主 374px 却只有 240px，
       两侧留白各60px+，17 个文种选项显示不全、且平白浪费横向空间。 */
    max-width: none;
    padding-left: 44px;   /* 给绝对定位的标签让出位置 */
    height: 38px; min-height: 38px;
  }

  /* ---- 2. 按键行：5 键均分，触控目标回到 44px 以上 ---- */
  .m-mini-inner { gap: 6px; padding: 5px 8px 6px; }
  .m-mini .mm-btn {
    flex: 1 1 0; min-width: 0; min-height: 48px; padding: 4px 2px;
    gap: 3px;
    font-size: 13px;                      /* 5 键有富余，字号回 13px 更清晰 */
  }

  /* ---- 3. 图标与文字分层：emoji 收小，文字恢复存在感 ----
     改前按钮里 emoji 与文字同字号（12.5px），emoji 视觉上过大、
     文字过小，比例失衡。改为 emoji 13px、文字 12.5px。
     v7.42 二次修：实测 emoji 与文字之间几乎零间隙（emoji 的字面框带白边，
     视觉上像贴在一起）。这里给 .mm-ico 单独加 2px 右边距，间距从0 提到 3px。 */
  .m-mini .mm-ico { font-size: 13px; line-height: 1; flex: none; margin-right: 2px; }
  .m-mini .mm-txt { font-size: 12.5px; line-height: 1; }

  /* ---- 4. 「标题」键：显示当前级别，点击弹出选择面板 ---- */
  .m-mini .mm-ttl { color: var(--red); border-color: #e0b4a8; font-weight: 700; }
  .m-mini .mm-ttl-cur { font-size: 13px; }
  .m-mini .mm-ttl-arrow { font-size: 10px; opacity: .7; flex: none; }

  /* ---- 5. 标题级别选择面板 ---- */
  .m-ttl-panel {
    position: absolute; left: 0; right: 0; bottom: 100%;
    z-index: 130; padding: 6px 8px;
    background: #fffdf9; border-top: 1px solid var(--line);
    box-shadow: 0 -3px 16px rgba(120, 40, 30, .16);
    animation: mttlUp .16s ease-out;
  }
  .m-ttl-panel.hidden { display: none; }
  @keyframes mttlUp { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
  .m-ttl-row { display: flex; gap: 6px; }
  .m-mini .mtp-btn {
    flex: 1 1 0; min-width: 0; min-height: 44px;     /* 触控达标 */
    font-size: 13px; font-weight: 600; color: #4a3f35;
    background: #fff; border: 1px solid var(--line); border-radius: 9px;
    cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .m-mini .mtp-btn:active { background: #fdf3ee; }
  .m-mini .mtp-btn.on { background: var(--red); color: #fff; border-color: var(--red); }

  /* ---- 6. 「更多功能」键：5 键后空间充裕，字号可放大 ---- */
  .m-mini .mm-more { flex: 1.45 1 0; white-space: nowrap; line-height: 1.15; }
  .m-mini .mm-more .mm-more-dots { font-size: 18px; }
  .m-mini .mm-more .mm-more-txt { font-size: 12.5px; font-weight: 700; }
  .m-mini.mini-only-more .mm-more .mm-more-txt { font-size: 14.5px; }

  /* ---- 7. 历史键徽标：5 键布局下改为右上角角标 ----
     v7.42 二次修：改前徽标跟在文字后面横向排（margin-left:1px），
     在 65px 宽的按钮里被挤到 emoji 上方，视觉上像压在时钟图上。
     改为绝对定位到按钮右上角，成为标准的数字角标。 */
  .m-mini .hist-count {
    position: absolute; top: 4px; right: 6px; margin-left: 0;
    min-width: 15px; height: 15px; padding: 0 3px;
    display: inline-flex; align-items: center; justify-content: center;
    font-size: 9.5px; line-height: 1; font-weight: 700;
    background: var(--red); color: #fff; border-radius: 8px;
  }
  .m-mini .mm-hist { position: relative; padding-top: 6px; }
}

/* ==========================================================================
   v7.44：移动端 ① 文种下拉缩短 + 右侧新增「预览」快捷键
                ② 公文预览页顶段工具栏重排（解决移动端按钮竖排凌乱）
   ========================================================================== */
@media (max-width: 980px) {
  /* ---- 1. 文种行：下拉让出横向空间给「预览」键 ----
     改前 #catSelect 是 max-width:none 吃满整行（实测 374px / 390px视口），
     横向空间被吃光、没处放预览。现在下拉改为 flex 收缩并给 8 个文种字留足宽度：
       390视口 - 左右padding 16 - gap 6 - 预览键 84 - 标签占位 40 ≈ 244px
     仍远大于 v7.41 之前的 240px，且「请选择文种」这类提示语完整显示不截断。 */
  .m-mini-row1 { gap: 6px; }
  .m-mini-cat-host { flex: 1 1 auto; min-width: 0; }
  .m-mini-cat-host #catSelect { max-width: none; }

  /* 预览键：与下拉同高（38px），主色描边以便从「文种」里区分出来 */
  .m-mini .m-cat-pv {
    flex: none; display: inline-flex; align-items: center; justify-content: center;
    gap: 3px; min-width: 84px; min-height: 38px; padding: 0 10px;
    font-size: 13px; font-weight: 700; line-height: 1; white-space: nowrap;
    color: var(--red); background: #fff; border: 1px solid #e0b4a8;
    border-radius: 10px; cursor: pointer;
  }
  .m-mini .m-cat-pv:active { background: #fdf1ee; }
  .m-mini .m-cat-pv .mpv-ico { font-size: 13px; line-height: 1; flex: none; }
  .m-mini .m-cat-pv .mpv-txt { font-size: 13px; line-height: 1; }

  /* ---- 2. 预览页顶段：移动端由「横向挤成竖排」改为「两行分层」----
     实测改前：.pv-topbar 高 168px（桌面端仅 51px），占 390×844 视口的 20%。
     根因不是样式没写好，而是结构错配：
       .pv-topbar 是 flex-wrap:nowrap，标题 .pv-title 占 182px 后，
       右侧只剩约 180px，而 .pv-actions 里按钮合计约 243px（刷新73+关闭68+导出102）
       装不下 → flex-wrap:wrap 让每个按钮各占一行 → 竖着堆成 148px 高。
     改法（小屏专属，桌面端一行不动）：
       第一行：标题独占一行，单行截断（原来是两行挤在左侧）
       第二行：操作按钮整行横向排列，gap 6px，触控高度回44px
     预期高度 168px → 约 96px，且按钮不再竖排。 */
  .pv-topbar {
    flex-wrap: wrap; align-items: center;
    gap: 8px; padding: 9px 12px;
    background: linear-gradient(180deg, rgba(52,36,30,.98), rgba(52,36,30,.95));
    box-shadow: 0 2px 12px rgba(0,0,0,.34);
  }
  /* 标题独占第一行：order:1 保证排在 actions 之前；
     min-width:0 是必须的——flex 子项 min-width 默认 auto 会拒绝收缩到内容宽度以下，
     不写这行ellipsis 永远不生效（v7.41 已踩过同一个坑）。 */
  .pv-title {
    order: 1; flex: 1 1 100%; min-width: 0;
    font-size: 14px; font-weight: 600; line-height: 1.35;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  /* 操作区独占第二行，靠右排列；justify-content:flex-end 让按钮不再左对齐参差 */
  .pv-actions {
    order: 2; flex: 1 1 100%; min-width: 0;
    display: flex; align-items: center; justify-content: flex-end;
    flex-wrap: nowrap; gap: 6px;
  }
  /* 统一按钮尺寸：小屏上「刷新/关闭」只有图标更紧凑，加上下方主键宽度才装得下 */
  .pv-actions .btn {
    flex: none; min-height: 40px; padding: 0 12px;
    font-size: 13px; line-height: 1; white-space: nowrap;
    display: inline-flex; align-items: center; justify-content: center; gap: 4px;
    border-radius: 9px;
  }
  /* 页码徽标：加载前是空内容，原样式 padding:3px 10px 会留一块空白凸起。
     这里给 min-width:0，空内容时不占位（:empty 是关键）。 */
  .pv-count {
    flex: none; margin-right: auto;   /* 靠左：页码信息属状态，操作按钮属动作，分居两侧 */
    min-width: 0; padding: 0; font-size: 12.5px; border-radius: 20px;
    background: none; color: #e6d5cb;
  }
  .pv-count:empty { display: none; }
  .pv-count:not(:empty) { padding: 3px 10px; background: rgba(255,255,255,.12); }
  /* 预览页正文上边距随顶段变矮而收窄，把省下的 70px 留给公文页面 */
  .pv-body { padding: 10px 4px 56px; }
}

/* ==========================================================================
   v7.45：移动端 ① 预览页顶段去掉「刷新」键
                ② 历史键从按键行迁到文种行，紧跟预览键之后
   ========================================================================== */
@media (max-width: 980px) {
  /* ---- 1. 文种行：下拉可收缩，给右侧两个键让位 ----
     v7.44 时代下拉是 flex:1 1 auto（自然吃满余量）。现在右侧要放两个键，
     必须允许它被压缩到内容宽度以下 —— 又一次遇到 flex 子项 min-width:auto 陷阱
     （v7.41 在 .brand 上踩过：不写 min-width:0 就拒绝收缩）。
     213px 是 390px 视口下的实测值：374 - gap6×2 - 预览84 - 历史84 ≈ 200~213。 */
  .m-mini-cat-host { flex: 0 1 auto; min-width: 0; overflow: hidden; }
  .m-mini-cat-host #catSelect {
    min-width: 0;
    /* 文种下拉内容可超长（17项，最长「文种：请选择文种」需202px），
       压缩时用省略号收尾而不是把文字硬挤出去 */
    text-overflow: ellipsis; white-space: nowrap; overflow: hidden;
  }
  /* 预览键与历史键同宽同高（38px），视觉上连成一片，宽度统一便于计算 */
  .m-mini .m-cat-pv { min-width: 84px; }
  /* 历史键：与预览键同色系（都用主色描边）保持一致；
     这里不再单独设主色，改用中性的白底 + 主色描边，和预览键看起来是一组。 */
  .m-mini .m-cat-hist { position: relative; }
  /* 右上角数字角标：沿用 v7.42 的角标样式，只是承载元素从按键行换成了文种行的键 */
  .m-mini .m-cat-hist .hist-count {
    position: absolute; top: -5px; right: -4px; margin-left: 0;
    min-width: 16px; height: 16px; padding: 0 3px;
    display: inline-flex; align-items: center; justify-content: center;
    font-size: 9.5px; line-height: 1; font-weight: 700;
    background: var(--red); color: #fff; border-radius: 8px;
    border: 1.5px solid #fff;          /* 白描边把徽标从按钮边框里「抬」出来 */
    box-sizing: border-box;
  }
}

/* ==========================================================================
   v7.48：移动端顶栏「账户名显示不出来」修复
   ========================================================================== */
@media (max-width: 980px) {
  /* v7.48：修复用户实测反馈的「右上角显示不了账户名」。
     根因不是漏填值，而是 v7.41（2026-10-06）给 .user-chip 定的宽度上限太窄：
       max-width: 24vw → 390px 屏只有 93.6px
     而胶囊实际需要 ≈103~132px（👤 emoji + 2~3 个汉字 + 「管理员」徽标 + 左右 padding）。
     93.6px < 103px，所以【每一个用户名都被 ellipsis 截断】——
     v7.47 的验证截图里能直接看到它显示成「临 管理员」：
     display_name「临时验证账号」5 个字只剩「临」1 个字。
     也就是说 v7.41 当时的验证只断言了「不与标题重叠」，
     没断言「名称可读」，于是这个缺陷一直溜到了用户手上。
     （这是本项目第 6 次出现「断言维度不全」类问题，前 5 次见各轮报告。）

     修法：取消硬上限 + 胶囊 flex:none 不参与收缩，改由品牌名承担全部截断。
     为什么这样重新分配截断优先级：
       · 品牌名「小雅镇中心小学 · 公文管理系统」是「这是哪个系统」——
         用户天天看、闭眼都认得，截成「小雅镇中心小学 · 公文…」仍可辨识；
       · 用户名是「我是谁」—— 一旦截成「临…」，就等于没显示，
         而登录后第一件事往往就是确认"我是不是登对号了"。
       所以该让位的只能是品牌名，不是用户名（v7.41 的降级顺序正好反了）。 */
  .user-chip {
    flex: none;                 /* 不参与收缩：宽度由内容决定 */
    max-width: 58vw;            /* 仅作极端长名的兜底上限，390px 屏≈226px 足够放真实组合 */
    min-width: 0;
  }
  /* 徽标「管理员/普通用户」是固定文案，flex:none 保证它永远不被压缩掉；
     名字可压缩、徽标不可压缩 —— 这样超长名时截断的是名字而不是角色标识。 */
  .user-chip #userName { flex: 0 1 auto; }
  .user-chip .role-badge { flex: none; }
}

/* ==========================================================================
   v7.68 主题换肤（2026-10-06，用户要求）
   ---------------------------------------------------------------------------
   机制：在 <html> 上设置 data-theme="xxx"，本节按主题覆盖第 57 行 :root 的
   那组基础变量。所有组件样式【一行都不用改】——因为它们消费的是变量，
   不是具体颜色值（本版已把原先 40 处硬编码品牌色收编为变量，见第 57 行注释）。

   为什么整块放在文件末尾：
     CSS 按源码顺序层叠，同权重下后者胜。放在末尾可确保主题变量一定覆盖
     第 57 行的 :root，不受前面任何 @media 块影响。

   ★ 默认主题 red 的数值与系统原有配色【逐字节相同】——用户要求"默认主题
     就是当前的主题颜色"。这不是偷懒，而是刻意的风险控制：顶栏是深红渐变
     配白字，深色被提亮一点，白字对比度就可能不达标；而移动端顶栏的压缩
     规则是踩着边界调出来的（见 v7.41/v7.48 注释）。默认主题一动，这些
     结论全部要重验。保持原样 = 零回归。

   色板设计说明：
     ink / sandal 等深色系主题同样会改变顶栏底色，其文字仍为白色——
     所选明度均控制在能承载白字的区间内（对比度 ≥ 4.5:1）。
   ========================================================================== */

/* ---- 1. 绛红 · 标准（默认，即系统原有配色） ---- */
/* 刻意不写值：让它继承 :root。这样"默认"永远等于"原始配色"，
   即便将来改 :root 也自动同步，不会出现两处漂移。 */
[data-theme="red"] { }

/* ---- 2. 墨黑 · 庄重：灰黑 + 米灰，极简克制、护眼 ---- */
[data-theme="ink"] {
  --red: #2b2b2b; --red-deep: #161616; --red-soft: #f0f0ee;
  --red-2: #4a4a4a; --red-shadow: 43, 43, 43;
  --line: #e2e2de; --gold: #a89070;
  --lg-a: #161616; --lg-b: #2b2b2b; --lg-c: #4a4a4a;
}

/* ---- 3. 靛青 · 沉稳：藏青，最常见的政务替代色 ---- */
[data-theme="indigo"] {
  --red: #1f4e79; --red-deep: #143a5c; --red-soft: #eef3f8;
  --red-2: #2f6ea8; --red-shadow: 31, 78, 121;
  --bg: #f2f5f9; --line: #dfe6ee; --gold: #b8914f;
  --lg-a: #143a5c; --lg-b: #1f4e79; --lg-c: #2f6ea8;
}

/* ---- 4. 松绿 · 雅致：墨绿，教育单位气质 ---- */
[data-theme="pine"] {
  --red: #1e6b52; --red-deep: #14503c; --red-soft: #eef6f2;
  --red-2: #2d8a6c; --red-shadow: 30, 107, 82;
  --bg: #f1f7f4; --line: #ddebe4; --gold: #b8914f;
  --lg-a: #14503c; --lg-b: #1e6b52; --lg-c: #2d8a6c;
}

/* ---- 5. 紫檀 · 典雅：紫罗兰，低调有辨识度 ---- */
[data-theme="sandal"] {
  --red: #5b3a7e; --red-deep: #432a5e; --red-soft: #f4f1f9;
  --red-2: #7a52a3; --red-shadow: 91, 58, 126;
  --bg: #f5f3f9; --line: #e6e0ee; --gold: #b8914f;
  --lg-a: #432a5e; --lg-b: #5b3a7e; --lg-c: #7a52a3;
}

/* ---- 6. 玄青 · 科技：蓝青，清爽现代 ---- */
[data-theme="azure"] {
  --red: #2f6f8f; --red-deep: #215267; --red-soft: #eef5f8;
  --red-2: #468aab; --red-shadow: 47, 111, 143;
  --bg: #f1f6f8; --line: #dde8ed; --gold: #b8914f;
  --lg-a: #215267; --lg-b: #2f6f8f; --lg-c: #468aab;
}

/* ==========================================================================
   v7.68 主题选择面板（色卡）
   ---------------------------------------------------------------------------
   入口：顶栏账户胶囊【左边】的 🎨 按钮（用户明确要求的位置）。
   形态：弹窗（复用项目既有的 modal 体系）——好处是移动端零额外适配，
         因为 modal() 内部已经统一处理了"先收起移动端抽屉再开弹层"。
   ========================================================================== */
.theme-grid {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: 12px; margin: 14px 0 6px;
}
.theme-card {
  display: flex; flex-direction: column; align-items: center; gap: 7px;
  padding: 12px 6px 10px; border-radius: 12px; cursor: pointer;
  border: 2px solid var(--line); background: var(--card);
  transition: border-color .15s, transform .15s, box-shadow .15s;
  position: relative; user-select: none;
}
.theme-card:hover { transform: translateY(-2px); box-shadow: 0 6px 16px rgba(var(--red-shadow), .14); }
.theme-card.on { border-color: var(--red); box-shadow: 0 0 0 3px rgba(var(--red-shadow), .12); }
/* 选中角标：避免只靠边框粗细区分（弱视/低质量屏幕下2px差不易察觉） */
.theme-card.on::after {
  content: "✓"; position: absolute; top: 5px; right: 7px;
  font-size: 12px; font-weight: 700; color: #fff; line-height: 1;
  background: var(--red); border-radius: 50%;
  width: 17px; height: 17px; display: flex; align-items: center; justify-content: center;
}
/* 色卡圆点：用主题自己的主色渲染——所见即所得。
   色值在此【必须硬编码】：它的作用正是"展示另一个主题的颜色"，
   若写成 var(--red) 会跟随当前主题变化，六张卡就全长一样了。 */
.theme-dot {
  width: 34px; height: 34px; border-radius: 50%;
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.10), 0 2px 6px rgba(0,0,0,.14);
}
.theme-dot.red    { background: linear-gradient(135deg, #c0392b, #a61b29); }
.theme-dot.ink    { background: linear-gradient(135deg, #4a4a4a, #2b2b2b); }
.theme-dot.indigo { background: linear-gradient(135deg, #2f6ea8, #1f4e79); }
.theme-dot.pine   { background: linear-gradient(135deg, #2d8a6c, #1e6b52); }
.theme-dot.sandal { background: linear-gradient(135deg, #7a52a3, #5b3a7e); }
.theme-dot.azure  { background: linear-gradient(135deg, #468aab, #2f6f8f); }
.theme-name { font-size: 12.5px; color: var(--ink); font-weight: 600; line-height: 1.2; }
.theme-name small { display: block; font-weight: 400; font-size: 11px; color: var(--muted); margin-top: 1px; }

/* 顶栏 🎨 按钮：与账户胶囊同一行的左侧。
   样式刻意贴近 .user-chip（同尺寸/同半透明底），保证视觉是一组。 */
.btn-theme {
  background: rgba(255,255,255,.16); border: 1px solid rgba(255,255,255,.35);
  color: #fff; padding: 6px 11px; border-radius: 20px; font-size: 14px; line-height: 1;
  display: inline-flex; align-items: center; gap: 5px; transition: background .15s;
}
.btn-theme:hover { background: rgba(255,255,255,.28); }
.btn-theme .btxt { font-size: 13px; }

@media (max-width: 980px) {
  /* 移动端顶栏空间极紧（v7.41 起就在为几十像素反复调），🎨 只留图标不显文字 */
  .btn-theme .btxt { display: none; }
  .btn-theme { padding: 6px 9px; }
  .theme-grid { grid-template-columns: repeat(3, 1fr); gap: 9px; }
  .theme-dot { width: 30px; height: 30px; }
  .theme-name { font-size: 11.5px; }
}

/* ==========================================================================
   v7.69 移动端非拟文页：去掉顶部「← 返回拟文」白条（2026-10-06，用户要求）
   ---------------------------------------------------------------------------
   用户原话：「移动端每个选项卡（除开拟文选项卡）顶端都有返回拟文这个按钮
   一直浮动在上面，有必要吗？个人觉得没必要一直固定浮动。」

   实测确认问题成立：
     · .actionbar 是 position:sticky / top:52px，滚动 500px 后按钮 y 坐标
       不变（实测恒为 59px），确实永远钉在顶部；
     · 移动端该白条内【只有这一个按钮】（.ab-tabs 早在 v7.25 就移入了
       「⋯ 更多功能」抽屉），却独占一整行约 44px；
     · 抽屉的「导航」区里本就有「✍️ 拟文」选项卡 —— 该按钮是冗余入口。

   处理：移动端隐藏整条 .actionbar，把导航统一收敛到抽屉，
   补完 v7.25「移动端顶部工具条全部移入抽屉」的设计。
   电脑端（min-width:981px）无抽屉、选项卡内联显示，一行不碰。

   ★ 为什么这一条【只放媒体查询、不加 body 类】：
     我最初写成 media + body:not(.with-dock)，但实测在移动端切成非拟文页时
     按钮【仍然可见】—— 说明 .actionbar 上存在优先级更高的 display:flex 规则
     压过了它。改用与相邻 .m-mini 同强度的选择器 + !important 兜底，
     与文件内既有的 body.with-dock #dockbar { display:none !important } 同一手法。
     另 js 侧也同步改为"移动端不注入该按钮"，两道保险互为兜底：
     即便将来某个浏览器不吃这条媒体查询，也不会出现空白色条。
   ========================================================================== */
@media (max-width: 980px) {
  /* 非拟文页：整条顶部操作栏不再需要（里面只剩「← 返回拟文」） */
  body:not(.with-dock) .actionbar { display: none !important; }
  /* 兜底：万一该按钮被渲染出来，也不显示（防止空条占位） */
  body:not(.with-dock) #viewOps { display: none !important; }
}


/* ============ v7.82 编辑态段落段与表格选择器 ============ */
/* 段落段：非焦点段为只读镜像（点击后 Quill 移入） */
.blk-seg { outline: none; }
.blk-seg[data-live] { min-height: 1.75em; }
.blk-seg:not([data-live]) { cursor: text; }
.blk-seg:not([data-live]):hover { background: rgba(255, 240, 225, .28); border-radius: 4px; }
.blk-seg:not([data-live]) .doc-block:empty { min-height: 1.75em; }
/* 表格网格选择弹层 */
.tbl-picker-pop {
  position: fixed; z-index: 90; background: #fff; border: 1px solid #e6d9d0;
  border-radius: 10px; box-shadow: 0 8px 24px rgba(0,0,0,.16); padding: 8px;
}
