/* ══════════════════════════════════════════════════════════════════
   customers.css —— 客户站：全宽表格客户列表页（13 列 · 合计 1370px + 横滚）
   纪律：本文件不得出现字面色值，一律 var() 令牌。
   来源：mockup/中台-统一原型.html 1172–1219 / 2191–2197 行。
   ★ 与中栏 .row 的差异是刻意的：表格页 = 「在一群人里找/比/批量操作」⇒ 密度不同、组件不同。
   ══════════════════════════════════════════════════════════════════ */
/* ★ 页头允许自然换行（2026-09-17）：页头动作簇里新增了「AI 研判」两枚形态按钮，
   窄窗（B 版副驾栏占走 300px 后 crmbody 只剩 373px）必然放不下 ⇒ 不换行就被
   `#crmbody{overflow:hidden}` 静默剪掉最右的「导出当前筛选」。同 `.fbar` 一条纪律：宁换行不裁掉。 */
/* ★ `position:relative` 是**给列设置面板当锚点**用的（2026-09-23 · D 线）：
   面板是 `.pagehd` 的绝对定位子元素（见下方 `.ddcolset`），没有这一步它就会去认更外层的
   定位祖先（`.scroll` 或 `body`）⇒ 位置整个跑掉。
   ⚠ 加 `relative` **不改任何布局尺寸**：`.pagehd` 仍是 flex 容器、高度仍是它那三段之和
     （`crmai.mjs` 有一条量 `.pagehd` 高度的断言 ⇒ 这里动不得别的属性）。
   ⚠ 反过来也成立：`.pagehd` 内**不许**出现参与排版的额外子元素（那会改高度）——
     面板正是靠 `position:absolute` 把自己排除在排版之外的。 */
.crm .pagehd{display:flex;flex-wrap:wrap;align-items:baseline;gap:10px;row-gap:6px;padding:14px 18px 10px;position:relative}
.crm .pagehd h2{font-size:var(--fs-h3);font-weight:600}
.crm .pagehd .cnt{color:var(--t3);font-size:var(--fs-caption)}
.crm .pagehd .sp{margin-left:auto;display:flex;align-items:center;gap:8px;flex-wrap:wrap;row-gap:6px}
/* AI 研判形态按钮：外壳零新增样式 —— 复用页头既有的 `.chipbtn`（`.on` = 当前态），
   只补一个前缀小标签与键盘焦点环（既有 `.chipbtn` 没有 focus 样式）。
   ★ 加「槽」的理由（2026-09-17 出图复看后补）：本开关是**设计稿没有、按"两版都做·可切换"
     新增的件**，而页头右边原本已有「列设置 / 导出当前筛选」两枚同为 `.chipbtn` 的按钮 ——
     不加槽时五枚胶囊视觉同级，读起来像五个平级按钮，看不出"全宽带/副驾栏"是一组二选一。
     槽的做法：一个 `--e2` 底 + 圆角的口袋包住两枚 chip，与后面的独立按钮拉开层级。
     ⚠ 槽只包 `.chipbtn`，**不包 `.lb` 文字标签**（标签是组名，包进去会挤成一体）；
     选中态沿用 `.chipbtn.on` 的 accent-wash，不改成"浮起白块" —— 少引入一种状态语言。
     ⚠️⚠️ 套槽时必须显式 `flex:none` + `white-space:nowrap`（2026-09-17 实测踩到）：
     给一个既有 flex item **套一层新容器**，会改变它的 flex 上下文 ——
     chip 的宽度约束从「内容自然宽」变成「槽的可用宽」，于是「全宽带」被压成三行**竖排字**、
     页头被撑高。而当时 253 条断言**全 PASS**：它们只断"槽在不在、里面几枚 chip"，
     不断尺寸 ⇒ **判据覆盖不到这个成因**。出图复看才发现。
     ⚠️⚠️⚠️ 而且第一次「修」没修对，因为**真正的成因是类名撞车**（见下）：
     ⇒ 经验：**"加一层容器"不是免费的，它会替换掉内部元素的尺寸上下文**；
       凡做这种包装，必须把被包元素显式钉回原尺寸策略（这里 = 不收缩 + 不换行）。
       并且要补一条"同组件同尺寸"的判据（见 _verify/crmai.mjs ③ 段 chipNowrap）。

   ★★ 类名撞车（RULES 58 复现，2026-09-17）：槽最初写成 `class="slot"` ——
     而 `shell.css:168` 有一个**全局单类** `.slot{width:40px;height:40px;border-radius:50%;…}`
     （那是左栏「其它平台」的圆形字母槽，抖 / 快 / 红）。
     我的 `.crm .pagehd .vsw .slot`（0,4,0）特异性更高，赢了 `display/align-items/gap/padding/flex`，
     **但没赢 `width/height`**（我没声明它们）⇒ 槽被**钉成 40×40**，两枚 61px 的 chip 塞不进去。
     ⇒ 改名 `.slot` → **`.vslot`**。
     ⇒ 更重要的教训：当时 crmai.mjs 里**已有**撞车判据，但它**只扫 `.ap-*` 前缀**，
       `.slot` 不在前缀里 ⇒ **判据有盲区，撞车照样过**。
       修法是判据改成「**本轮新增类名全集**逐个求交」，不再按前缀挑（见 ② 段 NEW_CLASSES）。
     ⇒ 通用问句升级：**"我这轮新加的每一个类名"（不是"我加的前缀那批"）都求过交集了吗？** */
/* ★ 2026-09-19：`.vsw` 的作用域从「只在页头」放宽到「`.crm` 全域」——
   客户站新增的「客户范围」切换落在 `.fbar` 里（层级：先定看哪些号的人，再筛这些人）。
   ⚠ 为什么是**去掉 `.pagehd` 限定**、而不是并列加 `.crm .fbar .vsw`：
     `crmai.mjs` 的「AI 层命名规范」判定 AI 层块的口径是
     `AI_ROOT_RE = /\.aipool|#crmSide|\.vsw|\.aic(?![a-z])/` —— **含 `.vsw` 的选择器即 AI 层块**，
     块里每个类名都必须在白名单或 `ap-` 前缀内，而白名单里**没有 `fbar`**
     ⇒ 并列写法会让它报「未加前缀：fbar」（实测已踩，250 PASS / 1 FAIL）。
     改成只留白名单内的 `crm` / `vsw` / `vslot` / `chipbtn` / `on` ⇒ 两侧都合规，
     且**一处定义两处生效**（复制成两套规则 = 改一处忘一处，RULES 53）。 */
.crm .vsw{display:inline-flex;align-items:center;gap:6px;flex:none}
.crm .vsw .ap-lb{color:var(--t3);font-size:var(--fs-micro);flex:none;white-space:nowrap}
/* ★ 槽的底与描边（2026-09-17 实测修 · 两处都错，是**两个独立的错**叠在一起）：
   实测口径 = 沿祖先链把每层非透明底**合成**后，再与真实背板比最大通道差 Δ（见 _verify/_probe_tokens.mjs）。

   错 ①「描边」：原先写 `--hairline`。tokens.css:17 明写它是**亮色专用**：
        「亮色专用 1px 发丝线；深色下 transparent —— 深色靠明度跳变，不靠描边」。
        实测 A/B 两主题 `--hairline` = rgba(0,0,0,0) 且槽自身底也与背板同级
        ⇒ **深色下槽的边界 = 0 条**（描边透明 + 填充无差），分组感自然出不来。
        改成 `--line`（结构线，四主题都不透明）：实测边界 Δ = A13 / B14 / C28 / D29，
        与页头里既有的 `.chipbtn`（.crm .chipbtn = `1px solid var(--line)`）**完全同值** ⇒ 同类控件同族。

   错 ②「填充」：原先写 `background:var(--e2)`，但 `.pagehd` 自身 bg 是 transparent，
        它在 `#crmbody.crm` 上，而 `#crmbody` 的底**就是 `--e2`**（实测 A rgb(21,25,29) / C rgb(255,255,255)）
        ⇒ 这个填充的 Δ = **0**，是个**假填充**：看着像做了个设计决定，实际什么都没做。
        改 transparent，把意图写实。（`.chipbtn` 的 `--e2` 填充同样是与背板同级，同理无效果。）

   ⇒ 通用问句升级：**"我加的这条边界/填充，合成后与真实背板的差是多少？"**
     必须量出来，不能因为"我写了 background 就以为有底"。

   错 ② 的修法（不只"让它非零"，而是**选定形态**）：槽是"一个轨道装两个互斥选项"，
   形态上要么做成**凸起面**、要么做成**凹槽**。先按平台惯例定方向 = **凹槽**
   （分段控件的轨道就是下陷的；本设计系统也有原生凹槽概念：`--bevel` 的注释就写着
   「受光边（**凹槽上沿高光**）」），再按"哪个面阶在四主题下都是下陷"挑令牌。
   实测各面阶**相对页头背板**的合成后 Δ 与**方向**（背板 = A/B 的 --e2、C/D 的白）：

     令牌   A     B     C     D      方向（相对背板）
     --e1   8     7    14    10     恒下陷（弱：8/7 已是系统最小可见步长）
     --e3   8     7    10     7     恒下陷（四主题**全档都弱**）
     --e4  16    15    33    25     **深色凸起 / 亮色下陷 —— 方向随主题翻转**
     --e0  15    14    27    21     恒下陷，且四主题都不弱  ← 选它

   ⇒ 选 `--e0` 的判据**不是"我觉得好看"**，而是两条可实测的：
     ① Δ 在四主题下都够（最小 14）—— 不会被读成同级 chip；
     ② **方向恒为"下陷"**（四主题都不翻转）—— 这是 `--e4` 做不到的：
        它在深色是"更亮"、在亮色是"更暗"，同一个组件在四主题下会呈现两种相反的体感。
     ③ 顺带消除错 ② 的"假填充"：底不再与背板同级。
   ⚠ 以后若有人把 `--e0` 改成 `--e4`「因为 Δ 差不多」—— 就是踩 ② 的方向翻转。
     该不变量已写成判据（crmai.mjs ⑦·补 2：槽底相对亮度必须恒低于页头背板）。 */
.crm .vsw .vslot{display:inline-flex;align-items:center;gap:3px;padding:2px;flex:none;
  background:var(--e0);border:1px solid var(--line);border-radius:var(--r-full)}
/* 槽内的 chip 去掉自己的描边（槽已有边），靠 `.on` 的底/字色区分当前态 */
.crm .vsw .vslot .chipbtn{border-color:transparent;background:transparent;
  flex:0 0 auto;white-space:nowrap}
.crm .vsw .vslot .chipbtn.on{background:var(--accent-wash);color:var(--accent-text)}
/* ══ ★★ 客户范围 = **号选择器**（`2026-10-04`）════════════════════════════════════
   壳仍是既有的 `.vsw` / `.vslot` / `.chipbtn`（不新造控件族），只是那一枚从"恒选中的
   静态胶囊"变成"可选的下拉"。三条量上的约束（都被既有判据钉住，不是偏好）：
     ① ⚠ 本块含 `.vsw` ⇒ 属 `crmai.mjs` 的「AI 层块」⇒ 块内类名只许白名单或 `ap-` 前缀。
        `ddw*` 那组既有宽度类**不在白名单** ⇒ 宽度那条**另起一条不含 `.vsw` 的规则**
        （见下面 `.crm .fbar .chipbtn.ap-asel > .pop`）。
     ② `max-width` **必需**，不是保险：`.vsw` 是 `flex:none`（不收缩），而 `.fbar` 会换行
        ⇒ 号名一长，`.vsw` 会独占一行并**撑出内容盒右缘** ⇒ 打红 `crmai.mjs` 那条
        「筛选行无裁切（逐子元素右缘 vs 内容盒右缘 ≤ 0）」（9 档宽 × 2 形态）。
        ⇒ 超出的部分走**省略号**，完整号名在 `title` 与弹层里都有。
     ③ `.ap-asc` 必须 `min-width:0` **且** `overflow:hidden`：flex 子项的默认 `min-width:auto`
        ⇒ 省略号**永不生效**（现象 = "看着像没写"），于是照样撑破 ② 那条。 */
.crm .vsw .vslot .chipbtn.ap-asel{display:inline-flex;align-items:center;gap:3px;max-width:196px}
.crm .vsw .vslot .chipbtn.ap-asel .ap-asl{flex:none;opacity:.72}
.crm .vsw .vslot .chipbtn.ap-asel .ap-asc{flex:0 1 auto;min-width:0;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.crm .vsw .vslot .chipbtn.ap-asel .ap-asn{flex:none}
/* ★「新增客户」= 页头动作簇里的**主操作**（旁边几枚是从属动作：研判切换 / 列设置 / 导出）。
   给它一个不同样式的唯一理由是**主次可分**：页头右侧原本四枚胶囊长得完全一样，
   用户扫过去读不出"哪个是这页最该点的"—— 主次不分不是简洁，只是让每个人多读一遍。
   ⚠ 只加一个修饰类，**不新造按钮族**：底座仍是 `.chipbtn`，尺寸 / 圆角 / 内边距 / 焦点环
     全部继承（本仓「同类控件同族」）。
   ⚠ 色只用令牌：四主题（明度 × 色温 2×2）都要跟着换，写死任何一个色值都会在其中一档下失真。
   ★★ 本规则与**位置无关**，但本枚在动作簇里的**位置**是硬的：
      `app/_verify/crmai.mjs` 拿 `.pagehd .sp > .chipbtn:not([data-pool])` 的 first-match
      当"既有普通 chip"的描边基准，本枚若排到第一位就会把它顶掉、连带误判 8 项。
      ⇒ 摆放纪律（末位）写在 `app/js/customers.js` 的页头段 ★★ 注释里，改样式不必看，
        但**改位置**必须先看；本线探针 A-4/A-5 会先红。 */
.crm .pagehd .chipbtn.cnew{background:var(--accent-wash);border-color:var(--accent-line);
  color:var(--accent-text);font-weight:500;cursor:pointer}
.crm .pagehd .chipbtn.cnew:hover{border-color:var(--accent-text)}
.crm .pagehd .chipbtn:focus-visible,.crm .vsw .chipbtn:focus-visible{
  outline:2px solid var(--focus);outline-offset:1px}
/* ★ 筛选行允许**自然换行**（2026-09-17 补 · 客户站 AI 层实测驱动）：
   成因：`#crmbody{overflow:hidden}` + `.fbar{display:flex}` 不换行 ⇒ 放不下时
   **右侧控件被静默裁掉**（实测 B 版副驾栏占走 300px 后：W=900 溢出 8px、W=820 溢出 88px、
   W=741 溢出 167px —— 被裁的是最右的「筛选 ▾」，且不报错）。
   修法：加 `flex-wrap:wrap` + `row-gap`，**不加断点** ——
     · 放得下时（A 版全程、B 版 W≥950）行内元素本来就排得开，wrap 不触发 ⇒ 既有版式零变化；
     · 放不下时才换行，信息只换位置、不消失（本项目硬原则：宁换行，不裁掉）。
   为什么不改用"窄窗把副驾栏收起来"：那等于**偷偷改用户选的形态**（用户点的就是"副驾栏"）。
   ⚠ 三个 `.ddw*` 下拉是 `flex:0 0 auto` + min-width（内容不可收缩：收窄会裁掉
     「阶段 · 全部（14 值）」这类文案）⇒ 极窄时它们会各占一整行，这是**有意**的取舍。 */
.crm .fbar{display:flex;flex-wrap:wrap;align-items:center;gap:8px;padding:0 18px 10px}

/* 筛选快捷按钮组（客户分类/阶段值）：一组圆角胶囊。★ 17 枚放一行放不下 ⇒ 换行 + 限宽，
   否则 inline-flex 不换行 + overflow:hidden 会把右缘胶囊静默裁掉（见 customers.js fbarHtml）。 */
.crm .derived{display:inline-flex;flex-wrap:wrap;max-width:100%;border:1px solid var(--line);border-radius:var(--r-sm);overflow:hidden}
.crm .derived > span{padding:5px 12px;font-size:var(--fs-small);color:var(--t2);background:var(--e2)}
.crm .derived > span.on{background:var(--face-on);color:var(--t1);font-weight:600}
.crm .derived > span + span{border-left:1px solid var(--line)}
.crm .derived .lb{color:var(--t3);font-size:var(--fs-micro);background:var(--e1);border-right:1px solid var(--line);
  display:flex;align-items:center;padding:0 9px}
.crm .dd{flex:1;padding:5px 10px;background:var(--e2);border:1px solid var(--line);border-radius:var(--r-sm);
  color:var(--t1);font-size:var(--fs-small);display:flex;justify-content:space-between}
.crm .chipbtn{padding:5px 10px;border:1px solid var(--line);border-radius:var(--r-full);
  color:var(--t2);font-size:var(--fs-small);background:var(--e2);cursor:pointer}
.crm .chipbtn.on{background:var(--accent-wash);color:var(--accent-text);border-color:transparent}
.crm .alertbar{display:flex;flex-wrap:wrap;gap:6px 10px;padding:0 14px 10px;font-size:var(--fs-caption);color:var(--amber)}
.crm .alertbar .sp{margin-left:auto;color:var(--t3)}
/* ★ `available === false`（后端登记"结构上算不出来"）⇒ 灰态、**不给数字**。
   类名复用既有约定：`shell.css` 的 `.menubar .live .it.off` 就是 `available===false`
   的降级态（`shell.css` 里那条规则的注释明写），语义同构 ⇒ 不新造类名；
   写成复合选择器（不落成单类规则），不给别处误伤的机会。色值取令牌，不写字面色。 */
.crm .alertbar .off{color:var(--t3)}

/* ── 筛选行 / 异常条：接通真数后新增的**只有视觉**（2026-09-19）────────────────────
   接通前：整行写死字面量 + 4 个死下拉 + 2 枚死 chip（`客户线-1440` §2 第 8/9 条已登记）。
   接通后需要表达三件此前不存在的事：**能点**（手型）、**已生效**、**不可选**（置灰）。
   ⚠ 弹层必须**绝对定位**：`crmai.mjs` 逐个子元素量 `.fbar` 的溢出（`fbarWorst <= 0`，
     见该套第 501–509 行），弹层若参与 flex 排版会立刻把它撑破。
   ⚠ 一律走令牌：四主题（明度 × 色温 2×2）都要跟着换，写死色值必在其中一档下失真。 */
.crm .fbar .dd,.crm .fbar .chipbtn[data-crmdd]{position:relative}
.crm .fbar .dd{cursor:pointer}
/* ── ★ 搜索框（`2026-09-24` · 用户令「把搜索功能做一下，搜索微信、昵称、微信号之类的都做一下」）
   落筛选行里**筛选项之前**（排在 `.vsw` 之后、`.derived` 之前；理由与实际子元素序
   见 `customers.js` 的 `fbarHtml` 段）。
   ⚠ 尺寸策略三条，都是为了让 `crmai.mjs` 那条「`.fbar` 逐子元素右缘 ≤ 内容盒右缘」
     （9 档宽度 × 2 形态）继续成立：
       · `flex:0 1 208px` —— **不增长**（一增长就会把右边的胶囊/下拉挤走），可收缩；
       · `min-width:120px` —— 最窄也留 120px（最窄的内容盒 ≈ 337px，见本文件 `.fbar`
         `flex-wrap` 那段注释）⇒ **不会溢出**，而输入内容超宽时 input 自己横向滚动；
       · `min-width:0` 只加在**内部**的 input 上 —— 这是 flex 项溢出的经典陷阱：
         不写它，`<input>` 的默认固有宽度（size≈20 字符）会把 `.fsq` 整个顶破。
   ⚠ 全部走令牌（`crmai.mjs` 扫本文件的字面色值）：写死色值会在 4 主题里至少偏一档。 */
.crm .fbar .fsq{display:inline-flex;align-items:center;gap:6px;flex:0 1 208px;min-width:120px;
  height:26px;padding:0 8px;border:1px solid var(--line);border-radius:var(--r-sm);background:var(--e2)}
/* 生效态与焦点态**是两个维度**，刻意用两个不同令牌：
   有搜索 = `--accent-line`（"这个名字正在生效"，与旁边 `.chipbtn.on` 同族语义）；
   光标在里面 = `--focus`（"你能在这儿打字"）。混用一个会让"点进去但没搜"看起来像"已生效"。 */
.crm .fbar .fsq.on{border-color:var(--accent-line)}
.crm .fbar .fsq:focus-within{border-color:var(--focus)}
.crm .fbar .fsq input{flex:1 1 auto;min-width:0;width:100%;border:0;background:transparent;
  padding:0;outline:none;color:var(--t1);font-size:var(--fs-small);font-family:var(--font-ui)}
.crm .fbar .fsq input::placeholder{color:var(--t3)}
.crm .fbar .fsq .fsqx{flex:0 0 auto;padding:0 2px;border-radius:var(--r-xs);cursor:pointer;
  color:var(--t3);font-style:normal;font-size:var(--fs-small);line-height:1}
.crm .fbar .fsq .fsqx:hover{background:var(--face-hover);color:var(--t1)}
/* 命中数：与筛选行其它辅文同色同号（`--fs-micro` / `--t3`）——
   它是一句**读数**，不是一枚能点的东西（不加底色、不加边框）。 */
.crm .fbar .fsqn{flex:0 0 auto;color:var(--t3);font-size:var(--fs-micro);white-space:nowrap}
/* 「后端不认识 q」的告警（`2026-09-24`）。⚠ 走**告警色**而不是 `--t3`：
   它要顶掉旁边那枚"匹配 N 人"的读数（那个数此刻是全量、是假的），
   用同色同号就等于让一条假读数与一条真告警长得一样（本仓最忌的一族）。 */
.crm .fbar .fsqw{flex:0 0 auto;color:var(--danger-text);font-size:var(--fs-micro);white-space:nowrap}
.crm .derived > span[data-crmfilt]{cursor:pointer}
.crm .derived > span[data-crmfilt]:hover{background:var(--face-hover)}
/* 生效态：`.dd` 借用页头既有 `.chipbtn.on` 的同一组令牌（同类控件同族，不另起一套）。 */
.crm .fbar .dd.on{border-color:var(--accent-line);color:var(--accent-text);font-weight:600}
/* ── ★ 「待处理」片的**双热区**（`2026-10-02` · 用户令「全部一起做了」）──────────────────
   片本体（`待处理 143`）点了**直接筛并集**（`?todo=any`）；右侧那个 `▾` 才是"展开三来源"。
   ⚠ 为什么不把它拆成两枚并列的胶囊：`.fbar` 是 `flex-wrap` 的窄行（最窄内容盒 ≈ 337px，
     见本文件上方 `.fsq` 那段），多一枚就多一份越界风险；而外层 `.chipbtn[data-crmdd]`
     本来就是 `.pop` 的**定位上下文**与 `.open` 的载体（见 `:157` / `:203`）
     ⇒ **留着它、只往里加一层**是零结构改动的做法：`.fbar` 的子元素**个数不变**，
     宽度只差 `▾` 左边那 4px。
   ⚠ 两个热区**靠 `closest` 的就近规则分流**，不在事件里再判坐标 ——
     click 委托里 `hitFilt` 排在 `hitDD` **之前**且命中即 `return`（见 `customers.js` 那段）
     ⇒ 落在 `.tdpick` 内 = 筛；落在外层（含 `▾`）= 展开。
   ⚠ `.tdtri` 给 `padding-left:4px`：`▾` 的可点面积就不止一个字符宽（右侧另有 `.chipbtn`
     的 10px 内边距兜着）—— 本仓「不加 hover 才知道能点的」那条，在这里靠**间距**把两个
     热区分开；各自的 `title` 再说一遍要做什么（`customers.js` 的 `todoChip` 段）。 */
.crm .fbar .chipbtn .tdpick{cursor:pointer}
.crm .fbar .chipbtn .tdtri{padding-left:4px;cursor:pointer}
/* 异常条从"读数"变成"筛选入口" ⇒ 必须**看得出能点**，且生效态可见
   —— 加了筛选却看不出来，用户会以为屏上就是全部数据（本仓反复在防的一类）。 */
.crm .alertbar > span[data-crmfilt]{cursor:pointer;text-decoration:underline;
  text-decoration-style:dotted;text-underline-offset:3px}
.crm .alertbar > span.on{color:var(--t1);font-weight:600;text-decoration-style:solid}
/* 弹层：脱离文档流 ⇒ 不影响 `.fbar` 的行高与溢出。 */
.crm .fbar .pop{display:none;position:absolute;top:calc(100% + 4px);left:0;z-index:30;
  min-width:100%;max-height:264px;overflow:auto;background:var(--e0);border:1px solid var(--line);
  border-radius:var(--r-sm);box-shadow:0 12px 30px -10px var(--sh-2);padding:4px 0;text-align:left}
.crm .fbar .dd.open .pop,.crm .fbar .chipbtn.open .pop{display:block}
.crm .fbar .pop > i{display:flex;gap:10px;align-items:center;padding:6px 12px;font-style:normal;
  color:var(--t2);font-size:var(--fs-small);white-space:nowrap;cursor:pointer}
.crm .fbar .pop > i:hover{background:var(--face-hover);color:var(--t1)}
.crm .fbar .pop > i.on{color:var(--accent-text);font-weight:600}
/* `selectable === false`（来源字典里的**已停用**平台）⇒ 置灰、不进 hover。 */
.crm .fbar .pop > i.z,.crm .fbar .pop > i.z:hover{color:var(--t3);cursor:default;background:transparent}
/* 计数是**次要信息** ⇒ 在 `.on` 下也不跟着被强调（否则一行里两个 600 抢焦点）。 */
.crm .fbar .pop > i > b{margin-left:auto;font-weight:400;color:var(--t3);
  font-variant-numeric:tabular-nums}
.crm .fbar .pop > i.clr{color:var(--t3);border-top:1px solid var(--line);margin-top:4px}

/* ── ★★ 号选择器（客户范围）的弹层（`2026-10-04`）─────────────────────────────────
   ⚠⚠ 下面三条**刻意不含 `.vsw`**：一旦含了就成了 `crmai.mjs` 的「AI 层块」，而这里要用的
      `.pop` / `i` / `.z` **都不在白名单**里 ⇒ 当场打红（假 FAIL）。作用域改由
      `.chipbtn.ap-asel` 收窄 —— 与 `.vsw` 指的是同一枚 chip，只是换个说法限定它。
   ⚠ 开合/定位/条目样式**全部复用**上面 `.crm .fbar .pop` 那一族（`top:calc(100%+4px)`、
      `left:0`、`z-index:30`、`> i` 的 flex 行）—— 这里只补三处**它没有**的：
      宽度（`min-width:100%` 只能到 chip 宽，号名比 chip 长时会被截）、
      错误行的告警色、落款行的不可点态。 */
.crm .fbar .chipbtn.ap-asel > .pop{min-width:196px}
/* 读不到号名单那一行走**告警色**，不是 `--t3`：它要顶掉"这里本来就没东西"的观感 ——
   用同色就等于让「号名单没读到」与「你名下就一个号」长得一样（本仓最忌的一族）。 */
.crm .fbar .chipbtn.ap-asel > .pop > i.ap-aserr{color:var(--danger-text);cursor:default}
.crm .fbar .chipbtn.ap-asel > .pop > i.ap-aserr:hover{background:transparent;
  color:var(--danger-text)}
/* 落款「只改这一屏，不动左栏」：说明性文字 ⇒ 不可点、也不进 hover。 */
.crm .fbar .chipbtn.ap-asel > .pop > i.ap-asft{color:var(--t3);cursor:default;
  font-size:var(--fs-micro);border-top:1px solid var(--line);margin-top:4px}
.crm .fbar .chipbtn.ap-asel > .pop > i.ap-asft:hover{background:transparent;color:var(--t3)}

/* ★ 表格 used width = max(容器, colgroup 列宽和 1370px) —— table-layout:fixed + width:100% 的固有行为，
   **不靠 min-width**（任务 #4 复核实测：加/删 min-width:1256px 的 used width 都是 1256，即该声明是 no-op，
   已删；原型也从来没有 min-width 而 used width 同样是列宽和）。
   ⇒ 横滚由 .tblwrap{overflow-x:auto} 承载；若把它改成静态 overflow:hidden，
     会把**最后一列**静默剪掉（原话写的是「第 11 列」= 当时最后一列；2026-09-26 起 13 列
     ⇒ 本条说的是"最后一列"，与序号无关。原型 2191–2193 行的历史教训 = 铁律 9）。
   列宽改动的判据不是「和 = 某个数」，而是：① 每列 clientWidth ≥ 该列最长文本宽（不裁）；
   ② 容器窄于列宽和时出现横滚条。 */
/* ★ 2026-09-25（客户线 · 视觉批）：外框由 `--hairline` 改 `--line`。
   实测证据（`_probe_ncvisual.mjs` · 合成 Δ = 与真实背板的最大通道差，口径同 `_probe_tokens.mjs`）：
     表格外框   A/B: α=0 ⇒ **Δ=0（完全看不见）**   C/D: Δ=35
   `--hairline` 是**亮色专用**（`tokens.css` 原文「亮色专用 1px 发丝线；深色下 transparent」）
   ⇒ 在**默认主题 A** 下这张表**根本没有外框**，而 `--line` 四主题都不透明（C/D 实测同为 Δ=35）。
   ⚠ 同族**前科在册**：本文件「槽的描边」一节早为同一个错修过一次
     （「原先写 `--hairline`…实测 A/B 两主题 = rgba(0,0,0,0)」）—— 当时只修了那一处，
     **本条与下面「采集带」两处同形态未清** ⇒ 本批一并清掉。
   ⚠ 可复查判据 = **本文件里该令牌的 `var()` 引用数必须 0**。
     ⚠★ 判据**不能把令牌串连写在注释里** —— 那样这条注释会被它自己的判据命中。
     本行第一版就是那么写的：跑 `grep -c` 得 **1**，而那个 1 **正是这条注释本身**
     ⇒ 一个"应为 0"的判据**永远报 1**，与"真有一处没清"同形（同族：`R80` 一个取值要能区分「没有」与「读不到」）。
     ⇒ 复核时用 `grep -n` 看命中行的**内容**：**代码行 = 真缺陷；注释行 = 判据文本自命中**。
     ⇒ 通则：**判据文本与注释文本必须互不命中**，否则「恒真」与「恒假」只差一个字符。 */
.crm .tblwrap{background:var(--e1);border:1px solid var(--line);border-radius:var(--r-md);
  overflow-x:auto;overflow-y:hidden;margin:0 18px}
.crm .tblwrap::-webkit-scrollbar{height:9px}
.crm .tblwrap::-webkit-scrollbar-thumb{background:var(--scroll);border-radius:5px}
.crm .tblwrap::-webkit-scrollbar-track{background:transparent}
/* ★★ 2026-09-26 v3：**横向内边距 10 → 8**（本批「末列回归」的修复点，别当排版微调改回去）。
   起因：加「客户分类」「标签」两列后总宽 1422 > 1440 窗口的容器 1326 ⇒
     末列「操作」被整格推出可视区，行操作「详情」在窗口 ≲1472 时**完全点不到**
     （`dtl.mjs` ⑤ 真实命中测试回 `null`；该套件历史 `95 PASS / 0 FAIL` → `94 PASS / 1 FAIL`）。
   修法：横向内边距各减 2px（13 列共腾出 52px）＋ `data.js` 的 `CLIENT_COLS` **每列 −4px**
     ⇒ 新可用宽 = (w−4) − (2×8) = w − 20 = **与改前逐列相同** ⇒ `crmcols.mjs` 余量一格不动。
     ⇒ 总宽 1422 → **1370**，详情中心前移 52px 回到可视区内（18px 余量）。
   ⚠ 竖向 padding（th 8 / td 9）**不动** —— 行高与纵向节奏与本修法无关，动它属于另一个批。
   ⚠ 改这里必须同步改 `_verify/crmcols.mjs` 的 `PAD`（20 → 16）：它把「左右 padding」
     写成了常量；不同步会让该件报出的「可用宽 / 文本需宽」两列**整体偏低 4px**（余量本身不受影响，
     因为两边同时位移 —— 但那是**巧合**，不是可以不改的理由）。 */
.crm .ftbl{width:100%;border-collapse:collapse;table-layout:fixed}
.crm .ftbl th{background:var(--e2);color:var(--t3);font-weight:400;font-size:var(--fs-micro);
  text-align:left;padding:8px 8px;border-bottom:1px solid var(--line);
  white-space:nowrap;letter-spacing:.3px}
.crm .ftbl th.on{color:var(--t1);font-weight:600}
.crm .ftbl th .ar{color:var(--accent-text);margin-left:3px}
.crm .ftbl td{padding:9px 8px;border-bottom:1px solid var(--line);font-size:var(--fs-small);
  color:var(--t1);vertical-align:middle;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* ★ 2026-09-25（客户线 · 视觉批）：**空值格弱化**（`.nil` 由 `customers.js` 的 `td()` 自动打）。
   `—` 是「缺省」不是「一个值」（09-ui §4.4 ④「资料不全 → 字段级 —，绝不留白」），
   而它原先与真值**同色同重** ⇒ 13 列里"哪几格是空的"要逐格读才认得出
   （图上同一行的「课程 · 金额」「小鹅通订单号」「下单日期」可以是值也可以是 `—`）。
   ⚠ 只改**字色**、不改字号/行高 ⇒ `crmcols.mjs` 的逐列余量**逐字不变**
     （余量 = 可用宽 − 文本需宽，与颜色无关；min 余量当前仅 1.4px，任何影响宽度的写法都不许有）。
   ⚠ 特异性 0,3,1 > `.crm .ftbl td`(0,2,1) ⇒ 压得住，且不依赖文件内顺序。 */
.crm .ftbl td.nil{color:var(--t3)}
/* ★ 2026-09-25（客户线 · 视觉批）：hover / 选中行加**左缘 2px 色条**。
   起因：本表 hover 原先**只变底色**（`--face-hover` 对深色底只差 8 左右）——
   13 列宽表里"跟到哪一行"要靠数格子才认得出，而**行是有序号感的**（每条是个人）。
   同族已在 `xiaoe.css` 落过（`.xe-tbl tbody tr:hover td:first-child{box-shadow:inset 2px 0 0 var(--accent)}`）
   ⇒ 本批**照抄该写法**（同类控件同族，不另起一套语言）。
   ⚠ 用 `box-shadow:inset` 而**不是** `border-left`：`table-layout:fixed` 下 td 的边框
     会改**内容盒宽** ⇒ `crmcols.mjs` 的「13 列余量全部 ≥ 0」立刻变紧（当前 min 余量仅 1.4px）。
     `box-shadow` 不参与布局 ⇒ 余量逐列不变（本批实测复核见留痕件）。
   ⚠ **排除 `.grp`**（「全部号」视角的账号分组头）：它是说明行、`cursor:default`，
     加左缘条等于给它一个"可交互"的暗示（该行三条覆盖注释里写明不许暗示可点）。 */
.crm .ftbl tr:hover td{background:var(--face-hover)}
.crm .ftbl tbody tr:not(.grp):hover td:first-child{box-shadow:inset 2px 0 0 var(--accent)}
.crm .ftbl tbody tr.on:not(.grp) td:first-child{box-shadow:inset 2px 0 0 var(--accent)}
.crm .ftbl tr.on td{background:var(--sel)}
.crm .ftbl tr:last-child td{border-bottom:0}
/* ★「全部号」视角的账号分组头（2026-09-19）。它是 `colspan` 的独立行、**不属于任何列**
   ⇒ 逐列余量判据（`crmcols.mjs`）看不到它（这也正是当初不把号名塞进「客户」列的原因：
   那一列余量实测只有 3.9px）。
   ⚠ 三条覆盖都必需，缺一条它就"看起来像数据行"：
     ① `padding` —— 否则继承 `.ftbl td` 的 9px 8px，与数据行同高（横向 8 是 v3 的值，见上）；
     ② `background` —— 否则继承 `.ftbl tr:hover td` 的悬停底，鼠标一扫组头就变色（像可点）；
     ③ `cursor:default` —— 组头是**说明**，不能带任何"可交互"的暗示。
   ⚠ 色一律走令牌：四主题（明度 × 色温 2×2）都要跟着换，写死色值必在其中一档下失真。 */
.crm .ftbl tr.grp td{padding:6px 8px;background:var(--e2);border-bottom:1px solid var(--line);
  border-top:1px solid var(--line);cursor:default;font-size:var(--fs-micro);color:var(--t3)}
.crm .ftbl tr.grp:hover td{background:var(--e2)}
.crm .ftbl tr.grp .gk{color:var(--t2);font-weight:600}
.crm .ftbl tr.grp .gn{margin-left:8px}
.crm .ftbl .ck{text-align:center}
.crm .ftbl .ck i{display:inline-block;width:13px;height:13px;border:1px solid var(--line-strong);
  border-radius:var(--r-xs);vertical-align:-2px}
.crm .ftbl .ck i.on{background:var(--accent);border-color:transparent}
.crm .nmcell{display:flex;align-items:center;gap:8px;min-width:0}
.crm .nmcell .av{width:26px;height:26px;flex:0 0 26px;font-size:var(--fs-micro);border-radius:var(--r-full);
  display:flex;align-items:center;justify-content:center;background:var(--av-bg);color:var(--av-fg);font-weight:600}
.crm .nmcell .tx{min-width:0;overflow:hidden}
.crm .nmcell .tx b{font-weight:400;color:var(--t1);display:block;overflow:hidden;text-overflow:ellipsis}
.crm .nmcell .tx span{color:var(--t3);font-size:var(--fs-micro);font-family:var(--font-num)}
.crm .src{font-size:var(--fs-micro);padding:1px 6px;border-radius:var(--r-xs);
  background:var(--stage-chip-bg);color:var(--stage-chip-fg)}
.crm .cellsub{color:var(--t3);font-size:var(--fs-micro)}
.crm .cellnum{font-family:var(--font-num)}
.crm .ddw190{flex:0 0 auto;min-width:190px}
.crm .ddw118{flex:0 0 auto;min-width:118px}
.crm .ddw112{flex:0 0 auto;min-width:112px}
.crm .al18{padding:0 18px 10px}
.crm .tip{margin-left:auto;color:var(--t3);font-size:var(--fs-micro)}
.crm .tip2{margin-left:auto;color:var(--t3)}
.crm .stagechip{background:var(--stage-chip-bg);color:var(--stage-chip-fg);font-size:var(--fs-caption);
  padding:1px 9px;border-radius:var(--r-full);font-weight:400}
/* ══ ★★ 批 3（2026-10-03）：阶段带「四格进度条」════════════════════════════════════════
   `方案 §5.2②`：「现在列表上「交付阶段」那一列占了一格 14 值文本 ⇒ 改成阶段带进度条
   （一条四格，当前格亮）」。

   ⚠⚠★ **本段每一个字都在"零布局影响"这条线上** —— 上面那三条纪律（余量 **1.4px**、
     `dtl.mjs:106` 读 `textContent`、`:332` 两处 `backgroundColor` 逐值对拍）全部适用：
       · `position:absolute` 的伪元素 **不进文档流** ⇒ 盒尺寸**一个字都不变**；
       · `clip-path` 裁的是**绘制**，不参与布局 ⇒ 同上；
       · 两个伪元素的 `background*` 是**自己的**，不碰 `.stagechip` 的 `backgroundColor`
         ⇒ `dtl.mjs:332` 那条对拍**照旧成立**；
       · **不加上屏文字** ⇒ `textContent` 逐字不变。
     上面那条旧注释点名的 `::after{content:'▾'}` 之所以被禁，是因为它**参与布局**（+8px）；
     本段用绝对定位把它变成**纯绘制** —— 这是"能做"与"不能做"的分界。
   ⚠ 颜色一律走令牌（`--line` / `--accent` / `--stage-chip-bg`），四主题自适应、零硬编码。 */
.crm .stagechip[data-band]{position:relative}
/* 底：整条（四格的分隔靠"缝"露出的 chip 底色，不靠画四条 —— 那样反而会因取整而错位） */
.crm .stagechip[data-band]::after{content:'';position:absolute;left:9px;right:9px;bottom:1px;
  height:3px;border-radius:2px;
  background:repeating-linear-gradient(90deg,
    var(--line) 0, var(--line) calc(25% - 1px),
    transparent calc(25% - 1px), transparent 25%)}
/* 亮：**已经走到的段**（用 `clip-path` 控制长度 ⇒ 不改任何盒尺寸） */
.crm .stagechip[data-band]::before{content:'';position:absolute;left:9px;right:9px;bottom:1px;
  height:3px;border-radius:2px;background:var(--accent)}
.crm .stagechip[data-band="待承接"]::before{clip-path:inset(0 75% 0 0)}
.crm .stagechip[data-band="服务中"]::before{clip-path:inset(0 50% 0 0)}
.crm .stagechip[data-band="训练中"]::before{clip-path:inset(0 25% 0 0)}
/* 终态：不裁（= 走满四格）。⚠ 不写 `inset(0 0 0 0)` 而是**不写规则** ——
   少一条规则就少一处"两条规则打架时谁赢"的疑问（同族：`.on` 类的判定不要写两遍）。 */
/* ★ 详情抽屉那枚 —— 前缀必须换（抽屉**不在** `.crm` 里，见上面那段的长注释）；
   手段与上面**逐条相同**（两处必须长得一样，否则又是"两处说法"）。 */
.crmmode .dtl .dh-st .stagechip[data-band]{position:relative}
.crmmode .dtl .dh-st .stagechip[data-band]::after{content:'';position:absolute;left:9px;right:9px;
  bottom:1px;height:3px;border-radius:2px;
  background:repeating-linear-gradient(90deg,
    var(--line) 0, var(--line) calc(25% - 1px),
    transparent calc(25% - 1px), transparent 25%)}
.crmmode .dtl .dh-st .stagechip[data-band]::before{content:'';position:absolute;left:9px;right:9px;
  bottom:1px;height:3px;border-radius:2px;background:var(--accent)}
.crmmode .dtl .dh-st .stagechip[data-band="待承接"]::before{clip-path:inset(0 75% 0 0)}
.crmmode .dtl .dh-st .stagechip[data-band="服务中"]::before{clip-path:inset(0 50% 0 0)}
.crmmode .dtl .dh-st .stagechip[data-band="训练中"]::before{clip-path:inset(0 25% 0 0)}
/* ★★ 批 3：「推进一格 / 退一格」两枚（`方案 §5.2③`）。
   ⚠ 视觉语言**照抄** `.stagechip.msedit` 那一套（虚线下划线 + 手型 + 悬停底色）——
     本仓既有约定：这一套就是"这里能改"的记号（复杂度红线④：不许"要 hover 才知道能点"），
     换个记号 = 用户要重新学一次（"两处说法"）。
   ⚠ `.dis`（终态那枚）**不改成 `pointer-events:none`**：那样点了真的没反应。
     它保持可点，点击时由 `fireMsStep` **回话**说明为什么不行（本仓头号忌讳的处置惯例）。
   ⚠ 不加 `background` 常态色（与 `.stagechip` 同一条纪律的延伸：常态底色别动，
     免得 `dtl.mjs` 的 `backgroundColor` 对拍多出一个变量）。 */
.crmmode .dtl .dh-st .stpbtn{font-size:var(--fs-micro);color:var(--accent-text);cursor:pointer;
  padding:1px 7px;border:1px solid var(--line);border-radius:var(--r-full);
  text-decoration:underline dashed;text-underline-offset:2px;white-space:nowrap}
.crmmode .dtl .dh-st .stpbtn:hover{background:var(--face-hover)}
.crmmode .dtl .dh-st .stpbtn:focus-visible{outline:2px solid var(--accent);outline-offset:1px}
.crmmode .dtl .dh-st .stpbtn.dis{color:var(--t3);cursor:default;text-decoration:none;
  border-style:dashed}
/* ★★ 2026-10-01（D 线 · 用户令「交付阶段入口放列表行内」）：可编辑态的样子。
   ⚠⚠ 这三条**必须全部是零布局宽度**的手段 —— 交付阶段列实测**余量只有 1.4px**
     （见 `customers.js#stageCell` 的注释与 `crmcols.mjs`）。逐条说明为什么安全：
       · `text-decoration`（虚线下划线）**不进盒模型** ⇒ 宽度不变；
       · `outline`（不是 `border`）**不参与布局** ⇒ 宽度不变；
       · `cursor` / `color` / `background` 都不改变盒尺寸。
     ✗ 明确**不许**换成：`border-bottom`（+1px 高，且若写左右边就是 +2px 宽）、
       `padding` 增减、`::after{content:'▾'}`（+8px 宽）、换 `<select>`（+18px 宽）。
   ⚠ 「虚线下划线 + 手型 + 悬停底色」是本仓**既有**的"这里能改"语言（见上方 `.crm .ftbl .op`）
     ⇒ 不需要图例、不需要 hover 才发现（复杂度红线 ④）。 */
.crm .stagechip.msedit{color:var(--accent-text);cursor:pointer;
  text-decoration:underline dashed;text-underline-offset:2px}
.crm .stagechip.msedit:hover{background:var(--face-hover)}
.crm .stagechip.msedit:focus-visible{outline:2px solid var(--accent);outline-offset:1px}
/* ★★ 2026-10-01（D 线 · 同一用户令的**另一半**：「…和详情抽屉都放」）：抽屉头那枚的同一态。
   ⚠ 为什么**不能**复用上面那条：抽屉**不在** `.crm` 里 —— `.crm` 就是客户站主体
     （`#crmbody`），而抽屉 `#dtl` 挂在 `#app.crmmode` 之下、与 `.crm` 是**兄弟**
     （本文件给抽屉定样式一律用 `.crmmode .dtl` 前缀，见 `:661` 那一族）。
     照抄一条 `.crm` 前缀的规则 ⇒ **一条也不生效、且不报错**（本仓"对象在、判据不在"同族）。
   ⚠ 手段与上面**逐条相同**（零布局宽度）：抽屉这枚虽然不在那 1.4px 的紧列里，
     但**同一个交互在两处必须长得一样** —— 换手段就是"两处说法"。
   ⚠ 不设 `background`（除 hover）：`_verify/dtl.mjs:332` 拿 `#dtl .stagechip` 的
     `backgroundColor` 与 `#crmbody .stagechip` **逐值对拍** ⇒ 常态底色别动它。 */
.crmmode .dtl .dh-st .stagechip.msedit{color:var(--accent-text);cursor:pointer;
  text-decoration:underline dashed;text-underline-offset:2px}
.crmmode .dtl .dh-st .stagechip.msedit:hover{background:var(--face-hover)}
.crmmode .dtl .dh-st .stagechip.msedit:focus-visible{outline:2px solid var(--accent);outline-offset:1px}
.crm .st{font-size:var(--fs-micro);padding:1px 7px;border-radius:var(--r-full);white-space:nowrap}
.crm .st.p0{background:var(--amber-bg);color:var(--amber)}
.crm .st.p1{background:var(--stage-chip-bg);color:var(--t2)}
.crm .ftbl td.ops{white-space:nowrap}
.crm .ftbl .op{color:var(--accent-text);cursor:pointer;margin-right:12px;font-size:var(--fs-small)}
.crm .ftbl .op:last-child{margin-right:0}
.crm .ftbl .op:hover{text-decoration:underline}
/* ★ 2026-09-25（客户线 · 视觉批）：未选中态改**中性底**（原为强调底 `--accent-wash`）。
   事由：这条在「已选 0 人」时也顶着强调底色，而同刻那一排按钮（指派教练/加标签/发消息/导出）
   **全是灰的**（没有对象可作用）⇒ 屏上最抢眼的一块配着一排不能用的动作 = 权重与可用性错配。
   实测（`_probe_ncvisual.mjs`）：未选中态底相对背板 Δ=24，与「有选中」时**同级**。

   ⚠★ **令牌选择踩过一次坑（保留以免重蹈）**：第一版写 `--e2` ⇒ 实测 Δ=**0** ——
     因为 `.bulkbar` 在 `#crmbody.crm` 上，而**背板本身就是 `--e2`**
     ⇒ 那是个**假填充**（看着像做了个设计决定，实际什么都没做）。
     这正是本文件「槽的底与描边」一节记过的**错②**，同族复现。
     改用 `--e1`：实测 Δ = A8/B7/C14/D10，**弱但恒不为 0**，且与 `.tblwrap`（同用 `--e1`）
     **同族** —— 常态工具条本就该与表格容器同一档面阶。
   ⚠ 只改 `background`、**不动 `border`** —— `.has` 那枚 1px 边是**动态**出现的，
     若把它挪到基础规则里会改常态行高（本批纪律：任何影响几何的写法都不许有）。 */
.crm .bulkbar{display:flex;align-items:center;gap:8px;margin:0 18px 10px;padding:8px 12px;
  background:var(--e1);border-radius:var(--r-sm);color:var(--t1);font-size:var(--fs-small)}
/* ★ 批量选择（`2026-09-24`）—— 勾选框**可点**、表头全选、内嵌批量表单。
   ⚠ `.ck i` 原来是**纯展示**（无 `cursor`）⇒ 接通后必须补上：本仓纪律「不许加 hover
     才知道能点」，而 `cursor:pointer` 是**最基本的**可点提示（比 hover 更早被感知）。
   ⚠ 表头全选沿用同一个 `i` 元素与 `.on` 类 ⇒ 自动继承 `.ftbl .ck i` 的方块样式，
     这里只补"未全选时略淡"这一层视觉差（否则全选态与半选态长得一样）。 */
.crm .ftbl .ck i{cursor:pointer}
.crm .ftbl .ck i:hover{border-color:var(--accent)}
.crm .ftbl .ck i:focus-visible{outline:2px solid var(--accent);outline-offset:1px}
.crm .ftbl th.ck i{opacity:.6}
.crm .ftbl th.ck i:hover,.crm .ftbl th.ck i.on{opacity:1}
/* 有选中时给批量栏一道边 —— 让"已选 N 人"这一整条在视觉上**站起来**
   （否则它和普通工具条同形，用户扫表格时不会注意到自己还选着人）。
   ★ 2026-09-25：同时补回强调底 —— 基础规则已改中性 `--e2`（见上），
     强调态 = accent 底 + accent 边**两重**，与"未选中"拉开可辨的距离。 */
.crm .bulkbar.has{background:var(--accent-wash);border:1px solid var(--accent)}
/* `off` = "这一刻不能用的按钮"，**仍可点**（点了必须给出明确回话），只是视觉上标明不可用。
   ⚠ 不做成 `pointer-events:none` —— 那会变成"点了没反应"，正是本仓头号忌讳。
   ⚠ **使用者的变迁**（别照旧印象理解这个类）：
     `2026-09-24` 唯一使用者 = 「发提醒」（后端无此能力 ⇒ 灰着但仍说明原因）；
     `2026-09-25` 该按钮落成真「发消息」⇒ 现使用者 = **发送中的那枚「发送」键**
     （`CRMS.bulkBusy` 期间文案变「发送中…」并带本类）。
     ⇒ 语义已从"没能力"变成"正在忙 / 暂不可提交"。 */
.crm .btn.off{opacity:.5}
/* ★ 批量「发消息」的正文输入框（`2026-09-25`）—— 比 `coach` / `tag` 的格子**宽一档**：
   教练名 / 标签是短词（190px 够），而这里要敲**一整句消息**；190px 只看得见十来个字，
   用户没法回看自己写了什么 —— 而这条消息**发出后不可撤回**。 */
.crm .bulkform input[data-bulk-in="notify"]{min-width:340px}
.crm .bulkform{display:flex;align-items:center;gap:8px;margin:-4px 18px 10px;padding:8px 12px;
  background:var(--e2);border:1px solid var(--line);border-radius:var(--r-sm);font-size:var(--fs-small)}
.crm .bulkform .bk-k{color:var(--t2);font-size:var(--fs-micro);white-space:nowrap}
.crm .bulkform input,.crm .bulkform select{padding:4px 8px;border:1px solid var(--line);
  border-radius:var(--r-xs);background:var(--e2);color:var(--t1);font-size:var(--fs-small);
  min-width:190px;font-family:inherit}
.crm .bulkform .tip{margin-left:auto}
.crm .btn{padding:5px 12px;border-radius:var(--r-sm);font-size:var(--fs-small);border:1px solid var(--line);
  background:var(--e2);color:var(--t1);cursor:pointer}
.crm .mini{font-size:var(--fs-micro);padding:2px 6px;border:1px solid var(--line);border-radius:var(--r-xs);color:var(--t2);cursor:pointer}
.crm .cursorbar{display:flex;align-items:center;gap:10px;padding:12px 18px 2px;
  color:var(--t3);font-size:var(--fs-caption)}
/* ★ 页码条（`2026-09-24` 取代「加载更多（键集游标）」）——
   四个新类里**没有一个是按钮**：可点的项一律复用 `.mini`（自带 `cursor:pointer` 与既有边框），
   于是"能点的长得像能点的、点不动的长得像点不动的"这条**不需要任何新规矩**（复杂度红线④）。
   `.pgcur`（当前页 / 当前每页档位）= 焦点色描边 + 加粗 + 底色 —— 它是**状态显示**不是按钮，
   故**不给** `cursor:pointer`：给了就等于在屏上多一个"点了没反应"的假入口。
   `.pgnums` 单独收窄间距 —— `.cursorbar` 的 `gap:10px` 是给"一枚按钮 + 两句说明"配的，
   十几个页码挤在 10px 下会散成一片；而 `gap` 是容器的，改它会影响同容器里别的件。 */
.crm .cursorbar .pgnums{display:inline-flex;align-items:center;gap:3px}
.crm .cursorbar .pgcur{font-size:var(--fs-micro);padding:2px 6px;border:1px solid var(--focus);
  border-radius:var(--r-xs);color:var(--t1);background:var(--e4);font-weight:600;cursor:default}
.crm .cursorbar .pgoff{font-size:var(--fs-micro);padding:2px 6px;color:var(--t3);cursor:default}
.crm .cursorbar .pgsep{color:var(--t3);margin-left:4px}
.crm .cursorbar .pgsum{color:var(--t3)}
.crm .mono{font-family:var(--font-num);font-size:.92em;color:var(--t2);background:var(--e4);border-radius:3px;padding:0 4px}
.crm .foot{color:var(--t3);font-size:var(--fs-micro);line-height:1.75;padding:8px 18px 20px}
.crm .foot b{color:var(--t2);font-weight:400}
.crm .scroll{flex:1 1 auto;min-height:0;overflow-y:auto}
.crm .scroll::-webkit-scrollbar{width:8px}
.crm .scroll::-webkit-scrollbar-thumb{background:var(--scroll);border-radius:4px}
.crm .scroll::-webkit-scrollbar-track{background:transparent}

/* ── 空态 / 加载态（简版）── */
.crm .empty-note{font-size:13px;color:var(--t3);padding:22px 18px;line-height:1.7}
.crm .sk-row td{padding:12px 10px;border-bottom:1px solid var(--line)}
.crm .sk-bar{height:12px;border-radius:6px;background:var(--e4)}

/* ══════════════════════════════════════════════════════════════════════════
   ★★ AI 客户池研判（2026-09-17 · 客户站 AI 方案 A/B 两版）★★
   来源：mockup/_ai-vision/_shot_crm.mjs 的注入层（CSS 段 + AIBAND/AISIDE）。
   两版外壳不同、内件同源：
     A 版 #aipoolBand  —— 全宽横幅（插在 .pagehd 之后），表格保持全宽 13 列
     B 版 #crmSide     —— 右侧 300px 常驻栏（.app 的 flex item）
   共用的内件一律 `.aipool .ap-*`，只写一遍。

   ★ 类名纪律（RULES 58 两次血例之后写的）：**内件不沿用设计稿的 cop / sect / adv 等裸类名**——
     它们里有 `cop` / `sect` 已被 chat.css 的**全局单类**规则占用（`.cop{border-radius…}`、
     `.sect{flex:0 0 auto}`，2 处已知撞车源）。客户站副驾栏是**第二个消费者**，
     沿用同名会让"两处只靠祖先区分"，日后任一处放宽选择器立刻串味。
     故内件统一 `ap-` 前缀 + 唯一作用域根 `.aipool`；判据：`consistency.mjs` 断言
     `ap-*` 与 `.aipool` 在**本文件之外**命中数为 0（不跨源撞车）。
   ★ 零字面色值：全部 var()；渐变与半透明面阶同样由令牌派生。
   ★ 消费的 AI 令牌见 tokens.css 的 `--ai-*` 组（本文件只读不定义）。
   ══════════════════════════════════════════════════════════════════════════ */

/* ── 共用内件：标题行（A 版的头 / 两处都用同一套排布）──
   ★ 允许自然换行：极窄窗下整行 min-content 会超出带宽 —— 而 `#aipoolBand{overflow:hidden}`
     会**静默剪掉**右侧（实测 A 版 W≤1000 起就剪：1000 剪 81px、741 剪 340px，
     被剪的正是把握度条与口径句）。加 wrap 后放不下才换行，信息只换位置不消失。
   ★ 同理见下面 `.ap-nodes` 与 `customers.css` 的 `.fbar`。 */
.aipool .ap-hd{display:flex;flex-wrap:wrap;align-items:center;gap:7px;row-gap:6px;margin-bottom:8px}
.aipool .ap-ic{width:16px;height:16px;border-radius:5px;flex:0 0 auto;display:flex;
  align-items:center;justify-content:center;font-size:9.5px;font-weight:800;color:var(--e0);
  background:linear-gradient(135deg,var(--ai-1),var(--ai-2))}
.aipool .ap-hd b{font-size:12px;font-weight:700;color:var(--ai-fg);letter-spacing:.2px}
.aipool .ap-hd .ap-sub{font-size:var(--fs-micro);color:var(--t3)}
.aipool .ap-hd .ap-rt{margin-left:auto;display:flex;align-items:center;gap:9px;
  font-size:var(--fs-micro);color:var(--t3)}
.aipool .ap-hd .ap-rt .ap-mt{display:inline-flex;align-items:baseline;gap:3px}
.aipool .ap-hd .ap-rt b{font-size:12px;font-weight:800;color:var(--amber);font-family:var(--font-num)}
.aipool .ap-hd .ap-rt b.ap-ok{color:var(--ai-em)}
.aipool .ap-hd .ap-rt .ap-sp{width:1px;height:10px;background:var(--line-strong)}

/* ── ★ 「快照未生成」态（2026-10-04）──
   契约：`NO_SNAPSHOT | 503 | 客户池快照未生成 | 显示「待生成」，**不要**当空数据`
   （`contracts/C-framework.md:442`）。
   ★ 用**中性灰**、不染红：这是**设计内状态**，不是故障 —— 重算器属 M6 里程碑、尚未落地
     （见 `data.js` 的 `POOL.state` 段）。染红会把"没做"读成"做坏了"。
   ★ 与 `.ap-lv`（B 版的 LIVE 标）刻意不同色：没有快照还说 LIVE 是谎话。 */
.aipool .ap-hd .ap-st{margin-left:auto;font-size:9.5px;font-weight:700;letter-spacing:.5px;
  color:var(--t3);border:1px solid var(--line-strong);border-radius:5px;padding:1px 6px}
.aipool .ap-empty{font-size:11.5px;color:var(--t3);line-height:1.6}

/* ── 共用内件：把握度条（A 版定宽 56 / B 版撑满，故两处各自写尺寸、颜色共用）── */
.aipool .ap-gauge{display:flex;align-items:center;gap:6px;color:var(--t3)}
.aipool .ap-gauge .ap-gb{width:56px;height:3px;border-radius:2px;background:var(--e4);overflow:hidden}
.aipool .ap-gauge .ap-gb i{display:block;height:100%;border-radius:2px;background:var(--ai-track)}
.aipool .ap-gauge b{font-size:11.5px;font-weight:800;color:var(--ai-em);font-family:var(--font-num)}

/* ── A 版：节点链 ──
   ★ `flex-wrap:wrap` + `row-gap`：窄窗下 4 个节点 + 3 条连线 + 那句 nowrap 的口径句
     必然超宽（`.ap-nd` 是 flex:0 0 auto、口径句 nowrap，都收不动）⇒ 不换行就被剪。
     换行落点天然正确：口径句带 `margin-left:auto`，独占第二行时仍贴右缘。 */
.aipool .ap-nodes{display:flex;flex-wrap:wrap;align-items:stretch;row-gap:6px}
.aipool .ap-nd{display:flex;align-items:center;gap:6px;padding:4px 9px;border-radius:8px;flex:0 0 auto;
  background:var(--ai-node-bg);border:1px solid var(--ai-node-line)}
.aipool .ap-nd .ap-ni{width:13px;height:13px;border-radius:4px;flex:0 0 auto;display:flex;
  align-items:center;justify-content:center;font-size:9px;font-weight:800;
  color:var(--ai-chip-fg);background:var(--ai-chip-bg)}
.aipool .ap-nd.ap-last{background:var(--accent-wash);border-color:var(--accent-line)}
.aipool .ap-nd.ap-last .ap-v{color:var(--accent-text)}
.aipool .ap-nd.ap-last .ap-ni{color:var(--accent-text);background:transparent;
  border:1px solid var(--accent-line)}
.aipool .ap-nd .ap-col{display:flex;flex-direction:column;gap:1px}
.aipool .ap-nd .ap-k{font-size:9.5px;color:var(--ai-node-k);white-space:nowrap;letter-spacing:.2px}
.aipool .ap-nd .ap-v{font-size:12px;font-weight:700;color:var(--ai-node-v);white-space:nowrap;
  font-family:var(--font-num)}
.aipool .ap-nd .ap-v em{font-style:normal;font-size:10px;color:var(--ai-node-k);margin-left:2px;
  font-family:inherit;font-weight:400}
.aipool .ap-lk{flex:0 0 30px;align-self:center;height:1.5px;position:relative;
  background:linear-gradient(90deg,var(--e4),var(--ai-1))}
.aipool .ap-lk::after{content:"";position:absolute;right:-1px;top:-2.7px;width:0;height:0;
  border-left:4.5px solid var(--ai-1);border-top:3.7px solid transparent;
  border-bottom:3.7px solid transparent}
/* 双轨：两条打分路**并行**汇入（不是一根粗箭头）——轨距 5px 是实测值：
   3.5px 时两条线在 2x 图缩略后会被读成"一根粗箭头"，"两路并行"这个语义就白画了。 */
.aipool .ap-lk.ap-d2{align-self:stretch;height:auto;flex:0 0 42px;display:flex;flex-direction:column;
  justify-content:center;gap:5px;background:none}
.aipool .ap-lk.ap-d2 span{display:block;height:1.5px;border-radius:1px;position:relative}
.aipool .ap-lk.ap-d2 span.ap-a{background:linear-gradient(90deg,var(--e4),var(--ai-1))}
.aipool .ap-lk.ap-d2 span.ap-b{background:linear-gradient(90deg,var(--e4),var(--ai-2))}
.aipool .ap-lk.ap-d2 span::after{content:"";position:absolute;right:-1px;top:-2.7px;width:0;height:0;
  border-top:3.7px solid transparent;border-bottom:3.7px solid transparent}
.aipool .ap-lk.ap-d2 span.ap-a::after{border-left:4.5px solid var(--ai-1)}
.aipool .ap-lk.ap-d2 span.ap-b::after{border-left:4.5px solid var(--ai-2)}
.aipool .ap-note{margin-left:auto;align-self:center;font-size:var(--fs-micro);color:var(--t3);
  white-space:nowrap}

/* ── A 版外壳：全宽横幅（顶部整宽渐变线 + 左缘竖条 = "AI 出品"标识）── */
#aipoolBand{margin:0 18px 10px;padding:9px 13px 10px 15px;border-radius:var(--r-md);
  position:relative;overflow:hidden;background:var(--ai-surface);border:1px solid var(--ai-line);
  box-shadow:var(--sh-1)}
#aipoolBand::before{content:"";position:absolute;top:0;left:0;right:0;height:1.5px;
  background:linear-gradient(90deg,var(--ai-1),var(--ai-2))}
#aipoolBand::after{content:"";position:absolute;left:0;top:0;bottom:0;width:2.5px;
  background:linear-gradient(180deg,var(--ai-1),var(--ai-2))}

/* ── B 版外壳：右侧常驻副驾栏 ──
   宽度取 `var(--crm-side-w)`（tokens.css 单点定义）——**不写字面 300**：
   `#demo` 的让路规则要用同一个数，两处写死就是漂移源。
   `#crmSide:empty{display:none}` = 「没内容就不占位」；A 版下 customers.js 会清空它。
   ⚠ `flex-basis` 只在 `#crmSide` 上声明，**不写到共用的 `.aipool` 上** ——
     A 版那个根（`#aipoolBand`）是 `.scroll` 里的**块级子元素**，不是 flex item，
     把 flex 写在共用类上会有"一半在用、一半是死声明"的假象（读代码的人以为它在生效）。
   ⚠ 不用 JS 判宽度设 display：宽度判断只留在 CSS（本文件纪律）。 */
#crmSide{display:none;flex:0 0 var(--crm-side-w);min-width:0;background:var(--e1);
  border-left:1px solid var(--line);flex-direction:column;padding:14px;overflow-y:auto;
  position:relative}
.app.crmmode > #crmSide:not(:empty){display:flex}
#crmSide::-webkit-scrollbar{width:8px}
#crmSide::-webkit-scrollbar-thumb{background:var(--scroll);border-radius:4px}
#crmSide::before{content:"";position:absolute;top:0;right:0;width:220px;height:220px;
  pointer-events:none;
  background:radial-gradient(circle at 100% 0%, color-mix(in srgb, var(--ai-1) 12%, transparent),
    transparent 70%)}

/* B 版：副驾卡（与对话站右栏的 AI 研判同族：同令牌、同形状语言）*/
#crmSide .ap-cop{border-radius:var(--r-md);padding:12px;position:relative;overflow:hidden;
  flex:0 0 auto;margin-bottom:13px;background:var(--ai-cop);border:1px solid var(--ai-line)}
#crmSide .ap-ch{display:flex;align-items:center;gap:7px;margin-bottom:9px}
#crmSide .ap-ch .ap-ic{width:20px;height:20px;border-radius:6px;font-size:11px}
#crmSide .ap-ch .ap-tt{font-size:12.5px;font-weight:600;color:var(--ai-fg)}
#crmSide .ap-ch .ap-lv{margin-left:auto;font-size:9.5px;font-weight:700;letter-spacing:.5px;
  color:var(--accent-text);border:1px solid var(--ai-live-line);border-radius:5px;padding:1px 6px;
  background:var(--ai-live-bg)}
/* ★ 「快照未生成」态（2026-10-04）—— 口径与理由同 A 版那一处（见 `.aipool .ap-st` 段）。
   ⚠ 占的就是 `.ap-lv` 那个位置，但**刻意不沿用它的 LIVE 样式**（没有快照还标 LIVE 是谎话）。 */
#crmSide .ap-ch .ap-st{margin-left:auto;font-size:9.5px;font-weight:700;letter-spacing:.5px;
  color:var(--t3);border:1px solid var(--line-strong);border-radius:5px;padding:1px 6px}
#crmSide .ap-empty{font-size:11.5px;color:var(--t3);line-height:1.6}
#crmSide .ap-cr{display:flex;align-items:center;gap:8px;padding:4px 0;font-size:11.5px}
#crmSide .ap-cr .ap-k{flex:0 0 62px;color:var(--t3)}
#crmSide .ap-cr .ap-v{color:var(--t1);font-weight:600;font-family:var(--font-num)}
#crmSide .ap-cr .ap-v.ap-hot{color:var(--danger-text)}
#crmSide .ap-cr .ap-v.ap-warn{color:var(--amber)}
#crmSide .ap-gauge{margin-top:9px;padding-top:9px;border-top:1px solid var(--ai-line)}
#crmSide .ap-gauge .ap-gk{font-size:10px;color:var(--t3);flex:0 0 auto}
#crmSide .ap-gauge .ap-gbar{flex:1 1 auto;height:3px;border-radius:2px;background:var(--e4);overflow:hidden}
#crmSide .ap-gauge .ap-gbar i{display:block;height:100%;border-radius:2px;background:var(--ai-track)}
#crmSide .ap-gauge .ap-gv{font-size:11.5px;font-weight:800;color:var(--ai-em);
  font-family:var(--font-num);flex:0 0 auto}

/* B 版：分段（今日建议 / AI 最近动作）*/
#crmSide .ap-sect{flex:0 0 auto;margin-bottom:16px}
#crmSide .ap-sh{display:flex;align-items:center;gap:7px;margin-bottom:9px}
#crmSide .ap-sh .ap-ln{width:3px;height:11px;border-radius:2px;background:var(--accent-text);flex:0 0 auto}
#crmSide .ap-sh .ap-t{font-size:11.5px;font-weight:600;color:var(--t2);letter-spacing:.4px}
#crmSide .ap-sh .ap-n{margin-left:auto;font-size:10.5px;color:var(--t3)}
#crmSide .ap-adv{background:var(--e2);border:1px solid var(--line);border-radius:var(--r-sm);
  padding:11px 12px;margin-bottom:9px;position:relative;overflow:hidden}
#crmSide .ap-adv::before{content:"";position:absolute;left:0;top:0;bottom:0;width:2px;
  background:linear-gradient(180deg,var(--ai-1),var(--ai-2))}
#crmSide .ap-adv .ap-ah{display:flex;align-items:center;gap:6px;font-size:12px;font-weight:600;
  color:var(--t1)}
#crmSide .ap-adv .ap-ah .ap-tg{margin-left:auto;font-size:9.5px;font-weight:600;padding:1px 6px;
  border-radius:var(--r-full);background:var(--danger-bg);color:var(--danger-text)}
#crmSide .ap-adv .ap-ah .ap-tg.ap-w{background:var(--amber-bg);color:var(--amber)}
#crmSide .ap-adv .ap-ab{font-size:11px;color:var(--t3);margin:5px 0 7px}
#crmSide .ap-adv .ap-af{display:flex;align-items:center;gap:8px}
#crmSide .ap-adv .ap-af .ap-act{font-size:11px;font-weight:600;color:var(--accent-text)}
#crmSide .ap-adv .ap-af .ap-conf{margin-left:auto;display:flex;align-items:center;gap:6px}
#crmSide .ap-adv .ap-af .ap-bar{width:46px;height:3px;border-radius:2px;background:var(--e4);overflow:hidden}
#crmSide .ap-adv .ap-af .ap-bar i{display:block;height:100%;border-radius:2px;background:var(--ai-track)}
#crmSide .ap-adv .ap-af .ap-pc{font-size:10.5px;font-weight:700;color:var(--ai-em);
  font-family:var(--font-num)}
#crmSide .ap-log{display:flex;align-items:baseline;gap:8px;font-size:11px;padding:5px 0;color:var(--t2)}
#crmSide .ap-log .ap-lt{flex:0 0 60px;color:var(--t3);font-size:10px}
#crmSide .ap-log .ap-lb{color:var(--t1)}
#crmSide .ap-foot{margin-top:auto;flex:0 0 auto;padding-top:10px;border-top:1px solid var(--line);
  font-size:11px;color:var(--t3);line-height:1.6}

/* ── 行内 AI 研判标（A/B 两版都出 · 挂在「客户」列第二行 = 微信号那一行之后）──
   ⚠ 选择器**必须**从 `.crm .nmcell .tx` 起写（0,4,0），不能写成设计稿的 `.crm .aic`（0,2,0）：
     上面 `.crm .nmcell .tx span`（0,3,1）会把 color / font-size / font-family 全数覆盖，
     胶囊会变成 11px 等宽的灰色小字 —— 看上去"只是样式不太对"，实际是与"面元"那行同色，
     读者分不出这是 AI 标还是微信号的一部分（**不报错的错**，正是 RULES 57 那一支）。
   三档配色按**语义分工**（hi = 需处理 → danger 系；mid = 中性面阶；无 class = AI 色）：
   与「异常」列的琥珀**刻意不同色** —— 同一行两种"警告"同色时用户不知道该信哪个。 */
.crm .nmcell .tx .aic{display:inline-flex;align-items:center;gap:3px;margin-left:7px;padding:0 6px;
  height:15px;border-radius:var(--r-full);font-size:9.5px;font-weight:600;white-space:nowrap;
  vertical-align:1px;font-family:var(--font-ui);background:var(--ai-chip-bg);
  color:var(--ai-chip-fg)}
.crm .nmcell .tx .aic i{width:4px;height:4px;border-radius:50%;background:currentColor;
  opacity:.9;flex:0 0 auto}
.crm .nmcell .tx .aic.ap-hi{background:var(--danger-bg);color:var(--danger-text)}
.crm .nmcell .tx .aic.ap-mid{background:var(--stage-chip-bg);color:var(--t2)}

/* ── 姓名行「来源小标」（2026-09-24 · 用户令「列表能分辨备注/昵称」）────────────────
   事由：`name` 是后端 `display_name` 的**合并值**（= 备注，缺则昵称）⇒ 光看它
   分不出看到的是哪一个（本仓 `remark_name` / `latest_nickname` 两列此前**无写入者**）。
   本批后端新增 `name_src`（`'remark'` / `'nick'` / `null`）⇒ 这里把它显出来。
   ⚠ 用**全称**而非缩写/符号：本仓红线「符号必须配图例 = 培训成本 = 不要」，
     「备注」「昵称」自解释、零培训成本（写成「备」/「昵」就得再教一遍）。
   ⚠⚠ **必须另起一层 `.nmrow`（flex），绝不能把标塞进 `<b>` 里** —— 两条**独立**理由：
     ① 判据 `_probe_semcolor.mjs` 用 `.nmcell .tx b` 的 **`textContent`** 取名字 ⇒
        塞进去会把「张三」读成「张三备注」（读数被污染，且**不报错**）；
     ② `.tx b` 是 `display:block` + `text-overflow:ellipsis` ⇒ 标跟在名字后面会被
        长名字挤到第二行、再被 `.tx{overflow:hidden}` 裁掉 ⇒ **标看不见且不报错**。
     flex 行里 `<b>` 可压缩（`0 1 auto`，先走省略号）、标 `0 0 auto` 不可压缩 ⇒ 标恒可见。
   ⚠ 全部走令牌（`crmai.mjs` 扫本文件的字面色值）。
   ⚠ 「昵称」比「备注」更淡：无备注的人占多数（云上现取 11266 里备注非空仅 1 行、
     快照侧 remark 非空 ≈11%）⇒ 两态同等醒目时整表会被「昵称」两个字刷满，
     反而看不出哪些人**有**备注（标的作用就没了）。 */
.crm .nmcell .tx .nmrow{display:flex;align-items:center;gap:5px;min-width:0}
.crm .nmcell .tx .nmrow b{min-width:0;flex:0 1 auto;white-space:nowrap}
.crm .nmcell .tx .nmsrc{flex:0 0 auto;display:inline-block;height:14px;line-height:14px;
  padding:0 4px;border-radius:var(--r-xs);font-size:9.5px;font-weight:600;font-style:normal;
  white-space:nowrap;font-family:var(--font-ui)}
.crm .nmcell .tx .nmsrc.ns-remark{background:var(--stage-chip-bg);color:var(--stage-chip-fg)}
.crm .nmcell .tx .nmsrc.ns-nick{background:transparent;color:var(--t3);opacity:.75}
/* ★ 搜索命中的那枚（`2026-09-24`）：与上面两枚**同一位置、二选一**（由 `customers.js`
   的 `nmSrcHtml` 决定出哪一枚），**不是并排**。
   ⚠ 它比「备注」更醒目（`--accent-wash` 底 + `--accent-text` 字）是刻意的：
     搜索是**用户刚刚做的一件事**，屏上必须能找到它的痕迹；而来源标是**数据的属性**、
     一直在那儿，不需要抢注意力。
   ⚠ 文案白名单在 `customers.js` 的 `SQ_LB`（四个合法值各一支）——这里只管画。 */
.crm .nmcell .tx .nmsrc.ns-hit{background:var(--accent-wash);color:var(--accent-text)}

/* ══ ★ 2026-09-18（客户线）「数据从哪来」五态的可见部分 ══════════════════════════════
   本轮修的缺陷是**真假不分**：页头的「全库 N 人」（N 现读 POOL.total）来自真后端，
   而表格里那几行是内置演示数据，
   屏上**没有任何标记**。这组规则只做一件事：把「来源 / 新旧 / 取没取到」用色 + 字说清楚。

   ★ 全部走令牌，**禁任何字面色值**（crmai.mjs 会扫 customers.css 的字面色值）：
     四主题（明度 × 色温 2×2）切换时这组样式必须跟着走 —— 写死颜色会在浅色主题下
     变成"深底浅底糊在一起"，而且**只在切主题后才看得见**（默认主题下一切正常）。
   ★ 状态条在页头**允许换行**（`.pagehd{flex-wrap:wrap}` 已存在）：宁换行不裁掉（本条纪律见 :9）。 */

/* 页头数据来源条：贴着「全库 N 人」读，故字号与 `.cnt` 同级 */
.crm .dsrc{display:inline-flex;align-items:center;gap:5px;font-size:var(--fs-caption);
  padding:1px 8px;border-radius:var(--r-full);border:1px solid var(--line);color:var(--t2);
  background:var(--e2);white-space:nowrap}
.crm .dsrc.ok{color:var(--accent-text);border-color:var(--accent-line);background:var(--accent-wash)}
.crm .dsrc.er{color:var(--danger-text);border-color:var(--danger-line);background:var(--danger-bg)}
.crm .dsrc.st{color:var(--amber);border-color:var(--amber-line)}
/* 加载中的呼吸点：**必须有动效**。静止的小圆点与"装饰点"无法区分，
   而"它在动"才是"还在跑"的唯一信号 —— 这条就是「不许用空白代替加载中」的落点。 */
.crm .dsrc.ld i{width:6px;height:6px;border-radius:var(--r-full);background:var(--t3);
  animation:dsrcPulse 1s ease-in-out infinite}
@keyframes dsrcPulse{0%,100%{opacity:.25}50%{opacity:1}}
/* 失败态的「重试」：与页头其它 `.chipbtn` 同级，但用 danger 描边 —— 它是这一屏唯一的求救口 */
.crm .chipbtn.retry{color:var(--danger-text);border-color:var(--danger-line)}
.crm .chipbtn.retry:hover{background:var(--danger-bg)}
/* 失败并回落演示数据时给表体一个整体标记：只靠页头一行小字，用户扫表格时是看不到的。
   用描边 + 轻微降不透明度，**不用**遮罩（遮罩会挡点击，而表格里的「详情」此时仍然可用）。 */
.crm.degraded .tblwrap{border-color:var(--danger-line)}
.crm.degraded .ftbl tbody{opacity:.72}

/* ── 抽屉头部的「明细取数」状态 ────────────────────────────────────────────────────
   ⚠ 选择器**必须带 `.crmmode` 前缀**：`#dtl` 是 `.app` 的子元素、**不在** `#crmbody` 里
     ⇒ 写成 `.crm .dh-ld` 一条都匹配不上（本项目实测过的那类"静默失配"：样式写了、不报错、不生效）。
   ⚠ 这段落在 customers.css 而不是 shell.css：`.dtl` 的既有样式在 shell.css，而
     shell.css 归 F 线（本线只读）⇒ 新增样式放本线自有文件，用 `crmmode` 收窄作用面。 */
.crmmode .dtl .dh-ld,.crmmode .dtl .dh-er{display:inline-flex;align-items:center;gap:5px;
  margin-left:auto;font-size:var(--fs-caption);padding:1px 8px;border-radius:var(--r-full);
  border:1px solid var(--line);white-space:nowrap;flex:0 0 auto}
.crmmode .dtl .dh-ld{color:var(--t2)}
.crmmode .dtl .dh-ld i{width:6px;height:6px;border-radius:var(--r-full);background:var(--t3);
  animation:dsrcPulse 1s ease-in-out infinite}

/* ── 「② 要紧的事」里的红线条目（后端 `comm_log.is_red = 1`）────────────────────────
   ⚠ 为什么需要一条**独立**的样式、而不是复用 `chat.css` 的 `.hotrow`：`.hotrow` 是
     `display:flex` 的**整行块**（自带底色/描边/margin），而抽屉里每行是 `.dtl-tbl`
     这个 `grid` 的**两个格子**（`.k` + `.v`）。把 `.hotrow` 套进来会变成 grid 里一个
     跨列的自由块 —— 表就散了，而且**不会报错**（RULES 58 那类"类名撞车"的近亲）。
   ⇒ 只借它的**取值口径**（`chat.css:193`：`--danger-text` + `600` 字重），
     不借它的排版。字形不加粗到影响列宽：`.v` 本身已 `overflow-wrap:anywhere`。 */
.crmmode .dtl .dtl-tbl .v.red{color:var(--danger-text);font-weight:600}
.crmmode .dtl .dh-er{color:var(--danger-text);border-color:var(--danger-line);background:var(--danger-bg)}

/* ── 抽屉里的「发消息」输入条（2026-09-24 · 用户规划②「中台指定联系人的发送」）─────────
   ⚠ 选择器带 `.crmmode` 前缀：`#dtl` 是 `.app` 的子元素、**不在** `#crmbody` 里
     ⇒ 写成 `.crm .dtl-sendbar` 一条都匹配不上（本文件上面那段注释记的是同一个坑）。
   ⚠ 本段落在 customers.css（本线自有）而不在 shell.css：`.dtl` 的既有样式在 shell.css，
     而它归 F 线、本线只读 ⇒ 新增样式一律落本线文件、用 `crmmode` 收窄作用面。
   ⚠★ **令牌名必须现取自 `tokens.css`**：本段初稿随手写了 `--bg-1` / `--bg-2` / `--r-2`，
     三个**都不存在** ⇒ 写了、不报错、样式静默不生效（`R23` 的教科书形态，已逐条改成现取）。
     现用：`--panel` / `--inputbg` / `--line` / `--t1` / `--t2` / `--r-sm`
     / `--accent-line` / `--accent-text` / `--danger-text`（全部 `grep -c` 过 = 存在）。
   ⚠ `flex-wrap:wrap` 是**必须的**：状态文字是长句（"发不了 · 这个账号没有已登记的启用设备…"），
     不换行会把输入框挤成一条线 —— 而"被挤"在 flex 里**不报错、只是难看**。 */
.crmmode .dtl .dtl-sendbar{display:flex;align-items:center;flex-wrap:wrap;gap:8px;
  padding:8px 14px;border-bottom:1px solid var(--line);background:var(--panel)}
/* ⚠ `[hidden]` 这条**必须显式写**：上面那条 `display:flex` 会盖掉 UA 的
   `[hidden]{display:none}`（同特异性，而本文件后加载 ⇒ 本文件赢）
   ⇒ 漏了这一条 = 输入条**永远露在外面**，而症状是"点「发消息」看着没变化"（因为它本来就在）。
   同族：`R57` —— CSS 覆盖不能只靠"选择器写对了"。 */
.crmmode .dtl .dtl-sendbar[hidden]{display:none}
.crmmode .dtl .dtl-sendbar .dsn-in{flex:1 1 160px;min-width:0;height:28px;padding:0 10px;
  font-size:var(--fs-body);color:var(--t1);background:var(--inputbg);
  border:1px solid var(--line);border-radius:var(--r-sm)}
.crmmode .dtl .dtl-sendbar .dsn-in:focus{border-color:var(--accent-line)}
/* ⚠ **不写 `outline:none`**：那会抹掉键盘焦点环，而本仓要求"能点的都能用键盘做到"
   （Enter 即发就挂在这个输入框上）。焦点只用 `border-color` 强化。 */
.crmmode .dtl .dtl-sendbar .dsn-note{flex:1 1 100%;min-width:0;
  font-size:var(--fs-caption);color:var(--t2);overflow-wrap:anywhere}
.crmmode .dtl .dtl-sendbar .dsn-note.ok{color:var(--accent-text)}
.crmmode .dtl .dtl-sendbar .dsn-note.bad{color:var(--danger-text)}

/* ══ ★★ 客户详情抽屉：行线连续 + 核心字段权重（2026-09-25 · D 线「详情批」）★★
   1) 行线连续 —— 现场形态：`.dtl-tbl` 是 4 列网格（基础段在 shell.css：`100px 1fr 100px 1fr`
      + `column-gap:14px`），而 `.k` 与 `.v` **各自**带 `border-bottom:1px solid var(--line)`
      ⇒ 每行的横线被那 14px 空隙切成 **4 段**（`.wide` 行还多一道左侧空档）⇒ 整表看着像"断尺"。
      实测（`_probe_dtlkeys.mjs` 改前）：**行内空隙取值集合 = [14]** · 27 行全中。
      ⇒ 把空隙收到 0，改用**单侧内边距**制造同等的呼吸位
        ⇒ 相邻格的 border-bottom **首尾相接** ⇒ 行线连续，而**视觉间距一字未变**。
      ⚠ 只覆盖**单侧**（不写 `padding` 简写）：上下的 5px 仍由基础段给，
        将来基础段调行距，这里自动跟随（写简写就把基准抄死在别线文件里了）。
      ⚠ 收 gap 会把 14×3 的空隙还给列 ⇒ 两个 `1fr` 列各宽 **+21px**（值区更宽、更不易换行）；
        标签列因右垫 14px 内容宽 100→86px ⇒ **实测截断数 0**（改后复测，见留痕件 §三）。
      ⚠ `dtl.mjs` ⑨ 段量的是「抽屉内容**横向溢出**」—— 本改动只会让内容**更宽松**，不会踩它。
   2) 核心字段权重 —— `detail.js` 给**身高 / 现重 / 目标体重 / 忌口**打了 `key` 语义标记
      （依据 = 项目记忆明文「档案核心 = 身高/现重/目标体重 + 忌口」）。
      这四栏此前与「静息心率 / 转介绍链」**完全同权重**（400 字重、标签同为 `--t2`）
      ⇒ 用户开抽屉就是来找这几个数的，却没有任何视觉落点 ⇒ 标签提亮 `--t1`、值加粗 600。
      ⚠ 与 `.v.red`（要紧的事 · 锐利红）**不会同现**：`red` 只出现于 ② 区，`key` 在 ①③④ 区。
      ⚠ 与 `.v.wide` 不冲突：key 那四栏都不是 wide ⇒ 不参与跨列。
   ⚠ 作用面**只有 `.crmmode`（客户站）** —— 依据是本文件上一条 `dtl-sendbar` 段已写死的成文纪律：
     `.dtl` 的基础样式在 `shell.css`、**归 F 线、本线只读** ⇒ 新增一律落本线 + `crmmode` 收窄。
     ⇒ **对话站入口拿不到这两项**，是该纪律的**必然结果**（不是遗漏），已登记请 F 线定夺是否上提。 */
.crmmode .dtl .dtl-tbl{column-gap:0}
.crmmode .dtl .dtl-tbl .k{padding-right:14px}
.crmmode .dtl .dtl-tbl .v{padding-left:14px}
.crmmode .dtl .dtl-tbl .k.key{color:var(--t1);font-weight:500}
.crmmode .dtl .dtl-tbl .v.key{color:var(--t1);font-weight:600}

/* ── 状态栏反馈的**可见性**（本轮修 · 用户报「编辑点不了」的直接成因）────────────────
   现场取证（`app/_verify/_reports/客户线-1505-探针-编辑触点.mjs`，15 PASS / 0 FAIL）：
     两处「编辑」**都点得到、都触发了反馈** —— 列表 `.op[data-op]` @ (1373,474)、
     抽屉头 `button.dh-b` @ (1342,143)，`elementFromPoint` 命中的都是它们自己（无遮挡）；
     点击后 `#sbToast.textContent` = 「编辑 · 尚未开放」。
   但反馈**在视觉上读不出来**：运行时读到 `className = "(无 class)"`，实际落到
     `color: rgb(155,163,171)`（= `--t2`，次级灰）、`font-weight:400`、12px、
     位置 (1341,879) = **屏幕最右下角**、2.4s 后清空 ⇒ 体感就是「点了没反应」。
   根因：`shell.css:282` 写的是 `.statusbar .toast{color:var(--accent-text);font-weight:500}`，
     而 `index.html:151` 的元素是 `<span id="sbToast">` —— **没有 `class="toast"`**
     （同组邻居 `#sbNarrow` 有 `class="narrow"`、`#sbPause` 有 `class="pause"`，唯独它漏了）
     ⇒ 那条选择器**永不匹配 = 死规则**。
   ⚠ 本规则**照搬那条死规则的取值**（`--accent-text` + `500`），只把选择器落到 `#sbToast`
     并限定本站 —— **不另立一套颜色**。
   ⚠ **根修在 F 线**：给 `index.html:151` 补一个 `class="toast"`，一处修好全站
     （对话站的 `data-op / data-jump / data-gap / data-xa` 同族出口现在同样是灰的）。
     本规则是**本线范围内的止血**，F 线补完后**可整条删除**。
   ⚠ **选择器为什么是 `:has()` 而不是 `.crmmode .statusbar #sbToast`（首版写错，留痕）**：
     `index.html` 里 `</div>`(@124) **先关掉 `.app`**，`.statusbar`(@126) 是 `.win` 的
     **直接子元素**、在 `.app` **之外** ⇒ `.crmmode`（挂在 `#app` 上）与 `.statusbar`
     是**兄弟**，后代选择器**永不匹配**（首版就是这么静默失效的：改完探针仍 FAIL，
     正是它救的场 —— 若只看"CSS 写对了"就会误判已修）。
     `:has()` 是 CSS 里唯一能从"兄弟的后代"反向命中的写法；要维持"限本站"的边界
     就得用它，不能图省事写成全局 `.statusbar #sbToast`（那会越界改全站组件）。 */
.win:has(> .app.crmmode) .statusbar #sbToast{color:var(--accent-text);font-weight:500}

/* ══ ★ 编辑面板（2026-09-18 · 「编辑」的落地）══════════════════════════════════════
   DOM 由 `app/js/detail.js` 的 `edBox()` **动态创建**并挂到 `#app`（`index.html` 归 F 线，
   本线只读）⇒ 样式必须由本文件提供。
   层级：`.dtl` 是 41 ⇒ 本面板 **51**（它从抽屉内部打开，必须在抽屉**之上**；
   否则点「编辑」会看到面板被抽屉压住，而 `elementFromPoint` 命中的还是抽屉 —— 静默不可点）。
   遮罩用**真实元素**（`.cedit` 自身带 `background`）而不是 `::after`：伪元素接不到点击，
   而"点遮罩关闭"是这类面板的通用出口，键盘之外唯一的鼠标退出路径。
   ⚠ 全部取值走令牌，**无字面色值**（四主题共用一套结构，差异只在令牌值）。 */
.cedit{position:absolute;inset:0;z-index:51;display:none;align-items:center;
  justify-content:center;background:var(--scrim)}
.cedit.on{display:flex}
.ce-p{width:580px;max-width:calc(100% - 56px);max-height:calc(100% - 56px);
  display:flex;flex-direction:column;background:var(--e1);border:1px solid var(--line2);
  border-radius:var(--r-lg);box-shadow:0 26px 64px -22px var(--sh-2);overflow:hidden}
/* `tabindex="-1"` 被程序化聚焦时 Chrome 会画 focus-ring —— 面板本身不可 Tab 到，视觉必须无痕 */
.ce-p:focus{outline:none}
.ce-hd{flex:0 0 auto;display:flex;align-items:baseline;gap:10px;padding:13px 18px;
  border-bottom:1px solid var(--line)}
.ce-hd b{font-size:var(--fs-title);font-weight:500;color:var(--t1)}
.ce-sub{font-size:var(--fs-caption);color:var(--t2)}
.ce-x{margin-left:auto;align-self:center;width:26px;height:26px;padding:0;flex:0 0 auto;
  display:flex;align-items:center;justify-content:center;font-family:inherit;font-size:var(--fs-caption);
  background:none;border:1px solid transparent;border-radius:var(--r-sm);
  color:var(--t2);cursor:pointer}
.ce-x:hover{color:var(--t1);border-color:var(--line2)}
.ce-bd{flex:1 1 auto;min-height:0;overflow-y:auto;padding:4px 18px 12px}
.ce-sec{margin-top:12px}
/* 小标题行做成 flex：后面两块区块要在标题右侧挂「点一下就存」这类常驻小字与计数。
   对只含一段文字的旧分组无影响（单个文本节点就是唯一的 flex item）。 */
.ce-sh{display:flex;align-items:baseline;gap:8px;
  font-size:var(--fs-micro);color:var(--t3);margin:0 0 2px}
.ce-f{display:grid;grid-template-columns:92px 1fr;gap:3px 12px;align-items:center;
  padding:7px 0;border-bottom:1px solid var(--line)}
.ce-f:last-child{border-bottom:none}
.ce-f .ce-k{font-size:var(--fs-caption);color:var(--t2)}
.ce-f .ce-v{display:flex;align-items:center;gap:6px;min-width:0}
.ce-f input,.ce-f select,.ce-f textarea{width:100%;min-width:0;font-family:inherit;font-size:var(--fs-small);
  color:var(--t1);background:var(--inputbg);border:1px solid var(--line2);
  border-radius:var(--r-sm);padding:6px 9px}
.ce-f input:focus,.ce-f select:focus,.ce-f textarea:focus{outline:none;border-color:var(--line3)}
/* 多行字段（「新增客户」的备注）—— **与上面同一个控件族**，只多两条：
   ① `min-height` + `line-height`：textarea 的默认行高在 grid 里会贴住上沿，看起来比
      旁边的 input 矮一截；② 锁住**横向**伸缩（纵向留给用户）：
      横拖会把 `.ce-f` 的 grid 第二列撑破，拖出去的东西不会再自动缩回来。 */
.ce-f textarea{resize:vertical;min-height:44px;line-height:1.5}
.ce-f .ce-u{flex:0 0 auto;font-style:normal;font-size:var(--fs-micro);color:var(--t3)}
/* 提示占第二列第二行：只给"改错了有后果"的字段挂（每行都挂 = 等于没提示） */
.ce-f .ce-h{grid-column:2;font-size:var(--fs-micro);color:var(--t3);line-height:1.5}
/* 必填标记。**不用红色**：红色在本仓是"异常 / 危险"的语言，而"必填"是**正常的表单约束**
   —— 一个还没填的表单上出现红字，用户会以为已经出错了（本仓「符号必须配图例」同族：
   一种颜色只能有一个意思）。用次级灰 + 细边框，靠文字本身说话。 */
.cnw-req{margin-left:5px;font-size:var(--fs-micro);color:var(--t3);
  border:1px solid var(--line);border-radius:var(--r-full);padding:0 5px}
.ce-ft{flex:0 0 auto;display:flex;align-items:center;gap:10px;padding:11px 18px;
  border-top:1px solid var(--line)}
.ce-msg{flex:1 1 auto;min-width:0;font-size:var(--fs-caption);color:var(--accent-text);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ce-bt{font-family:inherit;font-size:var(--fs-caption);cursor:pointer;
  border:1px solid var(--line2);border-radius:var(--r-sm);padding:5px 14px;
  background:none;color:var(--t1)}
.ce-bt:hover{border-color:var(--line3)}
.ce-save{background:var(--accent);color:var(--on-accent);border-color:transparent}
.ce-save:disabled{opacity:.5;cursor:default}
.ce-ld,.ce-er{display:flex;align-items:center;gap:9px;padding:24px 4px;
  font-size:var(--fs-caption);color:var(--t2)}
.ce-er{color:var(--danger-text);flex-wrap:wrap}
.ce-ld i{width:6px;height:6px;border-radius:var(--r-full);background:var(--t3);
  animation:dsrcPulse 1s ease-in-out infinite}
/* 冲突条：它是 `.ce-p` 的直接子节点（在 `#ceBd` 滚动区**之外**，`detail.js` 的 `edBox` 铺的）
   —— 决定"现在填的值还算不算数"，长表单滚到下半屏时它也必须看得见。
   ⚠ `[hidden]` 必须显式写：本条规则里的 `display:flex` 会**压过**浏览器默认的
     `[hidden]{display:none}` ⇒ 不写的话 `hidden` 属性完全失效，冲突条会永远挂着。
     这是"设了属性、以为它在起作用"的典型（本仓「对象在、判据不在」的一族）。 */
.ce-cf{margin:10px 18px 0;padding:9px 12px;display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  font-size:var(--fs-caption);color:var(--danger-text);
  background:var(--danger-bg);border:1px solid var(--danger-line);border-radius:var(--r-sm)}
.ce-cf[hidden]{display:none}
.ce-rl{font-family:inherit;font-size:var(--fs-caption);cursor:pointer;color:inherit;
  background:none;border:1px solid currentColor;border-radius:var(--r-sm);padding:3px 10px}

/* ══ ★ 编辑面板里的「本号标签」与「体态三视图」（2026-09-18 新增）══════════════════
   两块都在 `.ce-bd` 里，但**各自独立提交**（点一下就写库，不等底部「保存」）⇒
   每块标题右侧挂一行常驻小字说明这件事（不许靠用户猜：猜错的方向是"我点了取消"）。
   全部取值走令牌，**无字面色值** —— 四主题共用一套结构，差异只在令牌值。 */
/* 标题右侧的常驻小字（"点一下就存" / "选图即上传"） */
.ce-shh{font-style:normal;color:var(--t3);opacity:.85}
/* 计数 / 容量（`n / 12`、`单张 ≤ 8 MB`）：推到最右，与标题形成一左一右的扫读线 */
.ce-cnt{margin-left:auto;font-style:normal;color:var(--t3)}
/* 区块级错误（标签/照片整块取不到）：比整体空态更靠内，所以不沿用 `.ce-er` 的 24px 高内边距 */
.ce-er-in{padding:8px 0}
.ce-none{font-size:var(--fs-caption);color:var(--t3);font-style:normal}

/* ── 标签 chip ───────────────────────────────────────────────────────────────
   两态必须一眼分得开（选中 = 靠色，不是靠描边深浅）：未选=中性底 `--chip`，
   选中=accent 洗色 `--accent-wash` + accent 字。四套主题下这两个令牌都成对存在。 */
.ce-tgs{display:flex;flex-wrap:wrap;gap:6px;padding:4px 0 2px}
.ce-tg{font-family:inherit;font-size:var(--fs-caption);cursor:pointer;line-height:1.6;
  padding:3px 10px;border-radius:var(--r-full);
  background:var(--chip);border:1px solid var(--line2);color:var(--t2)}
.ce-tg:hover{border-color:var(--line3);color:var(--t1)}
.ce-tg.on{background:var(--accent-wash);border-color:var(--accent-line);color:var(--accent-text)}
.ce-tg:disabled{opacity:.55;cursor:default}

/* ── 三视图（★★ 2026-10-02 第二版：**「小缩略图纵列」→「竖幅胶片条 + 并排对比」**）────
   用户令逐字（本版起因）：「**但是里面的展示，无法显示出对比效果，无法直接看到，
                             重新设计一下**」。
   承 2026-10-01 的「时间轴 + 并排对比」：那版**意图**对，但两处实现把它做废了，且都不报错：
     ① 时间轴上每张体态照只有 `52×38`（减边框后 50×36）—— 体态照看的是**身形轮廓**，
        50×36 连人都认不出，"对比"无从谈起；
     ② 大图**永远画"最新"那一张** ⇒ 旧的那张**没有任何地方能放大看**。
   本版：
     · **基础态** = 三列（正 / 侧 / 背）并排，列内一条**横向胶片条**（竖幅 ≈96×128，左右滚），
       列顶大图 = **点中的那一张**（不再是"最新"）；
     · **对比态**（`.ce-phs.cmp`）= **三行堆叠**（每行一个面），行内两张同尺寸竖幅大图并排。
       ⚠ 为什么不是"三列里再并排两张"：抽屉内宽有限，三列并排时每张只剩 ≈100px，
         那正是本次要修的毛病换个地方重演。三行堆叠后每张约 180px 宽 ⇒ 才真的看得到。
   ⚠ 尺寸一律写死（本仓从未用过 `aspect-ratio`，写死才被审计脚本量得到）。
   ⚠ 取值一律走令牌，**无字面色值** —— 四主题共用一套结构。 */
/* ⚠ 列间距/内边距从 `9/7` 收到 `6/6`：不是审美，是**为了刚好放得下两格 96px 胶片**
   （内容宽 = 215-12-2 ≈ 201 ≥ 96×2+6 = 198）。改回 9/7 会变成"一屏只见 1.9 格"，
   而**第 2 格被切掉一半**看起来像布局坏了（用户不会想到"其实可以横向滚"）。 */
.ce-phs{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:6px;padding:4px 0 2px}
/* 对比态改**单列**（= 三行堆叠）；行间距与基础态同量 */
.ce-phs.cmp{grid-template-columns:minmax(0,1fr);gap:10px}
.ce-ph{position:relative;display:flex;flex-direction:column;gap:6px;min-width:0;padding:5px;
  background:var(--e2);border:1px solid var(--line2);border-radius:var(--r-sm)}
/* 文件输入框是 1px 不可见元素（`.ce-sr`）⇒ 焦点环只能画在**整个槽位**上。
   不画的话键盘用户 Tab 到这里会"焦点凭空消失"（鼠标能用、键盘不能用 = 两套体验）。 */
.ce-ph:focus-within{border-color:var(--accent-line);box-shadow:0 0 0 1px var(--accent-line)}
.ce-ph-t{font-size:var(--fs-micro);color:var(--t3)}
.ce-ph-t em{font-style:normal;opacity:.8}
/* ★ 高度按**竖幅**取（列内容宽 ≈201，201:228 ≈ 1:1.13）——
   2026-10-01 那版是 150px（列 215 宽 ⇒ 近正方），而体态照是竖幅：塞进近正方形框后
   `object-fit:cover` 会沿**两侧**裁，裁掉的恰恰是腰/胯那一段轮廓 —— 即"对比"要看的部分。
   ⚠ 也不能改 `object-fit:contain`（会留白，且每张留白不等 ⇒ 反而更不利于并排比身形）。 */
.ce-ph-imw{position:relative;height:228px;display:flex;align-items:center;justify-content:center;
  overflow:hidden;background:var(--inputbg);border:1px solid var(--line);border-radius:var(--r-sm)}
/* `object-fit:cover` = **故意裁切**（不是"内容被静默剪掉"）：体态照是竖幅，
   塞进固定框只能裁；裁掉的是边角背景，不是信息。 */
.ce-ph-im{width:100%;height:100%;object-fit:cover;display:block}
.ce-ph-no{font-size:var(--fs-micro);color:var(--t3)}
/* 大图角上「这一张是哪天 / 第几张」—— 换图后用户要能**从大图本身**确认在看哪一张，
   而不是回头去数小图。
   ⚠ 压在图上 ⇒ 必须自带底（底下的图可能是任何亮度，透明底会读不出字）；
     底走 `--panel`、不透明。`pointer-events:none`：它不该抢走"点大图"这类后续手势。 */
.ce-ph-imd{position:absolute;left:5px;bottom:5px;font-size:var(--fs-micro);line-height:1.5;
  padding:0 6px;border-radius:var(--r-full);background:var(--panel);color:var(--t2);
  border:1px solid var(--line2);pointer-events:none}

/* ── 胶片条（★ 2026-10-02 · **横向**；一格 = 一次体态）────────────────────────────
   ⚠ 2026-10-01 那版是**纵列 52×38 小图**，本次重设计要修的正是它（见上）。
   ⚠ `overflow-x:auto` + `overflow-y:hidden`：一列可能很长（每周一张，一年 50 张），
     不设上限会把整块面板撑破（本仓：不许静默把别的区块挤走）；
     横向滚动是胶片条的标准形态，且**每格固定 96px** ⇒ 位置稳定、不随张数抖动。 */
.ce-ph-tl{display:flex;flex-direction:row;gap:6px;overflow-x:auto;overflow-y:hidden;
  padding:4px;background:var(--inputbg);border:1px solid var(--line);border-radius:var(--r-sm)}
/* 空态：这一列一张都没有。**仍占位**（与有照片时近似同高），否则三列高度参差。 */
.ce-ph-tl0{font-size:var(--fs-micro);color:var(--t3);align-items:center;min-height:64px;
  line-height:1.5}
/* ★ 每格 **72px**、图 **72×96**（竖幅 3:4）—— 这个数不是随手取的：
   三列并排时列内容宽实测 ≈161px（抽屉 542 宽 ÷ 3 列，再减间距/内边距/边框），
   而胶片条内再减自身的 padding+border ⇒ 可用 ≈155px。
   **一屏刚好放两格** = 2×72+6 = 150 ≤ 155（余 5px 抗窗口抖动）；取 96 就只放得下 1.5 格，
   而**第 2 格被切掉一半**看起来像布局坏了（用户不会想到"其实可以横向滚"）。
   ⚠ 代价记在这里：这仍是"横向滚动"的胶片条（4 张以上要滚），只是**头两格一定看得见**。 */
.ce-ph-i{display:flex;flex-direction:column;gap:3px;flex:0 0 auto;width:72px}
.ce-ph-tw{position:relative;display:block;flex:none}
/* 缩略图外面包的是**真 `<button>`**（键盘 Tab 得到、Enter/Space 天然触发，
   不必再写一份 keydown，也就不会"鼠标能用、键盘不能用"）⇒ 清零浏览器默认样式：
   只留"可点"这一个语义，外观全由下面那条 `img` 规则说了算。
   ⚠ `line-height:0`：不然 img 是 inline 元素，行框会给底下留一道缝。 */
.ce-ph-pk{display:block;width:72px;height:96px;padding:0;margin:0;cursor:pointer;
  background:none;border:0;font:inherit;color:inherit;line-height:0}
.ce-ph-pk:focus-visible{outline:2px solid var(--focus);outline-offset:1px}
.ce-ph-th{width:72px;height:96px;object-fit:cover;display:block;
  border:1px solid var(--line2);border-radius:var(--r-xs);background:var(--e3)}
/* 每格下方那一行日期 —— **纯显示**（不是控件）：72px 放不下原生日期输入框
   （`2026/10/01` 要约 105px，硬塞会截成 `2026/1`，看起来像坏了）。
   改日期挪到大图下方那一枚（`.ce-ph-db`）。`ellipsis` 是兜底：极窄主题下不撑破。 */
.ce-ph-dl{font-size:var(--fs-micro);color:var(--t3);text-align:center;line-height:1.5;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* 大图下方那一枚**可编辑**日期（编辑的是"正在看的那一张"，全列只此一枚）。 */
.ce-ph-db{display:flex;align-items:center;gap:5px}
.ce-ph-dn{font-style:normal;flex:none;font-size:var(--fs-micro);color:var(--t3)}
/* 「正在看的那一张」= 该列大图所画的那张（`.on` 取代 2026-10-01 的 `.now` ——
   那版标的是"最新"，本版标的是"你选的"；两者不再是同一件事）。
   ★ 描边必须走**实色 `--accent`**，不能走 `--accent-line`（2026-10-02 实测纠正）：
     `--accent-line` 在**深色**主题里是「亮色 + 30% alpha」（`rgba(78,143,114,.30)` /
     `rgba(200,169,110,.30)`）—— 落在深底上很显眼，于是**深色下看着是对的**；
     但在**浅色**主题里它是固定的**淡沙色**（`#E0D2AC` / `#BFD8C8`）—— 落在白卡上
     对比度只有 **1.50 : 1**，等于"看不见"（11px 上尤其）。
     ⇒ 一对令牌在两类主题里**语义相反**，用它画选中环 = 四主题里只有两个成立。
   实算 `--accent` 对各自卡底：A **4.59:1** · B **8.19:1** · C **5.34:1** · D **6.34:1**（全 ≥ 4.5）。
   ⚠ 这与本仓既有写法一致（`shell.css` 的 `.themebar .tb.on` / `.lvbar .lv.on`、
     `chatlog.css` 的 `.cl-row.on` 都是 `border-color:var(--accent)`）。
   ⚠ 缩略图是 `<img>` ⇒ **不能用 `background:var(--accent-wash)`**（被图盖住，等于没写）：
     故洗色改挂在 `box-shadow` 环上，作**次级**提示；主提示 = 那圈实色描边。
   ⚠ 缩略图是照片、颜色千差万别 ⇒ 不能靠"和图片对比深浅"，只能靠**周边**（描边/环）。 */
.ce-ph-i.on .ce-ph-th{border-color:var(--accent);box-shadow:0 0 0 2px var(--accent-wash)}
.ce-ph-i.on .ce-ph-dl{color:var(--accent-text)}
/* 撤下：**只撤这一张**（改前是撤整列）⇒ 位置贴在那张图上，不贴列头。 */
.ce-ph-xx{position:absolute;top:-5px;right:-5px;width:16px;height:16px;padding:0;line-height:1;
  display:flex;align-items:center;justify-content:center;
  font-family:inherit;font-size:9px;cursor:pointer;
  background:var(--panel);border-radius:var(--r-full)}
.ce-ph-xx:hover{background:var(--danger-bg)}
.ce-ph-xx:focus-visible{outline:2px solid var(--focus);outline-offset:1px}
/* 日期框：它**同时**是"显示"与"编辑"（值是后端的 `YYYY-MM-DD`，改一下就发 PATCH）
   ⇒ 不需要"先点编辑再出现输入框"那一层状态，也就没有"编辑态没退出"的静默残留。
   ⚠ `width:100%` + `min-width:0` 都必须写：原生日期控件在窄容器里会**自撑**
     （`flex`/`grid` 项默认 `min-width:auto`），把整行撑破了还不报错。
   ⚠ 空值 = 「未记日期」（历史行）—— 原生控件会显示 `年/月/日` 占位，与有值一眼可分；
      **不许**回落成入库日：那是编的，用户事后分不出"当时没记"与"记错了"。 */
/* ⚠ 它现在**只**出现在 `.ce-ph-db` 里（大图下方那一枚），是 flex 项 ⇒ 必须
   `flex:1 1 auto` + `min-width:0`（flex 项默认 `min-width:auto`，原生日期控件会**自撑**、
   把那一行撑破，且不报错）。`.ce-ph-db` 宽 ≈161px ⇒ 显示 `2026/10/01` 宽裕。 */
.ce-ph-d{flex:1 1 auto;width:100%;min-width:0;font-family:inherit;font-size:var(--fs-micro);
  padding:1px 3px;background:var(--inputbg);color:var(--t1);
  border:1px solid var(--line2);border-radius:var(--r-xs)}
.ce-ph-a{display:flex;gap:5px;flex-wrap:wrap;align-items:center}
/* 「这次体态属于哪一天」（可选，留空 = 今天）—— 与那枚「选择图片 / 再传一张」同排。
   ⚠ 传成功后由 `detail.js::onPick` **清空**它：不清的话下一次传图会**静默沿用**上一次的日期。 */
.ce-ph-nd{flex:0 1 112px;min-width:0;font-family:inherit;font-size:var(--fs-micro);
  padding:2px 4px;background:var(--inputbg);color:var(--t1);
  border:1px solid var(--line2);border-radius:var(--r-xs)}
.ce-ph-b{flex:1 1 auto;font-family:inherit;font-size:var(--fs-micro);cursor:pointer;text-align:center;
  padding:3px 8px;background:none;border:1px solid var(--line2);border-radius:var(--r-sm);color:var(--t1)}
.ce-ph-b:hover{border-color:var(--line3)}
/* 撤下 = 后果不可逆的观感（其实是归档，但用户不该以为"随手点点没事"）⇒ 走危险语义色。
   ★ 2026-10-01：语义色留在这一类上，**形状**交给 `.ce-ph-xx`（角上一枚 ✕）。 */
.ce-ph-x{color:var(--danger-text);border-color:var(--danger-line)}

/* ── 「对比」开关（★ 2026-10-02 新增 · 标题栏最右）──────────────────────────────
   两态必须一眼分得开（关 = 中性底描边 / 开 = accent 实色描边 + 洗色底）。
   ⚠ 2026-10-02 实测纠正：ON 态原先写 `border-color:var(--accent-line)`，**浅色主题下两态分不开** ——
     浅色主题的 `--accent-line` 是淡沙色（`#E0D2AC`/`#BFD8C8`）、`--accent-wash` 是浅底（`#F1E4C6`/`#D0E3D8`），
     而 OFF 底是 `--chip`（themeC 实测 `rgb(232,229,222)`）⇒ 两态底**只差 1.08:1**，等于没变。
     改走**实色 `--accent`**（与本仓 `.themebar .tb.on` / `.lvbar .lv.on` 同款写法）。
     ⚠ `align-self:center`：`.ce-sh` 是 `align-items:baseline`，按钮按基线对会歪；
       它比一行小字高，基线对齐后视觉上是"挂"在半空的。 */
.ce-ph-cb{flex:none;align-self:center;font-family:inherit;font-size:var(--fs-micro);
  cursor:pointer;line-height:1.5;padding:1px 9px;border-radius:var(--r-full);
  background:var(--chip);border:1px solid var(--line2);color:var(--t2)}
.ce-ph-cb:hover{border-color:var(--line3);color:var(--t1)}
.ce-ph-cb.on{background:var(--accent-wash);border-color:var(--accent);color:var(--accent-text)}
.ce-ph-cb:focus-visible{outline:2px solid var(--focus);outline-offset:1px}

/* ── 对比态（★ 2026-10-02 新增 · **三行堆叠**）──────────────────────────────────
   一行 = 一个面（`.ce-ph-crow`），行内两张同尺寸竖幅大图并排（`.ce-ph-cpair`）。
   两侧各一枚日期下拉（`.ce-ph-cs`），默认：该列最早 ⇄ 最新。
   ⚠ 对比态是**只读视图** —— 不出 `.ce-ph-d` / `.ce-ph-x` / 上传按钮
     （"看图"与"改数据"分开，见 `detail.js` 顶部那段口径注释）。
   ⚠ 对比大图**固定同高** ⇒ "变化了多少"是**眼睛直接量**出来的，不需要任何数字。
     这是本次重设计唯一的目的。 */
.ce-ph-crow{display:flex;flex-direction:column;gap:6px;padding:8px;
  background:var(--e2);border:1px solid var(--line2);border-radius:var(--r-sm)}
.ce-ph-ct{font-size:var(--fs-micro);color:var(--t3)}
.ce-ph-ct em{font-style:normal;opacity:.8}
.ce-ph-cpair{display:flex;gap:9px;align-items:flex-start}
.ce-ph-cside{flex:1 1 0;min-width:0;display:flex;flex-direction:column;gap:4px}
.ce-ph-cs{width:100%;min-width:0;font-family:inherit;font-size:var(--fs-micro);
  padding:2px 4px;background:var(--inputbg);color:var(--t1);
  border:1px solid var(--line2);border-radius:var(--r-xs)}
/* ★ 对比图框同一条理由（每侧 ≈258 宽 ⇒ 258:320 ≈ 1:1.24 竖幅）。
   三行堆叠后整块会比较高、抽屉内要滚 —— 这是**预期**的：对比的本意就是
   "把两张放大到看得清"，为省高度把它压小，等于把本次要修的毛病（看不清）又请回来。 */
.ce-ph-cim{height:320px;display:flex;align-items:center;justify-content:center;overflow:hidden;
  background:var(--inputbg);border:1px solid var(--line);border-radius:var(--r-sm)}
.ce-ph-ci{width:100%;height:100%;object-fit:cover;display:block}
/* 这一列只有 1 张时：**不出两枚下拉** —— 两枚都只有一项，用户点开才发现"选不了"，
   而"选不了"与"我选错了"在屏上同形（本仓最忌的读数歧义）⇒ 直接说清缺什么。 */
.ce-ph-csolo{align-items:center}
.ce-ph-csolo .ce-ph-cside{width:62%;flex:0 0 auto}
.ce-ph-cd{font-size:var(--fs-micro);color:var(--t3);text-align:center}
.ce-ph-cnote{align-self:center;font-size:var(--fs-micro);color:var(--t3);line-height:1.6}
.ce-ph-cempty{font-size:var(--fs-micro);color:var(--t3)}

/* 底部常驻一行口径：说明「点一下就存」这件本块特有的代价（与标签区同规矩）。
   ⚠ 对比态下这句话**必须换**成"对比是只读" —— 不换的话用户会以为"对比时改日期没生效"
     （而实际是"根本没给可改的入口"，两件事在屏上同形）。 */
.ce-ph-ft{font-size:var(--fs-micro);color:var(--t3);line-height:1.5;padding:2px 0 0}
.ce-ph-nb{display:flex;align-items:center;gap:5px;font-size:var(--fs-micro);color:var(--t3)}
.ce-ph-sp{width:6px;height:6px;border-radius:var(--r-full);background:var(--t3);
  animation:dsrcPulse 1s ease-in-out infinite}
.ce-ph-e{font-size:var(--fs-micro);color:var(--danger-text);line-height:1.5}
/* 视觉隐藏但**仍可聚焦**（`display:none` / `visibility:hidden` 会把键盘路径一起砍掉）。
   只挂在文件输入框上；不要跟 `.statusbar .sr`（那是另一回事，名字相近但无关）。 */
.ce-sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}

/* ── 列设置面板（2026-09-23 · D 线）────────────────────────────────────────────────
   位置：**`.pagehd` 的内部子元素**（`.sp` 之后、`</div>` 之前）+ **绝对定位**。
   两条约束同时成立才这么放，缺一条都会被既有判据打红：
     ① **DOM 顺序不能动** —— `crmai.mjs` 有一条紧邻断言
        `kids.indexOf(#aipoolBand) === kids.indexOf(.pagehd) + 1`（`kids` = `.scroll` 的子元素）。
        在 `.pagehd` 与研判带**之间**插任何兄弟元素都会打红它（实测 251 PASS → 250 PASS/1 FAIL）。
        放进 `.pagehd` **内部** ⇒ `.pagehd` 仍是那一个子元素、研判带仍是它的下一个 ⇒ 成立。
     ② **不能占流内空间** —— `crmai.mjs` 另有一条量 `.pagehd` 高度的断言。
        ⚠ 这里**故意不写那个高度值**：本段初稿曾把"顶栏三段设计口径 40+28+52 = 120"当成
          `.pagehd` 的高度，实测是 85；`crmai.mjs` 为同一个数字也踩过一次（写过 `phH <= 52`）。
          要数字请现取（`crmai.mjs` ⑦ 段收集的 `phH`）。
        绝对定位不参与排版 ⇒ 高度一个像素都不动。
   ⚠ 也不能放进 `.sp`：`.pagehd .sp > .chipbtn:not([data-pool])` 的 **first-match** 是
     crmai 的描边基准，多一枚 `.chipbtn` 就把基准换掉（误判 8 项）。
   ⚠ 与 `.fbar` 那套弹层同一个理由：**弹层必须绝对定位**，否则会参与 flex 排版、
     把 `crmai.mjs` 逐元素量的 `.fbar` 溢出判据撑破（那条注释在 `customers.css` 上文）。
   ⚠ 一律走令牌：四主题（明度 × 色温 2×2）都要跟着换，写死色值必在其中一档下失真。
   ⚠ 类名全部写成 `.crm .ddcolset …` **后代选择器**：`.hd` / `.gr` / `.ft` 这类短名在全库里
     太容易撞（`R58`：新增类名须与全库单类选择器求交集 ⇒ 能不加就不加，加了就**限定作用域**）。 */
.crm .ddcolset{display:none;position:absolute;top:100%;left:18px;right:18px;z-index:30;
  padding:10px 12px;background:var(--e2);border:1px solid var(--line);border-radius:var(--r-sm)}
.crm .ddcolset.open{display:block}
.crm .ddcolset .hd{display:block;font-size:var(--fs-caption);color:var(--t2);margin-bottom:8px}
.crm .ddcolset .hd i{font-style:normal;color:var(--t3);font-size:var(--fs-micro);margin-left:6px}
.crm .ddcolset .gr{display:flex;flex-wrap:wrap;gap:8px}
/* 逐列勾选：`on` = **这一列正在显示**。
   ⚠ 顺序有讲究：`:hover` 写在 `.on` **之前** —— 两者特异性相同（都是 4 个类/伪类），
     后写的胜。反过来的话，悬停一枚"显示中"的列会把它 hover 成灰底，
     看上去像"点了要关掉它"（状态语言自相矛盾）。 */
.crm .ddcolset .ccol{padding:4px 10px;border:1px solid var(--line);border-radius:var(--r-full);
  font-size:var(--fs-small);color:var(--t2);background:var(--e2);cursor:pointer}
.crm .ddcolset .ccol:hover{background:var(--face-hover)}
.crm .ddcolset .ccol.on{background:var(--accent-wash);color:var(--accent-text);border-color:var(--accent-line)}
.crm .ddcolset .ccol:focus-visible{outline:2px solid var(--focus);outline-offset:1px}
.crm .ddcolset .ft{display:block;margin-top:9px;font-size:var(--fs-micro);color:var(--t3)}

/* ══════════════════════════════════════════════════════════════════════════════
   ★★ 详情抽屉「字段设置」面板（2026-10-14 · 用户令「详情里的字段也能自己设置显隐」）。
   锚点 = `.dtl-hd`（`position:relative`，见下第一条），面板 `top:100%` 落在头部底边
   之下、盖到内容区顶部 —— 与列表「列设置」同款浮层，不占流内空间。
   ⚠ 用 `.dtl` 前缀（**不带** `.crmmode`）：抽屉是跨站覆盖层，对话站打开时没有
     `.crmmode`（同 crm-tlbd-css-fix 口径），用 `.dtl` 两站都生效。
   ⚠ 类名全部 `.dtl .dtl-fldpanel …` 后代选择器：`.hd`/`.gr`/`.ft`/`.ccol` 短名
     全库易撞（R58），必须限定作用域。 */
.dtl .dtl-hd{position:relative}
.dtl .dtl-fldpanel{display:none;position:absolute;top:100%;left:0;right:0;z-index:30;
  padding:12px 14px;background:var(--e2);border:1px solid var(--line);border-radius:var(--r-sm);
  box-shadow:0 12px 30px -16px var(--sh-2)}
.dtl .dtl-fldpanel.open{display:block}
.dtl .dtl-fldpanel .hd{display:block;font-size:var(--fs-caption);color:var(--t2);margin-bottom:8px}
.dtl .dtl-fldpanel .hd i{font-style:normal;color:var(--t3);font-size:var(--fs-micro);margin-left:6px}
.dtl .dtl-fldpanel .gr{display:flex;flex-wrap:wrap;gap:7px}
.dtl .dtl-fldpanel .gr.blk{margin-top:9px;padding-top:9px;border-top:1px dashed var(--line)}
/* 逐字段勾选：`on` = 这一字段正在显示。`:hover` 写在 `.on` 之前（同 ddcolset 纪律）。
   `.lock`（锁定核心字段）置灰 + 禁手型 + hover 不变色 —— 一眼看出不可点。 */
.dtl .dtl-fldpanel .ccol{padding:4px 10px;border:1px solid var(--line);border-radius:var(--r-full);
  font-size:var(--fs-small);color:var(--t2);background:var(--e2);cursor:pointer;font-style:normal;
  user-select:none}
.dtl .dtl-fldpanel .ccol:hover{background:var(--face-hover)}
.dtl .dtl-fldpanel .ccol.on{background:var(--accent-wash);color:var(--accent-text);border-color:var(--accent-line)}
.dtl .dtl-fldpanel .ccol.lock{opacity:.5;cursor:not-allowed}
.dtl .dtl-fldpanel .ccol.lock:hover{background:var(--e2)}
.dtl .dtl-fldpanel .ccol:focus-visible{outline:2px solid var(--focus);outline-offset:1px}
.dtl .dtl-fldpanel .ft{display:block;margin-top:10px;font-size:var(--fs-micro);color:var(--t3)}

/* ══════════════════════════════════════════════════════════════════════════════
   ★★ 账号与教练面板（`2026-09-24` · 用户令逐字「教练配置，采集微信号。配置。还有采集
   手机绑定，这些配置做一下，看放在哪里合适」）—— 三块：教练名单 / 微信号 / 采集设备。

   位置与 `.ddcolset` **同款**（`position:absolute; top:100%; left:18px; right:18px`）：
   它是 `.pagehd` 的**绝对定位子元素** ⇒ 不参与排版、不动 `.pagehd` 高度
   （`crmai.mjs` 有一条量页头高度的断言，绝对定位是它不被打红的前提）。

   ⚠⚠ **本面板是全仓第一个自带内层滚动容器的下拉**（`max-height` + `overflow:auto`）。
     为什么必须有：三栏内容加起来会超过一屏（设备台账 + 未登记机器可以很长），
     不设上限就会把下面的筛选行与表格整个推走 / 溢出视口。
     ⇒ 审计时**必须逐个查内层滚动容器**（本仓已有这条口径）：`max-height:64vh` 是
       "视口的一大部分但不全占"，滚动条只在内容确实超长时出现。
   ⚠ 类名一律 `ac-` 前缀 + `.crm .ddacct …` 后代选择器（`R58`：新增类名须与全库
     单类选择器求交集 ⇒ 能不加就不加，加了就限定作用域）。`.ac-*` 全库现取 = 0 命中。

   ⚠ 四主题安全：**一个硬编码色值都没有**，全部走 `tokens.css` 的变量
     （`--e2` / `--line` / `--t1..t3` / `--accent-*` / `--amber*` / `--stop*` / `--focus`）。
   ══════════════════════════════════════════════════════════════════════════════ */
.crm .ddacct{display:none;position:absolute;top:100%;left:18px;right:18px;z-index:30;
  padding:12px 14px;background:var(--e2);border:1px solid var(--line);border-radius:var(--r-sm);
  max-height:64vh;overflow:auto}
.crm .ddacct.open{display:block}
.crm .ddacct i{font-style:normal}
/* ★ 2026-09-26 重设计（用户令：「账号与教练，重新设计一下，不好看，不好用」）─────────────
   改前**探针实测**（`_probe_acct.mjs` 改前读数落 `/tmp/acct/before.txt`）：
     · 每行被排成 **2~4 行**，行高 **51 / 61 / 77px 三种**（同栏内也不等）
     · 面板内容高 585 > 可视 574 ⇒ 已经要滚；窄窗 900 时内容 1109（1.93×）
     · 操作项高仅 **20px**，最窄的「改」= **25×20**
   三条真因（都在下面逐条修掉，都**不报错**）：
     ① `.ac-ct` 是 `flex:1 1 100%` ⇒ **每行强制换行**：名字一行、副信息一行、操作又一行
        ⇒ 行高参差 + 三行之间大片空白（行高分布 `{2行:3, 3行:4, 4行:2}`）
     ② 三栏只有 12px `gap`、**没有任何边界** ⇒ 视觉上是"三段独立的碎行"而非"三块内容"
     ③ 设备表单 4 个输入框竖排各占一整行（`.ac-add4 .ac-in{flex:1 1 100%}`）⇒ 一串香肠
   布局改动（**只动本面板**，与表格 13 列无涉 ⇒ `crmcols` 那条"操作列余量 2px"不受影响）：
     · 行内**单线**：名字 + 副信息 + 操作排成一条线（副信息吃剩余空间 ⇒ 操作自然靠右）
     · 三栏 → **两栏并排 + 第三栏（采集设备）通栏**
       （设备栏内容最多：台账 + 表单 + 未登记 ⇒ 并排会被挤成极窄的一条）
     · 每栏加**卡片边界**（底 + 边框 + 圆角 + 内边距）⇒ "这是三块"一眼可见
     · 设备表单改**两列**
   ⚠ 输入框底从 `--e1` 改 `--e0`：卡片底现在是 `--e1` ⇒ 沿用 `--e1` 就是**假填充**
     （本仓 §5.2 那条：改 background 必须量 Δ，否则"看着像做了决定、其实什么都没做"）。
     改后四主题方向一致（都往"凹槽"走）：深色 A `#0A0C0E` vs 卡片 `#0F1215`；
     亮色 C `#ECEAE4` vs 卡片 `#F6F5F1`。 */
.crm .ddacct .ac-hd{display:block;font-size:var(--fs-caption);color:var(--t2);
  font-weight:600;margin-bottom:6px}
.crm .ddacct .ac-hd i{color:var(--t3);font-size:var(--fs-micro);font-weight:400;margin-left:8px}
/* ★ 「手机号填的是采集机那张卡，不是客户的」—— 这句**必须在头部常驻位**（实测面板内容可达
   5043px、可视仅 576px ⇒ 塞到底部脚注等于没写）。用 info 色而非警示色：它不是错误提示，
   是**语义澄清**（用户拍板的那条口径）。 */
.crm .ddacct .ac-tip{display:block;margin-bottom:10px;font-size:var(--fs-micro);
  color:var(--info);line-height:1.5}
.crm .ddacct .ac-tip strong{color:var(--t1);font-weight:600}
/* 回话区：**常驻空位**（`display:none` 只在没话说时生效 —— 有话说时它出现在标题下方，
   位置固定，不会因为"有没有回话"而让下面三栏上下跳）。 */
.crm .ddacct .ac-why{display:none}
.crm .ddacct .ac-why.on{display:block;margin-bottom:8px;padding:6px 9px;border-radius:var(--r-xs);
  font-size:var(--fs-micro);color:var(--t2);background:var(--e3);border-left:2px solid var(--accent-line)}
/* ★★ 三栏并排（**这一条是读数逼出来的，不是设计偏好**）──────────────
   中途做过一版「两栏 + 第三栏（采集设备）通栏」，理由是"设备栏内容多、并排会被挤窄"。
   **实测证伪**（`_probe_acct.mjs`）：面板内容高 **715**（比改前的 585 还高 130），
   因为三栏并排时总高 = **三栏的最大值**（479），而拆成"两栏 + 通栏"就变成 **两行高度相加**
   （201 + 12 + 389）。⇒ 每行确实矮了（77→38），但**布局行数 +1 把收益全吃掉还倒亏**。
   ⇒ 回三栏；"设备栏被挤窄"改用**表单两列**（见下面 `.ac-add4`）解决，不动栏数。
   ⚠ 这条是本批"假设被读数推翻"的实证：**"看起来更合理的布局"必须量了才算**。 */
.crm .ddacct .ac-cols{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px}
.crm .ddacct .ac-col{min-width:0;background:var(--e1);border:1px solid var(--line);
  border-radius:var(--r-sm);padding:10px 12px}
/* ★ 2026-09-26：加 `flex-wrap` —— 栏头从「栏名 + 一个计数」变成**三段**
   （微信号栏 = 栏名 + 计数 + 「从采集机收号」）。窄窗下三段挤不下时会**溢出卡片**
   （`.ac-col` 是 `min-width:0` 的 grid 项，子元素不 wrap 就等于把内容顶出去、不报错）。
   换行是安全降级：第二行只有那枚按钮，`.ac-hdop` 的 `margin-left:auto` 让它仍靠右。 */
.crm .ddacct .ac-sec{display:flex;flex-wrap:wrap;align-items:center;gap:8px;
  font-size:var(--fs-caption);color:var(--t2);font-weight:600;
  padding-bottom:6px;border-bottom:1px solid var(--line);margin-bottom:2px}
/* 计数做成胶囊：原来它是紧跟标题的一串同色小字（「教练名单3 位在用」连成一个词），
   数字与标题**分不开**。胶囊把"这是计数"与"这是栏名"分开，且四主题都有底。 */
.crm .ddacct .ac-sec i{color:var(--t3);font-size:var(--fs-micro);font-weight:400;
  padding:1px 8px;border-radius:var(--r-full);background:var(--e3)}
/* ★ 栏头右侧的**动作**（现只有微信号栏的「从采集机收号」）──────────────
   ⚠ 它也是 `<i>` ⇒ 已被上面那条 `.ac-sec i` 命中（拿到胶囊底与字号），本规则**只补**
     四样它没给的：贴右 / 指针 / **边界** / **内边距**。
   ⚠⚠ 「边界」这一样**不能省**：`.ac-sec i` 的胶囊是**计数**的外观，而这一枚是**可点的
     动作**。两者同形 ⇒ 用户看不出哪个能按 —— 正是复杂度红线④「不加 hover 才知道能点的」。
     所以这里给边框 + 一级文字色，让它与旁边那枚灰底计数**不用 hover 就能分开**。
   ⚠⚠★ 「内边距」这一样**同样不能省，而且是被判据连抓两次抓回来的**（2026-09-26）：
     首版只加了 border，实测该按钮 **84×19** —— 而**同一个面板**里 `.ac-op`
     （改 / 停用 / 登记 …）是 **25px 高**。⇒ 新按钮比旧按钮**更难按**，把 A5 那条
     「命中面积从 20px 提到 ≈25px，这是"好不好点"的**量化**问题」的既定纪律
     从新加的东西上绕过去了。判据 `acctpanel.mjs` 的 B5a 当场红、逐字报出 19px。
     ⇒ 内边距取 **与 `.ac-op` 逐字同款**（`4px 9px` + `line-height:1.4`）：
       不是"看起来差不多"，而是**同一个面板里的两个按钮必须同高** —— 这样任何一条
       按钮尺寸的改动都只有一处（`.ac-op`），不会养出第二个按钮规格。
   ⚠⚠★★ **选择器为什么必须写到 `.ac-sec .ac-hdop` 四个 class**（这一条是血例）：
     补内边距后**再跑一次，B5a 仍然报 19px** —— 因为**特异性算错了**。
     · 我以为竞争的是 `.ac-sec i`（数成 2 个 class）；
     · 实际的完整选择器是 **`.crm .ddacct .ac-sec i`** = **3 class + 1 type = (0,3,1)**；
     · 而 `.crm .ddacct .ac-hdop` = **(0,3,0)** ⇒ **输**。
     ⇒ 后果很隐蔽：`.ac-sec i` **声明过的**那几个（`padding` / `color` / `background`）
       全部把本规则吃掉，只有它**没声明过的**（`border` / `margin-left` / `cursor`）生效
       ⇒ 于是 B5b（只判 `borderStyle`/`cursor`）**照样绿**，看着像"改好了"。
     ⇒ 教训两句：① **算特异性要写全整条链**，"我数过了"不等于数对（这里漏数了一个 class）；
       ② **一条断言只覆盖一个属性**时会漏 —— B5a（尺寸）替 B5b（边框）报了警。
     ⇒ 故本规则写成 **四个 class**：`.crm .ddacct .ac-sec .ac-hdop` = (0,4,0) > (0,3,1) ✓
       （刻意用"加一层祖先"而不是 `!important` —— 本仓不引 `!important`，
        加了它会把这条的优先级抬到无法被后续正常规则覆盖）。 */
.crm .ddacct .ac-sec .ac-hdop{margin-left:auto;flex:none;cursor:pointer;
  padding:4px 9px;line-height:1.4;
  color:var(--t2);border:1px solid var(--line);background:transparent}
.crm .ddacct .ac-sec .ac-hdop:hover{background:var(--face-hover);color:var(--t1)}
.crm .ddacct .ac-sec .ac-hdop:focus-visible{outline:2px solid var(--focus);outline-offset:1px}
/* 第二级小标题（同一栏内再分块：设备栏的「登记新设备」与「有上报没登记」） */
.crm .ddacct .ac-sec2{margin-top:12px}
.crm .ddacct .ac-list{display:block}
.crm .ddacct .ac-row{display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 8px;
  padding:6px 0;border-bottom:1px solid var(--line)}
/* 末行去线：否则它与卡片内边距叠出一条"双线"，看着像多出一行 */
.crm .ddacct .ac-list > .ac-row:last-child{border-bottom:0}
.crm .ddacct .ac-row.off{opacity:.55}
.crm .ddacct .ac-row.ed{background:var(--e3);border-radius:var(--r-xs);padding:8px 9px;gap:6px;
  border-bottom:0}
.crm .ddacct .ac-nm{order:1;color:var(--t1);font-size:var(--fs-small);font-weight:600;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%}
/* ★★ 副信息**不再独占一行**（改前 `flex:1 1 100%` ⇒ 每行被排成 2~4 行）。
   现在它吃剩余空间 ⇒ 一行排完，操作被顶到右端。 */
.crm .ddacct .ac-ct{order:2;flex:1 1 auto;color:var(--t3);font-size:var(--fs-micro);min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* `.ro` 行的**名字**不上强调色（压到 400 + `--t2`），让它弱于教练名单里的名字。
   ⚠⚠ 这不是"整行不可写"的意思 —— **本注释 2026-09-26 改写过**：改前它写着
   「微信号那栏不能让人以为能点（它是身份域的行，本域不在那里写）」，而本批恰恰
   在那栏**加了写口**（「改名」→ `PATCH /api/v1/crm/accounts/<pk>`，只改 `display_name`；
   见 `acctWxCol()` 上方注释里那三条边界）。留着旧说法就是一条**与行为矛盾**的注释，
   下一个人会照着它把写入口删掉（`R37`/`R53` 同族）。
   ⇒ 现在的准确口径：**名字的灰 ≠ 能不能点**；可写的唯一入口一律是 `.ac-op`
     （胶囊 + 边框，不用 hover 就能看出能按）。 */
.crm .ddacct .ac-row.ro .ac-nm{font-weight:400;color:var(--t2)}
/* 可点项：命中面积从 **20px 高**提到 ≈25px（`.ac-op` 是「改名 / 停用 / 登记 …」唯一入口；
   实测最窄的「改」原来只有 25×20 —— 这是"好不好点"的**量化**问题，不是审美）。 */
.crm .ddacct .ac-op{order:3;color:var(--t3);font-size:var(--fs-micro);cursor:pointer;
  padding:4px 9px;border:1px solid var(--line);border-radius:var(--r-full);flex:none;line-height:1.4}
.crm .ddacct .ac-op:hover{background:var(--face-hover);color:var(--t1)}
.crm .ddacct .ac-op:focus-visible{outline:2px solid var(--focus);outline-offset:1px}
.crm .ddacct .ac-op.pri{color:var(--accent-text);border-color:var(--accent-line);background:var(--accent-wash)}
.crm .ddacct .ac-tag{order:2;flex:none;font-size:var(--fs-micro);color:var(--t3);
  padding:2px 8px;border-radius:var(--r-full);background:var(--e3);line-height:1.4}
/* 「机器未上报过」用 amber 而不是 red：它不是故障（机器还没上线是**正常顺序**，
   先配好等机器上来）⇒ 用"提醒"色，不用"错误"色。后端 `machine_seen=false` 的语义同此。 */
.crm .ddacct .ac-tag.warn{color:var(--amber);background:var(--amber-bg)}
/* ★ 设备行（`.roww`）**保持两行**：它有 5 段信息（别名 / 机器号 / 手机号 / 绑号 / 上报态），
   单行在窄窗下装不下。排法 = 第 1 行「别名 …… 标签 操作」，第 2 行「机器号 · 手机号 · 绑号」。
   ⚠ 用 `order` 而不是改 DOM：DOM 顺序是**屏读顺序**，动了会连带影响 Tab 序与朗读序。 */
.crm .ddacct .ac-row.roww .ac-tag{order:2;margin-left:auto}
/* ⚠ 设备行第二行**不截断**（`white-space:normal` + `overflow-wrap:anywhere`）：
   机器号是**长标识符**（实测 `mch_dbbridge_01M393MV93B5S000D06E0F45I3N3` 30 字符），
   在三栏并排的 425px 栏里放不下 ⇒ 用省略号截断后就**认不出是哪台机**了
   （正常行的 `.ac-ct` 是「名下 9 人」这类短文本，截断无所谓；长标识符不能截）。
   代价：设备行从 2 行变 3 行（面板 +36px）—— 用 36px 换"机器号看得全"。 */
.crm .ddacct .ac-row.roww .ac-ct{order:9;flex:1 1 100%;white-space:normal;overflow-wrap:anywhere}
.crm .ddacct .ac-in{flex:1 1 100%;min-width:0;box-sizing:border-box;
  padding:5px 9px;border:1px solid var(--line);border-radius:var(--r-xs);
  background:var(--e0);color:var(--t1);font-size:var(--fs-small);font-family:inherit}
.crm .ddacct .ac-in:focus{outline:none;border-color:var(--accent-line)}
.crm .ddacct .ac-in::placeholder{color:var(--t3)}
.crm .ddacct .ac-in[readonly]{color:var(--t3);background:var(--e1)}
.crm .ddacct .ac-empty{display:block;padding:6px 0;font-size:var(--fs-micro);color:var(--t3)}
/* 「没读到」必须与「确实没有」**视觉可分**：前者用 clay 色 + 不写"（）"那种"空态括号"。 */
.crm .ddacct .ac-empty.bad{color:var(--clay)}
/* ⚠ `acctPersonaSelect()` 在身份清单**没读到时**回的是
   `<i class="ac-in ac-empty">正在读取出战身份…</i>` —— 两个类都是 **0,2,0** 特异性，
   且 `.ac-empty` 源序在后 ⇒ 它会把 `.ac-in` 的 `padding:5px 9px` 吃掉、变成 `6px 0`
   ⇒ **文字贴住边框**（看着像个做了一半的框，而不是一句提示）。
   本规则把内边距收回 `.ac-in` 口径、字色压到三级、并给 `cursor:default`：
   它是**不可提交**的占位块 —— 外观像"框"（不能让"还没读到"与"选项就是『不配号』"同形），
   但不能像"可以打字"（它根本不是 `input`/`select`，点它不会发生任何事）。 */
.crm .ddacct .ac-in.ac-empty{padding:5px 9px;color:var(--t3);cursor:default}
/* ★ 2026-10-13：教练名下多个微信号的勾选编辑器（`coachAccountsEditor`）。
   `.ac-multi` 让整行竖排（名字 / 勾选组 / 操作 三段），勾选组可能多行。
   `.ac-chk` 命中区要够大：与 `.ac-op` 同一条「好不好点不能随手」的血例。 */
.crm .ddacct .ac-row.ac-multi{flex-direction:column;align-items:stretch;gap:6px}
.crm .ddacct .ac-chks{display:flex;flex-wrap:wrap;gap:4px 10px}
.crm .ddacct .ac-chk{display:inline-flex;align-items:center;gap:5px;cursor:pointer;
  padding:3px 8px;border:1px solid var(--line);border-radius:var(--r-xs);
  background:var(--e0);color:var(--t1);font-size:var(--fs-micro)}
.crm .ddacct .ac-chk:hover{background:var(--face-hover)}
.crm .ddacct .ac-chk input[type="checkbox"]{margin:0;cursor:pointer;accent-color:var(--accent)}
.crm .ddacct .ac-multi .ac-op{align-self:flex-start;flex:none}
.crm .ddacct .ac-add{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-top:8px}
.crm .ddacct .ac-add .ac-in{flex:1 1 120px}
/* ★ 设备表单**两列**（改前 4 个输入框竖排各占整行 ⇒ 表单高 ~136px）。
   `calc(50% - 4px)` + `gap:8px` = 恰好两列；操作项 `margin-left:auto` 落到末行右端。 */
.crm .ddacct .ac-add4 .ac-in{flex:1 1 calc(50% - 4px)}
.crm .ddacct .ac-add4 .ac-op{margin-left:auto}
.crm .ddacct .ac-note{display:block;margin-top:7px;font-size:var(--fs-micro);color:var(--t3);line-height:1.5}
.crm .ddacct .ac-ft{display:block;margin-top:12px;padding-top:9px;border-top:1px solid var(--line);
  font-size:var(--fs-micro);color:var(--t3);line-height:1.6}
.crm .ddacct .ac-ft strong{color:var(--t2);font-weight:600}
/* ★★ 订单分配策略段（`2026-10-13`）：全宽卡片，与上面三栏同底同边框。
   放三栏 grid **之后**（通栏），语义 = "本号下全局**一个**开关"（不是每栏一套）。
   ⚠ 类名 `ac-asg` / `ac-m` / `ac-mrow` 现取全库唯一命中 0（`R58`：新类名须先证未占用）。 */
.crm .ddacct .ac-asg{margin-top:12px;background:var(--e1);border:1px solid var(--line);
  border-radius:var(--r-sm);padding:10px 12px}
/* 模式三键一行排开；`.ac-op` 已给底/边/指针，这里只补"横向一组"与"选中态"。 */
.crm .ddacct .ac-mrow{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-top:6px}
/* 选中态 = 一级文字色 + 强调边框/底（同 `.ac-op.pri` 的四主题口径），
   让"当前是哪种"不靠 hover 就能看出（复杂度红线④）。 */
.crm .ddacct .ac-m.on{color:var(--accent-text);border-color:var(--accent-line);background:var(--accent-wash)}
.crm .ddacct .ac-note strong{color:var(--t1);font-weight:600}
/* 窄窗：三栏 → 两栏 → 一栏（沿用本仓既有断点 1279 / 949，不新造一套）。
   ⚠ 两栏档才需要"设备栏通栏"：那时三栏里只剩它一个落到第二行，不让它通栏右边就空一格。 */
@media (max-width:1279px){ .crm .ddacct .ac-cols{grid-template-columns:repeat(2,minmax(0,1fr))}
  .crm .ddacct .ac-col:last-child{grid-column:1/-1} }
@media (max-width:949px){ .crm .ddacct .ac-cols{grid-template-columns:minmax(0,1fr)} }
/* 矮窗：面板最多占视口一半，给下面的表格留出可见区（同 `.overlay` 那族矮窗口径）。 */
@media (max-height:820px){ .crm .ddacct{max-height:52vh} }
@media (max-height:700px){ .crm .ddacct{max-height:46vh} }

/* ══════════════════════════════════════════════════════════════════════════════
   ★★ 自动化设置面板（`2026-10-02` · 用户令第 ⑤ 问：「增加一个功能，叫自动化设置 /
   可以自己添加规则 / a 新加微信的客户发送对应的消息，可多条，设置 /
   c，下次预约联系时间 / d 规划一下其他，需要自动化的设置」）

   位置与 `.ddcolset` / `.ddacct` **逐字同款**（`position:absolute; top:100%;
   left:18px; right:18px`）⇒ 它是 `.pagehd` 的绝对定位子元素 ⇒ **不参与排版、
   不动 `.pagehd` 高度**（`crmai.mjs` 有一条量页头高度的断言，绝对定位是前提）。

   ⚠ 本面板**同样自带内层滚动容器**（`max-height` + `overflow:auto`）：
     规则卡片 + 编辑表单 + 预览结果三段加起来会超过一屏 ⇒ 不设上限会把下面的筛选行与
     表格整个推走。⇒ 审计时**必须逐个查内层滚动容器**（本仓既有口径），
     `max-height:64vh` = "视口的一大部分但不全占"。

   ⚠ 类名一律 `aut-` 前缀 + `.crm .ddauto …` 后代选择器。
     ⚠⚠ **不能用 `au-` 前缀** —— 现取全库它已被 `app/css/auth.css`（90 命中）与
       `app/js/auth.js`（66 命中）占用；撞名会让登录页与本站互相污染，**且不报错**。
       `aut-` / `ddauto` / `data-autom` / `data-automin` 现取全库**唯一命中 0**（已机械核过）。

   ⚠ 四主题安全：**一个硬编码色值都没有**，全部走 `tokens.css` 的变量
     （`--e0..--e3` / `--line` / `--t1..t3` / `--accent-*` / `--clay` / `--info` / `--focus`）。

   ⚠★ 「关着」的卡片用 `opacity` 而不是把它变灰字：**同一张卡片里的开关仍要可读可点**
     （用户下一件事就是点它打开）。把整卡调成低对比灰，会让"这行能点"这件事消失 ——
     正是复杂度红线④「不加 hover 才知道能点的」。
   ══════════════════════════════════════════════════════════════════════════════ */
.crm .ddauto{display:none;position:absolute;top:100%;left:18px;right:18px;z-index:30;
  padding:12px 14px;background:var(--e2);border:1px solid var(--line);border-radius:var(--r-sm);
  max-height:64vh;overflow:auto}
.crm .ddauto.open{display:block}
.crm .ddauto i{font-style:normal}
.crm .ddauto .aut-hd{display:block;font-size:var(--fs-caption);color:var(--t2);
  font-weight:600;margin-bottom:6px}
.crm .ddauto .aut-hd i{color:var(--t3);font-size:var(--fs-micro);font-weight:400;margin-left:8px}
/* ★ 「本波只生成待发、不会真的发出去」是**本功能最要紧的一句话**（对外动作的边界），
   放在头部常驻位 —— 与 `.ac-tip` 同一条理由（面板内容可滚动，塞到底部等于没写）。
   用 info 色而非警示色：它不是错误提示，是**口径声明**（用户拍板的那条）。 */
.crm .ddauto .aut-tip{display:block;margin-bottom:10px;font-size:var(--fs-micro);
  color:var(--info);line-height:1.5}
.crm .ddauto .aut-tip strong{color:var(--t1);font-weight:600}
/* 回话区：**常驻空位**（`display:none` 只在没话说时生效）—— 与 `.ac-why` 同款。
   有话说时它出现在标题下方固定位置，不会因为"有没有回话"让下面整块上下跳。 */
.crm .ddauto .aut-why{display:none}
.crm .ddauto .aut-why.on{display:block;margin-bottom:8px;padding:6px 9px;border-radius:var(--r-xs);
  font-size:var(--fs-micro);color:var(--t2);background:var(--e3);border-left:2px solid var(--accent-line)}
.crm .ddauto .aut-empty{display:block;padding:6px 0;font-size:var(--fs-micro);color:var(--t3)}
.crm .ddauto .aut-empty.bad{color:var(--clay)}
.crm .ddauto .aut-list{display:block}
/* 卡片：底 `--e1`（面板是 `--e2`）⇒ 卡片从面板里"浮"出来一档，一眼看出"这是一条规则"。 */
.crm .ddauto .aut-card{background:var(--e1);border:1px solid var(--line);border-radius:var(--r-sm);
  padding:9px 11px;margin-bottom:8px}
.crm .ddauto .aut-card.off{opacity:.72}
.crm .ddauto .aut-c-hd{display:flex;flex-wrap:wrap;align-items:center;gap:8px}
.crm .ddauto .aut-c-hd b{font-size:var(--fs-small);color:var(--t1);font-weight:600}
.crm .ddauto .aut-code{font-family:var(--font-num);font-size:var(--fs-micro);color:var(--t3);
  padding:1px 7px;border-radius:var(--r-full);background:var(--e3);line-height:1.5}
/* 开关：**可点** ⇒ 必须有边框 + 内边距（复杂度红线④：不许"要 hover 才知道能点"）。
   ⚠ 尺寸与 `.aut-op` 取同一组值（`padding:4px 9px` + `line-height:1.4`）——
     同一个面板里的按钮必须同高，否则"好不好点"就成了随手的（`.ac-op` 那条血例）。 */
.crm .ddauto .aut-sw{margin-left:auto;flex:none;cursor:pointer;font-size:var(--fs-micro);
  padding:4px 9px;line-height:1.4;border:1px solid var(--line);border-radius:var(--r-full);
  color:var(--t3);background:transparent}
.crm .ddauto .aut-sw:hover{background:var(--face-hover);color:var(--t1)}
.crm .ddauto .aut-sw:focus-visible{outline:2px solid var(--focus);outline-offset:1px}
.crm .ddauto .aut-sw.on{color:var(--accent-text);border-color:var(--accent-line);
  background:var(--accent-wash)}
.crm .ddauto .aut-c-meta{display:block;font-size:var(--fs-micro);color:var(--t2);margin-top:5px}
.crm .ddauto .aut-c-cfg{display:block;font-size:var(--fs-micro);color:var(--t3);margin-top:3px}
.crm .ddauto .aut-c-st{display:block;font-size:var(--fs-micro);color:var(--t3);margin-top:3px}
.crm .ddauto .aut-c-ops{display:flex;flex-wrap:wrap;gap:8px;margin-top:8px}
/* ⚠ `.aut-op` 与 `.ac-op` **逐字同规格**（见 `.ac-*` 那条血例）：同页两个面板里的按钮
   尺寸一样 ⇒ 任何一次"按钮好不好点"的调整都只有一处可改，不会养出第二套按钮规格。 */
.crm .ddauto .aut-op{flex:none;cursor:pointer;font-size:var(--fs-micro);color:var(--t3);
  padding:4px 9px;line-height:1.4;border:1px solid var(--line);border-radius:var(--r-full)}
.crm .ddauto .aut-op:hover{background:var(--face-hover);color:var(--t1)}
.crm .ddauto .aut-op:focus-visible{outline:2px solid var(--focus);outline-offset:1px}
.crm .ddauto .aut-op.pri{color:var(--accent-text);border-color:var(--accent-line);
  background:var(--accent-wash)}
/* 「删」用 clay（警示色）而不是 accent：它与旁边三枚**动作方向相反**（不可撤销），
   同色会让"顺手点一下"的代价一样低。 */
.crm .ddauto .aut-op.dgr{color:var(--clay);border-color:var(--clay)}
.crm .ddauto .aut-new{display:flex;flex-wrap:wrap;gap:8px;margin-top:4px}
.crm .ddauto .aut-form{display:block;margin-top:12px;padding:10px 12px;background:var(--e1);
  border:1px solid var(--line);border-radius:var(--r-sm)}
.crm .ddauto .aut-f-hd{display:block;font-size:var(--fs-caption);color:var(--t2);
  font-weight:600;margin-bottom:9px}
.crm .ddauto .aut-lb{display:flex;flex-wrap:wrap;align-items:center;gap:6px;
  font-size:var(--fs-micro);color:var(--t2);margin-bottom:7px}
.crm .ddauto .aut-lb.w{align-items:flex-start}
/* 输入框底用 `--e0`（卡片是 `--e1`）—— 本仓 §5.2：改 `background` 必须与所在面**不同档**，
   沿用同档 = 假填充（"看着像做了决定、其实什么都没做"）。 */
.crm .ddauto .aut-in{flex:1 1 220px;min-width:0;box-sizing:border-box;font-family:var(--font-ui);
  padding:5px 9px;font-size:var(--fs-micro);color:var(--t1);background:var(--e0);
  border:1px solid var(--line);border-radius:var(--r-xs)}
.crm .ddauto .aut-in:focus{outline:none;border-color:var(--accent-line)}
.crm .ddauto .aut-in[readonly]{color:var(--t3);background:var(--e1)}
.crm .ddauto .aut-ta{flex:1 1 100%;resize:vertical;min-height:64px;line-height:1.6}
.crm .ddauto .aut-hint{flex:1 1 100%;font-size:var(--fs-micro);color:var(--t3);line-height:1.5}
.crm .ddauto .aut-f-ops{display:flex;gap:8px;margin-top:6px}
.crm .ddauto .aut-f-note{display:block;margin-top:8px;font-size:var(--fs-micro);color:var(--t3);
  line-height:1.5}
.crm .ddauto .aut-prev{display:block;margin-top:12px;padding:9px 11px;background:var(--e1);
  border:1px solid var(--line);border-radius:var(--r-sm);font-size:var(--fs-micro);color:var(--t2)}
.crm .ddauto .aut-p-hd{display:block;color:var(--t1);margin-bottom:5px}
.crm .ddauto .aut-p-note{display:block;color:var(--t3);margin-bottom:6px}
.crm .ddauto .aut-p-row{display:block;color:var(--t2);line-height:1.7}
.crm .ddauto .aut-p-row em{font-style:normal;color:var(--t3)}
.crm .ddauto .aut-ft{display:block;margin-top:10px;font-size:var(--fs-micro);color:var(--t3);
  line-height:1.5}
@media (max-height:820px){ .crm .ddauto{max-height:52vh} }
@media (max-height:700px){ .crm .ddauto{max-height:46vh} }

/* ══════════════ ★★★ §G 体测记录（2026-10-01 · 用户令）══════════════════════════
   归属 = 客户线（`多线并行分工契约-v1.md §4` 第 142 行：`customers.css` ✅ 客户线）。
   作用面一律 `.crmmode .dtl` 前缀（同上方 643 行那段注释的理由）：
   `#dtl` 是 `.app` 的子元素、**不在** `#crmbody` 里，不带前缀会漏到对话站的抽屉上。

   ⚠ 颜色**全走令牌**（`tokens.css` 四主题 A/B/C/D 各定义一次；已机械核验四条边都在）：
     `--chart-line` 是四主题都有的**图表专用**令牌（深色取亮、浅色取深），
     所以折线在四个主题下都跟主题走 —— 硬写一个十六进制就等于把这个块钉死在深色上。
   ⚠ 类名一律 `bd-` 前缀：与全库单类选择器求过交集，**零命中**（R58：
     新类名撞上既有单类会静默改掉外观，而元素"看着还在"）。 */
.dtl .dtl-bsec:empty{display:none}
.dtl .bd-sec{margin-bottom:10px}
.dtl .bd-top{display:flex;align-items:center;gap:8px;margin:0 0 6px}
.dtl .bd-stat{flex:1;min-width:0;font-size:var(--fs-caption);color:var(--t3);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dtl .bd-add,.dtl .bd-mini{font-family:inherit;font-size:var(--fs-caption);
  padding:3px 10px;border:1px solid var(--line);border-radius:var(--r-sm);background:none;
  color:var(--t2);cursor:pointer}
.dtl .bd-add:hover,.dtl .bd-mini:hover{background:var(--face-hover);color:var(--t1)}
.dtl .bd-add:focus-visible,.dtl .bd-mini:focus-visible,
.dtl .bd-chip:focus-visible{outline:2px solid var(--focus);outline-offset:1px}
.dtl .bd-rl{margin-left:8px}
.dtl .bd-chips{display:flex;flex-wrap:wrap;gap:4px;margin-bottom:8px}
.dtl .bd-chip{font-family:inherit;font-size:var(--fs-micro);padding:2px 9px;
  border:1px solid var(--line);border-radius:var(--r-full);background:none;color:var(--t3);cursor:pointer}
.dtl .bd-chip:hover{color:var(--t1);border-color:var(--line3)}
.dtl .bd-chip.on{background:var(--accent-wash);border-color:var(--accent-line);color:var(--accent-text)}
.dtl .bd-cap{font-size:var(--fs-caption);color:var(--t2);margin-bottom:2px}
.dtl .bd-svg{display:block;width:100%;height:auto;overflow:visible}
.dtl .bd-gr{stroke:var(--line);stroke-width:1}
.dtl .bd-ln{fill:none;stroke:var(--chart-line);stroke-width:1.8;
  stroke-linejoin:round;stroke-linecap:round}
.dtl .bd-dot{fill:var(--chart-line);stroke:none}
.dtl .bd-last{stroke:var(--e1);stroke-width:1.6}
.dtl .bd-tx{fill:var(--t3);font-size:9px;font-family:var(--font-ui)}
.dtl .bd-ty{text-anchor:end}
.dtl .bd-tx1{text-anchor:start}
.dtl .bd-tx2{text-anchor:end}
/* ★ 末值标**会压在折线上** —— 实测出图第一版现场：那条线正好经过最后一点，
   标签与线叠成一个看不清的字。⇒ 用 `paint-order:stroke` 描一圈**底色** halo
   （先描边、后填字 ⇒ 字仍然压在 halo 上面）。
   ⚠ 不用"往上挪 7px"顶替：挪得开这一条斜率，挪不开下一条更陡的线。 */
.dtl .bd-tv{fill:var(--t1);font-weight:600;
  paint-order:stroke;stroke:var(--e1);stroke-width:3px;stroke-linejoin:round}
.dtl .bd-stat2{font-size:var(--fs-caption);color:var(--t2);margin:5px 0 8px}
.dtl .bd-msg{font-size:var(--fs-caption);color:var(--t3);padding:4px 0 8px}
.dtl .bd-msg.bad{color:var(--danger-text)}
/* 历史表：三列网格。⚠ 复用本仓"行线连续"的既有口径（border-bottom + 无 column-gap 的错觉），
   但这里**留 gap** —— 三列内容长度差异大（日期/数值/原文），不留 gap 会读成串。 */
.dtl .bd-ht{border-top:1px solid var(--line)}
.dtl .bd-hh,.dtl .bd-hr{display:grid;
  grid-template-columns:92px 78px minmax(0,1fr);gap:10px;padding:4px 0;
  border-bottom:1px solid var(--line);font-size:var(--fs-caption)}
.dtl .bd-hh{color:var(--t3);font-size:var(--fs-micro)}
.dtl .bd-hv{color:var(--t2);font-family:var(--font-num)}
.dtl .bd-hn{color:var(--t1);font-family:var(--font-num);font-weight:600}
.dtl .bd-hr2{color:var(--t3);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* ── 记录表单 ── */
.dtl .bd-form{margin-bottom:10px;padding:10px 12px;border:1px solid var(--line2);
  border-radius:var(--r-md);background:var(--e2)}
.dtl .bd-fr{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-bottom:8px}
.dtl .bd-fl{flex:0 0 62px;font-size:var(--fs-caption);color:var(--t3)}
.dtl .bd-warn{font-size:var(--fs-micro);color:var(--amber)}
.dtl .bd-fi{min-width:0;padding:3px 8px;border:1px solid var(--line);border-radius:var(--r-sm);
  background:var(--e1);color:var(--t1);font-family:inherit;font-size:var(--fs-small)}
.dtl .bd-fi:focus{outline:none;border-color:var(--line3)}
.dtl .bd-fi2{flex:1}
.dtl .bd-fg{margin-bottom:8px}
.dtl .bd-fh,.dtl .bd-frow{display:grid;
  grid-template-columns:92px 78px minmax(0,1fr);gap:10px;align-items:center}
.dtl .bd-fh{padding-bottom:3px;font-size:var(--fs-micro);color:var(--t3)}
.dtl .bd-frow{padding:2px 0}
.dtl .bd-fn{display:flex;align-items:baseline;gap:4px;font-size:var(--fs-caption);color:var(--t2)}
.dtl .bd-fu{font-style:normal;font-size:var(--fs-micro);color:var(--t3)}
.dtl .bd-fnote{min-height:16px;margin-bottom:6px;font-size:var(--fs-caption);color:var(--t3)}
.dtl .bd-fnote.bad{color:var(--danger-text)}
.dtl .bd-fnote.ok{color:var(--accent-text)}
.dtl .bd-fbtns{display:flex;justify-content:flex-end;gap:8px}
.dtl .bd-save{background:var(--accent-wash);border-color:var(--accent-line);color:var(--accent-text)}
/* 窄窗（抽屉最小 520px 已经在 `shell.css:490` 兜住，这里只处理**内容**在最小宽下的拥挤）。 */
@media (max-width:1279px){
  .dtl .bd-hh,.dtl .bd-hr,
  .dtl .bd-fh,.dtl .bd-frow{grid-template-columns:84px 70px minmax(0,1fr);gap:8px}
}

/* ══ 打卡记录块（2026-10-15 · 用户令「跟练中途打卡、教练跟踪」）══════════
   ⚠ 类名一律 `ck-` 前缀（与全库单类选择器求过交集，零命中 —— R58）。
   ⚠ 颜色全走令牌（`tokens.css` 四主题各定义一次），不硬写十六进制（同体测块的纪律）。
   ⚠ 与体测块同一条「不新开滚动容器」口径：内容塞进 `#dtlBd` 这个既有滚动容器。 */
.dtl .ck-sec{margin-bottom:10px}
.dtl .ck-stats{display:flex;gap:8px;margin:0 0 8px}
.dtl .ck-stat{flex:1;min-width:0;text-align:center;padding:6px 4px;
  border:1px solid var(--line);border-radius:var(--r-md);background:var(--e2)}
.dtl .ck-num{display:block;font-size:var(--fs-title);font-weight:600;color:var(--t1);
  font-family:var(--font-num);line-height:1.2}
.dtl .ck-lbl{display:block;font-size:var(--fs-micro);color:var(--t3);margin-top:2px}
.dtl .ck-ops{display:flex;gap:8px;margin:0 0 8px}
.dtl .ck-btn{font-family:inherit;font-size:var(--fs-caption);padding:3px 10px;
  border:1px solid var(--line);border-radius:var(--r-sm);background:none;color:var(--t2);cursor:pointer}
.dtl .ck-btn:hover{background:var(--face-hover);color:var(--t1)}
.dtl .ck-btn:focus-visible{outline:2px solid var(--focus);outline-offset:1px}
.dtl .ck-btn-sm{padding:1px 7px;font-size:var(--fs-micro)}
.dtl .ck-tip{font-size:var(--fs-caption);color:var(--t3);padding:4px 0 8px}
.dtl .ck-fnote{min-height:16px;margin-bottom:6px;font-size:var(--fs-caption);color:var(--t3)}
.dtl .ck-fnote.err{color:var(--danger-text)}
.dtl .ck-form{margin-bottom:10px;padding:10px 12px;border:1px solid var(--line2);
  border-radius:var(--r-md);background:var(--e2)}
.dtl .ck-fld{display:flex;align-items:center;gap:8px;margin-bottom:8px;
  font-size:var(--fs-caption);color:var(--t3);min-width:0}
.dtl .ck-fld input,.dtl .ck-fld select{min-width:0;flex:1;padding:3px 8px;
  border:1px solid var(--line);border-radius:var(--r-sm);background:var(--e1);
  color:var(--t1);font-family:inherit;font-size:var(--fs-small)}
.dtl .ck-fld input:focus,.dtl .ck-fld select:focus{outline:none;border-color:var(--line3)}
.dtl .ck-fld-full input{flex:1}
.dtl .ck-list{border-top:1px solid var(--line)}
.dtl .ck-row{display:flex;align-items:center;gap:8px;padding:4px 0;
  border-bottom:1px solid var(--line);font-size:var(--fs-caption)}
.dtl .ck-row .ck-date{font-family:var(--font-num);color:var(--t2);flex:0 0 82px}
.dtl .ck-row .ck-st{flex:0 0 64px;color:var(--t2)}
.dtl .ck-row .ck-txt{flex:1;min-width:0;color:var(--t1);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dtl .ck-row .ck-w{font-family:var(--font-num);color:var(--t3);flex:0 0 auto}
.dtl .ck-row .ck-src{font-size:var(--fs-micro);color:var(--t3);flex:0 0 auto}
.dtl .ck-row.ck-done .ck-st{color:var(--accent-text)}
.dtl .ck-row.ck-skip .ck-st{color:var(--danger-text)}
.dtl .ck-row.ck-note .ck-st{color:var(--amber)}
@media (max-width:1279px){
  .dtl .ck-row .ck-date{flex:0 0 70px}
  .dtl .ck-row .ck-st{flex:0 0 56px}
  .dtl .ck-row .ck-src{display:none}
}

/* ══ 体测记录块 · 对话站右栏（2026-10-05 · 用户令「右侧栏下方把⑥体测记录展示出来」）══════════
   ⚠ 折线图是**同一份实现**（`WXM.bodychart`，见 bodychart.js），SVG 内部类名沿用 `bd-*`，
     但 `.dtl .bd-*` 那条作用域**不含 `#side`** ⇒ 这里补 `#side .bd-*` 一份。
   ⚠ 只补右栏**用得到**的（chips / cap / svg / stat2 / 历史表 / 空态）；**不搬**记录表单
     （`.bd-form` / `.bd-fi` / `.bd-fbtns` 等）—— 表单是抽屉的写路径，右栏只读。
   ⚠ 颜色全走令牌（`tokens.css` 四主题各一套）；类名已与全库单类求交、零命中（R58）。
   ⚠ 右栏窄（`--side-w` 300px，最窄 208px ⇒ 内容 180px）⇒ 历史表用**更窄的三列**网格，
     仍走 `minmax(0,1fr)` + ellipsis 收尾，保证**零横向溢出**（与抽屉 dtl.mjs 那条同口径）。 */
#side .bd-chips{display:flex;flex-wrap:wrap;gap:4px;margin-bottom:8px}
#side .bd-chip{font-family:inherit;font-size:var(--fs-micro);padding:2px 9px;
  border:1px solid var(--line);border-radius:var(--r-full);background:none;color:var(--t3);cursor:pointer}
#side .bd-chip:hover{color:var(--t1);border-color:var(--line3)}
#side .bd-chip.on{background:var(--accent-wash);border-color:var(--accent-line);color:var(--accent-text)}
#side .bd-chip:focus-visible{outline:2px solid var(--focus);outline-offset:1px}
#side .bd-cap{font-size:var(--fs-caption);color:var(--t2);margin-bottom:2px}
#side .bd-svg{display:block;width:100%;height:auto;overflow:visible}
#side .bd-gr{stroke:var(--line);stroke-width:1}
#side .bd-ln{fill:none;stroke:var(--chart-line);stroke-width:1.8;
  stroke-linejoin:round;stroke-linecap:round}
#side .bd-dot{fill:var(--chart-line);stroke:none}
#side .bd-last{stroke:var(--e1);stroke-width:1.6}
#side .bd-tx{fill:var(--t3);font-size:9px;font-family:var(--font-ui)}
#side .bd-ty{text-anchor:end}
#side .bd-tx1{text-anchor:start}
#side .bd-tx2{text-anchor:end}
#side .bd-tv{fill:var(--t1);font-weight:600;
  paint-order:stroke;stroke:var(--e1);stroke-width:3px;stroke-linejoin:round}
#side .bd-stat2{font-size:var(--fs-caption);color:var(--t2);margin:5px 0 8px}
#side .bd-msg{font-size:var(--fs-caption);color:var(--t3);padding:4px 0 8px}
#side .bd-ht{border-top:1px solid var(--line)}
#side .bd-hh,#side .bd-hr{display:grid;
  grid-template-columns:70px 56px minmax(0,1fr);gap:6px;padding:4px 0;
  border-bottom:1px solid var(--line);font-size:var(--fs-caption)}
#side .bd-hh{color:var(--t3);font-size:var(--fs-micro)}
#side .bd-hv{color:var(--t2);font-family:var(--font-num)}
#side .bd-hn{color:var(--t1);font-family:var(--font-num);font-weight:600}
#side .bd-hr2{color:var(--t3);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* ══ 快速建档块（2026-10-05 · 右栏「这人是谁」段内联表单 · 用户令「未成交也要建档」）══════
   ⚠ 作用面 `#side`（右栏），类名 `qbd-` 前缀（与全库单类选择器求交集，零命中）。
   ⚠ 颜色全走令牌（四主题 A/B/C/D 各定义一次）；右栏最窄 180px ⇒ 横向不许溢出（min-width:0）。 */
#side .qbd-open{font-family:inherit;font-size:var(--fs-caption);color:var(--accent-text);
  background:var(--accent-wash);border:1px solid var(--accent-line);border-radius:var(--r-md);
  padding:4px 12px;margin:8px 0 2px;cursor:pointer}
#side .qbd-open:hover{border-color:var(--accent-text)}
#side .qbd-open:focus-visible{outline:2px solid var(--focus);outline-offset:1px}
#side .qbd{margin:8px 0;padding:10px;border:1px solid var(--line);border-radius:var(--r-md);
  background:var(--e2)}
#side .qbd-hd{font-size:var(--fs-caption);font-weight:600;color:var(--t1);margin-bottom:9px}
#side .qbd-row{display:flex;align-items:center;gap:8px;margin-bottom:7px}
#side .qbd-l{flex:0 0 52px;font-size:var(--fs-caption);color:var(--t2)}
#side .qbd-in{flex:1 1 auto;min-width:0;font-family:inherit;font-size:var(--fs-caption);
  color:var(--t1);background:var(--e1);border:1px solid var(--line);border-radius:var(--r-sm);
  padding:4px 8px}
#side .qbd-in:focus{outline:2px solid var(--focus);outline-offset:0;border-color:var(--accent-line)}
#side .qbd-in::placeholder{color:var(--t3)}
#side .qbd-acts{display:flex;gap:8px;margin-top:10px}
#side .qbd-save{font-family:inherit;font-size:var(--fs-caption);font-weight:600;
  background:var(--accent);color:var(--on-accent);border:1px solid transparent;
  border-radius:var(--r-md);padding:5px 14px;cursor:pointer}
#side .qbd-x{font-family:inherit;font-size:var(--fs-caption);color:var(--t2);
  background:transparent;border:1px solid var(--line);border-radius:var(--r-md);
  padding:5px 12px;cursor:pointer}
#side .qbd-x:hover{border-color:var(--line3)}
#side .qbd-msg{font-size:var(--fs-caption);color:var(--t3);margin-top:9px;line-height:1.5}
#side .qbd-msg.bad{color:var(--danger-text)}

/* ══ 「关联与合并」块（2026-10-01 · #112 · 用户令批「把第一，第二批全做」）══════════
   作用面一律 `.crmmode .dtl` 前缀（同上面两段的理由：`#dtl` 是 `.app` 的子元素、
   **不在** `#crmbody` 里，不带前缀会漏到对话站的抽屉上）。
   ⚠ 类名一律 `mg-` 前缀：与全库单类选择器求过交集，**零命中**（`R58`：新类名撞上
     既有单类会静默改掉外观，而元素"看着还在"）。
   ⚠ 颜色**全走令牌**（`tokens.css` 四主题 A/B/C/D 各定义一次；本段用到的十六条已机械核验
     在四个主题块里都存在）—— 硬写十六进制就等于把这个块钉死在某一个主题上。
   ⚠★ **横向不许溢出**：`_verify/dtl.mjs` 有一条硬判据「抽屉内容零横向溢出」
     （`bdS <= bdC`）⇒ 本段一律 `min-width:0` + `flex-wrap`，
     长名字/长号名用 `text-overflow:ellipsis` 收，不用 `nowrap` 撑宽。
   ⚠ **不给 `#dtl` / `.dh-st .stagechip` 设任何 background** —— `dtl.mjs:332` 拿
     `#dtl` 与 `#crmbody` 的 `backgroundColor` 逐值对拍。本段设背景的全是**内部**元素。 */
.dtl .mg-sec{margin-bottom:10px}
.dtl .mg-hd{font-size:var(--fs-caption);color:var(--t2);font-weight:600;margin-bottom:4px}
.dtl .mg-ph{font-size:var(--fs-caption);color:var(--t3);margin-bottom:4px}
.dtl .mg-num{font-family:var(--font-num);color:var(--t1);font-weight:600}
.dtl .mg-none{color:var(--t3)}
.dtl .mg-rule{font-size:var(--fs-micro);color:var(--t3);margin-bottom:8px;line-height:1.5}
.dtl .mg-msg{font-size:var(--fs-caption);color:var(--t3);padding:4px 0 8px;line-height:1.5}
.dtl .mg-msg.bad{color:var(--danger-text)}
/* 一条候选 */
.dtl .mg-it{border:1px solid var(--line);border-radius:var(--r-md);
  padding:8px 10px;margin-bottom:8px;background:var(--e2)}
.dtl .mg-it.stale{border-style:dashed;opacity:.72}
.dtl .mg-who{display:flex;align-items:center;gap:6px;flex-wrap:wrap;min-width:0;
  font-size:var(--fs-caption);color:var(--t1);line-height:1.5}
.dtl .mg-tag{flex:0 0 auto;font-size:var(--fs-micro);padding:1px 7px;
  border:1px solid var(--amber);border-radius:var(--r-full);color:var(--amber)}
.dtl .mg-ev{font-size:var(--fs-micro);color:var(--t3);margin-top:3px;line-height:1.5}
.dtl .mg-hint{font-size:var(--fs-micro);color:var(--t3);margin-top:3px;line-height:1.5}
.dtl .mg-win{font-size:var(--fs-caption);color:var(--t2);margin-top:6px;
  line-height:1.5;min-width:0}
.dtl .mg-win.warn{color:var(--amber)}
.dtl .mg-why{display:block;font-size:var(--fs-micro);color:var(--t3);margin-top:2px}
.dtl .mg-btns{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px}
.dtl .mg-btn{font-family:inherit;font-size:var(--fs-caption);
  padding:3px 10px;border:1px solid var(--line);border-radius:var(--r-sm);
  background:none;color:var(--t2);cursor:pointer;
  max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dtl .mg-btn:hover{background:var(--face-hover);color:var(--t1)}
.dtl .mg-btn:focus-visible{outline:2px solid var(--focus);outline-offset:1px}
.dtl .mg-btn:disabled{opacity:.5;cursor:default}
.dtl .mg-btn:disabled:hover{background:none;color:var(--t2)}
/* 跨号那一枚：**不是装饰色** —— 它是"这一对需要再确认一次"的唯一视觉落点 */
.dtl .mg-btn.warn{border-color:var(--amber);color:var(--amber)}
.dtl .mg-btn.warn:hover{background:var(--face-hover);color:var(--amber)}
/* 「人工指定同一人」子面板 */
.dtl .mg-pick{border-top:1px solid var(--line);padding-top:8px;margin-top:2px}
.dtl .mg-pbox{margin-top:6px;padding:8px 10px;border:1px solid var(--line2);
  border-radius:var(--r-md);background:var(--e2)}
.dtl .mg-q{width:100%;box-sizing:border-box;font-family:inherit;
  font-size:var(--fs-caption);padding:4px 8px;border:1px solid var(--line);
  border-radius:var(--r-sm);background:var(--e1);color:var(--t1)}
.dtl .mg-q:focus{outline:none;border-color:var(--line3)}
.dtl .mg-pcap{font-size:var(--fs-micro);color:var(--t3);margin-top:5px;line-height:1.5}
.dtl .mg-prows{margin-top:6px;border-top:1px solid var(--line)}
.dtl .mg-prow{display:flex;align-items:center;gap:8px;width:100%;text-align:left;
  font-family:inherit;font-size:var(--fs-caption);padding:5px 4px;border:0;
  border-bottom:1px solid var(--line);background:none;color:var(--t2);cursor:pointer}
.dtl .mg-prow:hover{background:var(--face-hover);color:var(--t1)}
.dtl .mg-prow:focus-visible{outline:2px solid var(--focus);outline-offset:-2px}
.dtl .mg-pn{flex:1 1 auto;min-width:0;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap;color:var(--t1)}
.dtl .mg-pm{flex:0 0 auto;font-family:var(--font-num);color:var(--t3)}
.dtl .mg-pa{flex:0 1 auto;min-width:0;max-width:9em;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap;color:var(--t3)}
.dtl .mg-note{font-size:var(--fs-caption);color:var(--t3);padding:6px 0 2px;line-height:1.5}
.dtl .mg-note.bad{color:var(--danger-text)}
.dtl .mg-note.ok{color:var(--t2)}
/* 窄窗：只处理**内容**在抽屉最小宽（520px）下的拥挤 —— 候选头不许把"跨账号"胶囊挤掉行外。 */
@media (max-width:1279px){
  .dtl .mg-it{padding:7px 9px}
  .dtl .mg-pa{max-width:7em}
}

/* ══ ★★ 跟踪记录 / 统一客户时间轴（2026-10-14 · 用户令）══════════════════════════
   ⚠ 前缀一律 `.crmmode .dtl`，与本抽屉其它块一致；零硬编码色值、全走 `tokens.css`。
   四类事件标签色：微信=accent · 跟进=amber · 体测=violet · 体态=clay（四主题各定义一次，
   已机械核验 `--accent`/`--amber`/`--violet`/`--clay` 四条边都在）。 */
.dtl .tl-sec{margin-bottom:10px}
.dtl .tl-top{display:flex;align-items:center;gap:8px;margin:0 0 6px}
.dtl .tl-it{padding:5px 0;border-bottom:1px solid var(--line)}
.dtl .tl-it:last-of-type{border-bottom:0}
.dtl .tl-tp{display:flex;align-items:center;gap:6px;flex-wrap:wrap;min-width:0}
.dtl .tl-tag{font-family:inherit;font-size:var(--fs-micro);padding:1px 7px;
  border:1px solid var(--line);border-radius:var(--r-full);color:var(--t3);white-space:nowrap;line-height:1.4}
.dtl .tl-tag.tl-wx{border-color:var(--accent-line);color:var(--accent-text);background:var(--accent-wash)}
.dtl .tl-tag.tl-fo{border-color:var(--amber);color:var(--amber)}
.dtl .tl-tag.tl-bd{border-color:var(--violet);color:var(--violet)}
.dtl .tl-tag.tl-ph{border-color:var(--clay);color:var(--clay)}
.dtl .tl-dir{font-size:var(--fs-micro);color:var(--t3)}
.dtl .tl-dir.out{color:var(--accent-text)}
.dtl .tl-time{font-size:var(--fs-micro);color:var(--t3);font-family:var(--font-num)}
.dtl .tl-by,.dtl .tl-view{font-size:var(--fs-micro);color:var(--t3);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dtl .tl-body{font-size:var(--fs-caption);color:var(--t1);margin-top:2px;line-height:1.5;word-break:break-word}
.dtl .tl-del{margin-left:auto;font-family:inherit;font-size:var(--fs-micro);padding:0 6px;
  border:1px solid transparent;border-radius:var(--r-sm);background:none;color:var(--t3);cursor:pointer}
.dtl .tl-del:hover{color:var(--danger-text);border-color:var(--danger-line);background:var(--danger-bg)}
.dtl .tl-del:focus-visible{outline:2px solid var(--focus);outline-offset:1px}
.dtl .tl-phbody{display:flex;align-items:flex-start;gap:6px}
.dtl .tl-ph{max-width:96px;max-height:96px;border-radius:var(--r-sm);border:1px solid var(--line)}
.dtl .tl-more{display:block;margin:8px auto 0;font-family:inherit;font-size:var(--fs-caption);
  padding:3px 12px;border:1px solid var(--line);border-radius:var(--r-full);background:none;
  color:var(--t2);cursor:pointer}
.dtl .tl-more:hover{background:var(--face-hover);color:var(--t1)}
.dtl .tl-more:disabled{opacity:.5;cursor:default}
.dtl .tl-more:focus-visible{outline:2px solid var(--focus);outline-offset:1px}
/* ── 记跟进表单（与体测表单同族：`--e2` 底、`--line2` 框）── */
.dtl .tl-form{margin-bottom:10px;padding:10px 12px;border:1px solid var(--line2);
  border-radius:var(--r-md);background:var(--e2)}
.dtl .tl-fr{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-bottom:8px}
.dtl .tl-fl{flex:0 0 48px;font-size:var(--fs-caption);color:var(--t3)}
.dtl .tl-fi{min-width:0;padding:3px 8px;border:1px solid var(--line);border-radius:var(--r-sm);
  background:var(--e1);color:var(--t1);font-family:inherit;font-size:var(--fs-small)}
.dtl .tl-fi:focus{outline:none;border-color:var(--line3)}
.dtl .tl-ta{flex:1;min-width:220px;min-height:52px;resize:vertical}
.dtl .tl-fbtns{display:flex;gap:8px;justify-content:flex-end}
.dtl .tl-save{background:var(--accent-wash);border-color:var(--accent-line);color:var(--accent-text)}
.dtl .tl-save:hover{background:var(--accent-wash);color:var(--accent-text)}
.dtl .tl-note{font-size:var(--fs-caption);color:var(--t3);padding:4px 0 2px;line-height:1.5}
.dtl .tl-note.bad{color:var(--danger-text)}
/* ── 系统日志 tab 与条目（0.38.0）── */
.dtl .tl-tabs{display:inline-flex;gap:2px;background:var(--e2);
  border:1px solid var(--line);border-radius:var(--r-full);padding:2px}
.dtl .tl-tab{font-family:inherit;font-size:var(--fs-micro);padding:1px 10px;line-height:1.5;
  border:0;border-radius:var(--r-full);background:none;color:var(--t3);cursor:pointer;white-space:nowrap}
.dtl .tl-tab.on{background:var(--e1);color:var(--t1);box-shadow:0 0 0 1px var(--line)}
.dtl .tl-tab:focus-visible{outline:2px solid var(--focus);outline-offset:1px}
.dtl .tl-tag.tl-man{border-color:var(--amber);color:var(--amber)}
.dtl .tl-tag.tl-sys{border-color:var(--violet);color:var(--violet)}
.dtl .tl-it.tl-slog{padding:7px 0}
.dtl .tl-stage{font-size:var(--fs-caption);color:var(--t1)}
.dtl .tl-stage .tl-fs{color:var(--t3)}
.dtl .tl-meta{display:block;font-size:var(--fs-micro);color:var(--t3);margin-top:2px}
.dtl .tl-layer{font-family:var(--font-num);opacity:.85}

/* ══ ★★ M4-B：自动化矩阵（5 动作 × 4 阶段带 = 20 格）══════════════════════════════════
   `方案-客户界面与流程重设计` §6.3 那张表在屏上的形态。替换掉原来的"一列规则"。

   ⚠ 前缀一律 `.crm .ddauto` —— 与本面板**其它段完全一致**。不另开作用域：
     同一条规则在两个地方各写一份，改一处忘一处，且**不报错**（本仓最贵那族）。
   ⚠ 四主题安全：**零硬编码色值**，全部走 `tokens.css`
     （`--e0..--e3` / `--line` / `--t1..t3` / `--accent-*` / `--clay` / `--focus`）。
   ⚠ 三态**一眼可分**（这是本件的全部意义 —— "哪一格还空着"要能一眼看出来）：
       `.new`（空·可建）= 虚线框 + `＋` · `.on`（已有规则）= 实底 + 规则名
       `.gray`（无意义）= 更淡 + `—` · 四者**不靠 hover 才能分辨**（红线④）。
   ══════════════════════════════════════════════════════════════════════════════════ */
.crm .ddauto .aut-mx{display:block;margin:2px 0 10px}
.crm .ddauto .aut-mx-hd,
.crm .ddauto .aut-mx-row{display:grid;grid-template-columns:88px repeat(4,1fr);gap:1px}
.crm .ddauto .aut-mx-row{margin-top:1px}
.crm .ddauto .aut-mx-corner,
.crm .ddauto .aut-mx-ch,
.crm .ddauto .aut-mx-rh,
.crm .ddauto .aut-mx-c{display:flex;align-items:center;justify-content:center;
  min-height:30px;padding:3px 5px;font-size:var(--fs-micro);line-height:1.25;
  background:var(--e3);color:var(--t2);border-radius:var(--r-xs);text-align:center;
  overflow:hidden}
.crm .ddauto .aut-mx-corner{justify-content:flex-start;background:transparent;color:var(--t3)}
.crm .ddauto .aut-mx-ch{color:var(--t1);font-weight:600}
.crm .ddauto .aut-mx-rh{justify-content:flex-start;background:transparent;color:var(--t1)}
/* ① 空格子 = **可建**。它就是"这一格还空着"的待办清单 ⇒ 要看得见，不能淡到没了 */
.crm .ddauto .aut-mx-c.new{background:transparent;color:var(--t3);
  border:1px dashed var(--line);cursor:pointer}
.crm .ddauto .aut-mx-c.new:hover{color:var(--accent-text);border-color:var(--focus)}
.crm .ddauto .aut-mx-c.on{background:var(--e1);color:var(--t1);cursor:pointer;gap:3px}
.crm .ddauto .aut-mx-c.on b{font-weight:600;max-width:100%;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.crm .ddauto .aut-mx-c.on i{color:var(--accent-text)}
.crm .ddauto .aut-mx-c.on em{color:var(--t3)}
/* ② 灰格 = 语义上无意义（**不是**"还没做"）。可点 ⇒ 点了下方回话说明为什么。
   ⚠ 用 `opacity` 而不是"藏起来"：藏起来会被当成渲染坏了（"怎么少两格"）。 */
.crm .ddauto .aut-mx-c.gray{background:transparent;color:var(--t3);opacity:.55;
  border:1px dashed var(--line);cursor:pointer}
/* ③ 选中格：描边（`outline` 不占位 ⇒ 不会让整张表抖一下） */
.crm .ddauto .aut-mx-c.sel{outline:2px solid var(--focus);outline-offset:-2px}
.crm .ddauto .aut-mx-lg{display:block;margin-top:7px;font-size:var(--fs-micro);
  color:var(--t3);line-height:1.6}
.crm .ddauto .aut-mx-lg i{display:block}
.crm .ddauto .aut-mx-lg b{color:var(--t2);font-weight:600}
/* ④ 「其他触发」区（非阶段类规则 —— 一条都不许消失，见 `autoOthersHtml`） */
.crm .ddauto .aut-other{display:block;margin:10px 0 4px}
.crm .ddauto .aut-other-hd{display:block;font-size:var(--fs-micro);color:var(--t3);
  margin-bottom:6px}
.crm .ddauto .aut-other-g{display:block;margin-bottom:6px}
.crm .ddauto .aut-other-t{display:block;font-size:var(--fs-micro);color:var(--t2);
  margin-bottom:3px}
.crm .ddauto .aut-other-t em{color:var(--clay)}
/* ⑤ 选中格的详情（下方） */
.crm .ddauto .aut-sel{display:block;margin:10px 0 4px;padding:8px 10px;
  border:1px solid var(--line);border-radius:var(--r-sm);background:var(--e3)}
.crm .ddauto .aut-sel.gray{background:transparent}
.crm .ddauto .aut-sel-hd{display:block;font-size:var(--fs-caption);color:var(--t1);
  font-weight:600;margin-bottom:6px}

/* ══ ★★ 批 1 / 批 2（2026-10-03）：四工作台 · 今日变动 · 待分配卡片 ═══════════════════
   前缀一律 `.crm`（与本页其它段完全一致）。**零硬编码色值**，全部走 `tokens.css`
   （`--e0..--e3` / `--line*` / `--t1..t3` / `--accent-*` / `--focus`）⇒ 四主题安全。
   ⚠ 三态**一眼可分**（这是本件的全部意义，红线④「不加 hover 才知道能点的」）：
       `.wb-i`（未选）= 描边 + `--e2` 底 ｜ `.wb-i.on`（当前）= accent 底 + 强调色
     两态**不靠 hover** —— hover 只做一点点提亮，摘掉它这行仍然分得清。
   ══════════════════════════════════════════════════════════════════════════════════ */
.crm .crmwb{display:flex;align-items:center;gap:8px;flex-wrap:wrap;row-gap:6px;
  padding:8px 18px;border-top:1px solid var(--line);background:var(--e0)}
.crm .crmwb .wb-i{display:inline-flex;align-items:center;gap:6px;padding:3px 11px;
  border:1px solid var(--line);border-radius:var(--r-full);background:var(--e2);
  color:var(--t2);font-size:var(--fs-caption);cursor:pointer;white-space:nowrap}
.crm .crmwb .wb-i:hover{border-color:var(--accent-line);color:var(--t1)}
.crm .crmwb .wb-i.on{background:var(--accent-wash);border-color:var(--accent-line);
  color:var(--accent-text);font-weight:600}
.crm .crmwb .wb-i b{font-weight:600;color:var(--t1)}
.crm .crmwb .wb-i.on b{color:var(--accent-text)}
.crm .crmwb .wb-i:focus-visible{outline:2px solid var(--focus);outline-offset:1px}
.crm .crmwb .wb-note{margin-left:auto;color:var(--t3);font-size:var(--fs-micro);
  white-space:nowrap}

/* 今日变动条 —— 页头里的一条**陈述**（不可点 ⇒ 不加 cursor:pointer、不加 hover 反馈：
   让一个不能点的东西长得能点，与"能点却点了没反应"是同一个病的反向）。 */
.crm .pagehd .tday{display:inline-flex;align-items:center;gap:5px;color:var(--t3);
  font-size:var(--fs-caption);white-space:nowrap}
.crm .pagehd .tday .tday-i em{font-style:normal;color:var(--t3)}
.crm .pagehd .tday .tday-i b{color:var(--t1);font-weight:600;margin-left:3px;
  font-variant-numeric:tabular-nums}
.crm .pagehd .tday .tday-sp{color:var(--line-strong)}

/* 待分配池卡片 —— 一行一客。**不是**表格：没有列宽、没有横滚、没有表头。 */
.crm .wbcards{display:block}
.crm .wbc{display:flex;align-items:center;gap:10px;padding:9px 18px;
  border-bottom:1px solid var(--line)}
.crm .wbc:hover{background:var(--e1)}
.crm .wbc.on{background:var(--accent-wash)}
.crm .wbc-ck{display:inline-block;flex:0 0 13px;width:13px;height:13px;
  border:1px solid var(--line-strong);border-radius:var(--r-xs);cursor:pointer}
.crm .wbc-ck.on{background:var(--accent);border-color:transparent}
.crm .wbc-ck:hover{border-color:var(--accent)}
.crm .wbc-ck:focus-visible{outline:2px solid var(--accent);outline-offset:1px}
.crm .wbc-bd{flex:1 1 auto;min-width:0}
.crm .wbc-l1{display:flex;align-items:baseline;gap:9px;min-width:0}
.crm .wbc-l1 b{font-weight:400;color:var(--t1);overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.crm .wbc-ph{color:var(--t2);font-size:var(--fs-caption);
  font-variant-numeric:tabular-nums;white-space:nowrap}
.crm .wbc-src{color:var(--t3);font-size:var(--fs-caption);white-space:nowrap}
.crm .wbc-l2{display:flex;align-items:baseline;gap:10px;margin-top:3px;min-width:0;
  color:var(--t3);font-size:var(--fs-micro)}
.crm .wbc-l2 .wbc-amt{color:var(--t2);font-variant-numeric:tabular-nums;white-space:nowrap}
.crm .wbc-l2 .wbc-cu{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.crm .wbc .op{cursor:pointer;color:var(--accent-text);font-size:var(--fs-caption);
  white-space:nowrap}
.crm .wbc-empty{padding:26px 18px;color:var(--t3);font-size:var(--fs-caption);
  text-align:center}

/* 待分配池的动作条 —— **常驻可见**（不是"选中了才浮出来"）。
   ★★ `position:sticky;bottom:0` 是**必需**的，不是装饰：本池一页 20 张卡（卡片比表格行高），
     "底部那条动作"在流里的自然位置**远在视野之外**——不钉住的话，用户勾了 8 个人，
     还要滚到底才能找到「确认指派」，而 §7.2 红线写的是「指派动作条**常驻可见**」。
     ⚠ `z-index` 要显式给：卡片有 `background`，不抬起来会被后面的卡盖住（视觉上"半截"）。 */
.crm .wbbar{display:flex;align-items:center;gap:10px;flex-wrap:wrap;row-gap:6px;
  padding:10px 18px;border-top:1px solid var(--line);background:var(--e1);
  position:sticky;bottom:0;z-index:2}
.crm .wbbar .wbb-n{color:var(--t2);font-size:var(--fs-caption);white-space:nowrap}
.crm .wbbar .wbb-n b{color:var(--t1);font-weight:600}
.crm .wbbar .wbb-sel{padding:2px 6px;border:1px solid var(--line);
  border-radius:var(--r-sm);background:var(--e0);color:var(--t1);
  font-size:var(--fs-caption)}
.crm .wbbar .wbb-why{color:var(--t2);font-size:var(--fs-caption);min-width:0}

/* ★★ 批 2（2026-10-03）：行内「今日下单」小亮点。
   ⚠★ **必须**是绝对定位的伪元素：`crmcols.mjs` 逐列余量表钉着 13 列，而「下单日期」列
     的余量只有 **1.7px**（全表最紧的两列之一）⇒ 任何参与布局的圆点都会当场打红。
     伪元素不进文档流 ⇒ 列的 `scrollWidth` / 单元格盒尺寸**一个像素都不变**。
   ⚠ `position:relative` 只加在**这一格**（不带 `.dnew` 的格子不受影响）——
     不给 `.ftbl td` 全局加定位上下文（那会一次改动全部 13 列的行为）。
   ⚠ 落点取**右上角**：单元格是 `padding:9px 8px` + `vertical-align:middle`，
     文字占中间那一条 ⇒ 右上角那 5px 是空位，不与日期文本打架。
     放右中是"贴着字"，放左中会挡住日期的头一位。 */
.crm .ftbl td.dnew{position:relative}
.crm .ftbl td.dnew::after{content:'';position:absolute;top:3px;right:3px;
  width:5px;height:5px;border-radius:50%;background:var(--accent)}

/* ══════════════════════════════════════════════════════════════════════════════
   ★ 2026-10-17 · 首次信息采集面板（`.dtl .dtl-intakepanel`）

   位置与 `.dtl-fldpanel` **同款**（`top:100%` 贴 `.dtl-hd` 底边，`z-index` 比它高 1）：
   两个面板不会同时打开（点「采集表」时若字段面板开着，会盖住它而不是并排）。
   ⚠ 类名全部 `.dtl .dtl-intakepanel …` 后代选择器：`.hd/.st/.row/.u/.b/.ft` 都是短名，
     全库易撞（R58），必须限定作用域。
   ⚠ 不新增 `.dtl-hd` 的定位（已 `position:relative`，见上方字段面板段）。
   ══════════════════════════════════════════════════════════════════════════════ */
.dtl .dtl-intakepanel{display:none;position:absolute;top:100%;left:0;right:0;z-index:31;
  padding:12px 14px;background:var(--e2);border:1px solid var(--line);border-radius:var(--r-sm);
  box-shadow:0 12px 30px -16px var(--sh-2)}
.dtl .dtl-intakepanel.open{display:block}
.dtl .dtl-intakepanel .hd{display:block;font-size:var(--fs-caption);color:var(--t2);margin-bottom:8px}
.dtl .dtl-intakepanel .hd i{font-style:normal;color:var(--t3);font-size:var(--fs-micro);margin-left:6px}
/* 状态条：四态各自一色。「客户已提交」= 好消息 ⇒ 主色；「不一致 / 出错」= 需要人管 ⇒ 危险色。
   其余（未生成 / 已发未开 / 已过期）保持中性 —— 用颜色表达"要不要动手"，不是表达"发生了什么"。 */
.dtl .dtl-intakepanel .st{display:block;font-size:var(--fs-small);line-height:1.5;color:var(--t2);
  padding:7px 10px;border-radius:var(--r-sm);background:var(--e1);border:1px solid var(--line)}
.dtl .dtl-intakepanel .st b{font-weight:600}
.dtl .dtl-intakepanel .st-submitted,.dtl .dtl-intakepanel .st-opened{
  background:var(--accent-wash);border-color:var(--accent-line);color:var(--accent-text)}
.dtl .dtl-intakepanel .st-err,.dtl .dtl-intakepanel .st-revoked{
  background:var(--danger-bg);border-color:var(--danger-line);color:var(--danger-text)}
.dtl .dtl-intakepanel .row{display:flex;gap:8px;align-items:center;margin-top:2px}
.dtl .dtl-intakepanel .u{flex:1;min-width:0;font-size:var(--fs-small);color:var(--t1);
  padding:7px 10px;border:1px solid var(--line);border-radius:var(--r-sm);background:var(--e1);
  font-family:var(--font-mono,ui-monospace,SFMono-Regular,Menlo,monospace)}
.dtl .dtl-intakepanel .b{flex:0 0 auto;padding:7px 14px;border-radius:var(--r-sm);cursor:pointer;
  font-size:var(--fs-small);font-family:inherit;
  background:var(--accent);color:var(--on-accent);border:1px solid var(--accent)}
.dtl .dtl-intakepanel .b:hover{filter:brightness(1.04)}
.dtl .dtl-intakepanel .b:active{transform:translateY(.5px)}
.dtl .dtl-intakepanel .b.ghost{background:transparent;color:var(--t1);border-color:var(--line)}
.dtl .dtl-intakepanel .b.ghost:hover{background:var(--face-hover)}
.dtl .dtl-intakepanel .ops{display:flex;gap:8px;margin-top:10px}
/* ⚠ 不铺满整宽：只有一个次要按钮时铺满 = 一整条深色带，看着像"主操作"，
   而且误触面变大（实测截图 `ui-3-panel.png` 就是这种形态）。 */
.dtl .dtl-intakepanel .ops .b{flex:0 0 auto;min-width:132px}
.dtl .dtl-intakepanel .ft{display:block;margin-top:9px;font-size:var(--fs-micro);color:var(--t3);
  line-height:1.6}
.dtl .dtl-intakepanel .ft b{color:var(--t2);font-weight:600}

/* ══════════════════════════════════════════════════════════════════════════════
   ★ 2026-10-18 · 首采**填写记录**（列表 / 单条详情 / 对比）

   面板还是 `.dtl-intakepanel` 那一个（只切视图），这里补三样：
     ① `.intk-recs` 状态下的滚动（记录十几条，不滚会把抽屉顶掉）
     ② 返回条（列表和详情共用一套）
     ③ 对比徽标 `.intk-d` —— 颜色语义见 detail.js `dTag()`：**降绿升红**，
        只表达方向不表达好坏（心率降不是好事，围度降才是）。

   ⚠⚠ **类名全部 `intk-` 前缀，这是被咬过之后改的**：初版用了 `.cm/.db/.rr/.rl`，
     自带 `.dtl .dtl-intakepanel` 作用域看着够保险 —— 结果 `.cm` 撞上 `colleagues.css:35`
     的**裸类名** `.cm{display:none;flex:1 1 auto;background:…}`。作用域只赢"我写了的属性"，
     没写的（background / flex / min-width）**照样从那条全局规则继承** ⇒ 对比条里每个指标
     变成一块等宽灰底格子（实测 computed: `background:rgb(21,25,29)`、`flex:1 1 auto`）。
     单靠提高特异性挡不住这种"漏属性继承"，唯一稳的办法是**换一个库里不存在的名字**。
   ⚠ 不引新主题变量：`--accent-text` / `--danger-text` 四套主题都已定义；
     新加 `--up/--down` 就要四套各写一份，漏一套就是一个"看不见的字"。
   ══════════════════════════════════════════════════════════════════════════════ */
.dtl .dtl-intakepanel.intk-recs{max-height:min(66vh,580px);overflow-y:auto;
  overscroll-behavior:contain}

/* ── 返回条 ── */
.dtl .dtl-intakepanel .intk-hd{display:flex;align-items:center;gap:7px;
  font-size:var(--fs-caption);color:var(--t2);margin:0 0 8px 0}
.dtl .dtl-intakepanel .intk-hd i{font-style:normal;margin-left:auto;color:var(--t3);
  font-size:var(--fs-micro)}
.dtl .dtl-intakepanel .intk-bk{flex:0 0 auto;width:22px;height:22px;line-height:1;
  display:flex;align-items:center;justify-content:center;margin:0;padding:0 0 2px 0;
  background:var(--e1);border:1px solid var(--line);border-radius:var(--r-sm);
  color:var(--t2);font-size:15px;font-family:inherit;cursor:pointer}
.dtl .dtl-intakepanel .intk-bk:hover{background:var(--face-hover);color:var(--t1)}

/* ── 累计对比（列表顶部）── */
.dtl .dtl-intakepanel .intk-cmp{display:block;padding:9px 11px;margin:0 0 9px 0;
  background:var(--e1);border:1px solid var(--line);border-radius:var(--r-sm)}
.dtl .dtl-intakepanel .intk-cmp-h{display:flex;align-items:baseline;gap:6px;
  margin:0 0 6px 0;font-size:var(--fs-micro);color:var(--t3)}
.dtl .dtl-intakepanel .intk-cmp-h b{color:var(--t2);font-size:var(--fs-small);font-weight:600}
.dtl .dtl-intakepanel .intk-cmp-g{display:flex;flex-wrap:wrap;gap:7px 16px}
.dtl .dtl-intakepanel .intk-ci{display:flex;align-items:baseline;gap:4px;
  flex:0 0 auto;width:auto;min-width:0;margin:0;padding:0;
  background:none;border:0;font-size:var(--fs-micro);line-height:1.4}
.dtl .dtl-intakepanel .intk-ci u{text-decoration:none;color:var(--t3)}
.dtl .dtl-intakepanel .intk-ci s{text-decoration:none;color:var(--t2);
  font-variant-numeric:tabular-nums}
.dtl .dtl-intakepanel .intk-ci s b{color:var(--t1);font-weight:600}

/* ── 记录列表 ── */
.dtl .dtl-intakepanel .intk-list{display:block;margin:0;padding:0}
.dtl .dtl-intakepanel .intk-row{display:flex;align-items:center;gap:10px;
  width:100%;margin:0;padding:6px 4px;
  border:0;border-top:1px solid var(--line);background:none;
  font-family:inherit;font-size:var(--fs-small);text-align:left;
  color:inherit;cursor:pointer}
.dtl .dtl-intakepanel .intk-row:first-child{border-top:0}
.dtl .dtl-intakepanel .intk-row:hover{background:var(--face-hover)}
.dtl .dtl-intakepanel .intk-row-l{flex:0 0 auto;display:flex;flex-direction:column;
  gap:1px;min-width:66px;line-height:1.35}
.dtl .dtl-intakepanel .intk-row-l b{font-size:var(--fs-small);color:var(--t1);font-weight:600}
.dtl .dtl-intakepanel .intk-row-l i{font-style:normal;font-size:var(--fs-micro);
  color:var(--t3);font-variant-numeric:tabular-nums}
.dtl .dtl-intakepanel .intk-row-m{flex:1;min-width:0;font-size:var(--fs-micro);
  color:var(--t2);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dtl .dtl-intakepanel .intk-row-g{flex:0 0 auto;color:var(--t3);font-size:14px}

/* ── 单条详情 ── */
.dtl .dtl-intakepanel .intk-dbar{display:flex;flex-wrap:wrap;align-items:baseline;
  gap:4px 10px;padding:7px 10px;margin:0 0 9px 0;border-radius:var(--r-sm);
  background:var(--accent-wash);border:1px solid var(--accent-line);
  color:var(--accent-text);font-size:var(--fs-micro)}
.dtl .dtl-intakepanel .intk-dbar0{background:var(--e1);border-color:var(--line);color:var(--t3)}
.dtl .dtl-intakepanel .intk-db{display:flex;align-items:baseline;gap:3px;flex:0 0 auto}
.dtl .dtl-intakepanel .intk-db u{text-decoration:none;opacity:.85}
.dtl .dtl-intakepanel .intk-grp{display:block;margin:10px 0 0 0}
.dtl .dtl-intakepanel .intk-grp>b{display:block;margin:0 0 4px 0;font-size:var(--fs-micro);
  color:var(--t3);font-weight:600;letter-spacing:.02em}
.dtl .dtl-intakepanel .intk-frs{display:block;margin:0;padding:0}
.dtl .dtl-intakepanel .intk-f{display:flex;align-items:baseline;gap:8px;
  margin:0;padding:3px 0;font-size:var(--fs-small);line-height:1.5}
.dtl .dtl-intakepanel .intk-f u{flex:0 0 78px;text-decoration:none;color:var(--t3);
  font-size:var(--fs-micro)}
/* 徽标紧贴值：剩余空间由**徽标自己**的 `margin-right:auto` 吸收。
   ⚠ 别写成 `s{margin-right:auto}` —— `auto` 会把"值之后"的空间全吃掉，反而把徽标
     推到面板最右（实测 `s.right=952` vs 徽标 `left=1445`，中间空 493px）。 */
.dtl .dtl-intakepanel .intk-f s{flex:0 1 auto;min-width:0;
  text-decoration:none;color:var(--t1);font-variant-numeric:tabular-nums;word-break:break-all}
.dtl .dtl-intakepanel .intk-f .intk-d{margin-right:auto}
.dtl .dtl-intakepanel .intk-u{font-style:normal;color:var(--t3);font-size:var(--fs-micro);
  margin-left:2px}
.dtl .dtl-intakepanel .intk-f-rj s{color:var(--t3);text-decoration:line-through;
  text-decoration-color:var(--danger-line)}
.dtl .dtl-intakepanel .intk-rj{font-style:normal;color:var(--danger-text);
  font-size:var(--fs-micro);margin-left:5px;text-decoration:none;display:inline-block}

/* ── 差值徽标 ── */
.dtl .dtl-intakepanel .intk-d{flex:0 0 auto;font-style:normal;font-size:var(--fs-micro);
  font-variant-numeric:tabular-nums;font-weight:600;margin:0}
.dtl .dtl-intakepanel .intk-d.dn{color:var(--accent-text)}
.dtl .dtl-intakepanel .intk-d.up{color:var(--danger-text)}
