/* ═══════════════════════════════════════════════════════════════════════════
   polish.css —— 全站精修层 · 2026-10-07
   ---------------------------------------------------------------------------
   这一层解决的是「覆盖层统一了、页内细节还是散」的问题。配套的机械收敛见
   _qctest/polish-apply.cjs（字号 1959 处 / 圆角 794 处 / 色值 8236 处归一）。

   本层只做四件事，全部是"外观"层面，不碰 DOM、不动业务：
     ① 版式骨架：顶部标签条、页头身份带、卡脚注、空态、滚动条
     ② 数据面：表格（表头/行高/分隔线/数字对齐）与统计卡的统一
     ③ 交互面：焦点环、悬停、控件高与字体族
     ④ 防溢出：网格/弹性子项 min-width:0、文本省略

   加载位置：index.html 里所有样式表之后（最后一行 link）。
   回退：删掉那一行 <link> 即恢复（本层不修改任何既有文件）。
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── 0. 本层用到的补充令牌 ────────────────────────────────────────────────
   青色（氨解工序）与品红（分装工序）是**功能色**，tokens.css 里没有，
   而 polish-apply 已把它们的近似值收敛到这几个变量上，这里必须定义齐。 */
:root {
  --pl-cyan: #0C9AB8;
  --pl-cyan-ink: #075E75;
  --pl-cyan-bg: #E8F6F9;
  --pl-cyan-line: #BEE3EB;
  --pl-pink: #D9538A;
  --pl-pink-ink: #B03A6A;
  --pl-pink-bg: #FDF0F5;
  --pl-pink-line: #F6D3E2;

  --pl-ctl: 34px;          /* 统一控件高 */
  --pl-row: 44px;          /* 统一数据行高 */
  --pl-head: 34px;         /* 统一表头高 */
  --pl-r: 12px;            /* 统一卡片圆角（= --ui-r-3） */
  --pl-gap: 12px;
}

/* ── 1. 全局：数字一律等宽，中文优先字体 ───────────────────────────────── */
.app, .app * { font-variant-numeric: tabular-nums; }
.app { font-family: "PingFang SC", "Microsoft YaHei", "Segoe UI", system-ui, -apple-system, Roboto, sans-serif; }
/* 顶栏按钮此前算出来是 Arial（字体族漏配），统一跟随全局 */
.tbtn, .sidebar, .sidebar *, .topbar .crumb, .clock { font-family: inherit; }

/* 焦点环：全站统一，键盘可达性 */
.app :focus-visible,
.app a:focus-visible,
.app button:focus-visible,
.app input:focus-visible,
.app select:focus-visible,
.app textarea:focus-visible,
.app [tabindex]:focus-visible {
  outline: 2px solid var(--ui-brand-600);
  outline-offset: 2px;
  border-radius: 6px;
}

/* 滚动条：细、中性、不抢视线（此前各页宽窄不一） */
.app *::-webkit-scrollbar { width: 10px; height: 10px; }
.app *::-webkit-scrollbar-track { background: transparent; }
.app *::-webkit-scrollbar-thumb {
  background: var(--ui-ink-300);
  border: 3px solid transparent;
  background-clip: content-box;
  border-radius: 999px;
}
.app *::-webkit-scrollbar-thumb:hover { background: var(--ui-ink-400); background-clip: content-box; }
.app * { scrollbar-width: thin; scrollbar-color: var(--ui-ink-300) transparent; }

/* ── 2. 顶部多标签条：20+ 页签时此前直接顶出屏幕，没有任何滚动手段 ──────── */
.app-tabs {
  overflow-x: auto !important;
  overflow-y: hidden !important;
  scrollbar-width: none;
  -ms-overflow-style: none;
  flex-wrap: nowrap !important;
  padding-bottom: 0 !important;
}
.app-tabs::-webkit-scrollbar { height: 0 !important; }
.app-tabs > * { flex: 0 0 auto !important; }
.app-tab {
  height: 30px !important;
  min-height: 30px !important;
  display: inline-flex !important;
  align-items: center !important;
  gap: 6px;
  padding: 0 10px !important;
  border-radius: 8px 8px 0 0 !important;
  font-size: 12px !important;
  font-weight: 700 !important;
  line-height: 1 !important;
  white-space: nowrap !important;
  border: 1px solid transparent !important;
  box-shadow: none !important;
}
/* 「唯一的高光」留给当前页签：顶部 2px 品牌色条（原来这里被 box-shadow:none 误杀过） */
.app-tab.on, .app-tab.is-active, .app-tab.active {
  background: var(--ui-brand-050) !important;
  border-color: var(--ui-line-200) !important;
  border-bottom-color: transparent !important;
  color: var(--ui-brand-700) !important;
  font-weight: 800 !important;
  box-shadow: inset 0 2px 0 0 var(--ui-brand-600) !important;
}

/* 页头面包屑：字号进档、字距收紧 */
.crumb .mt { font-size: 16px !important; font-weight: 800 !important; letter-spacing: -.2px !important; }
.crumb .ms { font-size: 11px !important; letter-spacing: .04em !important; color: var(--ui-ink-400) !important; }
.clock .t { font-size: 18px !important; letter-spacing: -.2px !important; }
.tbtn { height: var(--pl-ctl) !important; border-radius: 8px !important; font-size: 12px !important; }

/* ── 3. 重复页头身份带：顶部面包屑已经写了模块名，这里再摆一个 86~114px 的
      大标题带 = 纯重复 + 大片留白。压成一条紧凑身份带，去掉装饰光斑。 ────── */
:is(.page-hero, .rp-hero, .mq-hero, .am-hero, .sp-hero, .od2-hero, .fqc-cockpit, .pd-hero, .oc-hero) {
  min-height: 0 !important;
  padding: 14px 18px !important;
  border-radius: var(--pl-r) !important;
  background: var(--ui-bg-card) !important;
  background-image: none !important;
  border: 1px solid var(--ui-line-200) !important;
  box-shadow: var(--ui-sh-1) !important;
  color: var(--ui-ink-900) !important;
  overflow: hidden;
}
/* 装饰光斑/球体一律隐藏（信息量为 0，却把对比度拉低） */
:is(.page-hero, .rp-hero, .mq-hero, .am-hero, .sp-hero, .od2-hero, .fqc-cockpit, .pd-hero, .oc-hero)
  :is([class*="-orb"], [class*="-glow"], [class*="-blob"], [class*="-deco"], [class*="-shine"]) {
  display: none !important;
}
:is(.pp-hero, .rp-hero, .mq-hero, .am-hero, .sp-hero, .pd-hero) h1,
:is(.page-hero, .rp-hero, .mq-hero, .am-hero, .sp-hero, .od2-hero) h1 {
  text-shadow: none !important;
}
/* 带内的英文副标题：统一成极小灰字（此前 10/12px 混用且字距夸张） */
:is(.mq-hero-s, .sp-hero-sub, .am-hero-sub, .page-hero-sub, .rp-hero-sub, .od2-hero-sub, .pd-hero-sub) {
  font-size: 11px !important;
  letter-spacing: .04em !important;
  color: var(--ui-ink-400) !important;
  opacity: 1 !important;
  text-transform: none !important;
}

/* ── 4. 说明性小字段 → 统一「卡脚注」语气 ────────────────────────────────
   这些段落解释的是"这个页面怎么算"而不是数据本身，占的视觉权重却和正文一样。
   统一压到 11px / 次灰 / 1.55 行高，并限宽，避免整行灰墙。 */
:is(.ov3-foot, .ovz-footbar, .ovz-note, .sp-hero-sub, .sp-kpi-sub, .mq-hero-s, .mqz-aux-hint,
    .fqc-qmode-desc, .am-hero-sub, .am-ledger-path, .am-text-dim-sm, .am-perm-hint, .ov3-meta,
    .dg-note, .fl-note, .rp-note, .pd-note, [class$="-foot"]:not(:where(.mc4-foot)),
    [class*="-foot "]:not(:where(.mc4-foot)), [class$="-hint"]) {
  font-size: 11px !important;
  line-height: 1.55 !important;
  color: var(--ui-ink-400) !important;
  letter-spacing: 0 !important;
  font-weight: 500 !important;
  max-width: 108ch;
}

/* ── 5. 数据表格：全站一套表头/行高/分隔线/数字对齐 ──────────────────────
   排除 96 孔板一类"网格型"表格（.dbe-grid / plate / well），那些是图形不是台账。
   ⚠ 排除条件一律包在 `:where()` 里（零特异性），让本节的整体特异性降到 (1,0,2) ——
      这样各页自己写的 `#pdContent .pd-tbl-import th:nth-child(6){white-space:normal}`
      这类"页面级列规则"能正常压过本节的通用规则。
      （第一版用裸 `:not()` 把特异性抬到 (1,3,3)，实测把分装表头的折行设置吃掉了。） */
#view table:where(:not(.dbe-grid)):where(:not([class*="plate"])):where(:not([class*="well"])):where(:not([class*="cell-well"])) {
  width: 100%;
  border-collapse: separate !important;
  border-spacing: 0 !important;
  font-size: 13px;
  color: var(--ui-ink-700);
}
#view table:where(:not(.dbe-grid)):where(:not([class*="plate"])):where(:not([class*="well"])) thead th {
  height: var(--pl-head) !important;
  padding: 0 10px !important;
  background: var(--ui-bg-soft) !important;
  background-image: none !important;
  color: var(--ui-ink-400) !important;
  font-size: 12px !important;
  font-weight: 800 !important;
  letter-spacing: 0 !important;
  text-align: left;
  white-space: nowrap;
  border-bottom: 1px solid var(--ui-line-200) !important;
  border-top: none !important;
  position: sticky;
  top: 0;
  z-index: 2;
}
#view table:where(:not(.dbe-grid)):where(:not([class*="plate"])):where(:not([class*="well"])) tbody td {
  height: var(--pl-row) !important;
  padding: 0 10px !important;
  border-bottom: 1px solid var(--ui-line-100) !important;
  border-top: none !important;
  font-size: 13px !important;
  line-height: 1.35 !important;
  vertical-align: middle !important;
}
/* 斑马纹取消：分隔线已经足够，两套一起用就是"表格感过重" */
#view table:where(:not(.dbe-grid)):where(:not([class*="plate"])) tbody tr:nth-child(even) td { background: transparent !important; }
#view table:where(:not(.dbe-grid)):where(:not([class*="plate"])) tbody tr:hover td { background: var(--ui-brand-050) !important; }
/* 数字列右对齐（表头带 ↕/⇅ 排序标记或列名以"数/率/条/单/额/量/套/h/%"结尾） */
#view table th[class*="num"], #view table td[class*="num"],
#view table th[class*="qty"], #view table td[class*="qty"] { text-align: right !important; }
/* 单元格里的"+"角标与状态胶囊在竖向居中 */
#view table td > :is(span, b, i, em, div) { vertical-align: middle; }

/* ── 6. 统计卡 / KPI 卡：统一高度、内边距、字号层级与描边 ───────────────── */
:is(.ui-kpi, [class*="kpi-card"], .ov-kpi-d, .sp-kpi-card, .dg-g, .cr-b, .cr-row) {
  min-width: 0;
  border-radius: var(--pl-r) !important;
  box-shadow: var(--ui-sh-1) !important;
}
/* 卡内标签 → 三级灰；数值 → 一级墨；单位 → 小号灰 */
:is(.ui-kpi, [class*="kpi-card"], .ov-kpi-d, .sp-kpi-card, .dg-g, .cr-b) :is(.lb, .k-lb, .lbl, [class*="-label"], [class*="-cap"]) {
  font-size: 12px !important;
  font-weight: 700 !important;
  color: var(--ui-ink-400) !important;
  letter-spacing: 0 !important;
}
:is(.ui-kpi, [class*="kpi-card"], .ov-kpi-d, .sp-kpi-card, .dg-g, .cr-b) :is(b, .v, .val, [class*="-val"], [class*="-value"], [class*="-num"]) {
  font-weight: 800 !important;
  letter-spacing: -.4px !important;
  color: var(--ui-ink-900);
}
:is(.ui-kpi, [class*="kpi-card"], .ov-kpi-d, .sp-kpi-card, .dg-g, .cr-b) :is([class*="-sub"], [class*="-unit"], small, em) {
  font-size: 11px !important;
  font-weight: 600 !important;
  color: var(--ui-ink-400) !important;
}

/* ── 7. 状态胶囊 / 标签：高度与行内基线统一，一律不换行 ─────────────────── */
:is(.badge, [class*="badge"]:not(:where(.has-badge, .badges, [class*="-badges"])), .ui-pill, .bp-tag, .oc-chip, .mqz-tag, .mqz-status, .sp-tag, .sp-badge, .plateTag, .wellTag) {
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center;
  height: 22px !important;
  min-height: 22px !important;
  padding: 0 8px !important;
  border-radius: 999px !important;
  font-size: 11px !important;
  font-weight: 700 !important;
  line-height: 1 !important;
  letter-spacing: 0 !important;
  white-space: nowrap !important;
  vertical-align: middle !important;
  text-shadow: none !important;
}
/* 筛选片/页签形态的"大胶囊"保持 30px，跟状态胶囊区分开 */
:is(.chip, .diag-fbtn, .oc-filtercard .chip, .due-slicer .chip, .search .chip) {
  height: 30px !important;
  min-height: 30px !important;
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  padding: 0 12px !important;
  border-radius: 8px !important;
  font-size: 12px !important;
  font-weight: 700 !important;
  line-height: 1 !important;
  white-space: nowrap !important;
  letter-spacing: 0 !important;
}

/* ── 8. 空态：此前 .ov3-empty 撑到 644×286，一整块空白占掉半屏 ───────────
   ★★ 2026-10-08 修一个真 bug（用户：「有多少加了这种方框，不仅丑还把我的数据都挤压变形了」）：
      原来末尾用的是 `[class$="-empty"], [class*="-empty "]` —— **子串匹配**，
      于是把"状态类" `is-empty` 也一起命中了（中间质检的 `.mq-mv.is-empty`、
      `.mqx-mt-v.is-empty`，工作台的 `.tp-grp.is-empty`、`.pd-collist span.is-empty`，
      工序看板的 `.stcol.is-empty` …）。后果正是用户看到的两件事：
        ① 这里只写了 `border-style: dashed` —— border-width 的初始值是 medium(3px)，
           所以**凭空长出一圈 3px 虚线方框**（截图里"BIO""37470.0"外面那圈框）；
        ② `padding: 22px 16px !important` 把一个 13px 高的数值格子撑到 ~60px，
           同一网格里别的格子被挤到溢出、被容器 overflow 裁掉半截 ⇒「数据被挤压变形」。
      改法：子串匹配 → **明确类名清单**（下表来自全站扫描 `_qctest/collide-inventory.cjs`
      与源码里 48 个以 `-empty` 结尾的类名，`is-empty` 这个状态类排除在外）。
      真空态面板的虚线外观一个不变；数据格子不再长框。 */
:is(.ov3-empty, .ui-empty, .mqz-empty, .mqz-empty2, .am-empty, .pd-empty, .fqc-empty,
    .pd3-empty, .pd2-empty, .dbe-empty, .ov-empty, .tr-empty, .rp-empty, .sp-empty, .dv-empty,
    .mp-empty, .mq-empty, .mqx-empty, .mqs-empty, .mg-empty, .mwx-empty, .w-empty, .live-empty,
    .drawer-empty, .nav-empty, .rework-empty, .rpf-empty, .fqc2-empty, .hr-empty, .sjt-empty,
    .bp-empty, .dlu-empty, .pool-empty, .cart-empty, .mo-cart-empty, .stcol-empty, .dc-empty,
    .ps-empty, .rm-empty, .pv-empty, .log-empty, .rail-empty, .la-empty, .devgrid-empty,
    .mm-empty, .home-empty, .cfg-empty, .dp-empty, .feed-empty) {
  min-height: 0 !important;
  padding: 22px 16px !important;
  gap: 8px !important;
  font-size: 12px !important;
  line-height: 1.5 !important;
  color: var(--ui-ink-400) !important;
  border-style: dashed !important;
  border-color: var(--ui-line-200) !important;
  background: transparent !important;
}
:is(.ov3-empty, .ui-empty, .mqz-empty, .mqz-empty2, .am-empty, .pd-empty, .fqc-empty,
    .pd3-empty, .pd2-empty, .dbe-empty, .ov-empty, .tr-empty, .rp-empty, .sp-empty, .dv-empty,
    .mp-empty, .mq-empty, .mqx-empty, .mqs-empty, .mg-empty, .mwx-empty, .w-empty, .live-empty,
    .drawer-empty, .nav-empty, .rework-empty, .rpf-empty, .fqc2-empty, .hr-empty, .sjt-empty,
    .bp-empty, .dlu-empty, .pool-empty, .cart-empty, .mo-cart-empty, .stcol-empty, .dc-empty,
    .ps-empty, .rm-empty, .pv-empty, .log-empty, .rail-empty, .la-empty, .devgrid-empty,
    .mm-empty, .home-empty, .cfg-empty, .dp-empty, .feed-empty) :is(svg, img, i) {
  width: 26px !important;
  height: 26px !important;
  opacity: .45 !important;
}
/* 工序看板里空列的高度是版面结构（对齐各列），不能压 */
.stcol.is-empty, .stcol-empty { padding: 12px 10px !important; }

/* ── 9. 防溢出：网格/弹性子项默认 min-width:auto，长中文会把卡片撑破 ────── */
#view, .app-tabs, .topbar, :is(.ui-card, .ov3-card, .panel, .mqz-card, .sp-panel, .fqc-panel) { min-width: 0; }
:is(.ov3-card, .mqz-card, .sp-panel, .fqc-panel, .am-hero, .page-hero, .rp-hero, .dq-card) { overflow-wrap: anywhere; }
#view :is(.ov3-h, .ui-card-h, .mqz-head, .sp-panel-h, .panel-h) { min-width: 0; }
#view :is(.ov3-h, .ui-card-h, .mqz-head, .sp-panel-h, .panel-h) h3,
#view :is(.ov3-h, .ui-card-h, .mqz-head, .sp-panel-h, .panel-h) .t {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── 10. 卡片外壳统一：1px 细边 + 一档阴影 + 12px 圆角 ───────────────────
   此前同屏并存 16px/14px/11px/9px 四种圆角与三档阴影强度。 */
:is(.ov3-card, .ui-card, .panel, .mqz-card, .mqs-card, .fqc-card, .fqc-panel, .sp-panel,
    .oc-filtercard, .rp-card, .am-page .ui-card, .oc-tbl-wrap, .pd2-card, .pd3-top) {
  border-radius: var(--pl-r) !important;
  border: 1px solid var(--ui-line-200) !important;
  box-shadow: var(--ui-sh-1) !important;
}
/* 悬停不再"浮起 + 大投影"（大投影在白底上只会发灰） */
:is(.ov3-card, .mqz-card, .fqc-card, .sp-panel, .rp-card):hover {
  transform: none !important;
  box-shadow: var(--ui-sh-2) !important;
}

/* ── 11. 按钮：控件高、圆角、字重、过渡统一（不再 37/34/30/28 混用） ───── */
.app button:not(.app-tab):not(.app-tab-close):not([class*="seg"]):not([class*="tab"]) {
  border-radius: 8px;
  font-weight: 700;
  letter-spacing: 0;
  transition: background-color .14s ease, border-color .14s ease, color .14s ease;
}
/* 只保底"可点面积"≥24px（WCAG 2.2 目标尺寸下限），不强行拉高小图标按钮 */
.app button:not([class*="close"]):not([class*="icon"]):not([class*="ic-"]):not([class*="ic "]) {
  min-height: 24px;
}
.app :is(input, select, textarea) { border-radius: 8px; font-family: inherit; }

/* ── 11.5 固定列宽 + 容器 overflow:hidden = 内容**无声消失** ──────────────
   ⚠ 2026-10-07 修正（第一版这里写得太宽，误伤了作者已经做对的表）：
   全站逐个量过之后，"容器 overflow:hidden 且内容比容器宽"的**只有两处**：
     · 订单中心  `.oc-tbl-wrap` —— app.css 里被 `.panel{overflow:hidden}` 覆盖，
       客户名 232px 塞进 213px 的格子、类别 227px 塞进 187px，
       用户看到"南京世和基…"/"合作 …"且没有任何办法看到全文；
     · 跨工段对账 `.fl-verdict` —— 卡 1372 宽、内容 1440 宽，右边一列数字直接看不见。
   其余表格的容器**本来就是** `overflow-x:auto`
   （app.css:825 `.sp-tbl-wrap`、app.css:5091 `.pd-table-wrap`、remake.js `.rm-tablewrap`），
   而且作者已经用 `table-layout:fixed` + 百分比列宽把表**塞进了容器**
   （workbench.css:4332 `#pdContent .pd-tbl-import`，13/12/8/9/11/21/17/9% + 长文列折行）。
   第一版对二十多个表格类一律 `table-layout:auto !important`，实测把分装那张表
   从 760px 撑到 960px、把作者调好的列宽全部推翻 —— 所以这里收窄到**只修这两处**。 */
#view .oc-tbl-wrap { overflow-x: auto !important; overflow-y: hidden !important; -webkit-overflow-scrolling: touch; }
#view .oc-table { table-layout: auto !important; width: auto !important; min-width: 100% !important; }
#view .fl-verdict { overflow-x: auto !important; }

/* ── 11.6 表格行内的"微型入口"被通用按钮规格撑坏了 ────────────────────────
   skin.css 的按钮统一规则把 `.oc-ship-btn` / `.oc-trace-btn` 和真按钮列在一起，
   套了 `min-height:34px; padding:0 14px`。这两个其实是**订单号后面的行内小胶囊**：
     · 「发货」被撑成宽块，把订单号那一列顶满；
     · 追溯按钮的 12px svg 被挤成 0 宽，只剩一个空的粉色药丸（实测 28×34，svg 0×11）。
   放这里是"最后加载 + 更高特异性"，覆盖 skin.css 那条通用规格。 */
#view table tbody td :is(.oc-ship-btn, .oc-trace-btn, .oc-tag, .board-more) {
  min-height: 0 !important;
  height: 20px !important;
  padding: 0 8px !important;
  border-radius: 999px !important;
  font-size: 11px !important;
  line-height: 1 !important;
  vertical-align: middle !important;
}
#view table tbody td :is(.oc-ship-btn, .oc-trace-btn, .oc-tag) > svg {
  width: 11px !important;
  height: 11px !important;
  flex: 0 0 auto !important;
  min-width: 11px !important;
}

/* ── 11.7 页内"结论/概览"宽卡：内容比卡宽 60~80px 时此前被 overflow:hidden 吞掉
   （实测「跨工段对账」的 `.fl-verdict` 1372 宽 / 内容 1440 宽 —— 最右一列数字看不见）。 */
#view :is(.fl-verdict, .fl-audit-h, .dg-cover-t, .ov3-meta, .dg-cover-hd) { overflow-x: auto !important; }

/* ── 11.8 工序作业台的中栏比台账页窄得多（760px 要放 8~9 列），
      统一收窄单元格内边距与正文字号，把横向滚动条出现概率压到最低。 */
#pdContent :is(.pd-table, .pd2-wtable, .pd-table-wrap table, .pd-tbl-import) th,
#pdContent :is(.pd-table, .pd2-wtable, .pd-table-wrap table, .pd-tbl-import) td {
  padding-left: 6px !important;
  padding-right: 6px !important;
}
#pdContent :is(.pd-table, .pd2-wtable, .pd-table-wrap table, .pd-tbl-import) td { font-size: 12px !important; }

/* ── 11.9 页内「视图」页签条（.ov-tabs）：按钮被写成固定 90px，而里面的英文副标题
      （CAPACITY / CUSTOMER & RISK / QUALITY & OTHERS）在 12px 下要 100px 宽，
      于是英文溢到隔壁页签上，整条页签看起来"高低不齐、字挤在一起"。
      改成按内容宽度 + 英文降到 9px 字距放大一档。 */
#view .ov-tabs { gap: 6px; align-items: stretch; }
#view .ov-tabs > button {
  width: auto !important;
  min-width: 84px !important;
  height: 44px !important;
  padding: 0 14px !important;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 2px;
  white-space: nowrap;
}
#view .ov-tabs > button :is(em, i, small, b + *, span[class*="en"], [class*="-en"]) {
  font-size: 11px !important;
  font-weight: 600 !important;
  letter-spacing: .08em !important;
  line-height: 1 !important;
  opacity: .7;
  white-space: nowrap !important;
  text-transform: uppercase;
}

/* ═══════════════════════════════════════════════════════════════════════════
   14. 行为补丁的样式（配 polish-ux.js）
   ═══════════════════════════════════════════════════════════════════════════ */

/* 14.1 口径说明：脚注灰字墙 → 一枚小胶囊，内容放第二层（悬浮/聚焦/点击） */
.pl-note { position: relative; display: inline-block; margin: 8px 0 2px; }
.pl-note-src { display: none !important; }
.pl-note-btn {
  display: inline-flex; align-items: center; gap: 4px;
  height: 20px; padding: 0 8px;
  border: 1px solid var(--ui-line-200);
  border-radius: 999px;
  background: var(--ui-bg-soft);
  color: var(--ui-ink-400);
  font: inherit; font-size: 11px; font-weight: 700; letter-spacing: 0;
  cursor: pointer;
  transition: color .14s ease, border-color .14s ease, background .14s ease;
}
.pl-note-btn:hover, .pl-note.is-open .pl-note-btn {
  color: var(--ui-brand-700); border-color: var(--ui-brand-600); background: var(--ui-brand-050);
}
.pl-note-btn svg { flex: 0 0 auto; }
.pl-note-pop {
  display: none;
  position: absolute; left: 0; top: calc(100% + 6px); z-index: 60;
  /* ⚠ 绝对定位 + width:auto 会"收缩包裹"到**包含块（这枚胶囊，约 77px）**的宽度，
     实测气泡只有 77×117、文字被压成细长一列。所以必须给 max-content 再靠 max-width 收口。 */
  width: max-content;
  max-width: min(460px, 62vw);
  padding: 10px 12px;
  border: 1px solid var(--ui-line-200);
  border-radius: 10px;
  background: var(--ui-bg-card);
  box-shadow: var(--ui-sh-3);
  color: var(--ui-ink-500);
  font-size: 12px; font-weight: 500; line-height: 1.65; letter-spacing: 0;
  white-space: normal; text-align: left;
}
.pl-note:hover .pl-note-pop,
.pl-note:focus-within .pl-note-pop,
.pl-note.is-open .pl-note-pop { display: block; }
/* 靠右的脚注把气泡翻到右侧对齐，避免溢出卡片 */
.pl-note.is-flip .pl-note-pop { left: auto; right: 0; }

/* 14.2 零值工序行：连续 ≥3 行为 0 时收成一条摘要（零的信息保留，空轨道去掉） */
.pl-zerorow {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px;
  min-height: 30px; height: 30px;
  padding: 0 10px; margin: 2px 0;
  border: 1px dashed var(--ui-line-200);
  border-radius: 8px;
  background: transparent;
  color: var(--ui-ink-400);
  font-size: 12px; font-weight: 600; letter-spacing: 0;
  cursor: pointer;
  transition: color .14s ease, border-color .14s ease, background .14s ease;
}
.pl-zerorow:hover { color: var(--ui-ink-700); border-color: var(--ui-ink-300); background: var(--ui-bg-soft); }
.pl-zerorow b { font-variant-numeric: tabular-nums; color: var(--ui-ink-700); font-weight: 800; }
.pl-zerorow-c { display: inline-flex; align-items: center; gap: 4px; color: var(--ui-ink-300); font-weight: 700; }
.pl-zerorow-c svg { transition: transform .16s ease; }
.pl-zero-open .pl-zerorow-c svg { transform: rotate(180deg); }
.pl-zero-folded:not(.pl-zero-open) > .ps-row.is-zero { display: none !important; }

/* 14.3 页头身份带里的重复标题（与顶栏 #modTitle 同字符串）：隐藏后整条更像"页脚注" */
.pl-hero-dup { display: none !important; }
.pl-hero-nodup { padding-top: 10px !important; padding-bottom: 10px !important; }

/* ── 15. 数据面收尾 ───────────────────────────────────────────────────── */

/* ── 15. 告警砖（.dg-acts > .dg-g）文案被砍 ───────────────────────────────
   实测结构：砖宽 218px，第一行「标题 + 查看 N 单 →」共享 194px，
   `.dg-g-go` 固定吃掉 61px ⇒ 标题只剩 125px，而
     「需处理 · 逾期 + 风险窗内（≤3 天）」需要 184px
     「已过预计完成时间 · 立即处理」需要 143px（副标题只剩 126px）
   两处都是 nowrap + ellipsis ⇒ 用户看到「需处理 · 逾期 + 风险…」「已过预计完成时间 · 立…」。
   做法：标题/副标题改成最多两行折行（不再是砍一半），砖高交给 grid 自动等高，
   并把「查看 N 单」压小一档把宽度还给标题。 */
#view .dg-acts.is-compact .dg-g { height: auto !important; min-height: 60px; justify-content: space-between !important; }
#view .dg-acts.is-compact .dg-g-k {
  white-space: normal !important;
  overflow: visible !important;
  text-overflow: clip !important;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  line-height: 1.35 !important;
  min-width: 0;
  /* 标题一律预留两行：这样 6 块砖的「查看 N 单 →」全部落在第二行同一条基线上，
     否则标题一行的砖链接在上、两行的砖链接在下，横着扫过去是锯齿。 */
  min-height: 2.7em;
}
#view .dg-acts.is-compact .dg-g-s {
  white-space: normal !important;
  overflow: visible !important;
  text-overflow: clip !important;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  line-height: 1.35 !important;
  min-width: 0;
}
#view .dg-acts .dg-g-go { font-size: 11px !important; white-space: nowrap !important; }
/* 两行内容块内部按"底边"对齐：标题折两行时「查看 N 单」贴它最后一行，
   数值折两行时副标题贴它最后一行 —— 这样 6 块砖的链接与副标题各自落在同一条基线上。 */
#view .dg-acts .dg-g-d1 { align-items: flex-end !important; }
#view .dg-acts .dg-g-d2 { align-items: flex-end !important; }

/* ── 11.10 分装中栏表（`.pd-tbl-import`）：列宽再平衡 ─────────────────────
   修掉内联 `min-width:960px` 之后表宽回到 758px（中栏 760，横向滚动消失），
   但照实测的「最长内容（含内边距）」对一遍，有 3 列差 7~13px 会被省略号吃掉：

   | 列 | 内容 | 需要 | 原分配(13/12/8/9/11/21/17/9%) |
   | --- | --- | --- | --- |
   | 引物编号 | `WI09_160993` | 106px | 99px |
   | 订单编号 | `HS260916046` | 104px | 91px |
   | 离心管类型 | `1.5ml离心管` | 91px | 83px |

   编号列是**标识符**，被省略号吃掉等于查不了；而「客户特殊要求 / 工单备注」本来就是两行折行
   （`.pd-clamp2` 两行截断 + `title` 提示 + 点击展开全文），多给它们是浪费。
   据此把百分比重新分配（合计仍是 100%）。放本层是因为最后一个加载 = 同特异性下胜出，
   不改 workbench.css 里作者那一段。 */
#pdContent .pd-tbl-import th:nth-child(1) { width: 15.5%; }
#pdContent .pd-tbl-import th:nth-child(2) { width: 15%; }
#pdContent .pd-tbl-import th:nth-child(3) { width: 8.5%; }
#pdContent .pd-tbl-import th:nth-child(4) { width: 9%; }
#pdContent .pd-tbl-import th:nth-child(5) { width: 13%; }
#pdContent .pd-tbl-import th:nth-child(6) { width: 15%; }
#pdContent .pd-tbl-import th:nth-child(7) { width: 13%; }
#pdContent .pd-tbl-import th:nth-child(8) { width: 11%; }

/* ── 11.11 发货出库台账：有 3 个单元格**连 title 提示都没有** ─────────────
   实测 `.sp-table`（12 列 / 容器 1368，不滚动）：
     · 客户单位（列3）205px 装 368px → 10 个单元格省略号（这 10 个都有 title，悬停可看）
     · 包装人 / 报工人 / 发货人（列5/6/7）各 71px 装「戴婷婷、杨璐瑶」115px
       → 3 个单元格省略号，**且没有 title** —— 也就是说这 3 格的内容在界面上根本拿不到。
   这四列本来就是人名 / 公司名，折行是自然的（「、」与空格都是断点），
   直接允许两行，既不用重排列宽，也不会把行撑高（两行 32px 仍在 44px 行高内）。 */
#view .sp-table :is(th, td):nth-child(3),
#view .sp-table :is(th, td):nth-child(5),
#view .sp-table :is(th, td):nth-child(6),
#view .sp-table :is(th, td):nth-child(7),
#view .sp-table :is(th, td):nth-child(10) {
  white-space: normal !important;
  overflow-wrap: anywhere;
  line-height: 1.35 !important;
}

/* ── 11.12 发货出库：列宽再分配 ──────────────────────────────────────────
   实测 `.sp-table-fixed` 的 colgroup（app.css:5456），用"逐单元格 scrollWidth"量：
     · `col.c-ops` 13.3% = 182px，里面只有「驳回 删除」两个按钮（实测需 129px）→ 空 53px
     · `col.c-oid` 12.7% = 174px，要放「WS260921010延期发货合作」232px → 2 个单元格被吃掉
     · `col.c-cust` 15% 客户单位列已经在折行，不差这 0.5%
   把操作列与客户单位列空出来的宽度挪给订单号列。 */
.sp-table-fixed col.c-oid { width: 17%; }
.sp-table-fixed col.c-ops { width: 9.5%; }
.sp-table-fixed col.c-cust { width: 14.5%; }

/* ── 11.13 现场变更表（`.pd-site-tbl`）：2190px 收进 1376px 容器 ────────────
   实测（Range 量内容自然宽度 / 容器 1376）：

   | 列 | 自然需要 | 说明 |
   | --- | --- | --- |
   | 变更类型 | 72 | |
   | 工段 | **149** | 实测最长是 `dispensing,packaging`，不是"合成" |
   | 位置 | **181** | 实测最长是「Frits膜生产产品的后处理体积」 |
   | 变更前 | **747** | 工序描述长文 |
   | 变更后 | **994** | 工序描述长文 |
   | 原因 | **765** | 工序描述长文（原来靠 764px 列宽"刚好全显示"，**没有 title**） |
   | 其余 7 列 | 627 | 审核/签署/进度/人/时间/操作 |
   | 合计 | **3535** | |

   ⇒ 13 列在 1376px 里**不可能全展开**。按已确认的方案：三段长文**两行截断 + title 悬停看全文**
   （原因列的 title 是本轮新补的），工段/位置两列折行，其余列按自然需要给宽。
   表头内联的 `min-width:1500px` 已去掉 —— 内联写死宽度会和样式表打架（分装表吃过一次亏）。 */
#pdContent .pd-site-tbl { table-layout: fixed !important; width: 100% !important; min-width: 0 !important; }
#pdContent .pd-site-tbl th:nth-child(1) { width: 5%; }      /* 变更类型 */
#pdContent .pd-site-tbl th:nth-child(2) { width: 6%; }      /* 工段（折行） */
#pdContent .pd-site-tbl th:nth-child(3) { width: 6%; }      /* 位置（折行） */
#pdContent .pd-site-tbl th:nth-child(4) { width: 13%; }     /* 变更前（两行截断） */
#pdContent .pd-site-tbl th:nth-child(5) { width: 13%; }     /* 变更后（两行截断） */
#pdContent .pd-site-tbl th:nth-child(6) { width: 12.5%; }   /* 原因（两行截断） */
#pdContent .pd-site-tbl th:nth-child(7) { width: 5.5%; }    /* 审核 */
#pdContent .pd-site-tbl th:nth-child(8) { width: 6.5%; }    /* 签署 */
#pdContent .pd-site-tbl th:nth-child(9) { width: 5%; }      /* 执行进度 */
#pdContent .pd-site-tbl th:nth-child(10) { width: 4.5%; }   /* 变更人 */
#pdContent .pd-site-tbl th:nth-child(11) { width: 8.5%; }   /* 审核/执行人 */
#pdContent .pd-site-tbl th:nth-child(12) { width: 8.5%; }   /* 时间（"2026-08-03 08:00" 需 113px） */
#pdContent .pd-site-tbl th:nth-child(13) { width: 8%; }     /* 操作（按钮组需 109px） */
/* 工段 / 位置：标签型内容，允许折行（`dispensing,packaging` 在逗号处断） */
#pdContent .pd-site-tbl :is(th, td):nth-child(2),
#pdContent .pd-site-tbl :is(th, td):nth-child(3) {
  white-space: normal !important;
  overflow-wrap: anywhere;
  line-height: 1.35 !important;
}
/* 三段长文：两行截断（td 上不能用 -webkit-line-clamp，会破坏表格布局，所以套了一层 span） */
#pdContent .pd-site-tbl td.pd-site-long { white-space: normal !important; vertical-align: top !important; padding-top: 6px !important; padding-bottom: 6px !important; }
#pdContent .pd-site-clamp {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  text-overflow: ellipsis;
  overflow-wrap: anywhere;
  line-height: 1.45;
  cursor: zoom-in;
}
#pdContent .pd-site-clamp.is-open {
  display: block;
  -webkit-line-clamp: unset;
  overflow: visible;
  cursor: zoom-out;
}

/* ── 11.14 交期天数分布「刻度尺」（.dr）：把「N 单」行钉齐 ─────────────────
   实测（`_qctest/probe-dueruler.cjs`）：8 格的「N 单」散落在 **5 个不同高度**上
   （y = 146 / 174 / 190 / 192 / 194），「条数」也一样（y = 10 ~ 158）。

   根因在 theme.css:2505：`.dr-c{height:var(--h,100%);justify-content:space-between}`
   —— **卡片高度本身在编码数值**（--h = 38% + 62%×值/最大值），格子一高一矮，
   里面四行（条数 / 横条 / 单数 / 标签）就被 space-between 各自拉开。

   后果很具体：用户把「已过交期」的 **9 单**（y=146）读成了「今天」那一格的
   （今天的「0 单」在 y=194，中间差 48px ≈ 两行）。

   而这个高度编码是**冗余的** —— 同一个数已经用「横条宽度 + 数字」表达过两次。
   去掉它，四行自然对齐：
     第 1 行 条数（顶） ｜ 第 2 行 横条 ｜ 第 3 行 单数 ｜ 第 4 行 标签（底）
── */
#view .dr { height: 240px; align-items: stretch !important; }
#view .dr-c {
  height: 100% !important;
  justify-content: flex-start !important;
  gap: 6px !important;
}
#view .dr-c > b { flex: 0 0 auto; }
#view .dr-c > .dr-b { flex: 1 1 auto !important; margin-top: 2px; }
/* 「N 单」不许折行：实测「今天」那格只有 31px 宽，「0 单」在空格处断成两行，
   于是它的上沿比别的格高 18px —— 8 格里就它一个错位，最扎眼。 */
#view .dr-c > u { flex: 0 0 auto; font-size: 11px !important; white-space: nowrap !important; }
/* 标签固定占两行高度：标签长短不一（"今天" vs "30 天以后"），
   如果按内容高，折行的标签会把上面的「N 单」顶高，一样错位。 */
#view .dr-c > .dr-lb {
  margin-top: auto !important;
  flex: 0 0 auto;
  min-height: 2.5em;
  display: flex;
  align-items: flex-end;
  justify-content: center;
}

/* —— 把 5px 横条换成"液体柱" ——
   这一格的数据形态是"8 个桶、5 个是 0"，正是**液体柱**最合适的场景：
   柱高＝该桶占最大桶的比例，零桶就是一条空的浅色轨道（"0" 本身仍由上方数字显式给出）。
   原来那条 5px 横条 + 用卡片高度编码数值，等于同一个数表达三次，
   而且腾出来的 158px（占刻度尺高度 66%）全是空白。现在这块空间变成了信息。 */
#view .dr-b {
  width: 100% !important;
  height: auto !important;
  min-height: 34px;
  border-radius: 6px !important;
  background: rgba(28,28,28, .05) !important;
  display: flex !important;
  align-items: flex-end !important;
  overflow: hidden;
  margin-top: 4px !important;
}
#view .dr-b > i {
  display: block !important;
  width: 100% !important;
  height: var(--f, 0%) !important;
  min-height: 0 !important;
  border-radius: 6px 6px 0 0 !important;
  transition: height .18s ease;
}
/* 零值桶：轨道留一条虚线边，明确"这一格问过了，答案是 0"（不是没数据） */
#view .dr-c.is-z .dr-b { background: transparent !important; border: 1px dashed var(--ui-line-200); }
#view .dr-c.is-z .dr-b > i { display: none !important; }

/* ── 11.15 深色主题下"装饰圆"撑破卡片（浅色下本来是对的） ────────────────
   app.css 给三处挂了"半透明白圆"装饰：
     `.grid.kpis .pk-card::before/::after`（app.css:3791 / 3800）
     `.am-hero::before/::after`（app.css:635 / 636）
     `.sp-hero::before/::after`（app.css:778 / 779）
   这些圆的坐标是**负偏移**（例：`top:-38px;right:-38px;140px×140px`），
   而 skin.css 的中和规则全部带 `html:not([data-theme="dark"])` 前缀 —— **只管浅色**。

   实测后果（1680×1000，深色）：
     · 工序看板 6 张 `.pk-card` 全中：卡 218px / 内容 252px（**横向溢出 34px**），
       且内容高 128 > 盒高 118（纵向也溢出 10px）；
     · 发货出库 `.sp-hero` 1378 / 1406；
     · 系统管理 `.am-hero` 1378 / 1396。
     浅色下这三个页面都不溢出（因为 ::before 被隐藏、::after 被改成 inset:0 的白纱）。

   ⚠ 不能两个主题一起隐藏 `::after`：浅色下它已经被 skin.css 改造成**盖在卡上的白纱**
   （`background:rgba(255,255,255,.88)`），是"彩卡压成浅卡"的关键，去掉会让深色文字
   落在彩色卡面上、对比度直接崩。所以这里**只针对深色**隐藏装饰圆。 */
html[data-theme="dark"] :is(.grid.kpis .pk-card, .am-hero, .sp-hero)::before,
html[data-theme="dark"] :is(.grid.kpis .pk-card, .am-hero, .sp-hero)::after {
  display: none !important;
}

/* ═══════════════════════════════════════════════════════════════════════════
   16. 对比度补课（WCAG 2.2 AA）· 2026-10-07
   ---------------------------------------------------------------------------
   `_qctest/audit-contrast.cjs` 全站 42 页实测（每页采样所有可见文字，往上找
   第一个不透明背景算比值）。改前浅色主题有 **4770 个**元素低于阈值，
   而且高度集中在少数几类上 —— 最大元凶是 **`--ui-ink-400` (#767676) 被用在
   12px 以下的小字上：白底 3.7:1、浅灰底 3.25:1，而 WCAG 对 <18.66px 正文要求 4.5:1。**

   本节把"小字"统一提到 `--ui-ink-500`（白底 5.4:1 / 浅灰底 5.1:1），
   `--ui-ink-400` 只留给 ≥14px 的次要文字。另外几个是源层的语义色本身就偏亮。
   ═══════════════════════════════════════════════════════════════════════════ */

/* ① 表头：24 页命中，实测 3.25:1（我自己在第一轮把 th 设成了 ink-400，属自造问题） */
#view table:where(:not(.dbe-grid)):where(:not([class*="plate"])):where(:not([class*="well"])) thead th {
  color: var(--ui-ink-500) !important;
}
/* ② 顶栏英文副标题：31 页命中，3.70:1 */
.crumb .ms { color: var(--ui-ink-500) !important; }
/* ③ 顶栏日期：24 页命中，2.99:1 */
.clock .d { color: var(--ui-ink-500) !important; }
/* ④ 交期预警计数徽标：31 页命中，3.76:1（#EF4444 红字在白底上偏亮） */
.tbtn.delivery-alert .da-badge, .da-badge { color: var(--ui-danger-ink) !important; }
/* ⑤ 顶栏班次绿字：28 页命中，2.53:1（skin.css 里有一条压深规则但没生效，这里兜住） */
.shift b, .shift .B { color: var(--ui-ok-ink) !important; }
.shift-cnt { background: var(--ui-ok-ink) !important; }
/* ⑥ 图卡英文副标题（"7-DAY TREND" 这类）：1.90:1 ≈ 看不见。它是中文标题的附注，
      提到 ink-400（3.5:1）即可 —— 比原来好一倍，且不抢中文标题的层级。 */
:is(.ov3-en, .ov3-h .en, [class$="-en"], [class*="-en "]) { color: var(--ui-ink-400) !important; }
/* ⑦ 占位破折号 / 装饰箭头：1.45~1.73:1。它们是纯图形符号（"无数据"的占位），
      提到 ink-300 保证能看见轮廓，但仍明显弱于正文。 */
:is(.sep, .pd3g-arw) { color: var(--ui-ink-300) !important; }

/* ═══════════════════════════════════════════════════════════════════════════
   17. 深色主题补课 · 2026-10-07
   ---------------------------------------------------------------------------
   之前 42 页只验了浅色。补测深色（`QC_THEME=dark`）发现三类真问题：
   ═══════════════════════════════════════════════════════════════════════════ */

/* 17.1 ★ 最严重：深色下侧栏主菜单几乎看不见
   活动皮肤 E 的侧栏配色写在 `html[data-skin="E"]:not([data-theme="dark"])` —— **只配了浅色**。
   深色下 `--sk-rail-txt` 掉回 :root 的 `#4f4f4f`（那是"浅色侧栏配深字"用的），
   而侧栏底色仍是深海军蓝 → 实测 `#4f4f4f on #292929 = 1.69:1`，**38 页全中**。
   这里把皮肤 E 那套深蓝侧栏的"字/线/态"值按深色主题补上（只补文字与描边，
   不动 `--sk-rail-1/2`，避免改变深色侧栏现有的渐变观感）。 */
html[data-theme="dark"] {
  --sk-rail-txt: #cecece;
  --sk-rail-txt-2: #818181;
  --sk-rail-txt-hi: #f9f9f9;
  --sk-rail-line: rgba(255, 255, 255, .10);
  --sk-rail-hover: rgba(255, 255, 255, .08);
  --sk-rail-pin-bg: rgba(255, 255, 255, .045);
  --sk-rail-field: rgba(255, 255, 255, .08);
  --sk-rail-field-focus: rgba(255, 255, 255, .13);
  --sk-rail-badge: rgba(255, 255, 255, .14);
  --sk-rail-thumb: rgba(255, 255, 255, .18);
  --sk-rail-thumb-hover: rgba(255, 255, 255, .30);
  --sk-rail-rail-bg: rgba(15,15,15, .42);
}

/* 17.2 我自己漏的：--pl-cyan-* / --pl-pink-* 没有深色版本
   这两个工序功能色是 2026-10-07 新登记进 tokens.css 的，只写了 `:root`。
   深色下它们的 `-ink` 仍是深色值（#075E75）叠在深底上 → 实测 `在制 9` = 2.11:1。 */
html[data-theme="dark"] {
  --pl-cyan: #4FC3DC;   --pl-cyan-ink: #8FDCEB;   --pl-cyan-bg: #0E2C33;   --pl-cyan-line: #1C4A55;
  --pl-pink: #F08CB4;   --pl-pink-ink: #F7AFCB;   --pl-pink-bg: #2E1622;   --pl-pink-line: #55283C;
}

/* 17.3 顶栏「班次」胶囊：深色下底仍是浅灰、字却变浅 → 1.21~1.46:1（浅字叠浅底） */
html[data-theme="dark"] .shift {
  background: rgba(255, 255, 255, .07) !important;
  border-color: rgba(255, 255, 255, .14) !important;
}
html[data-theme="dark"] .shift .lbl { color: var(--ui-ink-400) !important; }
html[data-theme="dark"] .shift b, html[data-theme="dark"] .shift .B { color: #6FE3AE !important; }
html[data-theme="dark"] .shift-cnt { background: rgba(255, 255, 255, .16) !important; color: #eeeeee !important; }

/* 17.4 深色下语义"ink"色本来就是浅色（tokens.css 已重映射），但徽标底仍是白的 →
   交期预警计数在深色下变成"浅粉字叠白底"。这里把徽标底也交给令牌。 */
html[data-theme="dark"] .da-badge {
  background: rgba(255, 154, 165, .16) !important;
  color: var(--ui-danger-ink) !important;
}

/* 17.5 ★ 深色下最大的单一来源：`--sk-*` 整套没被重映射
   ---------------------------------------------------------------------------
   `tokens.css` 的深色块把 `--ui-*`（含老变量桥 `--txt/--line/--panel*`）全翻过来了，
   但 **`--sk-*` 一个都没管** —— 而 skin.css 的消费量很大：

     令牌            当前景  当背景  当边框    方向
     --sk-ink          312      5      1     文字 → 深色下必须变亮
     --sk-ink-2        137      0      1     文字 → 变亮
     --sk-ink-3         99      3      0     文字 → 变亮
     --sk-soft           0     53      0     表面 → 变暗
     --sk-line           1      0     54     边框 → 变暗
     --sk-page           0      8      1     表面 → 变暗
     --sk-line-2         0      0      7     边框 → 变暗

   因为"文字/表面"方向是**单向**的（文字令牌几乎只当文字、表面令牌只当表面），
   所以这一处重映射是安全的，并且一次性修掉大片深色失败。
   取值直接对齐 `tokens.css` 深色块里 `--ui-*` 的对应档，保证两套令牌不打架。 */
html[data-theme="dark"] {
  /* 文字三档 */
  --sk-ink: #eeeeee;
  --sk-ink-2: #939393;
  --sk-ink-3: #888888;
  /* 表面与分隔 */
  --sk-card: #202020;
  --sk-soft: #272727;
  --sk-page: #181818;
  --sk-page-2: #272727;
  --sk-line: #3c3c3c;
  --sk-line-2: #313131;
  /* 阴影在深色下要更实，否则卡片完全浮不起来 */
  --sk-sh-1: 0 1px 2px rgba(0, 0, 0, .35);
  --sk-sh-2: 0 8px 22px -12px rgba(0, 0, 0, .65);
  --sk-sh-3: 0 18px 44px -28px rgba(0, 0, 0, .8);
}

/* 17.6 工序作业台 KPI 卡的配色令牌（浅/深各一套）
   来源：`production.js` 的 `PD3_KPI_COLOR` 原来是字面量十六进制，只适合浅色。
   现在它引用 `--kpi-*`，浅色值 = 原来的字面量（**浅色下视觉零变化**），
   深色值取 tokens.css 深色块里同族的 `-ink` 档（那些值本来就是为了在深底上可读）。 */
:root {
  --kpi-pending: #5e5e5e;
  --kpi-running: #D97706;
  --kpi-waiting: #075E75;
  --kpi-done: #0A7043;
  --kpi-rework: #DC2626;
  --kpi-supp: #D9538A;
  --kpi-handoff: #D97706;   /* "待下游队列"（待氨解/待纯化/待分装）——需要关注，不是完成 */
  --kpi-default: #6e6e6e;
}
html[data-theme="dark"] {
  --kpi-pending: #767676;
  --kpi-running: #F5C77E;
  --kpi-waiting: #8FDCEB;
  --kpi-done: #5FE0A8;
  --kpi-rework: #FF9AA5;
  --kpi-supp: #F7AFCB;
  --kpi-handoff: #F5C77E;
  --kpi-default: #767676;
}

/* 17.7 深色：按**元素数量**排出来的头部问题（前 22 类占全站 73%）
   ---------------------------------------------------------------------------
   实测体量（`report-contrast-volume.cjs`）：
     .pd-op-exec           583 个（线边物料 583 行 × 行内「编辑」按钮）  4.15:1
     .pd-badge-running     120 个（同一页的行内状态胶囊）              4.15:1
     .tl-dot                60 个（装饰点）                            1.19:1
     .bp-tag.tone-a         36 个（4 页的红色标签）                    3.98:1
     .badge.b-cyan          34 个（10 页）                             1.75:1
     .k-lb/.k-cap           56 个（8 页 hero 带上的灰标签）             3.56:1
   共同点：**浅色下成立的"中/深色文字"，在深底上对比度不够**。
   这不是"没配深色"，而是"配了但用的是浅色的那一档"。统一提到同族的 `-ink`/亮档即可。 */
:is(.pd-op-exec, .pd-badge-running,
    .badge.b-cyan, .badge.b-blue, .badge.b-info, .badge.b-brand) {
  color: var(--ui-brand-700) !important;
}
:is(.badge.b-amber, .badge.b-warn, .badge.b-orange) { color: var(--ui-warn-ink) !important; }
:is(.badge.b-red, .badge.b-danger) { color: var(--ui-danger-ink) !important; }
:is(.badge.b-violet, .badge.b-purple, .badge.b-pink) { color: var(--pl-pink-ink) !important; }
:is(.badge.b-gray, .badge.b-grey, .badge.b-mute) { color: var(--ui-ink-400) !important; }
/* 红色系"文字型"用法：链接、标签、日期刻度 */
:is(.bp-tag.tone-a, .dg-g-go, .dg-rl-d, .bp-link, .bp-link-block, [class*="more-link"]) {
  color: var(--ui-danger-ink) !important;
}
/* hero 带 / 深色卡上的灰标签。
   ⚠ 踩坑：tokens.css 的深色块里**中性阶的绝对亮度是反的** ——
     ink-900=#eeeeee（最亮）… ink-300=#6b6b6b（最暗）。
   所以"深色下要把文字提亮"要往**小号**走（ink-700/500），不能想当然用 ink-300。
   我第一版写成 ink-300，实测把 3.56:1 反而压到 2.88:1。 */
:is(.k-lb, .k-cap, .ov-kpi-d .k-cap) { color: var(--ui-ink-500) !important; }
.tl-dot { color: var(--ui-ink-500) !important; }

/* ── 18. 收尾：把「只有深色才修」的那批规则放开到两个主题 + 浅色压深 --sk-ink-3 ──
   ---------------------------------------------------------------------------
   ① 浅色下同一批类也在失败，根因完全相同（品牌亮蓝 / 语义中调色被当**文字**用）：
        .pd-op-exec   浅色 3.20:1（on #eeeeee） ｜ 深色 4.15:1
        .q-view       浅色 3.24:1
      所以第 17.7 节的规则**不再挂 html[data-theme="dark"] 前缀** ——
      它们指向的 -ink / -700 档本来就是"给浅底当文字用"调的，两个主题都成立。

   ② --sk-ink-3 在浅色下压深一档：
      盘点过它的用法是**单向**的（99 处当前景 / 仅 3 处当背景），整体压深是安全的。
      实测 #727272 在白底上 3.24:1、在 #f1f1f1 上 2.88:1；
      压到 --ui-ink-500 那一档（#616161）→ 白底 5.1:1。
      这一条一次修掉 547 个空值占位「—」、.tr-dim 说明文字、以及一批 --sk-ink-3 标题。
      （深色下 --sk-ink-3 已在 17.5 节单独给值，:root 这条不影响深色。） */
:root { --sk-ink-3: #616161; }

/* ③ 剩余点名类（两个主题通用，令牌会自己翻） */
:is(.ui-count, .tr-dim, .wc-st.is-todo) { color: var(--ui-ink-500) !important; }
:is(.q-view) { color: var(--ui-brand-700) !important; }
:is(.g-u) { color: var(--ui-ok-ink) !important; }
:is(.hot, .tl-k3.is-over) { color: var(--ui-danger-ink) !important; }

/* ── 12. 表格底部/分页条：把"共 N 条 · 第 x-y 条"这类拼串统一语气 ──────── */
:is(.ui-count, .oc-count, .sp-count, .tbl-count, [class$="-pager"], [class*="pager"]) {
  font-size: 12px !important;
  color: var(--ui-ink-400) !important;
  letter-spacing: 0 !important;
}

/* ── 13. 减少无效动效（保留加载与淡入） ────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .app *, .app *::before, .app *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}
