/* 义齿设计质检系统 · 前端样式
 *
 * ⚖️ 第 91 批（业主报「录单选客户后显示很大一块」——一块黑框）：**本系统只有浅色一套设计**，
 *   所以在根上声明 `color-scheme: light`。这一句能挡住浏览器/系统的**深色模式与"强制暗色"**
 *   把界面里"没写死颜色"的块反相成黑底（白底黑字会变成黑底黑字，看上去就是一大块黑），
 *   同时让原生控件（下拉、日期选择器、滚动条）按浅色渲染。改了它整套配色一个字都不动。
 *
 * 视觉直接沿用**业主已确认的草图**（`草图\style.css`）：纯白简洁 —— 浅灰底 + 白卡片、扁平、无渐变、无重阴影。
 * 这样"你点头看过的样子"就是交付的样子，不会出现"实现出来跟草图是两回事"。
 * 底下那一大段是本文件**新增**的：真实应用需要而草图不需要的东西（弹层、表单、提示条、
 * 空态/加载态、进度条、打勾清单、3D 画布、分页、标签页、铃铛下拉等）。
 *
 * 约束：CSP 是 `style-src 'self' 'unsafe-inline'`，所以本文件可以内联样式；但 `script-src 'self'`
 * 意味着**页面里不许写内联 <script>**，所有脚本都必须在 js/ 下的文件里。
 */
* { box-sizing: border-box; }
/* 第 91 批：整套界面按**浅色**渲染（挡深色模式/强制暗色把白底反相成黑底） */
:root { color-scheme: light; }
html, body { height: 100%; }
body {
  margin: 0;
  font-family: "Microsoft YaHei", "PingFang SC", system-ui, sans-serif;
  background: #f5f6f8;
  color: #1f2430;
  font-size: 13px;
}
a { color: #2563eb; text-decoration: none; }
a:hover { text-decoration: underline; }
.mono { font-family: Consolas, "Courier New", monospace; }
.hide { display: none !important; }

/* ───────── 布局：左导航 + 主区 ─────────
   第 56 批（业主：「滑动右边的窗口的时候，左边窗口的这些工作台也会跟着一起滑动，我需要固定
   左边的工作台，不跟随右边的窗口滑动，然后把顶部右边的账号、改密码、退出这 3 个信息位置改到左下角」）：
   左栏改成**固定**（position: fixed，自己内部滚动），主区用 margin-left 让开它的宽度 ——
   这样只有右边在滚，菜单一直停在原地；账号 / 改密码 / 退出搬进左栏底部的 `.side-foot`。 */
.app { display: flex; min-height: 100vh; }
.side {
  position: fixed; top: 0; left: 0; bottom: 0; width: 196px; flex: 0 0 196px;
  background: #fff; border-right: 1px solid #e6e8ee; padding: 14px 0 0;
  display: flex; flex-direction: column; overflow: hidden; z-index: 30;
}
.logo { padding: 0 16px 14px; font-weight: 700; font-size: 15px; border-bottom: 1px solid #eef0f4; margin-bottom: 10px; }
.logo span { display: block; font-weight: 400; font-size: 11px; color: #8a92a6; margin-top: 3px; }
.nav { list-style: none; margin: 0; padding: 0; overflow-y: auto; flex: 1 1 auto; }
/* 左栏底部：当前账号 + 改密码 / 退出（第 56 批从顶栏搬过来） */
.side-foot { border-top: 1px solid #eef0f4; padding: 10px 14px 12px; background: #fff; }
.side-foot .who { color: #4b5563; font-size: 12px; margin-bottom: 8px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.side-foot .row { display: flex; gap: 8px; }
.side-foot .row .btn { flex: 1; text-align: center; }
.nav li { padding: 9px 16px; color: #4b5563; border-left: 3px solid transparent; display: flex; justify-content: space-between; align-items: center; gap: 6px; }
.nav li a { color: inherit; flex: 1; }
.nav li a:hover { text-decoration: none; }
.nav li:not(.grp):not(.off):hover { background: #f7f9fc; cursor: pointer; }
.nav li.on { background: #f0f6ff; color: #1d4ed8; border-left-color: #2563eb; font-weight: 600; }
.nav li .cnt { background: #eef1f6; color: #6b7280; border-radius: 9px; padding: 1px 7px; font-size: 11px; }
.nav li.on .cnt { background: #dbeafe; color: #1d4ed8; }
.nav .grp { padding: 12px 16px 5px; font-size: 11px; color: #9aa1b1; }
.nav li.off { color: #b9bfcb; cursor: default; }
.nav li.off .cnt { background: #f6f7f9; color: #b9bfcb; }

.main { flex: 1; min-width: 0; display: flex; flex-direction: column; margin-left: 196px; }
.top { height: 52px; background: #fff; border-bottom: 1px solid #e6e8ee; display: flex; align-items: center; gap: 14px; padding: 0 18px; position: sticky; top: 0; z-index: 20; }
.top .crumb { font-size: 14px; font-weight: 600; }
.top .sp { flex: 1; }
.top .who { color: #4b5563; }
.content { padding: 16px 18px 28px; }

/* ───────── 通用组件（与草图一致） ───────── */
.card { background: #fff; border: 1px solid #e6e8ee; border-radius: 10px; margin-bottom: 14px; }
.card > h2 { margin: 0; padding: 12px 14px; font-size: 14px; border-bottom: 1px solid #eef0f4; display: flex; align-items: center; gap: 8px; }
.card > h2 .sp { flex: 1; }
.card .bd { padding: 14px; }
.row { display: flex; gap: 12px; flex-wrap: wrap; align-items: center; }
.row.tight { gap: 8px; }
.grid { display: grid; gap: 12px; }
.g4 { grid-template-columns: repeat(4, 1fr); }
.g3 { grid-template-columns: repeat(3, 1fr); }
.g2 { grid-template-columns: repeat(2, 1fr); }
@media (max-width: 1100px) { .g4 { grid-template-columns: repeat(2, 1fr); } .g3, .g2 { grid-template-columns: 1fr; } .split { grid-template-columns: 1fr; } }

.kpi { background: #fff; border: 1px solid #e6e8ee; border-radius: 10px; padding: 12px 14px; }
.kpi .lab { color: #6b7280; font-size: 12px; }
.kpi .num { font-size: 24px; font-weight: 700; margin-top: 4px; }
.kpi .num small { font-size: 12px; font-weight: 400; color: #9aa1b1; margin-left: 4px; }
.kpi.warn .num { color: #d97706; }
.kpi.bad .num { color: #dc2626; }
.kpi.ok .num { color: #059669; }
.kpi.link { cursor: pointer; }
.kpi.link:hover { border-color: #c7dbfe; background: #fbfdff; }

.bar { background: #fff; border: 1px solid #e6e8ee; border-radius: 10px; padding: 10px 12px; margin-bottom: 12px; display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.tab { padding: 6px 11px; border-radius: 8px; color: #4b5563; border: 1px solid transparent; cursor: pointer; }
.tab.on { background: #eef4ff; color: #1d4ed8; border-color: #c7dbfe; font-weight: 600; }
.tab .n { color: #93a0b5; font-size: 11px; margin-left: 4px; }

.btn { display: inline-block; padding: 6px 12px; border-radius: 8px; border: 1px solid #d6dae3; background: #fff; color: #374151; font-size: 13px; white-space: nowrap; cursor: pointer; font-family: inherit; }
.btn:hover { border-color: #b9c2d0; }
.btn.pri { background: #2563eb; border-color: #2563eb; color: #fff; }
.btn.pri:hover { background: #1d4ed8; }
.btn.danger { background: #fff; border-color: #f0b4b4; color: #dc2626; }
.btn.ok { background: #059669; border-color: #059669; color: #fff; }
.btn.sm { padding: 3px 8px; font-size: 12px; }
.btn.dis, .btn[disabled] { background: #f3f4f6; color: #a5acba; border-color: #e6e8ee; cursor: not-allowed; }

/* ── 第 124 批（业主原话）：「对账与收款工作台里面的订单信息和表格都没有竖线把项目分开，
   要和表格一样有竖线把每个项目之间分开，和任务管理里面的订单格式一样。应收对账表格也没有竖线，
   后面只要是表格的显示都要有竖线分开，做到风格统一」。
   做法：**全站表格与任务管理那张订单表用同一套格线** —— 横竖都有 1px 细线、外面一圈边框
   （`border-collapse: collapse` 让相邻格线合成一条，不会出现 2px 的双线）。 ───────────── */
table { width: 100%; border-collapse: collapse; background: #fff; border: 1px solid #e3e7ee; }
th, td { padding: 8px 10px; text-align: left; border: 1px solid #e9ecf2; vertical-align: top; }
thead th { border-bottom-color: #dde2ea; }
th { background: #fafbfd; color: #6b7280; font-weight: 600; font-size: 12px; white-space: nowrap; }
tr.on td { background: #f7faff; }
tbody tr:hover td { background: #fbfdff; }
td .sub { color: #8a92a6; font-size: 11px; margin-top: 2px; }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }
.nowrap { white-space: nowrap; }

.tag { display: inline-block; padding: 1px 7px; border-radius: 6px; font-size: 11px; border: 1px solid #e0e4ec; background: #f7f8fb; color: #4b5563; }
.tag.blue { background: #eef4ff; border-color: #c7dbfe; color: #1d4ed8; }
.tag.amber { background: #fff7e6; border-color: #f6d99b; color: #b45309; }
.tag.red { background: #fef2f2; border-color: #f5c2c2; color: #dc2626; }
.tag.green { background: #ecfdf5; border-color: #a7e8c8; color: #047857; }
.tag.gray { background: #f3f4f6; border-color: #e5e7eb; color: #6b7280; }
.tag.purple { background: #f5f0ff; border-color: #ddd0fb; color: #6d28d9; }

/* ── 第 32/36 批：任务列表新增的三样 ─────────────────────────────────────
   ① 客户名称用颜色区分（业主：「不同客户之间的订单使用不同的颜色区分开，就把客户名称那一个
      项目使用不同颜色做区分」）—— 底色由 JS 按 customer_id 稳定算好，这里只管形状。
   ② 订单进度（第 36 批重做）：**不再单独占一行**，放在「交货日期 → 剩余时效」之间那一列；
      进度条改成**步骤之间的箭头**，箭头亮到当前步，当前步自己高亮；整条一行内联不换行。
   ③ 行高：任务表专门调紧（`.tasks-table`），一屏能多看几单 —— 业主原话
      「行高要窄让一个版面显示更多订单……每一份订单看着就是一行」。
   ──────────────────────────────────────────────────────────────────────── */
.cust { display: inline-block; padding: 1px 7px; border-radius: 999px; border: 1px solid transparent; font-size: 12px; white-space: nowrap; }

/* ── 第 57/58 批：任务详情页头 = **三块一个整体，中间用线隔开**（业主第 58 批点名）──
   顶栏一条（不再折叠）；左列上半 = 订单信息（照任务管理那一行的模板，只到"订单进度"之前）
   左列下半 = 订单进度；右边一列 = 备注与要求（窄一档）；最下面一条 = 其它操作 */
.task-head .head-bar { display: flex; align-items: center; gap: 10px; flex-wrap: nowrap; }
.task-head .head-bar .hname { font-weight: 600; max-width: 32%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.task-head .head-bar .btn.big { height: 38px; padding: 0 18px; border-radius: 19px; font-size: 14px; font-weight: 600; }
.task-head .head-grid { display: grid; grid-template-columns: minmax(0, 1.8fr) minmax(230px, 1fr); border-top: 1px solid #eef0f4; }
.task-head .hg-left { display: flex; flex-direction: column; border-right: 1px solid #eef0f4; min-width: 0; }
.task-head .hg-info { padding: 11px 14px 9px; }
/* 第 63 批：左上那块「订单信息」现在是**一张和任务管理同一份的小表**（task-row.js 渲染）——
   以前是十几个"标签+值"横向换行，宽度随文字长短变，看着是歪的（业主原话）。
   ⚠️ 表宽**必须用它自己那串固定列宽**（`<table style="width:964px">` + colgroup），不要把宽度改成
   auto —— 改了之后浏览器会按内容缩，列宽就不固定了、长订单还会顶到右边那块上去。
   左列比 964px 还窄（小屏）时就在这一块里横滚，不影响右边的「备注与要求」。 */
.task-head .hg-table { overflow-x: auto; overflow-y: hidden; }
/* 兜底横滚的滑条做细一点（正常屏宽度下它不会出现） */
.task-head .hg-table::-webkit-scrollbar { height: 6px; }
.task-head .hg-table::-webkit-scrollbar-thumb { background: #ccd3df; border-radius: 3px; }
.task-head .hg-table .tasks-table { border: 0; }
/* ⚖️ 第 113 批（业主原话：「订单详情页面的订单信息**没有竖着的框线**，每个项目之间加上框线」）：
   原来这一块把格线全关了（`border: 0`）—— 现在**恢复成和任务管理那张表一样的网格**
   （横竖都有 1px 细线），每个项目之间看得出来是分开的。
   内边距也从"3px 10px 3px 0"改成"4px 10px"：有框线之后行首不能再顶到边上。 */
.task-head .hg-table .tasks-table th,
.task-head .hg-table .tasks-table td { border: 1px solid #e9ecf2; padding: 4px 10px; }
.task-head .hg-table .tasks-table thead th { background: transparent; font-weight: 600; color: #6b7280; font-size: 12px; position: static; }
/* 下面那条补充信息（交货日期 / 打回·文件 / 设计软件）：也是"标签 + 值"，固定标签宽度才对齐 */
.task-head .hg-extra { margin-top: 8px; padding-top: 7px; border-top: 1px dashed #eef0f4; gap: 6px 20px; }
.task-head .hg-flow { border-top: 1px solid #eef0f4; padding: 10px 14px 12px; }
.task-head .hg-right { padding: 11px 14px 12px; min-width: 0; }
.task-head .hg-t { display: flex; align-items: center; color: #6b7280; font-size: 12px; font-weight: 600; margin-bottom: 8px; }
.task-head #req-box { font-size: 13px; line-height: 1.6; white-space: pre-wrap; word-break: break-word; }
.task-head #req-box.empty { color: #a2a9b8; }
.task-head .head-ops { border-top: 1px solid #eef0f4; }
/* 第 58 批：操作列**两小排**（上面 改单/复制/领取/退单，下面 当前订单浏览） */
.ops-row { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; }
/* ⚖️ 第 59 批（业主原话：「任务管理这里的订单每行占用行高有点多了，我看是因为改单和当前订单浏览这两行
   字体过大导致的，吧这两行改小，**行高与工作台里面的订单行高一样**」）：
   实测两屏：任务管理 **71px** / 工作台 **46.5px** —— 差的那 24px 全在操作列上，因为全站按钮是第 55 批
   的"大圆角玻璃按钮"（30px 高），两排 30px + 4px 间距 + 上下内边距 10px 就把行撑到 71。
   所以**只把这一张表操作列里的按钮压小**（高 17px、字号 11px、两排间距 2px → 行高回到 ~46px，与工作台一致）。
   ⚠️ 作用域必须留在 `.tasks-table td .ops-row` 里 —— 别动全站 `.btn.sm`（顶栏、卡片、弹层里的按钮都靠它）。 */
.tasks-table td .ops-row { gap: 3px; }
.tasks-table td .ops-row .btn,
.tasks-table td .ops-row .btn.sm {
  height: 17px; min-height: 0; padding: 0 6px; font-size: 11px; line-height: 15px; border-radius: 5px;
}
/* 两小排之间的间距：`.mt4` 是给卡片用的 4px，这儿要跟按钮一起收一档 */
.tasks-table td .ops-row + .ops-row { margin-top: 2px; }
/* ③ 右栏折叠卡（时间轴）也做成一张白纸卡的样子 */
details.card { display: block; }
details.card > summary { list-style: none; }
details.card > summary::-webkit-details-marker { display: none; }
details.card > summary::after { content: ' ▾'; color: #9aa1b1; }
details.card[open] > summary::after { content: ' ▴'; }

/* 任务表：紧凑行（只作用于这一张表，别动全站的其他表格）
   第 38 批业主反馈"行高稍微再高一点点，现在稍微有点紧凑" → 内边距从 3px 8px 放到 5px 10px，
   小字行也松一档（字号 11px、行距 1.3），但**仍然是一行字那么高**，一屏还是能放很多单。 */
.tasks-table th, .tasks-table td { padding: 5px 10px; line-height: 1.4; vertical-align: middle; }
.tasks-table td .sub { margin-top: 0; font-size: 11px; line-height: 1.3; }
.tasks-table .sub-i { color: #9aa1b1; font-size: 11px; }
.tasks-table tr.returned > td { opacity: .65; }

/* 第 52 批（业主：「每个项目之间用一条线隔开，相当于横纵和表格一样都要用线隔开」）：
   订单表原来是"只有横线"（每行底边一条），看着像一列列浮着；现在补上**竖线 + 外框**，
   横竖都成格 —— 只作用于 .tasks-table（任务管理与工作台这两张订单表），全站其它表格不动。 */
.tasks-table { border: 1px solid #e3e7ee; }
.tasks-table th, .tasks-table td { border: 1px solid #e9ecf2; }
.tasks-table thead th { border-bottom-color: #dde2ea; }
/* 第 58 批：表头里"上下两小行"的那种列（批次 / 剩余时效、发货时间 / 要求回传时间），
   第二行比第一行浅一档，和格子里的小字对得上 */
.tasks-table thead th .h2l { display: block; font-weight: 600; color: #98a1b5; font-size: 11px; margin-top: 1px; }

/* 「交货日期 / 时间 / 剩余时效」合成的一格（第 37 批）：
   第一行是三个时间项目（还是挨着），第二行 10px 小字放"进度 + 最后操作"。
   为什么合并：进度单占一列之后表格宽到一屏放不下；并成一格既保住三个项目，又把列数降下来。 */
.tasks-table .timcell { max-width: 560px; }
.tasks-table .timcell .tline { display: flex; align-items: center; gap: 5px; white-space: nowrap; }
.tasks-table .timcell .tline .dot { color: #c9ced9; }
/* 第 52 批：那一格里的三个项目（发货 / 要求回传 / 剩余时效）也用**真竖线**隔开 —— 业主说
   "每个项目之间用一条线隔开"，原来只是个竖杠字符（|），现在换成一根 1px 的线，与格线同色。 */
.tasks-table .timcell .tline .dot { font-size: 0; display: inline-block; width: 0; height: 13px; border-left: 1px solid #e3e7ee; margin: 0 7px; flex: none; }
/* 小巧的项目名（发货 / 要求回传）：灰、小一号 —— 三个值挨着排，没有名字会分不清哪个是哪个 */
.tasks-table .timcell .tline .lbl { color: #9aa1b1; font-size: 11px; }
.tasks-table .timcell .sline { display: flex; align-items: center; gap: 5px; white-space: nowrap; margin-top: 2px; }
.tasks-table .timcell .sline .sub { color: #9aa1b1; font-size: 11px; }

/* ── 第 58 批（业主：「把发货日期与时间和回传日期与时间分两小行放，上面是发货时间，下面是回传时间，
   把剩余时间放到批次哪里，相当于改成批次/剩余时效，也是两行」「批次和时效文字对齐」「发货时间和
   要求回传时间对齐」「进度放到与其他信息同一行的」）：
   · 「批次 / 剩余时效」和「发货 / 要求回传」两格改成**上下两小行**；
   · 进度从"时间格里的第二行小字"独立成**一列**（.flowcell）；
   · 上下两行的**文字左边缘**必须对齐 —— 批次那行缩进 7px（＝下面胶囊的内边距），
     时间那两行都**不缩进**（两行都是"标签 + 值"，标签等宽就对得齐）。
   行高仍然是第 38 批定的 5px 10px 内边距（两小行自然比原来高，一屏还是能看十几单）。

   ⚠️ 这里踩了两个坑，都记下来免得再犯：
     ① 一开始给"两小行"统一加了 7px 缩进 → 时间格变成"上行缩进、下行没缩"，两行错开 7px，
        业主一眼就看出来了。所以缩进只给**批次**那一格（.cell2.batch）。
     ② 小标签原本叫 `.lb`，而全站**已经有一个 `.lb`**（图片灯箱：min(88vh,900px) 高 + 近黑底色）——
        撞名之后每个"发货/回传"标签都变成 900px 高的黑条，整行被顶到 868px（真浏览器门禁的
        "行高 ≤ 80px" 当场报警）。所以改名 `.cell-k`。
        教训：加短类名之前先全站搜一遍（`.l1/.l2` 也确认过只有 `.qitem .l1` 这种带前缀的用法）。 */
.tasks-table .cell2 .l1, .tasks-table .cell2 .l2 { display: flex; align-items: center; gap: 5px; line-height: 1.25; }
.tasks-table .cell2 .l2 { margin-top: 3px; }
.tasks-table .cell2 .cell-k { color: #9aa1b1; font-size: 11px; flex: none; }
.tasks-table .cell2 .v { color: #374151; }
.tasks-table .cell2.batch .l1 { padding-left: 7px; }
.tasks-table .cell2.time .cell-k { width: 22px; }   /* 「发货」「回传」都是两个字，等宽即对齐 */
/* 第 86 批：**订单名称**那一格是两小行（订单名称 + 设计要求原文）。
   要求那一行**不带"要求"这个标签**（业主要求直接显示原文，例如填了"美观"就显示"美观"），
   所以它从格子左边缘起排、与上面的订单名称对齐；过长就省略号 + 悬停看全文。
   （业主要求先放"系统单号下面"，随后改口"放到订单名称下面"、再去掉"要求"标签。） */
.tasks-table .cell2.order { align-items: flex-start; }
.tasks-table .cell2.order .l1 { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }
.tasks-table .cell2.order .l2 { overflow: hidden; }
.tasks-table .cell2.order .v.req { display: inline; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; vertical-align: bottom; }
.tasks-table .flowcell { min-width: 440px; }

/* ── 第 98 批（业主选的方案 2）：整行按客户上极淡底 + 行首色条 + 分段进度条 ──────────
   ① 整行淡底：由 JS 写在 `<tr style="background:…;--c:…">` 上（色值取自 api.CUST_COLORS 的
      row / fg）。退单的行不参与（整行置灰，与以前一致）。
   ② 行首色条：第一个格子的内阴影 —— 底色调淡之后，"这是哪家客户"主要靠这条 4px 竖条。
   ③ 分段进度条：`.flowseg` —— 第 98 批把"7 个方框排成一长串"换成"N 段小格 + 当前步的名字"
      （业主原话：「订单进度看着也怪怪的」）。
   ⚠️ 悬停高亮**不能**再写死蓝底（会把客户色盖掉）→ 用 filter 压暗一档。
   ⚠️ 上面第 58 批那套 `.cell2`（上下两小行）**保留不动**：任务详情页那块"订单信息"还在用
      两小行的口径（compact 版），列表这边只是不再渲染它了。 */
.tasks-table tbody tr[style] > td:first-child { box-shadow: inset 4px 0 0 var(--c, transparent); }
.tasks-table tbody tr[style]:hover > td { filter: brightness(.985); }
.flowseg { display: inline-flex; align-items: center; gap: 4px; vertical-align: middle; }
.flowseg .s { width: 26px; height: 7px; border-radius: 4px; background: #e2e7f0; flex: none; }
.flowseg .s.done { background: #7ea9f5; }
.flowseg .s.now { background: #2563eb; }
.flowseg .lab { margin-left: 8px; font-size: 12.5px; font-weight: 700; color: #2563eb; }

/* 第 58 批：进度独立成一列之后，这张表**比小屏宽**（11 列 ≈ 1570px）。
   业主的机器是 1854+ 宽，一屏放得下；但车间也有 1440 的小屏，那时候**不能把右边的"操作"列切掉**
   （业主最早就骂过"被右边的窗口挡住了一部分"）。所以给它一个横向滚动条：
   宽度够就完全不动，不够就滚 —— 宁可滚，不可切。

   ⚖️ 第 62 批（业主原话：「现在屏幕滑动的滑条在屏幕下面隐藏掉的，**每次需要滑动订单到最下面才能看到
   底部的滑条**，吧滑条改到屏幕最下方固定」）：
   原来 `.tablewrap` 是**普通文档流**里的一个盒子，它的横向滚动条在**整张表的底部**（实测在 1802px 处，
   而视口只有 758px 高）—— 于是"要往下滚一整页才能拖动横向滑条"。
   改法：把这一块做成**视口内自己的滚动区**（`max-height` 卡在视口高度以内 + `overflow: auto`），
   于是纵向、横向两条滚动条**永远都在这块区域的底边 = 屏幕下方**，不用再把整页滚到底。
   表头跟着 `position: sticky` 钉在这块区域的顶部（滚订单的时候列名一直在）。 */
/* 高度由 `taskRow.fitWrap()` 按"它在视口里的位置"现算（见 web/js/task-row.js）；
   这里的 `max-height` 只是"JS 还没跑起来/跑失败"时的兜底值。 */
.tablewrap { overflow: auto; max-height: calc(100vh - 300px); }
/* 表**按内容自身的宽度**排版（width:max-content），不够宽时整张表横向滚 —— 这样任何一列都不会被压窄。
   ⚠️ 不能只写 width:100%：那样表会缩到容器宽，被压窄的列（订单名称那种中文）就会折成三行，
   看着像"排版炸了"（第一次就是这样）。min-width:100% 保证窗口很宽时表仍然铺满、不留空隙。 */
.tablewrap > .tasks-table { width: max-content; min-width: 100%; }
/* 第 62 批：表头钉住（这个滚动区自己滚的时候列名不跟着跑） */
.tablewrap > .tasks-table thead th { position: sticky; top: 0; z-index: 3; background: #f7f9fc; }
.tablewrap::-webkit-scrollbar { height: 10px; width: 10px; }
.tablewrap::-webkit-scrollbar-thumb { background: #c2cad8; border-radius: 5px; }
.tablewrap::-webkit-scrollbar-track { background: #eef1f6; }

/* 第 62 批（业主：「任务管理里面现在一个页面显示不完一整个订单，订单太长有的项目可以固定宽度，
   多的不显示出来隐藏就是」）：**列宽固定 + 超长省略号**，行里不再被长文字顶宽。
   宽度由 `task-row.js` 的 `<colgroup>` 给出（那一份知道"有没有勾选框 / 操作列"），
   这里只负责"超出的部分裁剪 + 悬停能看到全文"（全文放在 title 里）。 */
.tablewrap > .tasks-table { table-layout: fixed; }
.tasks-table th, .tasks-table td { overflow: hidden; text-overflow: ellipsis; }
/* 两小行的格子与进度链自己会裁剪，不需要省略号（它们是 flex/nowrap 结构） */
.tasks-table td.cell2, .tasks-table td.flowcell { text-overflow: clip; }

/* 进度：一行内联的"步骤 —箭头→ 步骤"，箭头亮到当前步（小字版，跟着 .sline 走） */
.flowline { display: inline-flex; align-items: center; white-space: nowrap; font-size: 10px; line-height: 1.15; }
/* ⚖️ 第 59 批（业主原话：「当前步骤的字体是加粗了的，不是当前步骤的没加粗，**都加粗字体**」）：
   10 步**全部加粗**（600），当前步再重一档（700）—— 这样扫一眼是"链条厚实"，不是"只有一个字厚"。 */
.flowline .st { display: inline-block; padding: 0 4px; border-radius: 4px; color: #9aa1b1; background: #f6f7fa; border: 1px solid #edeff4; font-weight: 600; }
.flowline .st.done { color: #1d4ed8; background: #eef4ff; border-color: #c7dbfe; }
/* 橙色（.rework）**只在"这一关真的被打回改过"时才有** —— 判据在 api.js 的 flowLine 里按
   setup_reject_count / result_reject_count 给（第 59 批业主：「没打回修改的话这两个颜色改成一样，
   打回修改了的颜色才做区分」）。这两个类本身不删，等着 api.js 来加。 */
.flowline .st.done.rework { color: #b45309; background: #fff7e6; border-color: #f6d99b; }
.flowline .st.now { color: #fff; background: #2563eb; border-color: #2563eb; font-weight: 700; }
.flowline .st.now.rework { background: #d97706; border-color: #d97706; }
/* 箭头：用一个 CSS 三角 + 一小段线，比字符更整齐、也不受字体影响 */
.flowline .ar { position: relative; width: 11px; height: 9px; margin: 0 1px; flex: none; }
.flowline .ar::before { content: ''; position: absolute; left: 0; top: 4px; width: 6px; height: 1.5px; background: #e2e5ec; border-radius: 1px; }
.flowline .ar::after { content: ''; position: absolute; left: 5px; top: 1px; width: 0; height: 0; border-left: 4px solid #e2e5ec; border-top: 3.5px solid transparent; border-bottom: 3.5px solid transparent; }
.flowline .ar.lit::before { background: #2563eb; }
.flowline .ar.lit::after { border-left-color: #2563eb; }

/* ── 第 54 批：图片预览器（在黑底上翻页看图，不再一张张点开新窗口） ────────────── */
.lb-mask { position: fixed; inset: 0; background: rgba(17, 20, 26, .82); z-index: 120; display: flex; align-items: center; justify-content: center; }
.lb { width: min(1180px, 94vw); height: min(88vh, 900px); background: #12151b; border: 1px solid #2a2f3a; border-radius: 12px; display: flex; flex-direction: column; overflow: hidden; }
.lb-top { display: flex; align-items: center; gap: 8px; padding: 8px 10px; border-bottom: 1px solid #262b35; color: #e8ebf2; }
.lb-top .lb-name { font-size: 13px; color: #cfd6e4; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 46%; }
.lb-top .sp { flex: 1; }
.lb-top .btn.sm { background: #222833; border-color: #333b49; color: #dbe2ee; }
.lb-top .x { cursor: pointer; font-size: 20px; line-height: 1; padding: 0 6px; color: #98a2b6; }
.lb-top .x:hover { color: #fff; }
.lb-body { position: relative; flex: 1; display: flex; align-items: center; justify-content: center; min-height: 0; padding: 10px; }
.lb-body img { max-width: 100%; max-height: 100%; object-fit: contain; background: #0d1015; border-radius: 6px; transition: transform .12s ease; }
.lb-nav { position: absolute; top: 50%; transform: translateY(-50%); width: 44px; height: 68px; border: 1px solid #333b49; background: rgba(34, 40, 51, .88); color: #e8ebf2; font-size: 26px; line-height: 1; cursor: pointer; border-radius: 8px; }
.lb-nav:hover { background: #2c3341; }
.lb-nav.prev { left: 6px; }
.lb-nav.next { right: 6px; }
.lb-foot { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-top: 1px solid #262b35; color: #98a2b6; font-size: 12px; }
.lb-foot .sp { flex: 1; }
.lb-foot .btn.sm { background: #222833; border-color: #333b49; color: #dbe2ee; }
.lb-mask.single .lb-nav, .lb-mask.single .lb-foot [data-lbprev2], .lb-mask.single .lb-foot [data-lbnext2] { display: none; }

.alert { background: #fffbeb; border: 1px solid #f8e3ae; border-radius: 10px; padding: 10px 12px; margin-bottom: 12px; display: flex; gap: 10px; align-items: flex-start; }
.alert.info { background: #f0f7ff; border-color: #c7dbfe; }
.alert.bad { background: #fef2f2; border-color: #f5c2c2; }
.alert.ok { background: #ecfdf5; border-color: #a7e8c8; }
.alert b { font-weight: 700; }
.alert .sp { flex: 1; }

.pager { display: flex; gap: 6px; align-items: center; padding: 10px 12px; color: #6b7280; border-top: 1px solid #eef0f4; }
.pager .p { padding: 3px 9px; border: 1px solid #e6e8ee; border-radius: 6px; background: #fff; cursor: pointer; }
.pager .p.on { background: #2563eb; border-color: #2563eb; color: #fff; }
.pager .sp { flex: 1; }

.note { color: #8a92a6; font-size: 12px; }
.hint { color: #9aa1b1; font-size: 12px; margin-top: 6px; }
.filelist { list-style: none; margin: 0; padding: 0; }
.filelist li { display: flex; align-items: center; gap: 8px; padding: 7px 10px; border: 1px solid #eef0f4; border-radius: 8px; margin-bottom: 6px; background: #fff; }
.filelist li .nm { flex: 1; min-width: 0; }
.filelist li .nm b { font-weight: 600; }

/* ── 第 91 批：投递口「认不出的文件夹」那一屏 ──────────────────────────────────────
   业主三条：①「所有的客户是在一起的，没办法很好的区分，最好是可以筛选客户」
            ②「只能一个一个点用这个文件夹建单，改成可以批量建单」
   所以这一屏多了：一条筛选/批量工具条（.iu-bar）、行首的勾选框（.iu-pick）、
   以及"全部客户"时的分组小标题（.iu-group-hd）。 */
.iu-bar { display: flex; align-items: flex-end; gap: 8px; flex-wrap: wrap; margin: 0 0 10px; }
.iu-bar .sp { flex: 1; }
.iu-group { margin-bottom: 12px; }
.iu-group-hd { display: flex; align-items: center; gap: 8px; margin: 0 0 5px; color: #2d3550; font-size: 13px; }
.iu-pick { flex: none; display: inline-flex; align-items: center; }
.iu-pick input { width: 16px; height: 16px; margin: 0; cursor: pointer; }
.hist { color: #8a92a6; font-size: 11px; }
.split { display: grid; grid-template-columns: 1.35fr 1fr; gap: 14px; align-items: start; }
.split.wide { grid-template-columns: 1fr 340px; }
.split.wide2 { grid-template-columns: 340px 1fr; }

/* 第 33 批：两栏**各占一半**（质检台的"队列 ↔ 判定"、排班台的两个组名单都用它）
   为什么不用 1.35fr/1fr：队列那栏原来只有 1/2.35 宽，单号 + 订单名 + 客户挤成一团、
   最后一列还被右边压掉 —— 业主原话"被右边的窗口挡住了一部分"。 */
.split.half { grid-template-columns: 1fr 1fr; }
/* ⚖️ 第 124 批：全站表格加竖线格线之后，排班台左边那张组名单的 min-content 大了一点，
   于是 `1fr 1fr` 被撑成 624/574（真浏览器门禁当场报"两栏不是各占一半"）。
   `min-width: 0` 让两栏**严格各占一半**，表里的字按自己的列宽换行（表格仍是 width:100%，不会溢出去）。 */
.split.half > * { min-width: 0; }

/* 窄屏（车间的老显示器/平板）退成一栏，别硬挤 */
@media (max-width: 1200px) {
  .split.half { grid-template-columns: 1fr; }
}

/* 第 34 批：质检台「待检队列」的一行一块
   为什么不用表格：表格在窄栏里会被 nowrap 挤掉字、最后一列还会被右栏压住（业主原话
   "显示的订单信息不全并且被右边的窗口挡住了一部分"）。卡片流没有"列宽"这回事，信息一定给全。
   ⚠️ **第 68 批起这张卡片流已被"任务管理那张表"取代**（业主要求格式一致），
   所以 `.qlist/.qitem` 这几条只剩历史意义（下面第 68 批那一段是新口径）。 */
.qlist { max-height: calc(100vh - 260px); overflow: auto; }
.qitem { padding: 8px 12px; border-bottom: 1px solid #eef0f4; }
.qitem:hover { background: #fbfdff; }
.qitem.on { background: #eef4ff; box-shadow: inset 3px 0 0 #2563eb; }
.qitem .l1 { display: flex; align-items: center; gap: 6px; }
.qitem .l2 { margin-top: 2px; font-weight: 600; color: #1f2937; word-break: break-all; }
.qitem .l3 { margin-top: 2px; color: #6b7280; font-size: 12px; display: flex; flex-wrap: wrap; gap: 5px; }

/* ───────── 第 68 批：质检台两栏 ─────────
   业主两条：
     ①「左边订单详情格式要与任务管理的格式相同…左边只显示任务管理订单里面，订单进度以前的内容即可」
        → 左栏现在是**任务管理那张表**（紧凑版 880px 宽），所以左栏要够宽（比一半稍宽一点）；
     ②「现在在这个界面滑动左右两个窗口是一起动的，把他们分开，鼠标在那边滑动那边就滑动，另外一边不动」
        → 两栏**各自是自己的滚动容器**（左 = 订单表 `.tablewrap`，右 = 详情那一串卡片），
          都带 `overscroll-behavior: contain`：在某一栏里滚到底**不会再"接着滚整页"**把另一栏带着动。 */
.qc-split { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 14px; align-items: start; }
/* 宽屏（业主那台是 1854）：左栏**定到 920px**，正好装下"任务管理那张表"（紧凑版 880px + 表格线），
   8 列全看得见、不用横滚；右边剩下的地方给详情（还有 700px 左右，够）。窄屏仍按各占一半。 */
@media (min-width: 1700px) {
  .qc-split { grid-template-columns: minmax(0, 920px) minmax(0, 1fr); }
}
#queue-col .tablewrap, #judge-col { overflow: auto; overscroll-behavior: contain; }
#judge-col { padding-right: 4px; }
#queue-col .tasks-table tr[data-id] { cursor: pointer; }
.tasks-table tr.on > td { background: #eef5ff; }
.tasks-table tr.on > td:first-child { box-shadow: inset 3px 0 0 #0a84ff; }
@media (max-width: 1200px) {
  .qc-split { grid-template-columns: 1fr; }
}

/* ───────── 以下是本文件新增（草图里没有、真实应用要用的） ───────── */

/* 表单 */
label.f { display: block; margin-bottom: 10px; }
label.f > span { display: block; color: #4b5563; margin-bottom: 4px; font-size: 12px; }
label.f > span .req { color: #dc2626; margin-left: 2px; }
input[type=text], input[type=password], input[type=date], input[type=number], input[type=search], select, textarea {
  width: 100%; padding: 6px 9px; border: 1px solid #d6dae3; border-radius: 8px; font-size: 13px;
  font-family: inherit; background: #fff; color: #1f2430;
}
input:focus, select:focus, textarea:focus { outline: none; border-color: #2563eb; box-shadow: 0 0 0 3px #e8f0ff; }
input[disabled], select[disabled], textarea[disabled] { background: #f7f8fa; color: #9aa1b1; }
input[type=checkbox], input[type=radio] { width: auto; }
textarea { min-height: 68px; resize: vertical; }
.f-err { color: #dc2626; font-size: 12px; margin-top: 3px; }
.inline { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.inline > input, .inline > select { width: auto; min-width: 120px; }
.f-row { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }

/* ⚖️ 第 96 批：原来这里有一套"自绘彩色下拉"（.cs / .cs-btn / .cs-pop / .cs-row）。业主两次报修
   「选客户后一大块黑的、字看不见」—— 自绘那层的颜色、大小全归页面管，深色模式 / 强制暗色 / 深色插件 /
   旧缓存都可能把"白底深字"反相成"黑底深字"。现在换成**系统自带的下拉**（原生 <select> + 行内配色 +
   字段上一个客户色圆点）：下拉列表由浏览器/系统画，页面样式碰不到它，任何主题下都看得清。
   这一套 .cs* 样式随之删掉（`ui.colorSelect` 里已经一个字都不引用了）。 */

/* 登录页 */
.login-wrap { min-height: 100vh; display: flex; align-items: center; justify-content: center; background: #f0f2f6; padding: 20px; }
.login-box { width: 360px; background: #fff; border: 1px solid #e6e8ee; border-radius: 12px; padding: 26px 24px; }
.login-box h1 { margin: 0 0 4px; font-size: 18px; }
.login-box .sub { color: #8a92a6; font-size: 12px; margin-bottom: 18px; }
.login-box .btn { width: 100%; text-align: center; padding: 8px; }
.login-box .foot { margin-top: 14px; color: #9aa1b1; font-size: 12px; text-align: center; }

/* 弹层 */
.mask { position: fixed; inset: 0; background: rgba(17, 24, 39, 0.45); display: flex; align-items: flex-start; justify-content: center; padding: 40px 16px; z-index: 50; overflow: auto; }
.modal { background: #fff; border-radius: 12px; width: 100%; max-width: 640px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.18); }
.modal.wide { max-width: 900px; }
.modal > h3 { margin: 0; padding: 14px 16px; border-bottom: 1px solid #eef0f4; font-size: 15px; display: flex; align-items: center; gap: 8px; }
.modal > h3 .sp { flex: 1; }
.modal > h3 .x { cursor: pointer; color: #9aa1b1; font-size: 18px; line-height: 1; }
.modal .bd { padding: 16px; }
.modal .ft { padding: 12px 16px; border-top: 1px solid #eef0f4; display: flex; gap: 8px; justify-content: flex-end; }
/* 第 34 批：字段一多（"改订单信息"现在是 9 个字段），弹层会比屏幕还高 ——
   原来整块靠遮罩滚动，"保存/取消"被顶到屏幕外，用户以为没按钮（真浏览器门禁就是这么卡住的）。
   改成：标题与按钮固定在弹层里，只有中间那截滚动。 */
.modal { max-height: calc(100vh - 80px); display: flex; flex-direction: column; }
.modal .bd { overflow: auto; }
.modal > h3, .modal .ft { flex: 0 0 auto; }

/* 提示条 / 空态 / 加载 */
#toasts { position: fixed; right: 16px; bottom: 16px; z-index: 90; display: flex; flex-direction: column; gap: 8px; }
.toast { background: #111827; color: #f3f4f6; padding: 9px 13px; border-radius: 8px; max-width: 380px; font-size: 13px; box-shadow: 0 6px 18px rgba(0, 0, 0, 0.2); }
.toast.err { background: #b91c1c; }
.toast.ok { background: #047857; }
.empty { color: #9aa1b1; padding: 22px; text-align: center; }

/* ⚖️ 第 88 批：「别的账号改了东西」的提示条（业主选的口径：**不打断**正在打字的人，
   只在底部中间弹一条，点「刷新」才真的重拉；见 web/js/api.js 的 api.watchServer）。
   放在底部**中间**是有意的：右下角是 toast 的地盘，两条叠在一起会互相盖住。 */
.upd-chip {
  position: fixed; left: 50%; bottom: 18px; transform: translate(-50%, 24px); z-index: 88;
  display: none; align-items: center; gap: 10px;
  padding: 8px 10px 8px 14px; border-radius: 999px;
  background: #111827; color: #f3f4f6; font-size: 13px;
  box-shadow: 0 10px 26px -8px rgba(10, 16, 34, .55);
  transition: opacity .16s ease, transform .16s ease; opacity: 0;
}
.upd-chip.show { display: flex; opacity: 1; transform: translate(-50%, 0); }
.upd-chip .dot { width: 8px; height: 8px; border-radius: 50%; background: #38bdf8; box-shadow: 0 0 0 4px rgba(56, 189, 248, .18); }
.upd-chip .t { white-space: nowrap; }
.upd-chip .go { border: 0; border-radius: 999px; padding: 4px 12px; font-size: 12.5px; cursor: pointer; background: #2563eb; color: #fff; }
.upd-chip .go:hover { background: #1d4ed8; }
.upd-chip .x { border: 0; background: transparent; color: #9aa4b8; font-size: 16px; line-height: 1; cursor: pointer; padding: 0 4px; }
.upd-chip .x:hover { color: #e5e7eb; }

.loading { color: #9aa1b1; padding: 18px; text-align: center; }
.skel { background: linear-gradient(90deg, #f2f4f7, #e9edf3, #f2f4f7); border-radius: 6px; height: 12px; }

/* 进度条 */
.prog { height: 8px; background: #eef1f6; border-radius: 6px; overflow: hidden; }
.prog > i { display: block; height: 100%; background: #2563eb; width: 0; transition: width 0.3s; }
.prog.ok > i { background: #059669; }
.prog.bad > i { background: #dc2626; }

/* 打勾清单 */
.checks { list-style: none; margin: 0; padding: 0; }
.checks li { display: flex; align-items: flex-start; gap: 8px; padding: 7px 4px; border-bottom: 1px solid #f2f4f7; }
.checks li:last-child { border-bottom: none; }
.checks li .t { flex: 1; }
.checks li.no { color: #b45309; }

/* 铃铛与下拉 */
.bell { position: relative; padding: 4px 6px; border: 1px solid #e6e8ee; border-radius: 8px; background: #fff; cursor: pointer; }
.bell i { position: absolute; top: -5px; right: -5px; background: #ef4444; color: #fff; border-radius: 9px; font-size: 10px; font-style: normal; padding: 1px 5px; }
.dropdown { position: absolute; right: 14px; top: 48px; width: 360px; background: #fff; border: 1px solid #e6e8ee; border-radius: 10px; box-shadow: 0 10px 26px rgba(0, 0, 0, 0.12); z-index: 40; max-height: 70vh; overflow: auto; }
.dropdown h4 { margin: 0; padding: 10px 12px; border-bottom: 1px solid #eef0f4; font-size: 13px; display: flex; align-items: center; gap: 8px; }
.dropdown h4 .sp { flex: 1; }
.msg { padding: 10px 12px; border-bottom: 1px solid #f4f6f9; cursor: pointer; }
.msg:hover { background: #fbfdff; }
.msg.unread { background: #f7faff; }
.msg .ti { font-weight: 600; }
.msg .bd { color: #6b7280; font-size: 12px; margin-top: 2px; }
.msg .mt { color: #9aa1b1; font-size: 11px; margin-top: 3px; display: flex; gap: 8px; }

/* 走势图（纯 CSS 柱状，不引图表库） */
.chart { display: flex; align-items: flex-end; gap: 10px; height: 130px; padding: 6px 2px 0; }
.chart .col { flex: 1; display: flex; flex-direction: column; justify-content: flex-end; align-items: center; gap: 3px; height: 100%; }
.chart .stack { width: 100%; display: flex; flex-direction: column; justify-content: flex-end; align-items: center; gap: 2px; height: 100%; }
.chart .b { width: 70%; border-radius: 4px 4px 0 0; background: #93c5fd; min-height: 2px; }
.chart .b.pass { background: #6ee7b7; }
.chart .lbl { color: #9aa1b1; font-size: 11px; }
.chart .vv { color: #6b7280; font-size: 11px; }
.legend { display: flex; gap: 12px; color: #6b7280; font-size: 12px; }
.legend i { display: inline-block; width: 10px; height: 10px; border-radius: 3px; margin-right: 4px; }

/* ── 第 35 批：统计报表的图形（业主：「现在只有数据显示没有图形显示，给重要数据加上图形统计显示」）
   零依赖、纯 CSS：横向条形（排行/对比）+ 纵向柱状（趋势）+ 单条占比条。
   配色沿用项目里那套语义色：ok=绿、warn=黄、bad=红、blue=蓝、gray=灰；数值都直接写在图形上。 ── */
.grid.g2 { grid-template-columns: 1fr 1fr; }
.grid.g3 { grid-template-columns: 1fr 1fr 1fr; }
@media (max-width: 1100px) { .grid.g2, .grid.g3 { grid-template-columns: 1fr; } }

.hbars { display: flex; flex-direction: column; gap: 7px; }
.hbars .hb { display: grid; grid-template-columns: 150px 1fr 74px; align-items: center; gap: 8px; }
/* ⚠️ 第 62 批：这个类名原来是 `.lb`，与**全站图片灯箱的 `.lb`** 撞名（灯箱是 1180×900 的近黑盒子）
   → 排行里每一条都渲染成一块**大黑板**（业主：「打回分析和时效性里面的表格是很大的黑板」）。
   改名 `.hb-lb`。教训与第 58 批的 `.cell-k` 一样：**加短类名之前先全站搜一遍**。 */
.hbars .hb .hb-lb { color: #4b5563; font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hbars .hb .tr { background: #f1f3f7; border-radius: 5px; height: 16px; overflow: hidden; }
.hbars .hb .fl { height: 100%; background: #93c5fd; border-radius: 5px 0 0 5px; transition: width .3s; min-width: 2px; }
.hbars .hb .fl.ok { background: #6ee7b7; }
.hbars .hb .fl.warn { background: #fcd34d; }
.hbars .hb .fl.bad { background: #fca5a5; }
.hbars .hb .fl.gray { background: #d1d5db; }
.hbars .hb .vl { text-align: right; font-variant-numeric: tabular-nums; font-size: 12px; color: #374151; }
.hbars .hb .vl small { color: #9aa1b1; margin-left: 2px; }

.cchart { display: flex; align-items: flex-end; gap: 8px; height: 128px; padding: 4px 2px 0; }
.cchart .cl { flex: 1; display: flex; flex-direction: column; justify-content: flex-end; align-items: center; gap: 3px; height: 100%; min-width: 0; }
.cchart .cl .vv { color: #6b7280; font-size: 11px; }
.cchart .cl .stack { width: 100%; display: flex; flex-direction: column; justify-content: flex-end; align-items: center; gap: 2px; height: 100%; }
.cchart .cl .b { width: 66%; border-radius: 4px 4px 0 0; background: #93c5fd; min-height: 2px; }
.cchart .cl .b.ok { background: #6ee7b7; }
.cchart .cl .b.warn { background: #fcd34d; }
.cchart .cl .b.bad { background: #fca5a5; }
.cchart .cl .b.gray { background: #d1d5db; }
.cchart .cl .lbl { color: #9aa1b1; font-size: 11px; white-space: nowrap; }

.ratio .rt { color: #4b5563; font-size: 12px; margin-bottom: 4px; }
.ratio .rb { display: flex; height: 18px; border-radius: 5px; overflow: hidden; background: #f1f3f7; }
.ratio .rb > div { height: 100%; }
.ratio .rb .ok { background: #6ee7b7; }
.ratio .rb .warn { background: #fcd34d; }
.ratio .rb .bad { background: #fca5a5; }
.ratio .rb .gray { background: #d1d5db; }
.ratio .rb .blue { background: #93c5fd; }
.ratio .rl { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 6px; color: #6b7280; font-size: 12px; }
.ratio .rl i, .rl i { display: inline-block; width: 10px; height: 10px; border-radius: 3px; margin-right: 4px; vertical-align: middle; }
.rl i.blue { background: #93c5fd; }
.rl i.ok { background: #6ee7b7; }
.rl i.warn { background: #fcd34d; }
.rl i.bad { background: #fca5a5; }
.rl i.gray { background: #d1d5db; }
.ratio .rl span { white-space: nowrap; }

/* 流程速查（一条线） */
.flow { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.flow .st { border: 1px solid #e6e8ee; border-radius: 8px; padding: 6px 10px; background: #fff; }
.flow .st b { display: block; font-size: 13px; }
.flow .st .ow { color: #9aa1b1; font-size: 11px; }
.flow .ar { color: #c3cad6; }

/* 3D 预览 */
.viewer { position: relative; background: #12161c; border-radius: 10px; overflow: hidden; }
.viewer canvas { display: block; width: 100%; height: 340px; cursor: grab; }
.viewer .hud { position: absolute; left: 10px; bottom: 10px; color: #c9d1d9; font-size: 11px; background: rgba(0, 0, 0, 0.35); padding: 4px 8px; border-radius: 6px; }
.viewer .tools { position: absolute; right: 10px; top: 10px; display: flex; gap: 6px; }
.viewer .tools .btn { background: rgba(255, 255, 255, 0.9); }
/* 第 45 批：六视图（颊/舌/近中/远中/颌面/底部）——画布在 `.mv` 里，工具条在画布上方一行
   ⚖️ 第 63 批（业主原话：「3d 浏览窗口**左下角的 7 个快捷视图按键位置改到右上角**，然后把这个浏览
   窗口**底部的呐一排小字隐藏去掉不要显示出来**」）：
   · 工具条从"画布下面一行"改成**浮在画布右上角**（半透明底，压在模型上也不挡太多）；
   · 底部那排小字（`.hud`：多少面 / 拖动旋转 / 滚轮缩放）**整条隐藏**。 */
.viewer .mv { position: relative; }
.viewer .mv canvas { display: block; width: 100%; height: 340px; cursor: grab; }
.viewer .mv-views {
  position: absolute; right: 8px; top: 8px; z-index: 3;
  display: flex; align-items: center; gap: 5px; flex-wrap: wrap; justify-content: flex-end;
  max-width: 72%; padding: 4px 6px; border-radius: 9px;
  background: rgba(14, 18, 24, 0.62); backdrop-filter: blur(2px);
}
.viewer .mv-views .mv-lab { color: #c9d1d9; font-size: 11px; margin-right: 0; }
.viewer .mv-views .btn { background: #fff; }
.viewer .hud { display: none !important; }

/* 缩略图墙 */
.thumbs { display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 8px; }
.thumb { border: 1px solid #e6e8ee; border-radius: 8px; overflow: hidden; background: #fff; }
.thumb img { display: block; width: 100%; height: 88px; object-fit: cover; background: #f6f7f9; }
.thumb .cap { padding: 5px 7px; font-size: 11px; color: #6b7280; }
.thumb.bad { border-color: #f5c2c2; }
.thumb.bad .cap { color: #dc2626; }

/* 第 84 批：上传设计单图片后的**缩略图墙**（录单"待上传"与改单"已上传"共用）
   业主原话：「上传设计单图片后都不会显示图片，需要在窗口显示图片，这样才方便知道上没上传成果」
   —— 只列文件名的话，"粘-2026-10-09-08-31-12.png"这种名字根本认不出是哪张图。 */
.thumbs .thumb { position: relative; }
/* 第 90 批（业主：「订单详情页面上传后的图片有的删除按键会被隐藏掉一部分」）：
   卡片只有 120~140px 宽，这一行是「文件名 + 改分类 + 删除」，而两颗按钮都 white-space:nowrap、
   一个字都缩不了（真浏览器实测固定占 130.5px）→ 一行放不下就**溢出**，被 .thumb 的
   overflow:hidden 裁掉，最后那颗「删除」首当其冲（②③页签那种 300px 格子里实测整颗看不见、点不到）。
   所以：这一行允许换行 + 文件名先收缩出省略号（`.nm1`），按钮再也不会被裁。 */
.thumb .cap { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.thumb .cap .nm1 { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.thumb .x-mini {
  flex: none; width: 18px; height: 18px; line-height: 1; padding: 0; cursor: pointer;
  border: 0; border-radius: 50%; background: #f1f3f7; color: #6b7280; font-size: 13px;
}
.thumb .x-mini:hover { background: #fde2e2; color: #dc2626; }
/* 非图片（修复模型 .stl 之类）没有缩略图 → 给一个文件徽标占同样的位置，墙才整齐 */
.thumb-file {
  height: 88px; display: flex; align-items: center; justify-content: center;
  background: #f6f7f9; color: #6b7280; font-weight: 700; font-size: 13px; letter-spacing: 1px;
}
.thumb img { cursor: zoom-in; }

/* 时间轴 */
.tl { list-style: none; margin: 0; padding: 0 0 0 14px; border-left: 2px solid #eef1f6; }
.tl li { padding: 5px 0 10px 12px; position: relative; }
.tl li::before { content: ""; position: absolute; left: -19px; top: 10px; width: 8px; height: 8px; border-radius: 50%; background: #c7dbfe; border: 2px solid #fff; }
.tl li.on::before { background: #2563eb; }
.tl .at { color: #9aa1b1; font-size: 11px; }

/* 小工具 */
.kv { display: grid; grid-template-columns: 96px 1fr; gap: 6px 10px; }
.kv dt { color: #6b7280; }
.kv dd { margin: 0; }
.sep { height: 1px; background: #eef0f4; margin: 12px 0; }
.mb0 { margin-bottom: 0; }
/* 第 44 批补：`.mb12` 这个 class 在排班台被用了（`<div class="split half mb12">`），
   而样式文件里**只有 .mb0 / .mt8 / .mt12** —— 也就是说那个 class 一直是空转的，
   两块名单之间真的一丝缝都没有（真机量出来 0px）。 */
.mb12 { margin-bottom: 12px; }
.mt8 { margin-top: 8px; }
.mt12 { margin-top: 12px; }
.right { text-align: right; }
.center { text-align: center; }
.trunc { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.scroll-y { max-height: 320px; overflow: auto; }
.badge-dot { display: inline-block; width: 6px; height: 6px; border-radius: 50%; background: #ef4444; margin-right: 5px; vertical-align: middle; }

/* 使用说明页（help）：步骤 / 要点 / 目录树 */
.steps, .bul { margin: 0; padding-left: 20px; }
.steps li, .bul li { padding: 3px 0; line-height: 1.75; }
pre.tree { margin: 0; padding: 12px 14px; background: #fafbfd; border-bottom: 1px solid #eef0f4; border-radius: 0 0 10px 10px;
  font-family: Consolas, "Courier New", monospace; font-size: 12.5px; line-height: 1.75; color: #374151; overflow: auto; }
code { background: #f3f4f6; border: 1px solid #e5e7eb; border-radius: 4px; padding: 0 4px; font-size: 12px; font-family: Consolas, "Courier New", monospace; }

/* 统一弹层（web/js/ui.js）：横排单选、静态说明、拖拽/粘贴上传区 */
.seg { display: flex; gap: 6px; flex-wrap: wrap; }
.seg-i { display: inline-flex; align-items: center; gap: 5px; border: 1px solid #d6dae3; border-radius: 8px; padding: 5px 10px; cursor: pointer; background: #fff; font-size: 13px; }
.seg-i input { margin: 0; }
.seg-i:has(input:checked) { border-color: #c7dbfe; background: #eef4ff; color: #1d4ed8; font-weight: 600; }
.f-static { color: #4b5563; font-size: 13px; }
.f-check { display: flex; align-items: center; gap: 8px; }
.f-check > span { color: #374151; }
.modal textarea { font-family: inherit; }
.modal .bd .f { display: block; margin-bottom: 12px; }
.modal .bd .f > span { display: block; color: #374151; font-size: 13px; margin-bottom: 4px; }
.modal .bd .f input[type=text], .modal .bd .f input[type=number], .modal .bd .f input[type=date],
.modal .bd .f input[type=time], .modal .bd .f input[type=password], .modal .bd .f select, .modal .bd .f textarea {
  width: 100%; box-sizing: border-box; padding: 7px 9px; border: 1px solid #d6dae3; border-radius: 8px; font-size: 13px; font-family: inherit; background: #fff; }
.modal .bd .f input:focus, .modal .bd .f select:focus, .modal .bd .f textarea:focus { outline: none; border-color: #93b8fb; box-shadow: 0 0 0 3px #e8f0ff; }

/* ── 第 44 批：任务详情的「订单信息四排」+ 带时间的进度条（业主点名）──
   业主原话：「任务详情这里，需要显示外面订单的所有信息……把前面的客户设计师牙位等信息放一排，
   然后要求与备注放第2排，然后时间信息和进度信息放第3排，进度显示和外面的订单显示一样，这个流程
   都显示出来，然后到哪一步哪一步就亮，然后因为这是详情页面所以每个步骤的完成时间都要详细记录，
   然后第4排就不改保持现在的样子就是当天可操作的一些选项」。 */
.task-head .bd { padding-top: 10px; }
/* 一排"名字 + 值"的小块（第 1 排）：值和名字同宽不跳动，窄屏自动换行 */
.kv-row { display: flex; flex-wrap: wrap; gap: 6px 18px; align-items: baseline; }
.kv-row .kv { display: inline-flex; align-items: baseline; gap: 6px; white-space: nowrap; }
.kv-row .kv > i { color: #8a92a6; font-size: 12px; font-style: normal; }
.kv-row .kv > b { font-weight: 600; color: #1f2430; }
/* 第 2 排：要求与备注（长文本，自己一行，窄屏也不挤别人） */
.kv-row.req { display: block; }
.kv-row.req > i { display: block; margin-bottom: 3px; }
.kv-row.req > span { color: #374151; white-space: pre-wrap; word-break: break-word; }
.kv-row.req > span.empty { color: #9aa1b1; }
/* 第 3 排：时间信息（与列表同一口径：发货 ｜ 要求回传 ｜ 剩余时效） */
.tline.big { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.tline.big .lbl { color: #9aa1b1; font-size: 12px; }
.tline.big .tcol { font-variant-numeric: tabular-nums; }
.tline.big .dot { color: #c9ced9; }
/* 第 3 排的进度：和列表同一套 `.flowline`（步骤 + 箭头），只是每一步下面多一行到达时间 */
.flowline.big { display: flex; flex-wrap: wrap; align-items: center; font-size: 12px; margin-top: 8px; }
.flowline.big .st { padding: 4px 9px; border-radius: 7px; display: inline-flex; flex-direction: column; align-items: center; gap: 1px; line-height: 1.25; }
.flowline.big .st .at { font-family: Consolas, "Courier New", monospace; font-size: 10.5px; font-weight: 400; color: #9aa1b1; }
.flowline.big .st.done .at { color: #7d93c0; }
.flowline.big .st.now .at { color: #dbe7ff; }
.flowline.big .st.now.rework .at { color: #ffe9c9; }
.flowline.big .ar { width: 14px; height: 9px; }
.flowline.big .ar::before { width: 8px; }
.flowline.big .ar::after { left: 7px; }

/* ── 第 43 批：牙位格子图（业主：「牙位选择改成图2的牙位格子图……中间还要有点代表连接杆」）
   画法见 `web/js/tooth-chart.js`：上排 16…11 │ 21…26、下排 46…41 │ 31…36，共 24 格；
   两颗相邻牙之间那个小圆点＝连接杆：点了＝连桥（文本写成区间 `14-16`），不点＝各自单冠（`14,15,16`）。
   尺寸刻意做小：一格 34×30，整张图 500 出头，塞进弹层里不挤掉别的字段。 ───────────────────── */
.tc { border: 1px solid #e6e8ee; border-radius: 10px; padding: 8px 10px 10px; background: #fbfcfe; overflow-x: auto; }
.tc-head { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
.tc-tip { flex: 1; color: #8a92a6; font-size: 11px; }
.tc-jaw { display: flex; align-items: center; justify-content: center; gap: 4px; }
.tc-jaw + .tc-jaw { margin-top: 4px; }
.tc-side { color: #9aa1b1; font-size: 11px; writing-mode: horizontal-tb; flex: none; margin-right: 6px; }
.tc-quad { display: flex; flex-direction: column; align-items: center; }
.tc-cap { color: #b9bfcb; font-size: 10px; line-height: 1; margin-bottom: 2px; }
.tc-cells { display: flex; align-items: center; }
.tc-mid { width: 1px; align-self: stretch; background: #dfe3ea; margin: 0 7px; }
/* 第 81 批：中线那颗连接杆（11+21 / 31+41）—— 与别的杆同一套样式，只是两侧留点气 */
.tc-c.mid { margin: 0 4px; }
/* 第 85 批：四个区各补上 7、8 号位（每区 8 颗）→ 格子与杆都收窄一点，16 格 + 中线才排得下
   （改单弹层也一并加宽到 780：原来 620 装 8 格 × 2 会挤） */
.tc-t {
  width: 28px; height: 28px; padding: 0; border: 1px solid #d6dae3; border-radius: 7px; background: #fff;
  color: #374151; font: 600 11.5px/1 "Consolas", "Courier New", monospace; cursor: pointer;
}
.tc-t:hover { border-color: #b9c2d0; background: #f7faff; }
.tc-t.on { background: #2563eb; border-color: #2563eb; color: #fff; }
/* 连接杆：一颗 8px 的小圆点，藏在两颗牙中间；亮起来才是"连桥" */
.tc-c { width: 11px; height: 26px; padding: 0; border: 0; background: transparent; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; }
.tc-c > i { width: 8px; height: 8px; border-radius: 50%; background: #fff; border: 1px solid #cfd5e0; display: block; }
.tc-c:hover > i { border-color: #93b8fb; background: #e8f0ff; }
.tc-c.on > i { background: #2563eb; border-color: #2563eb; box-shadow: 0 0 0 2px #dbeafe; }
.tc-in { margin-top: 8px; font-family: "Consolas", "Courier New", monospace; }
.tc .btn.sm { padding: 2px 8px; }

/* 拖拽 / 粘贴上传区 */
.drop { border: 1px dashed #c7dbfe; background: #fbfdff; border-radius: 10px; }
.drop.over { border-color: #2563eb; background: #eef4ff; }
.drop-tip { color: #6b7280; font-size: 12px; padding: 8px 10px; }
.drop-tip b { color: #1d4ed8; }
.paste-list { margin: 8px 0 0; padding-left: 18px; color: #4b5563; font-size: 12px; }

/* 可点选的"上传位置"（第 29 批：先点位置、再上传）
   只加 outline，不动 border/background —— 否则会盖掉 .drop.over 的拖拽高亮 */
.upload-slot { border-radius: 10px; }
.upload-slot.on { outline: 2px solid #93b8fb; outline-offset: 2px; }

/* 第 82 批：录单页「原始数据」两格 —— **单击选中、双击选文件**（与任务详情第 54 批同一套口径）
   业主原话：「录单界面上传设计单图片**点击就打开上传详情页面**了，导致我还没来得及粘贴图片，
   改成单击选中，双击打开上传详情页面，这样方便我单击选中然后粘贴」。
   老写法是 `<label>` 包着 `<input type=file>` —— 那种写法**点哪儿都会弹出系统文件框**，
   "单击选中再按 Ctrl+V"这套动作还没做完就被文件框打断了。所以文件框藏起来，由双击/按钮去点它。 */
.src-file { display: none; }
[data-src-cell] { cursor: pointer; }
[data-src-cell] .src-cell-tip { color: #6b7280; font-size: 12px; margin: 6px 0 8px; }
[data-src-cell] .btn { align-self: flex-start; }
[data-src-cell].on { background: #f4f8ff; }
[data-src-cell].on .src-cell-tip { color: #1d4ed8; font-weight: 600; }

/* ═══════════════════════════════════════════════════════════════════════════
   第 42 批：外壳 + 工作台改「iOS 26 液态玻璃（纯色底档）」
   ---------------------------------------------------------------------------
   风格出处：`草图\10-工作台-iOS26液态玻璃.html` 的 #solid 档（效果图 `10-工作台-iOS26液态玻璃-纯色底.png`）。
   业主原话：「把外壳工作台改成这个风格，其他不变」—— 所以这条线划得很清楚：

     · **全站会变的只有"外壳"这一层**：页面底色、左导航、顶栏（它们本来每一屏共用）；
     · **只有工作台那一屏**才换成玻璃指标卡 + 白纸订单卡：下面带 `.screen-dashboard` 的规则才是；
       （屏标识由 shell.js 挂在 `#app` 上：`class="app screen-dashboard"`）
     · 任务管理 / 质检台 / 打包交付 / 统计报表 / 排班台 / 客户与时效 / 系统设置 / 使用说明
       这 8 屏的卡片、表格、标签、按钮样式**一行都没动**，它们只跟着底色和外壳走。

   为什么质感不靠"模糊"：参考图里玻璃能"透"，是因为底下压着一张照片；我们底下是纯色，
   玻璃里没有东西可透，`backdrop-filter` 模糊一个常数还是那个常数。所以质感靠四样：
     ① 白雾：半透明的高白填充 —— 底色是从白雾里"透"上来的；
     ② 折边：`::after` 用 mask-composite 描一圈 1px 渐变内亮边，玻璃的"厚度"全在这一笔；
     ③ 中性灰细线：浅灰底上白色高光边是看不见的，得补一道 0.5px 灰线，边界才立得住；
     ④ 投影收紧：浅灰底上投影比白底上清楚得多，这是"浮起来"的主力。

   ⚠️ 换底色只改 `--lg-ground` 一行（第 40 批是 #dfe3ea，第 41 批压深半档到现在的值）。
   ⚠️ 老浏览器（不支持 backdrop-filter）会退化成半透明白面板，字照样读得清 —— 这是刻意的兜底，
      车间那些老机器不能因为一个样式就白屏。
   ⚠️ 工作台指标卡的玻璃配比（白雾 0.30）是量出来的：门禁要求"玻璃 − 底色"的亮度差落在
      [13, 20]：低于 13 玻璃就隐身（白底版只有 1.1），高于 20 又变成实心白卡片。
   ═══════════════════════════════════════════════════════════════════════════ */
:root {
  --lg-ground: #d5dae4;                 /* ← 纯色底：换色只改这一行 */
  --lg-line: rgba(24, 34, 74, .10);      /* 中性灰细线（浅灰底上唯一看得见的边界） */
  --lg-shadow: 0 24px 48px -22px rgba(24, 34, 74, .30);
  --lg-shadow-s: 0 2px 8px -3px rgba(24, 34, 74, .14);
  --lg-rim: inset 0 1px 0 rgba(255, 255, 255, 1), inset 0 12px 20px -14px rgba(255, 255, 255, .95),
    inset 0 -14px 22px -16px rgba(24, 34, 74, .14), inset 0 -1px 1px rgba(255, 255, 255, .85);
}

body { background: var(--lg-ground); }

/* ── 玻璃面板：白雾 + 模糊 + 折边（左导航 / 顶栏 / 指标卡共用同一块玻璃）
      第 55 批：指标卡原来是 `.screen-dashboard .kpi`（只有工作台），业主说"其余 8 屏也统一"，
      而排班台/统计报表/系统设置三屏也在用 `.kpi`（同一个 .lab/.num 结构），所以去掉屏前缀，
      一处定义、四屏通用。 ── */
.side, .top, .kpi {
  position: relative;
  background: transparent;
  background-image:
    radial-gradient(132% 82% at 6% -24%, rgba(255, 255, 255, .66), rgba(255, 255, 255, .24) 50%, rgba(255, 255, 255, .08) 86%),
    linear-gradient(160deg, rgba(255, 255, 255, .46) 0%, rgba(255, 255, 255, .30) 46%, rgba(255, 255, 255, .40) 100%);
  -webkit-backdrop-filter: blur(40px) saturate(140%) brightness(1.04);
  backdrop-filter: blur(40px) saturate(140%) brightness(1.04);
  box-shadow: var(--lg-shadow), var(--lg-shadow-s), 0 0 0 .5px var(--lg-line), var(--lg-rim);
}
/* 折边：1px 渐变内描边（不是普通 border）—— 白雾越薄，这一笔越重要 */
.side::after, .top::after, .kpi::after {
  content: ''; position: absolute; inset: 0; border-radius: inherit; padding: 1px; pointer-events: none;
  background: linear-gradient(142deg, rgba(255, 255, 255, 1) 0%, rgba(255, 255, 255, .76) 14%, rgba(255, 255, 255, .30) 40%,
    rgba(255, 255, 255, .36) 62%, rgba(255, 255, 255, .86) 86%, rgba(255, 255, 255, 1) 100%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
}

/* ── 外壳 ①：左导航（浮起来的一块玻璃） ── */
/* 宽度是**算过**的，别随手调大：外壳每多占 1px，正文就少 1px。第 33 批业主要求排班台
   「两个组名单各占一半」（`.split.half` = 1fr 1fr），而左栏那张名单表的 min-content
   跟着里面每个标签的宽度走 —— 正文宽度不够，左栏就被自己的内容顶宽、右边那栏被挤瘪
   （真浏览器门禁会当场报「两栏不是各占一半」）。第 42 批第一次用 16+214+14+16=260，
   正文 1180，踩响；第 55 批统一 8 屏时把标签内边距放大 2px、卡片左右内边距 +2px，
   又踩响一次（min-content 600 → 613）；**第 97 批字号 +1 之后 min-content 又涨到 ~616**，
   第三次踩响（超 41.9，容差 40）—— 那次是把导航从 174 收到 166 让出 8px 才守住的。
   **最终口径**：1440 宽窗口下 10 + 166(导航) + 10(间距) + 10 = 196 的外壳开销，正文 1244；
   卡片左右内边距 14（原值）、标签内边距 1px 8px（几乎原值）—— 必须留出 ≥10px 余量，
   因为滚动条、字体、别的窗口加的组件都会吃掉几像素。
   ⚠️ 记住了：**这条红线只能靠"外壳让宽"来守，不能靠缩字号**（业主已经点名要字大）。 */
.app { gap: 10px; padding: 10px; }
/* ⚠️ 第 56 批：左栏改成**固定**（业主：「滑动右边的窗口的时候，左边窗口的这些工作台也会跟着一起
   滑动，我需要固定左边的工作台」）。它原来是 flex 里的一项、跟着整页滚；现在脱离文档流贴在
   左上角（留出与 .app 一样的 10px 外边距，玻璃面板的样子一点没变），高度撑满视口、自己内部滚动。
   注意这里必须写在上面那条 `.side, .top, .kpi { position: relative }` **之后**才生效；
   另外 `.main` 要补 `margin-left`（174 宽 + 10 间距），否则正文会被左栏压住。 */
.side {
  position: fixed; top: 10px; left: 10px; width: 166px; height: calc(100vh - 20px);
  flex: 0 0 166px; border-right: 0; border-radius: 30px; padding: 14px 8px 12px;
  overflow: hidden;
}
.main { margin-left: 176px; }
.side-foot { border-top: 1px solid var(--lg-line); padding: 10px 4px 0; background: transparent; }
.side-foot .who { color: #3d465e; font-weight: 600; }
.logo { border-bottom: 0; padding: 2px 6px 16px; font-size: 14.5px; }
.logo::before {
  content: '义'; display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; margin-right: 8px; border-radius: 7px; vertical-align: -4px;
  color: #fff; font-size: 13px; font-weight: 700;
  background: linear-gradient(150deg, #5aa7ff, #0a84ff 48%, #5e5ce6);
  box-shadow: 0 6px 14px -6px rgba(10, 132, 255, .9), inset 0 1px 0 rgba(255, 255, 255, .5);
}
.nav li { height: 37px; padding: 0 11px; border-left: 0; border-radius: 15px; color: #3d465e; font-size: 13.5px; }
.nav li:not(.grp):not(.off):hover { background: rgba(255, 255, 255, .55); }
.nav li.on {
  border-left-color: transparent; color: #0a5fd0; font-weight: 600;
  background: #fff; background-image: linear-gradient(168deg, #fff, rgba(255, 255, 255, .68));
  box-shadow: 0 12px 22px -10px rgba(20, 34, 84, .5), inset 0 1px 0 #fff, inset 0 0 0 .5px rgba(255, 255, 255, .9);
}
.nav .grp { padding: 14px 11px 6px; }
.nav li .cnt { border-radius: 10px; padding: 1px 7px; background: rgba(255, 255, 255, .6); color: #5b6480; box-shadow: inset 0 0 0 .5px var(--lg-line), 0 2px 6px -3px rgba(24, 34, 74, .2); }
.nav li.on .cnt { background: #fff; color: #0a5fd0; }
.nav li.off { color: #8a93a8; }
.nav li.off .cnt { background: rgba(255, 255, 255, .5); color: #9aa1b1; }

/* ── 外壳 ②：顶栏（浮起来的玻璃条；滚动时贴住页顶） ── */
.top {
  /* ⚠️ 第 44 批修回来的一个真 bug：上面那条共用规则（`.side, .top, .screen-dashboard .kpi`）
     把 `position` 写成了 `relative`，于是顶栏**不再贴顶**，而这里的 `top: 10px` 从"粘住的偏移"
     变成了"相对定位的位移" —— 元素被画低了 10px、**布局盒子没动**，下面那条 12px 的外边距
     就被"看"掉了 10px：业主看到的正是"最上面那一栏和下面内容之间的间隙太小"
     （真机量出来每屏只有 2px）。所以这里把 sticky 明确写回来。 */
  position: sticky;
  height: 58px; border-bottom: 0; border-radius: 24px; padding: 0 10px 0 18px; gap: 10px;
  margin: 0 0 12px; top: 10px;
}
/* 贴顶时上面那道 10px 缝要盖住，不然正文会从缝里"穿"过去 */
.top::before { content: ''; position: absolute; left: 0; right: 0; top: -10px; height: 10px; background: var(--lg-ground); }
.top .crumb { font-size: 16.5px; font-weight: 700; }
.top .who {
  display: inline-flex; align-items: center; height: 38px; padding: 0 13px; border-radius: 19px; color: #333c58;
  background-image: linear-gradient(170deg, rgba(255, 255, 255, .86), rgba(255, 255, 255, .5));
  box-shadow: inset 0 0 0 .5px var(--lg-line), 0 6px 14px -8px rgba(20, 34, 84, .45);
}
.top .btn, .top .btn:hover {
  border: 0; border-radius: 17px; height: 34px; padding: 0 15px; display: inline-flex; align-items: center; color: #2d3550;
  background: #fff; background-image: linear-gradient(178deg, rgba(255, 255, 255, .95), rgba(255, 255, 255, .6));
  box-shadow: inset 0 0 0 .5px var(--lg-line), 0 8px 16px -10px rgba(20, 34, 84, .6);
}
.top .btn.sm { height: 30px; padding: 0 12px; font-size: 12.5px; border-radius: 15px; }
.bell {
  width: 38px; height: 38px; border: 0; border-radius: 19px; padding: 0; font-size: 15px;
  display: inline-flex; align-items: center; justify-content: center;
  background: #fff; background-image: linear-gradient(170deg, rgba(255, 255, 255, .92), rgba(255, 255, 255, .55));
  box-shadow: inset 0 0 0 .5px var(--lg-line), 0 8px 16px -10px rgba(20, 34, 84, .6);
}
.bell i {
  position: absolute; top: -4px; right: -4px; min-width: 19px; height: 19px; padding: 0 5px; border-radius: 10px;
  display: flex; align-items: center; justify-content: center; font-size: 10.5px; font-weight: 700; color: #fff;
  background: linear-gradient(180deg, #ff5b52, #ff2d20);
  box-shadow: 0 4px 9px -3px rgba(255, 45, 32, .85), inset 0 1px 0 rgba(255, 255, 255, .45);
}
.dropdown { top: 72px; right: 24px; border: 0; border-radius: 20px; box-shadow: 0 24px 48px -22px rgba(24, 34, 74, .4), 0 0 0 .5px var(--lg-line); }

/* ── 外壳 ③：主区对齐（内容和顶栏同一左边缘，间距跟草图一致） ──
   第 44 批（业主：「工作台最上方的一栏和中间的方块显示栏目和最下面的订单栏目之间的间隙不正常太小了
   修复一下，任务管理里面的最上面那一栏和下面的内容也是间隙太小不正常，包括其他工作台都是这样的」）：
     · 顶栏 → 第一块：`12px 外边距 + 这里 10px 上内边距` = 22px（原来被 `position:relative` 吃掉只剩 2px）；
     · **块与块之间统一至少 14px**：`> * + *` 加 14px 上外边距，兄弟外边距会**折叠**（取大者），
       所以已有 14px 的卡片不会变成 28px，只有原来 0px/12px 的地方被抬到 14px ——
       量出来的两处"贴在一起"（工作台的指标卡 → 我的订单卡 = 0px、排班台两块名单 = 0px）就是这么修的。
     · **左右不加内边距**：正文宽度是算过的（左导航 182 + 各处 12px 间距），再加左右内边距会把
       排班台"两个组名单各占一半"挤垮（见上面 `.app` 那段注释），这里不动它。 */
.content { padding: 10px 0 30px; }
.content > * + * { margin-top: 14px; }

/* ── 指标卡（玻璃 + 彩色圆点 + 大数字）—— 第 55 批起四屏通用 ────────────────
   圆点/彩晕都是纯 CSS 挂上去的（`::before`），不动 screen-*.js 渲染出来的结构。 */
.screen-dashboard .grid.g4 { gap: 13px; }
.kpi { border: 0; border-radius: 22px; padding: 12px 16px 13px; overflow: hidden; cursor: default; }
/* 最后两张各占两列，把那半行空位填满（只有工作台是 10 张卡，所以这条留着屏前缀） */
.screen-dashboard .grid.g4 > .kpi:nth-child(9), .screen-dashboard .grid.g4 > .kpi:nth-child(10) { grid-column: span 2; }
.kpi::before {
  content: ''; position: absolute; width: 170px; height: 170px; right: -52px; top: -80px; border-radius: 50%;
  filter: blur(30px); opacity: .12; background: radial-gradient(circle, #9ec9ff, transparent 70%);
}
.kpi.warn::before { background: radial-gradient(circle, #ffcd7a, transparent 70%); }
.kpi.bad::before { background: radial-gradient(circle, #ff9d95, transparent 70%); }
.kpi.ok::before { background: radial-gradient(circle, #9ff0b6, transparent 70%); }
.kpi .lab { position: relative; display: flex; align-items: center; gap: 7px; color: #535c78; font-size: 12.5px; font-weight: 600; }
.kpi .lab::before { content: ''; flex: 0 0 7px; width: 7px; height: 7px; border-radius: 50%; background: #0a84ff; box-shadow: 0 0 0 3px rgba(10, 132, 255, .18); }
.kpi.warn .lab::before { background: #ff9f0a; box-shadow: 0 0 0 3px rgba(255, 159, 10, .2); }
.kpi.bad .lab::before { background: #ff3b30; box-shadow: 0 0 0 3px rgba(255, 59, 48, .2); }
.kpi.ok .lab::before { background: #30d158; box-shadow: 0 0 0 3px rgba(48, 209, 88, .2); }
.kpi .num { position: relative; margin-top: 5px; font-size: 31px; font-weight: 700; letter-spacing: -1px; line-height: 1.06; font-variant-numeric: tabular-nums; color: #0a63d8; }
.kpi.warn .num { color: #b25a00; }
.kpi.bad .num { color: #d70015; }
.kpi.ok .num { color: #0b7a3b; }
.kpi .num small { font-size: 13px; font-weight: 600; color: #6f7893; }
.kpi .sub { position: relative; color: #7d86a0; font-size: 11.5px; margin-top: 3px; }
.kpi.link:hover { filter: brightness(1.03); }

/* ── 卡片 = 落在浅灰底上的一张白纸（要盯着看的地方干净）—— 第 55 批起全站通用 ── */
.card {
  border: 0; border-radius: 26px; overflow: hidden; background: #fff;
  box-shadow: 0 20px 42px -26px rgba(24, 34, 74, .26), 0 0 0 .5px rgba(24, 34, 74, .08);
}
.card > h2 { min-height: 52px; padding: 6px 14px; border-bottom: 0; font-size: 14.5px; font-weight: 700; gap: 10px; }
.card > h2::before { content: ''; flex: 0 0 8px; width: 8px; height: 8px; border-radius: 50%; background: #0a84ff; box-shadow: 0 0 0 4px rgba(10, 132, 255, .16); }
.card .bd { padding: 12px 14px; }
.card .bar { background: transparent; border: 0; border-radius: 0; box-shadow: none; padding: 0; margin: 0 0 10px; }
.card select,
.card input[type=date] {
  height: 34px; border: 0; border-radius: 15px; color: #333c58; font-size: 12.5px;
  background-color: #fff; background-image: linear-gradient(180deg, #fff, #f5f7fb);
  box-shadow: inset 0 0 0 .5px var(--lg-line), 0 2px 6px -4px rgba(24, 34, 74, .35);
}
.card input[type=date] { padding: 0 10px; }
.card .tab {
  border: 1px solid transparent; border-radius: 14px; padding: 5px 12px; font-size: 12.5px; font-weight: 600; color: #3d465e;
  background: #fff; box-shadow: inset 0 0 0 .5px var(--lg-line), 0 2px 6px -4px rgba(24, 34, 74, .35);
}
.card .tab.on { background: #eef5ff; color: #0a5fd0; box-shadow: inset 0 0 0 1px #bcd8ff; }
.card .note { color: #6f7893; }
.card .btn {
  border: 0; border-radius: 17px; height: 32px; padding: 0 14px; color: #2d3550;
  display: inline-flex; align-items: center; justify-content: center;
  background: #fff; background-image: linear-gradient(180deg, #fff, #f4f6fa);
  box-shadow: inset 0 0 0 .5px var(--lg-line), 0 4px 10px -6px rgba(24, 34, 74, .45);
}
.card .btn:hover { border: 0; filter: brightness(1.02); }
.card .btn.pri, .card .btn.pri:hover {
  color: #fff; background-image: linear-gradient(178deg, #4ea4ff, #0a84ff 55%, #0a6ee0);
  box-shadow: 0 10px 20px -9px rgba(10, 132, 255, .85), inset 0 1px 0 rgba(255, 255, 255, .5);
}
.card .btn.sm { height: 30px; padding: 0 12px; font-size: 12.5px; border-radius: 15px; }

/* ── 表格：表头做成一条浅灰带，行分隔用极细线 ────────────────────────────────
   ⚠️ `:not(.tasks-table)` 是**必须的**：任务管理/工作台那张订单表是业主点名要"一屏看更多单"的
   紧凑表（第 38 批定的 5px 10px），它的样式靠 `.tasks-table th/td`（0,1,1）—— 和下面这些规则
   **同权重**，谁在后面谁赢。少了这个 `:not()`，紧凑表会被这里统一成 36px 表头 + 松行距，
   真浏览器门禁当场报「任务表行高被带跑」。 */
.card table:not(.tasks-table) { border-collapse: collapse; border-spacing: 0; background: #fff; }
.card table:not(.tasks-table) th {
  height: 34px; padding: 0 10px; background: #f1f4f9; background-image: none; color: #6a7391;
  font-size: 11.5px; font-weight: 700; border: 1px solid #e3e7ee; border-radius: 0; vertical-align: middle;
}
/* 第 124 批：表头那个"胶囊圆角"（首末两格 14px）撤掉 —— 业主要的是**所有表格都带竖线、
   与任务管理那张订单表一个样**；圆角带 + 竖线格线摆在一起是两套风格。 */
/* 左右内边距**保持 10px 不动**：正文宽度是算过的（排班台"两个组名单各占一半"卡在 min-content 上） */
.card table:not(.tasks-table) td { padding: 8px 10px; border: 1px solid #e9ecf2; vertical-align: middle; }
.card table:not(.tasks-table) tbody tr:hover td { background: #f7f9fc; }
.card table:not(.tasks-table) td .sub { color: #7d86a0; font-size: 11.5px; }

/* ── 第 45 批：工作台的订单表**就是任务管理那张表**（同一个行渲染器），所以上面这套
   "订单卡专用"的表格样式要给 `.tasks-table` 让位 —— 否则同一份订单在两屏长得不一样
   （行高 42px vs 30px、表头圆角灰带 vs 表头灰底），而业主点名的恰恰是"格式也要一样"。
   只覆盖 `.tasks-table`，工作台里其它表格（如果有）照旧。 ───────────────────────── */
/* ── 第 124 批（业主：「后面只要是表格的显示都要有竖线分开，做到风格统一」）：
   这一块原来只留了横线（`border-bottom`），把订单表的竖线盖掉了 → 现在**与订单表同一套格线**
   （横竖都是 1px #e9ecf2，表头下面那条稍深一点）。 ───────────────────────── */
.screen-dashboard .card table.tasks-table { border-collapse: collapse; border-spacing: 0; background: #fff; border: 1px solid #e3e7ee; }
.screen-dashboard .card table.tasks-table th {
  height: auto; padding: 5px 10px; border-radius: 0; background: #fafbfd; background-image: none;
  color: #6b7280; font-size: 12px; font-weight: 600; border: 1px solid #e9ecf2; border-bottom-color: #dde2ea; vertical-align: middle;
}
.screen-dashboard .card table.tasks-table th:first-child { border-radius: 0; }
.screen-dashboard .card table.tasks-table th:last-child { border-radius: 0; }
.screen-dashboard .card table.tasks-table td {
  height: auto; padding: 5px 10px; line-height: 1.4; vertical-align: middle; border: 1px solid #e9ecf2;
}
.screen-dashboard .card table.tasks-table tbody tr:last-child td { border-bottom: 1px solid #e9ecf2; }
.screen-dashboard .card table.tasks-table tbody tr:hover td { background: #fbfdff; }
.screen-dashboard .card table.tasks-table td .sub { color: #9aa1b1; font-size: 11px; }
/* ── 标签 = 软胶囊（第 55 批起全站通用：原来只有工作台那屏是圆角胶囊）
      ⚠️ 内边距几乎是原值（1px 8px，原 1px 7px）：标签宽度直接进排班台左栏的 min-content，
      这里多给 1px，那边"两个组名单各占一半"就少 1px 余量（见 `.app` 那段注释）。 */
.tag {
  border: 0; border-radius: 11px; padding: 1px 8px; font-size: 11.5px; font-weight: 600;
  background: #eef1f7; color: #4b5563; box-shadow: inset 0 1px 0 #fff;
}
.tag.blue { background: #e7f1ff; color: #0a5fd0; }
.tag.amber { background: #fff2df; color: #a95400; }
.tag.red { background: #ffe8e6; color: #c9001a; }
.tag.green { background: #e3f8eb; color: #0b7a3b; }
.tag.gray { background: #eef0f4; color: #6b7280; }
.tag.purple { background: #f6ecfe; color: #8b2fc4; }

/* ═══════════════════════════════════════════════════════════════════════════
   第 55 批（业主点名）：其余 8 屏也统一成这套液态玻璃
   ---------------------------------------------------------------------------
   业主：「其余 8 屏也统一一下这个风格」。
   第 42 批只换外壳 + 工作台（当时的要求是"其他不变"），于是就成了"新框装旧芯" ——
   外壳是玻璃，正文还是 10px 小圆角的白方盒 + 灰边框按钮 + 方标签。这一批把**通用组件**统一：
   卡片=白纸、指标卡=玻璃、按钮与筛选=胶囊、标签=软胶囊、表格=灰带表头 + 极细行线。

   ⚠️ 两条不能碰的红线（都有门禁盯着，别顺手改）：
     ① `.tasks-table`（任务管理 / 工作台的订单表）—— 业主点名要"一屏看更多单"，
        行高与内边距（5px 10px）是第 38 批定的。这一批**只换颜色，不碰尺寸**，
        所以上面所有表格规则都带 `:not(.tasks-table)`；
     ② 正文宽度 —— 排班台「两个组名单各占一半」卡在左栏的 min-content 上（见 `.app` 那段注释），
        所以这一批的内边距**只动纵向**，左右一律保持原值。
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── 按钮（卡片外的：筛选条里、弹层里、表格操作格） ── */
.btn {
  border: 0; border-radius: 17px; height: 32px; padding: 0 14px; color: #2d3550; font-family: inherit; font-size: 13px;
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  background: #fff; background-image: linear-gradient(180deg, #fff, #f4f6fa);
  box-shadow: inset 0 0 0 .5px var(--lg-line), 0 4px 10px -6px rgba(24, 34, 74, .45);
}
.btn:hover { border: 0; filter: brightness(1.02); }
.btn.pri, .btn.pri:hover {
  color: #fff; border: 0;
  background-image: linear-gradient(178deg, #4ea4ff, #0a84ff 55%, #0a6ee0);
  box-shadow: 0 10px 20px -9px rgba(10, 132, 255, .85), inset 0 1px 0 rgba(255, 255, 255, .5);
}
.btn.danger { border: 0; background-image: linear-gradient(180deg, #fff, #fff1f0); color: #c9001a;
  box-shadow: inset 0 0 0 .5px rgba(255, 59, 48, .3), 0 4px 10px -6px rgba(24, 34, 74, .35); }
.btn.ok { border: 0; color: #fff; background-image: linear-gradient(178deg, #3fd06a, #1eb84c);
  box-shadow: 0 10px 20px -9px rgba(30, 184, 76, .8), inset 0 1px 0 rgba(255, 255, 255, .5); }
.btn.sm { height: 30px; padding: 0 12px; font-size: 12.5px; border-radius: 15px; }
.btn.dis, .btn[disabled] { background-image: none; background: #eef1f6; color: #a5acba; box-shadow: none; cursor: not-allowed; }

/* ── 筛选条：卡片外的那些 `.bar` 也从"白方盒"改成"浅灰底上的一张白纸" ──
      （卡片**里面**的 .bar 上面已经统一成"跟着卡片走"，不重复画盒子） */
.bar {
  border: 0; border-radius: 22px; background: #fff;
  box-shadow: 0 16px 34px -26px rgba(24, 34, 74, .3), 0 0 0 .5px rgba(24, 34, 74, .08);
}
.bar select, .bar input[type=date], .bar input[type=text], .bar input[type=search] {
  height: 34px; border: 0; border-radius: 15px; color: #333c58; font-size: 12.5px;
  background-color: #fff; background-image: linear-gradient(180deg, #fff, #f5f7fb);
  box-shadow: inset 0 0 0 .5px var(--lg-line), 0 2px 6px -4px rgba(24, 34, 74, .35);
}
.bar .tab {
  border: 1px solid transparent; border-radius: 14px; padding: 5px 12px; font-size: 12.5px; font-weight: 600; color: #3d465e;
  background: #fff; box-shadow: inset 0 0 0 .5px var(--lg-line), 0 2px 6px -4px rgba(24, 34, 74, .35);
}
.bar .tab.on { background: #eef5ff; color: #0a5fd0; box-shadow: inset 0 0 0 1px #bcd8ff; }
.bar .note { color: #6f7893; }

/* ── 表单控件：白底 + 灰色细线（原来是一圈灰边框，和玻璃壳子不搭） ── */
input[type=text], input[type=password], input[type=date], input[type=number], input[type=search], select, textarea {
  border: 0; border-radius: 12px;
  box-shadow: inset 0 0 0 .5px var(--lg-line), 0 1px 2px rgba(24, 34, 74, .05);
}
input:focus, select:focus, textarea:focus {
  border-color: transparent;
  box-shadow: inset 0 0 0 1.5px #93b8fb, 0 0 0 3px rgba(10, 132, 255, .16);
}
input[disabled], select[disabled], textarea[disabled] { background: #f4f6fa; color: #9aa1b1; box-shadow: none; }

/* ── 弹层：圆角更大、投影更沉，遮罩后面虚化一点（更像 iOS） ── */
.mask { background: rgba(24, 34, 74, .34); -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px); }
.modal { border-radius: 24px; box-shadow: 0 30px 60px -24px rgba(14, 22, 54, .5); }
.modal > h3 { border-bottom: 0; font-weight: 700; }
.modal .ft { border-top: 1px solid rgba(24, 34, 74, .08); }
.dropdown, .toast { border-radius: 20px; }
.toast { box-shadow: 0 16px 34px -18px rgba(14, 22, 54, .6); }

/* ── 质检队列 / 文件清单 / 分段选择 / 流程速查 / 缩略图墙 ── */
.qitem { border-bottom: 1px solid rgba(24, 34, 74, .08); }
.qitem:hover { background: #f7f9fc; }
.qitem.on { background: #eef5ff; box-shadow: inset 3px 0 0 #0a84ff; }
.filelist li { border: 0; border-radius: 14px; background: #fff; box-shadow: inset 0 0 0 .5px var(--lg-line); }
.seg-i { border: 0; border-radius: 14px; background: #fff; box-shadow: inset 0 0 0 .5px var(--lg-line); }
.seg-i:has(input:checked) { background: #eef5ff; color: #0a5fd0; font-weight: 600; box-shadow: inset 0 0 0 1px #bcd8ff; }
.flow .st { border: 0; border-radius: 14px; background: #fff; box-shadow: inset 0 0 0 .5px var(--lg-line); }
.flow .st.on { background: #eef5ff; color: #0a5fd0; box-shadow: inset 0 0 0 1px #bcd8ff; }
.thumb { border: 0; border-radius: 16px; box-shadow: inset 0 0 0 .5px var(--lg-line), 0 6px 14px -10px rgba(24, 34, 74, .5); }
.checks li { border-bottom: 1px solid rgba(24, 34, 74, .08); }
.pager { border-top: 1px solid rgba(24, 34, 74, .08); color: #6f7893; }
.pager .p { border: 0; border-radius: 12px; background: #fff; box-shadow: inset 0 0 0 .5px var(--lg-line), 0 2px 6px -4px rgba(24, 34, 74, .35); }
.pager .p.on { background-image: linear-gradient(178deg, #4ea4ff, #0a84ff); color: #fff; box-shadow: 0 6px 12px -8px rgba(10, 132, 255, .9); }
.alert { border: 0; border-radius: 18px; box-shadow: inset 0 0 0 .5px rgba(24, 34, 74, .06); }
pre.tree { border-bottom: 0; border-radius: 0 0 24px 24px; background: #f7f9fc; }
code { border: 0; background: #eef1f7; border-radius: 6px; }
.prog, .prog > i { border-radius: 999px; }
.skel { background: linear-gradient(90deg, #eef1f6, #e4e9f1, #eef1f6); }

/* ── 登录页（第 98 批：业主选的 B 方案「左右分栏」）─────────────────────────────
   左：深蓝品牌面（logo + 主标语 + 三行要点 + 版本）；右：干净表单。
   为什么：业主说"登录界面有点丑" —— 原来是浅灰底上一张白卡，没有立场也没有信息；
   而这一屏每个学生每天都要过，左栏那三行正好替新来的学生回答"这系统是干嘛的"。
   ⚠️ 只动皮：表单元素与 id 一个没改（`#login-form` / `#login-alert` / `#change-box` /
   `#login-fields` / `#username` / `#password` / `#login-err` / `#login-btn` / `#login-foot`）。
   ⚠️ 窄屏（<1100px，车间平板）会退成"上面一小条品牌 + 下面表单"，不能把表单挤没。 */
.login-page { background: #f2f5fa; }
.login-split { display: flex; min-height: 100vh; }

.login-brand { position: relative; width: 46%; min-width: 420px; overflow: hidden; color: #eaf0ff; padding: 52px 54px;
  background: linear-gradient(150deg, #16224a 0%, #1d3b78 46%, #2b5fb8 100%); }
.lb-blob { position: absolute; border-radius: 50%; filter: blur(80px); opacity: .55; }
.lb-b1 { width: 520px; height: 520px; right: -140px; top: -120px; background: radial-gradient(circle, #5aa7ff, rgba(90, 167, 255, 0) 70%); }
.lb-b2 { width: 460px; height: 460px; left: -120px; bottom: -160px; background: radial-gradient(circle, #7c63d8, rgba(124, 99, 216, 0) 70%); }
.lb-inner { position: relative; height: 100%; display: flex; flex-direction: column; }
.lb-brand { display: flex; align-items: center; gap: 14px; }
.lb-mark { width: 52px; height: 52px; flex: 0 0 52px; border-radius: 16px; display: flex; align-items: center; justify-content: center;
  font-size: 24px; font-weight: 700; background: rgba(255, 255, 255, .16); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .32); }
.lb-brand b { display: block; font-size: 19px; font-weight: 700; letter-spacing: .3px; }
.lb-brand i { display: block; font-style: normal; font-size: 12.5px; color: #b9c9ee; margin-top: 3px; }
.login-brand h2 { margin: 60px 0 14px; font-size: 30px; font-weight: 700; line-height: 1.35; letter-spacing: .4px; }
.lb-lead { margin: 0; color: #c3d2f1; font-size: 14px; line-height: 1.9; }
.lb-pts { margin-top: 32px; display: flex; flex-direction: column; gap: 14px; }
.lb-pts div { display: flex; align-items: center; gap: 10px; font-size: 13.5px; color: #d7e2fb; }
.lb-pts i { width: 22px; height: 22px; flex: 0 0 22px; border-radius: 7px; background: rgba(255, 255, 255, .16);
  display: inline-flex; align-items: center; justify-content: center; font-style: normal; font-size: 12px; }
.lb-ver { margin-top: auto; font-size: 12px; color: #9fb2dd; }

.login-side { flex: 1; display: flex; align-items: center; justify-content: center; padding: 40px 24px; background: #f2f5fa; }
.login-form { width: 100%; max-width: 400px; }
.login-form h1 { margin: 0 0 6px; font-size: 23px; font-weight: 700; }
.login-form > .sub { margin: 0 0 26px; color: #6f7893; font-size: 13.5px; }
.login-form .f > span { font-size: 13px; font-weight: 600; color: #5b6480; }
.login-form .f > input { height: 46px; border: 0; border-radius: 14px; padding: 0 14px; font-size: 14.5px; font-weight: 600;
  background: #fff; box-shadow: inset 0 0 0 .5px rgba(24, 34, 74, .12); }
.login-form .f > input:focus { outline: none; box-shadow: inset 0 0 0 1.5px #93b8fb, 0 0 0 3px rgba(10, 132, 255, .14); }
.login-form #login-btn, .login-form #change-btn { width: 100%; height: 46px; border-radius: 14px; font-size: 15.5px; font-weight: 700; margin-top: 4px; }
.login-form .foot { margin-top: 20px; font-size: 12.5px; color: #8b93a7; line-height: 1.75; }
.login-form .foot b { color: #5b6480; }
/* 窄屏（平板/小显示器）：品牌面收成一条，表单仍占主位 */
@media (max-width: 1100px) {
  .login-split { flex-direction: column; }
  .login-brand { width: 100%; min-width: 0; padding: 26px 24px 24px; }
  .login-brand h2 { margin: 22px 0 10px; font-size: 22px; }
  .lb-lead, .lb-pts { display: none; }
  .lb-ver { margin-top: 14px; }
  .login-side { padding: 26px 20px 40px; }
}

/* ── 旧的登录页样式（居中一张卡）保留给其它页面兜底，别删 ── */

/* ═══════════════════════════════════════════════════════════════════════════
   第 97 批（业主点名）：全站字体换成「微软雅黑 UI · 600 · 13.5px」
   ---------------------------------------------------------------------------
   业主原话（一路问下来的结论）：「字体还是不好看，太瘦了」→ 看完四套方案后拍板
   「方案2（推荐）：微软雅黑 UI · 600 · 13.5px」，并且要求**全站改**。

   为什么"瘦"：中文字形回退到**微软雅黑的 Regular（400）**，屏幕上就是发虚。
   ⚠️ 为什么用 600 而不是 700：雅黑在小字号下 700 会有点"糊"（笔画粘连），
      600 既够实又干净 —— 这是雅黑这个字体的脾气。14.5px/700 那档远看更清楚，
      但**会把订单表撑宽到放不下**（见下面的宽度账），所以全站取 600/13.5px。

   令牌（全站只许用这几档，别再各自为政）：
     主信息 13.5px / 600（表格单元格、表单值、列表）
     次信息 12.5px / 400（note / hint / sub / hist）—— 原来是 11px，太小太虚
     标题   15px / 700（卡片 h2）、17px / 700（顶栏页名）、14px / 600（左导航）
     控件   13px / 600（按钮 / 页签 / 输入框 / 胶囊）
     进度链 12px / 600（原来是 10px，眼睛要贴上去看）

   ⚠️ **宽度账（踩过的坑，别再踩）**：字号一大，订单表的 min-content 就涨。
      实测：旧字体下这张表需要 1634px（业主屏可用 1634，刚好）；换 13.5px/600 之后
      需要 ~1700px —— 所以当批同时把操作列按钮压到 11px/17px（第 59 批那条）才回得来。
      结论：**调字号必须回头看订单表宽度**，它有真浏览器门禁盯着（B①′ 一节）。
   ═══════════════════════════════════════════════════════════════════════════ */
:root {
  --font-ui: "Microsoft YaHei UI", "Microsoft YaHei", "PingFang SC", system-ui, sans-serif;
  --fs-main: 13.5px; --fs-sub: 12.5px; --fs-ctl: 13px;
  --w-main: 600; --w-strong: 700;
}
body { font-family: var(--font-ui); font-size: 14px; }
/* 表单控件与按钮不会自动继承 body 的字体，要逐个点名 */
input, select, textarea, button, .btn, .tab, .fld, .chip, .tag, .who, .bell, .dropdown, .toast { font-family: var(--font-ui); }

/* 主信息：加粗一档 */
td, .kpi .num, .qitem .l2, .msg .ti, .filelist li .nm b, .act, .pager .p { font-weight: var(--w-main); }
td { font-size: var(--fs-main); }
th { font-size: var(--fs-sub); font-weight: var(--w-strong); }

/* 标题与导航 */
.card > h2 { font-size: 15px; font-weight: var(--w-strong); }
.top .crumb { font-size: 17px; font-weight: var(--w-strong); }
.modal > h3 { font-size: 15.5px; font-weight: var(--w-strong); }
.logo { font-weight: var(--w-strong); }
.nav li { font-size: 14px; font-weight: var(--w-main); }
.nav li.on { font-weight: var(--w-strong); }
.nav .grp { font-size: 11.5px; font-weight: var(--w-strong); }

/* 控件统一一档 */
.btn, .tab, .fld, .chip, .who, select, input[type=text], input[type=date], input[type=number], input[type=search], input[type=password], textarea {
  font-size: var(--fs-ctl); font-weight: var(--w-main);
}
.btn.sm, .tab, .chip { font-size: var(--fs-sub); }
.tag { font-size: 12px; font-weight: var(--w-main); }

/* 次要信息：比主信息小一档，但不再是 11px 那种"发虚的小字" */
.note, .hint, .sub, td .sub, .sub-i, .hist, .legend, .msg .bd, .msg .mt, .kv dt, .f-static { font-size: var(--fs-sub); }
.flowline { font-size: 12px; font-weight: var(--w-main); }
.flowline .st { padding: 1px 6px; }
.kpi .lab { font-size: 13px; font-weight: var(--w-main); }
.kpi .num { font-size: 32px; }

/* ── 第 101 批（业主：「工作台，质检台，打包交付，和任务管理的订单显示行高都不一样，**按照任务管理
   订单的行高其他改成一样的**」）── 四处订单表**行高统一** ────────────────────────────────

   为什么原来四个数：任务管理那一行里装着第 58 批点名的**两小排操作按钮**（上面 改单/复制/领取/退单，
   下面 当前订单浏览 + 删除），两排 17px 的按钮把行撑到 **47px**；工作台与质检台没有操作列，单排数据
   行只有 **32px**；打包预览的操作格里是"按钮 + 进包统计 + 可打包标"，三行叠起来到 **75px**。

   口径：**以任务管理那一行为准（47px）**，其余三处把它当**最小行高**顶上去 —— 用 `tr` 上的 `height`
   （对表格行就是 min-height）。这样不管哪一屏、有没有操作列，订单行都是 47px。

   ⚠️ 作用域只到 `.tablewrap` 里的订单表（任务管理 / 工作台两块 / 质检台队列 / 打包预览）。
      **任务详情页页头那块「订单信息」也走这条**（第 103 批起它与任务管理逐列一致，行高也就该一样）；
      `.hg-table` 里那张表**没有** `.tablewrap`，所以下面单独给它补一条同样的 min-height。
   ⚠️ 47px 是"算出来"的：两排 17px 按钮 + 2px 间距 = 36，加单元格上下内边距 5+5 与 1px 底线 = 47。
      想改行高就改这一个数（同时改 `_check-browser.js` D10 那条断言的口径）。 */
.tablewrap table.tasks-table tbody tr[data-id] { height: 47px; }
/* 任务详情页页头那块「订单信息」：与列表同一个模板，行高也同一个数 */
.task-head .hg-table table.tasks-table tbody tr[data-id] { height: 47px; }
/* 打包预览那一格的"进包统计"必须**只占一行**：文件数/大小一长（比如"共 128 个文件 · 1.2 GB"）就会
   折成第二行，行高又比别处高出一截（`tr` 上的 height 是最小值，装不下时照样会长）。所以这一行
   永远不折、放不下就省略号（鼠标停上去的 title 里还有完整信息）。 */
.tasks-table td .pk-stats { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ── 第 104 批（业主点名）：点订单 → 那一行**飞进详情页** ──────────────────────────────────
   三个类，都只动 transform / opacity（不碰布局，车间老机器也不卡）：
     · `.fly-out`  列表页上被点开的那一行：淡出 + 轻微缩一下（"这一行被拎起来了"）
     · `.flyer`    飞行的复制品：`position: fixed` 贴在屏幕上，从来源矩形过渡到详情页页头那一行
     · `.fly-wait` 详情页里"先藏着、落位后再浮出来"的区块（配合 `.fly-in` 一起淡入上浮）
   ⚠️ 动画只在 `prefers-reduced-motion` 没开时启用（见 `web/js/fly.js`）；`.fly-wait` 有 1.2 秒兜底，
      万一链路出岔子页面也不会停在半透明。 */
.tasks-table tbody tr.fly-out { opacity: .35; transform: scale(.995); transition: opacity .12s ease, transform .12s ease; }
.flyer { position: fixed; z-index: 90; pointer-events: none; background: #fff; border-radius: 12px; overflow: hidden;
  box-shadow: 0 30px 60px -24px rgba(24,34,74,.55), 0 0 0 1px rgba(10,132,255,.35);
  transition: left .42s cubic-bezier(.22,.7,.28,1), top .42s cubic-bezier(.22,.7,.28,1),
    width .42s cubic-bezier(.22,.7,.28,1), height .42s cubic-bezier(.22,.7,.28,1),
    border-radius .42s ease; }
.flyer table.tasks-table { width: 100%; border: 0; }
.flyer table.tasks-table th { display: none; }
.flyer table.tasks-table td { height: 47px; }
/* ── 第 113 批（业主：「把进度条的那 7 个进度条**放大**，然后**里面装入各个进度的名字**，
   然后**下面显示操作时间**」）── 详情页页头那一格现在是"七个格子" ────────────────────────
   每格 = 本步的名字（居中） + 这一步的操作时间（下面一行小字）；
   走过的浅蓝、当前那格实蓝白字、还没走到的灰底 —— 一眼看出走到哪、每步什么时候到的。 */
.task-head .hg-info td.flowcell { text-align: center; }
.flowsegbig { display: inline-flex; gap: 4px; align-items: stretch; vertical-align: middle; }
.flowsegbig .cell {
  display: inline-flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px;
  min-width: 54px; padding: 4px 6px; border-radius: 10px; background: #f4f6fa;
  box-shadow: inset 0 0 0 1px #e6eaf2;
}
.flowsegbig .cell b { font-size: 11.5px; font-weight: 700; color: #9aa1b1; white-space: nowrap; }
.flowsegbig .cell em { font-style: normal; font-size: 10.5px; font-weight: 600; color: #aab3c4; white-space: nowrap; }
.flowsegbig .cell.done { background: #eef4ff; box-shadow: inset 0 0 0 1px #c7dbfe; }
.flowsegbig .cell.done b { color: #1d4ed8; }
.flowsegbig .cell.done em { color: #7f95c8; }
.flowsegbig .cell.now { background: #2563eb; box-shadow: none; }
.flowsegbig .cell.now b { color: #fff; }
.flowsegbig .cell.now em { color: #d8e6ff; }

/* ── 第 113 批（业主：「原始修复数据窗口改成 **2 行**：第 1 行放**设计单和设计要求**（左右对半分，
   左边设计单、右边设计要求，这一行**行高要高**、不能是细条条；右边设计要求文字要**居中**，
   这样才能一眼看到）；第 2 行放**设计数据**」）───────────────────────────────────────── */
.src-row1 { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; align-items: stretch; }
.src-row2 { margin-top: 12px; }
.src-half { display: flex; flex-direction: column; min-width: 0; }
/* ⚖️ 第 114 批（业主：「设计单和设计要求**底部的框没对齐**，对齐；**设计要求和编辑的操作键
   改在框里而不是框外**」）：两个半边**都**是"一个框（flex:1 撑满）+ 框里一行标题 + 一块内容" ——
   所以顶边、底边天然对齐。原来右边把「设计要求 + 编辑」画在框**外面**，右边就比左边矮一截。 */
.src-row1 { min-height: 196px; }
.src-half > .upload-slot,
.src-half > .src-req-box { flex: 1; }
.src-hd { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; font-size: 12.5px; font-weight: 700; color: #4b5563; }
/* 右边那块：**标题与「编辑」都在框里**（第 114 批），设计要求**居中**显示、字号大一点，一眼就能看到 */
.src-req-box {
  display: flex; flex-direction: column; min-width: 0;
  border-radius: 16px; background: #f7f9fc; box-shadow: inset 0 0 0 .5px var(--lg-line, #e6eaf2);
}
.src-req-hd {
  display: flex; align-items: center; gap: 8px; flex: 0 0 auto;
  padding: 6px 10px 6px 12px; border-bottom: 1px solid rgba(24, 34, 74, .06);
  font-size: 12.5px; font-weight: 700; color: #4b5563;
}
.src-req > .src-req-box > .src-req-body {
  flex: 1; display: flex; align-items: center; justify-content: center; text-align: center;
  padding: 16px 18px;
  font-size: 15px; font-weight: 600; line-height: 1.7; color: #253046; white-space: pre-wrap; word-break: break-word;
}
.src-req > .src-req-box > .src-req-body.empty { color: #a2a9b8; font-weight: 400; }

/* 3D 浏览弹窗（第 113 批：点文件后面的「3D 浏览」弹出来看）——
   ⚠️ 类名不要用 `.lb`（那是图片灯箱，全站同名会互相污染，第 58/98 批各踩过一次） */
.mesh-modal {
  position: relative; width: min(1180px, 92vw); height: min(760px, 84vh); background: #fff;
  border-radius: 24px; box-shadow: 0 30px 60px -24px rgba(14, 22, 54, .5); display: flex; flex-direction: column; overflow: hidden;
}
.mesh-modal .mm-hd { display: flex; align-items: center; gap: 10px; padding: 12px 16px; border-bottom: 1px solid rgba(24, 34, 74, .08); }
.mesh-modal .mm-hd .sp { flex: 1; }
#mm-box { flex: 1; min-height: 0; }
#mm-box.viewer { border-radius: 0; }
#mm-box .loading, #mm-box .alert { margin: 16px; }

/* ── 第 90 批：多窗口 3D 浏览 ─────────────────────────────────────────────────────
   业主：「数据 3d 浏览只能单独打开看一个，我需要能够**同时打开多个**并选择显示哪个隐藏哪个
   或者同时打开」。
   原来的 3D 是一个全屏 `.mask` 遮罩里的弹窗 —— 后开的会盖住先开的（mask 是全屏、还带毛玻璃），
   所以"并排看两个"在遮罩那套里做不到。这里换成一层**透明浮层**：层本身不吃鼠标事件
   （pointer-events:none），只有窗口面板自己吃（pointer-events:auto）→ 两个窗口可以并排摆着，
   互不遮挡、都能点。 */
.mesh-layer { position: fixed; inset: 0; z-index: 60; pointer-events: none; }
.mesh-win {
  position: absolute; width: min(680px, 46vw); background: #fff; pointer-events: auto;
  border-radius: 20px; box-shadow: 0 26px 50px -22px rgba(14, 22, 54, .55), inset 0 0 0 .5px rgba(24, 34, 74, .12);
  display: flex; flex-direction: column; overflow: hidden;
}
.mesh-win .mw-hd {
  display: flex; align-items: center; gap: 8px; padding: 8px 12px; cursor: move; user-select: none;
  border-bottom: 1px solid rgba(24, 34, 74, .08); background: linear-gradient(180deg, #fff, #f7f9ff);
}
.mesh-win .mw-hd .sub { color: #6b7280; font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 40%; }
.mesh-win .mw-hd .sp { flex: 1; }
.mesh-win .mw-bd { padding: 0; }
.mesh-win .mw-host { height: 300px; min-height: 0; }
.mesh-win .mw-host.viewer { border-radius: 0; }
.mesh-win .mw-host .loading, .mesh-win .mw-host .alert { margin: 14px; }
/* 右下角总控条：几个窗口 + 全部显示/隐藏/关闭 + 每个窗口一个开关 */
.mesh-bar {
  position: fixed; right: 16px; bottom: 16px; pointer-events: auto; z-index: 61;
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap; justify-content: flex-end;
  max-width: min(760px, 92vw); padding: 8px 10px; border-radius: 18px;
  background: rgba(255, 255, 255, .92); backdrop-filter: blur(8px);
  box-shadow: 0 18px 40px -20px rgba(14, 22, 54, .5), inset 0 0 0 .5px rgba(24, 34, 74, .12);
}
.mesh-bar[hidden] { display: none; }
/* 窗口多了以后，那一串"显示/隐藏某个"的按钮默认收起来，点一下「🪟 3D 窗口 N」才展开 */
.mesh-bar .mw-list { display: none; align-items: center; gap: 6px; flex-wrap: wrap; }
.mesh-bar.open .mw-list { display: inline-flex; }
.mesh-bar .mw-list .btn { max-width: 190px; }
/* 待机与浮现：`.fly-anim` 只负责给过渡（这样 `.fly-wait` 摘掉的那一刻是"淡入上浮"而不是"啪地出现"） */
.fly-anim { transition: opacity .3s ease, transform .3s cubic-bezier(.22,.7,.28,1); }
.fly-wait { opacity: 0; transform: translateY(10px); }

/* ── 第 111 批（业主：「把"网盘不通"做成页面顶部一条黄色提示」）───────────────────────────
   车间网盘连不上时，每一屏顶部一条黄条：说清"哪四件事现在用不了"，并强调"订单数据没问题"。
   ⚠️ 只在**确定不通**（后端回 false）时才显示；"还没探测出来"（null）不显示 —— 宁可晚一点，
      也不要误报把人吓一跳。网盘恢复后由 5 秒一次的信号自己收起来。 */
.netwarn {
  display: flex; align-items: center; gap: 10px; margin: 0 0 10px;
  padding: 9px 14px; border-radius: 18px; font-size: 13px; color: #7a4a00;
  background: #fff7e6; box-shadow: inset 0 0 0 1px #f6d99b, 0 10px 24px -18px rgba(122, 74, 0, .6);
}
.netwarn .ic { font-size: 15px; }
.netwarn .tx { min-width: 0; }
.netwarn .tx b { font-weight: 700; }
.netwarn .sub { color: #a5722a; font-size: 12px; }
.netwarn .sp { flex: 1; }

/* ── 第 103 批（业主：「订单详情页面上放的信息模板要和外面的任务管理订单模板一样，多的设计要求
   放到第二行不要放到左边了」）── 页头改成"一张全宽的表 + 第二行放零碎信息" ────────────────

   改之前：页头是**三块**（左上 订单信息 / 左下 订单进度 / 右边 备注与要求），
   中间那张表被挤在 1.8fr 里，只能上"紧凑版 + 砍掉订单进度列"，看着和任务管理不一样。
   现在：备注与要求搬进「订单信息」的**第二行**（与 交货日期 / 打回·文件 / 设计软件 并列），
   页头整宽都给了那张表 —— 于是它可以与任务管理**逐列一致**（含订单进度列）。

   ⚠️ `.hg-right` 这块**撤了**（`screen-task.js` 里不再渲染）；这一条只是把网格收成一列、
      并把那条竖分隔线去掉，老样式留着不管也不会有元素用到。 */
.task-head .head-grid { grid-template-columns: minmax(0, 1fr); }
.task-head .hg-left { border-right: 0; }
/* 第二行：交货日期 / 打回·文件 / 设计软件 / 备注与要求（要求占剩下的宽度，长了就省略号） */
.task-head .hg-extra { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 20px; }
.task-head .hg-extra .req { flex: 1 1 360px; min-width: 0; display: inline-flex; align-items: center; gap: 8px; }
.task-head .hg-extra .req b { font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.task-head .hg-extra .req b.empty { font-weight: 400; color: #a2a9b8; }

/* ============================================================================
   第 129 批：录单的客户选择
   —— 一开始按业主说的做了"两列"；业主看过截图之后改口：「录单客户还是**改成一列**吧，然后
      **默认不要展开，点击后再展开**选择客户」→ 于是回到**一个系统自带的下拉**：
      一列、默认收起、点开才挑，生产 / 演练两组用 `<optgroup>` 分开；
      第 96 批那条"必须是原生下拉"的口径因此照旧成立（这里不再需要任何自定义样式）。
   ========================================================================== */
/* ============================================================================
   第 129 批补：筛选条上那一排勾选挤回一行
   （业主：「后面的这些框选项目**间隔太大**了，都变成两行了，完全可以间隔小一些就在一行显示完」）

   病根不在这几个字上：`.inline > input { min-width: 120px }` 那句是给"两个输入框并排"写的，
   落到 `<label class="inline"><input type="checkbox">只看加急</label>` 上就变成
   "一个小方框 + 120px 空白"，一排五个勾选被顶成两行。勾选框还原成小方框 + 间距收紧即可。
   ========================================================================== */
.bar .inline { gap: 5px; }
.bar .inline > input[type=checkbox],
.bar .inline > input[type=radio] { min-width: 0; width: auto; }
.bar > label.inline { margin-right: 2px; }

/* 客户列表里的「演练」标（第 129 批） */
.tag.drill { background: #efe7ff; color: #6b3fbf; }

/* ============================================================================
   第 130 批：页脚**悬挂备案号**（ICP + 公安联网备案）

   为什么要"固定"在窗口最下面（而不是塞进各页正文末尾）：ICP 备案号要求悬挂在**网站首页底部**，
   而公网上来的人第一眼看到的是**登录页**（那时还没有会话），登录页是整屏布局 —— 塞正文末尾会掉到
   折叠线以下，等于没挂。所以做成一条贴着窗口底边的细条：
     · **只有填了备案号才存在这个节点**（`api.js` 的 `renderBeian()` 两项都空就不建），
       内网一个像素都不变；
     · `z-index` 压得很低（5）：任何弹层（.mask 是 50）都能盖住它，不会挡住操作；
     · 容器 `pointer-events:none`、只有链接可点 —— 绝不挡住底下那一行内容的点击；
     · `body.has-beian` 补一点下边距，免得页面最后一行内容被这条细条压住。
   ========================================================================== */
.site-beian {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 5;
  padding: 2px 8px calc(2px + env(safe-area-inset-bottom, 0px));
  text-align: center; font-size: 12px; line-height: 18px; color: #6b7280;
  background: rgba(255, 255, 255, .9); border-top: 1px solid rgba(15, 23, 42, .08);
  pointer-events: none;
}
.site-beian a { color: #6b7280; text-decoration: none; pointer-events: auto; }
.site-beian a:hover { color: #2563eb; text-decoration: underline; }
.site-beian .beian-sep { padding: 0 6px; color: #c7ccd6; }
body.has-beian { padding-bottom: 26px; }
