/* ══════════════════════════════════════════════════════════════════
   xiaoe.css —— 小鹅通站（顶栏第 7 站 · 新增真站，2026-09-21）
   用户原话：「增加一个跟报表旁边的按钮，叫小鹅通，具体管理他里面的订单和课程」
             「订单管理，要分平台-抖音-视频号-快手-小红书-杉杉」
             「增加个订单导入功能，每次会导入订单，来管理新建客户、更新订单状态」

   数据口径：`backend/app/routes/xiaoe.py` 的
             `GET /xiaoe/orders` · `/xiaoe/courses` · `/xiaoe/platforms` ·
             `GET /xiaoe/import/sample` · `POST /xiaoe/import/precheck`（**恒 dry-run**）
   上游素材：用户给的三份平台导出范本（`backend/data/xe-samples/`，原样固化）。

   结构范式：app/css/chatlog.css（站头通栏 + 内容层 + 窄窗兜底）。
   纪律（引前已机械核过，命令见交付回报）：
     1. 本文件**不得出现字面色值**，一律 var() 令牌。★ 且只用**四主题齐备**的令牌——
        实测 `--warn` 只在 1 个主题里有定义（chatlog.css 头注已记过这条），
        本文件因此**不用** `--warn`；风险色一律 `--danger*`，其次级用 `--amber*`。
     2. 类名一律 `xe-` 前缀 + 内容层 `#xebody`；`.xe-` / `#xebody` / `data-xe*` / `xeq`
        在本仓**引前 0 命中**（R58 同族：命名撞车必须提前查）。
     3. ★★ **「忙」与「空」必须是两个类**（§5.9 那次的教训）：
        `.xe-busy`（取数中）与 `.xe-empty`（取到了、结果是空）**分开**——
        合成一个会让出图/判据的等待条件退化（表现为"偶发 0 张图 / 偶发假绿"）。
     4. ★ 本域正文大量来自**上游导出的原始字段**（课程名 / 订单状态 / 售后状态 / 线索归属…）
        ⇒ 渲染层一律 `esc`（XSS 面在 js 侧守），散文位过 `md()`（防「设计稿 `**` 直灌」那类漏字面）。
   ══════════════════════════════════════════════════════════════════ */
.xe{display:none;flex:1 1 auto;min-width:0;min-height:0;flex-direction:column;
  background:var(--e2)}
.app.xemode > .list,
.app.xemode > .chat,
.app.xemode > .side,
.app.xemode > .spl{display:none}
.app.xemode > #xebody{display:flex}

/* ══ ★★ `#xemain` = `render()` 加的那层**主体包装**（2026-09-23 实时检索批次引入；
      目的只是让「只换主体」时站头不重建 ⇒ `#xeq` 输入框节点原地不动 ⇒ 焦点不飞走）。
   ⚠⚠ 裸 div 会**吃断 flex 链**，而且**全程不报错**（实测 2026-09-23 19:5x）：
      `.xe-body{flex:1 1 auto;min-height:0;overflow:auto}` 是全站**唯一的纵向滚动容器**，
      它的定高**完全依赖父级是 flex 容器 + 自己是 flex 子项**。
      `#xemain` 默认 `display:block` / `flex:0 1 auto` ⇒ 两件事同时发生：
        ① 它自己不 grow ⇒ 高度 = 内容高度（实测 clientHeight = **16486**）；
        ② `.xe-body` 的 `flex` 属性在非 flex 父下**整条失效** ⇒ `overflow:auto` 拿到
           "无限高" ⇒ **永远不出滚动条**（实测 clientHeight == scrollHeight == 16486）。
      而祖先 `.app{overflow:hidden}` 会把溢出的那 1.5 万像素**直接裁掉**
      ⇒ 现象 =「**列表往下滑不动、后面的行根本够不着**」
      （实测末行 bottom = **16587**、视口高 900；`#xebody` 自身 `overflow:visible` 不兜底）。
   ⇒ 结论：这层包装**必须原样透传 flex 上下文**（grow + `min-height:0` + 纵向列）。
      ⚠ 判据面：所有既有断言都只查 DOM 存在性/文本 ⇒ **对布局退化全盲**，
        这条只能由「几何 + 真滚动」断言守（`_verify/xiaoe.mjs` §13 ⑯，负对照已做实）。 */
#xemain{flex:1 1 auto;min-height:0;display:flex;flex-direction:column}

/* ── 站头（44px）────────────────────────────────────────────────────
   ⚠ 高度 **44px 不许改**：它是站内三条横带（站头 44 / 筛选 36 / 内容）的第一条，
     与其余 6 站同量（顶栏总高 120px 是全局约束，本文件只负责站内这一段）。
     ⇒ 2026-09-24「小功能美化」批次**只动颜色/边/圆角/过渡，不动高度与顺序**。 */
.xe-hd{display:flex;align-items:center;gap:9px;flex:none;height:44px;padding:0 14px;
  border-bottom:1px solid var(--line);background:var(--e1)}
/* 图标底衬：26px 圆角方块（站头 44 ⇒ 上下各 9px 呼吸）。色只用 accent 三件套 —— 
   四主题各自取色，深色下是"青玉底 + 亮描边"，浅色下是"米底 + 深描边"。 */
.xe-ico{flex:none;width:26px;height:26px;border-radius:var(--r-sm);
  background:var(--accent-wash);border:1px solid var(--accent-line);color:var(--accent-text);
  display:flex;align-items:center;justify-content:center}
.xe-ttl{font-size:var(--fs-small);color:var(--t1);font-weight:600;letter-spacing:.2px;
  white-space:nowrap}
.xe-sep{width:1px;height:14px;background:var(--line-strong);flex:none}
/* 标签（订单与课程 / 预检·不落库）：给一层**柔底**，让它在深色与浅色下都读得出是"标签"
   而不是"被截断的文字"。底色一律 `--e3`（槽色），语义色只走边框与文字。 */
.xe-tag{font-size:var(--fs-micro);color:var(--t2);padding:1px 8px;border-radius:var(--r-full);
  border:1px solid var(--line);background:var(--e3);white-space:nowrap;line-height:1.7}
.xe-tag.ro{border-color:var(--accent-line);background:var(--accent-wash);color:var(--accent-text)}
.xe-tag.dry{border-color:var(--amber-line);color:var(--amber)}
.xe-hd .sp{flex:1 1 auto}
/* 三视图切换条（订单 / 课程 / 导入）—— 与 chatlog 的 .cl-views 同形同量
   2026-09-24 美化：加外框、选中态抬起 + 数字胶囊化。
   ★ 判据 §13 量的是 `[data-xeview]` 的数量与**真 click**，故结构一字未动，只加视觉。 */
.xe-views{display:flex;gap:2px;flex:none;padding:2px;border-radius:var(--r-md);
  background:var(--e3);border:1px solid var(--line)}
.xe-v{font-size:var(--fs-caption);color:var(--t2);padding:3px 12px;border-radius:var(--r-xs);
  cursor:pointer;white-space:nowrap;border:0;background:none;font-family:var(--font-ui);
  transition:color var(--dur-1),background var(--dur-1)}
.xe-v:hover{color:var(--t1)}
.xe-v.on{background:var(--e0);color:var(--t1);font-weight:600;box-shadow:0 1px 2px var(--sh-1)}
/* ⚠ 同 `.xe-p .n`：`flex:none` 是**显式防御**、非当前失效面（理由与实测见那里）。 */
.xe-v .n{font-family:var(--font-num);font-size:var(--fs-micro);color:var(--t3);margin-left:5px;
  padding:0 5px;border-radius:var(--r-full);background:var(--e0);flex:none}
.xe-v.on .n{color:var(--accent-text);background:var(--accent-wash)}
/* 检索框 —— 2026-09-24 美化：26 → 28px（站头 44 内仍余 8px 上下），
   加 `:focus-within` 焦点环（`--sel` 四主题齐备：深色是 accent 淡染、浅色是棕/绿淡染）。
   ⚠ **不动 `.clr` 的相邻兄弟约定**（`input:not(:placeholder-shown) + .clr`）——
     那是"清空按钮显隐"的唯一接线（显隐刻意交给 CSS），任何 DOM 顺序改动都会**静默失效**。 */
.xe-sbox{display:flex;align-items:center;gap:6px;flex:none;height:28px;padding:0 9px;
  border:1px solid var(--line);border-radius:var(--r-md);background:var(--e0);color:var(--t3);
  transition:border-color var(--dur-1),box-shadow var(--dur-1)}
.xe-sbox:focus-within{border-color:var(--accent-line);box-shadow:0 0 0 3px var(--sel)}
.xe-sbox:focus-within svg{color:var(--accent-text)}
.xe-sbox input{width:150px;border:0;outline:0;background:none;color:var(--t1);
  font-family:var(--font-ui);font-size:var(--fs-caption)}
.xe-sbox input::placeholder{color:var(--t3)}
/* ⚠ `flex:none` + `nowrap`（2026-09-21 顺手修的**既有**瑕疵，非本次需求引入）：
   `.xe-sbox` 是 flex 容器，第 3 个孩子 `.go`（「检索」按钮）默认 `flex-shrink:1`
   ⇒ 窄窗把输入框放到 100% 宽后，它被压到只剩一个字宽，「检索」**竖排成"检/索"两行**。
   这与本项目"不加 hover 才知道能点的"同族：**按钮被压变形**等于入口退化成看不懂的形状。 */
.xe-sbox .go{cursor:pointer;color:var(--t2);font-size:var(--fs-caption);
  padding:0 4px;border:0;background:none;font-family:var(--font-ui);
  flex:none;white-space:nowrap}
.xe-sbox .go:hover{color:var(--t1)}
/* ★ 清空检索（2026-09-23）：显隐**交给 CSS** `:not(:placeholder-shown)`。
   为什么不用 JS 条件渲染（`S.q ? … : ''`）：实时检索走的是**局部重绘**
   （只换 `#xemain`、站头不重建）⇒ 按钮会**停在打字以前的那一刻**
   （打了字它不出现、清空了它不消失，而两种都长得像"这个按钮坏了"）。
   ⇒ 分工：节点在不在 DOM 由渲染决定，**显示与否由输入框自己的内容决定**，两者不打架。
   ⚠ 依赖 `.clr` 紧跟在 `input` 之后（相邻兄弟选择器）—— 改 DOM 顺序会静默失效。 */
.xe-sbox .clr{display:none;flex:none;align-items:center;cursor:pointer;color:var(--t3);
  font-size:var(--fs-caption);line-height:1;padding:0 2px;border:0;background:none;
  font-family:var(--font-ui)}
.xe-sbox input:not(:placeholder-shown) + .clr{display:inline-flex}
.xe-sbox .clr:hover{color:var(--t1)}

/* ── 筛选行（**列表上方唯一一行**）──────────────────────────────────
   2026-09-21 建：平台段（用户点名：抖音 / 视频号 / 快手 / 小红书 / 杉杉）。
   2026-09-23 扩成**五维**（交付 / 时间 / 课程 / 状态 / 手机号）+ 重置 / 刷新 +
   勾选动作条 —— 复杂度红线 ③「筛选只放列表上方**一行**」是硬约束，故：
   整条 `overflow-x:auto`，窄窗**横向滚动**，**不许换行堆高**
   （换行 = 事实上的第二行：列表被顶下去，而这张表本来就要横向滚）。 */
.xe-fbar{display:flex;align-items:center;gap:6px;flex:none;padding:6px 14px;
  border-bottom:1px solid var(--hairline);background:var(--e1);overflow-x:auto;
  box-shadow:inset 0 1px 0 var(--veil)}
.xe-fbar .lb{font-size:var(--fs-micro);color:var(--t3);flex:none;margin-right:2px}
.xe-fseg{display:inline-flex;align-items:center;gap:6px;flex:none}
.xe-fsep{flex:none;width:1px;height:16px;background:var(--line);margin:0 3px}
/* 五维下拉。**用原生 `<select>`** 而非自绘弹出层：弹出层要额外处理"点外面收起"
   （再来一条交互路径 + 一层 z-index），而这一行的宽度预算本来就不够；
   原生控件的键盘 / 无障碍是白拿的。`appearance:none` 抹掉系统外观后用 tokens 重画。 */
.xe-selw{display:inline-flex;align-items:center;gap:5px;flex:none}
.xe-sel{height:24px;padding:0 18px 0 7px;border:1px solid var(--line);
  border-radius:var(--r-full);background:var(--e0);color:var(--t2);
  font-family:var(--font-ui);font-size:var(--fs-caption);cursor:pointer;
  appearance:none;-webkit-appearance:none;max-width:150px;
  background-image:linear-gradient(45deg,transparent 50%,currentColor 50%),
    linear-gradient(135deg,currentColor 50%,transparent 50%);
  background-position:calc(100% - 11px) 50%, calc(100% - 7px) 50%;
  background-size:4px 4px,4px 4px;background-repeat:no-repeat;
  transition:color var(--dur-1),border-color var(--dur-1),box-shadow var(--dur-1)}
/* hover 加底：与 `.xe-p` 同一口径 —— 反馈必须看得见（`--e1` 是这一行的底色，用它会零反馈）。 */
.xe-sel:hover{border-color:var(--line-strong);color:var(--t1);background-color:var(--e2)}
/* ★ 有筛选在生效 ⇒ 与平台按钮同一个 `.on` 语义。
   没有它，「筛了」与「没筛」在屏上同形 —— 用户会以为表里本来就只有这么多单。 */
/* ★ 左侧 3px 色条（2026-09-24 美化）：`.on` 原先只有"底色淡染 + 字色"两件事，
   5 个下拉并排时**扫读极弱**（要逐个读才知道哪几维在生效）。加 `inset` 色条后一眼可见。
   ⚠ 必须用 `inset` 而非 `border-left`：加边框会改盒子宽度 ⇒ 整行宽度抖动，
     而这一行是 `overflow-x:auto` 的，抖动会牵动横向滚动位置（用 `box-shadow` 零副作用）。 */
.xe-sel.on{background-color:var(--accent-wash);border-color:var(--accent-line);
  color:var(--accent-text);font-weight:600;box-shadow:inset 3px 0 0 var(--accent)}
/* 自定义时间区间的两个日期框（只在选了「自定义…」时出现，不占常驻宽度） */
.xe-dtr{display:inline-flex;align-items:center;gap:5px;flex:none}
.xe-dt{height:24px;padding:0 6px;border:1px solid var(--line);border-radius:var(--r-full);
  background:var(--e0);color:var(--t1);font-family:var(--font-num);font-size:var(--fs-micro)}
.xe-dtr .dash{color:var(--t3);font-size:var(--fs-micro)}
/* 勾选动作条（已选计数 + 复制 + 清空）—— **并进上面那一行**，不是第二行。
   ⚠ 计数 `已选 N 单` 是这一块的核心而不是装饰：勾选刻意跨筛选保留 ⇒
     "看不见的已选"必然出现，计数是唯一让它**可见**的东西。 */
.xe-selc{font-size:var(--fs-micro);color:var(--t2);flex:none;white-space:nowrap}
.xe-selc b{font-family:var(--font-num);color:var(--accent-text);font-weight:500}
.xe-p{display:inline-flex;align-items:center;gap:5px;flex:none;cursor:pointer;
  font-size:var(--fs-caption);color:var(--t2);padding:2px 9px;border-radius:var(--r-full);
  border:1px solid var(--line);background:var(--e0);font-family:var(--font-ui);
  transition:color var(--dur-1),background var(--dur-1),border-color var(--dur-1)}
/* hover 底用 `--e2`：`.xe-fbar` 自身是 `--e1` ⇒ 若用 `--e1` 做 hover 会与底同色
   （= 零反馈，正是"能点却看不出来"那一类）。`--e2` 在四主题都与 `--e1` 差一档。 */
.xe-p:hover{color:var(--t1);border-color:var(--line-strong);background:var(--e2)}
.xe-p.on{background:var(--accent-wash);border-color:var(--accent-line);color:var(--accent-text);
  font-weight:600;box-shadow:0 1px 2px var(--sh-1)}
/* 计数胶囊化：数字是"这个平台有多少单"的唯一读数 —— 单独给一枚胶囊底，
   扫读时先认平台名、再认数（比纯文字并排快一档）。
   ⚠ `flex:none` 是**显式防御**（2026-09-24 加），**不是**当前失效面 ——
     实测：把它删掉，`.n` 的 `scrollWidth` 仍等于 `clientWidth`（根本没被压缩）。
     原因：`.xe-p` **自身**就是 `flex:none`、宽度由内容决定 ⇒ 子项没机会被压缩。
     ⚠ 因此**没有**为它写断言：按 R85，写了也只会是恒真。
       （本批确实写了一条，变异自测当场否掉 —— 记录见 `_shot_xiaoe.mjs` 的 125 段。）
     留它的唯一理由是诚实的：胶囊化把"被压缩"从**看不见**变成**看得见**
     （原先 `.n` 是纯文字，压了只显得字窄），若将来有人给 `.xe-fbar` 加宽度上限，
     这里不至于当场变形。
     ⚠ 与 `.xe-v .n` 同族：两处要么都留、要么都不留（只留一处 = 半边防御）。 */
.xe-p .n{font-family:var(--font-num);font-size:var(--fs-micro);color:var(--t3);
  padding:0 5px;border-radius:var(--r-full);background:var(--e3);flex:none}
.xe-p.on .n{color:var(--accent-text);background:var(--e0)}
/* ★ 「上游没给范本」的平台：**不是 0 单**，是"这一维尚无来源" ⇒ 单独的灰态 + 不显示数字。
   把两者画成一样 = 让"没给"和"给了但零"同形（三态不许合并）。
   ⚠★ 2026-09-24 上线前核查修：原先是 `cursor:default` + 单独一条 hover 把高亮**取消掉**
     ——那是在**宣称这个按钮是死的**，而它**是活的**（`data-xepf` 照挂，
     `setPlatform()` 照收，点进去会给出「这个平台没有命中任何订单」+ 出路）。
     "画成不能点、其实能点"与"能点却要 hover 才知道"是同一枚硬币的两面，
     都是让外观对能力撒谎（本项目明确排除的形态）。
     ⇒ 去掉那两处"装死"：指针与 hover 反馈走 `.xe-p` 的**同一套**规则，
       灰态只由**颜色 + 虚线边框 + 不显示数字**表达（这三样已经足以区分三态）。 */
.xe-p.ns{color:var(--t3);border-style:dashed;background:none}
.xe-p.ns .n{display:none}

/* ── 口径提示条（金额 / 交付率的口径警告，逐平台）──────────────────── */
.xe-note{margin:9px 14px 0;padding:7px 10px;border-radius:var(--r-sm);
  border:1px solid var(--amber-line);background:var(--e0);color:var(--t2);
  font-size:var(--fs-micro);line-height:1.65}
.xe-note b{color:var(--t1);font-weight:500}
.xe-note.plain{border-color:var(--line)}

/* ── 读数带 ─────────────────────────────────────────────────────────
   2026-09-24 美化：由"一条连体格"改成**分卡组**（gap:8 + 每格独立边框/圆角/阴影）。
   ★ 为什么改（不只是好看）：连体格靠 `.xe-k{border-right:1px solid var(--hairline)}` 分隔，
     而 `--hairline` 在 **A/B 两主题是 `transparent`** ⇒ 深色主题下 4 个读数**糊成一片**，
     浅色（C/D）才有一条淡线 —— 同一张屏在四主题下观感不一致。
     改成独立卡后，分隔由"卡与卡之间的空隙"承担 ⇒ **与主题无关、恒定成立**。
   ⚠ 语义色从 `.v` **同时**挂到卡片本身（`.xe-k.ok` / `.xe-k.bad`，见 `kpi()`）——
     用于左缘 3px 色条：数字色只影响那一行数字，色条让"哪一格异常"在余光里就可见。
   ⚠ 刻意**不用** `:has()` 反查子元素：headless Chrome 版本不可控，且 `:has()` 一旦不支持
     会**静默**退化成"没有色条"（不报错）—— 本仓对这类"降级不报错"最忌讳。 */
.xe-kpi{display:flex;gap:8px;flex:none;margin:9px 14px 0;border:0;background:none;
  overflow:visible}
.xe-k{flex:1 1 0;min-width:0;padding:9px 12px;border:1px solid var(--line);
  border-radius:var(--r-md);background:var(--e0);box-shadow:0 1px 2px var(--sh-1);
  position:relative;overflow:hidden}
/* 顶缘 1px 高光：深色主题下微亮、浅色下微暗（`--veil` 四主题齐备）⇒ 卡片读起来是"一个面"。 */
.xe-k::after{content:'';position:absolute;left:0;right:0;top:0;height:1px;background:var(--veil)}
/* 左缘状态条：无 tone 时只是 `--line`（一个装饰位），有 tone 才上语义色。 */
.xe-k::before{content:'';position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--line)}
.xe-k.ok::before{background:var(--accent)}
.xe-k.bad::before{background:var(--danger)}
.xe-k .l{display:block;font-size:var(--fs-micro);color:var(--t3);white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}
.xe-k .v{display:block;font-family:var(--font-num);font-size:var(--fs-num);color:var(--t1);
  font-weight:600;margin-top:3px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.xe-k .v.sm{font-size:var(--fs-small)}
.xe-k .v.dim{color:var(--t3)}
.xe-k .s{display:block;font-size:var(--fs-micro);color:var(--t3);margin-top:1px}
.xe-k .v.ok{color:var(--accent-text)}
.xe-k .v.bad{color:var(--danger-text)}

/* ── 内容层（唯一滚动容器）────────────────────────────────────────── */
.xe-body{flex:1 1 auto;min-height:0;overflow:auto;padding:10px 14px 16px}

/* ── 订单表 ───────────────────────────────────────────────────────── */
/* ⚠ `overflow-x:auto` 是**防御**，不是"要横滚"（2026-09-21 第二批补，12 列后必须）
   —— 原值是 `overflow:hidden`，一旦表格最小宽度超过容器，**它会静默裁掉右边的列**，
      而最右一列恰恰是「详情」入口 ⇒ 屏幕上看不出报错、只是"点不着"，
      正是本仓血例「逻辑全对、入口没有」最省事的那种复现方式。
      换成 `auto`：不溢出时**行为与 hidden 完全一致**（不出条、照样裁圆角），
      溢出时才兜底可滚。`overflow-y:hidden` + 高度自适应 ⇒ 纵向永远不出条。 */
.xe-tw{border:1px solid var(--line);border-radius:var(--r-md);
  overflow-x:auto;overflow-y:hidden;background:var(--e0);box-shadow:0 1px 2px var(--sh-1)}
.xe-tbl{width:100%;border-collapse:collapse;font-size:var(--fs-caption)}
.xe-tbl thead th{position:sticky;top:0;z-index:1;text-align:left;font-weight:500;
  color:var(--t2);font-size:var(--fs-micro);padding:7px 9px;white-space:nowrap;
  letter-spacing:.3px;background:var(--e3);border-bottom:1px solid var(--line)}
/* ⚠★ 行分隔线由 `--hairline` 改 `--line`（2026-09-24 美化批次**顺手修的真缺陷**）：
   `--hairline` 只在 **C/D 两主题**有值（`rgba(62,52,38,.16)` / `rgba(34,48,44,.16)`），
   在 **A/B 是 `transparent`** ⇒ 深色主题下**整张 14 列表格没有行线**，
   而这一张表是"一行 = 一单"的宽表，读者要靠行线横向追踪（跨 14 列读一行）——
   没有行线时只能靠 hover，等于"要交互才读得出来"（本项目明确排除的形态同族）。
   ⇒ 分隔线属于**功能性**而非装饰，必须四主题齐备：`--line` 在四主题都有值（A 是 .055 白）。
   回滚方式：把这一条改回 `--hairline` 即可（只有一个落点）。 */
.xe-tbl tbody td{padding:7px 9px;color:var(--t1);border-bottom:1px solid var(--line);
  vertical-align:top}
.xe-tbl tbody tr:last-child td{border-bottom:0}
/* ★ 行 hover：底色 + **左缘 2px 色条**（2026-09-24 美化）。
   ⚠ 色条只能挂 `td:first-child`：`box-shadow` 挂在**每个** `td` 上会在**每列左缘**各画
     一条竖线（列与列之间排成竖条纹）—— 那是"看着像装饰、实则量错了落点"的典型。
   第一格是最左的勾选列（`.xe-tds`），它的左缘 = 整行的左缘。 */
.xe-tbl tbody tr:hover td{background:var(--e1)}
.xe-tbl tbody tr:hover td:first-child{box-shadow:inset 2px 0 0 var(--accent)}
.xe-tbl .num{font-family:var(--font-num);white-space:nowrap;text-align:right}
.xe-tbl .dim{color:var(--t3)}
.xe-tbl .mono{font-family:var(--font-num);font-size:var(--fs-micro);color:var(--t2)}
/* ⚠★ 本列**只有上限、没有下限** —— 这是 2026-09-27 那处真缺陷的根：
   视口 ≤1300 时它被压到 47–51px ⇒ 中文**每行 1–2 个字竖排**、课程名折成 **10 行**、行高 **185px**。
   【机制】`.xe-tbl{width:100%}` + 表头 `th{white-space:nowrap}` ⇒ 其余 13 列的最小宽度
     被表头文字钉死；而「课程」是**唯一可折行**的列 ⇒ 宽度亏空**全部**压在这一列上。
     ⚠ CJK 任意两字之间都可断行 ⇒ 它的 min-content 只有 **1 个字**宽。
   【❌ 下限**不能**写在这里（写成全局 `min-width`）—— 实测证伪，血例在案】
     第 3 轮曾把它写成 `.xe-tbl .cr{max-width:230px;min-width:116px}`（全局），
     在**每页 20 行**下量得"1200 档横溢回落到 0、1440 档逐项不变"⇒ 看似完美。
     但**每页 100 行**时（`xiaoe.mjs` §16 用的正是这一档）：1440 档本列的既有宽度只有 **92px**
     —— auto 表格布局的列宽取决于**全部行的内容**，不只看首屏 ⇒ 下限把它顶到 116px ⇒
     **整表最小宽度越过容器** ⇒ 全表落到 min-content ⇒ 连带压窄别的列 ⇒
     行高 49 → 66px、`xe-tw` 5765 → 6649、**横溢 0 → 9px**（= 在默认宽度上凭空多出一条横滚条）。
   【✔ 正确落点 = 下面那条 `@media (max-width:1300px)`】下限只许在"**本来就装不下**"的档位生效。
   【回滚】删掉 `@media (max-width:1300px)` 段里的 `min-width` 即可（单点）。 */
.xe-tbl .cr{max-width:230px}

/* ★ 客户详情列（末列，2026-10-17 起）—— 入口必须**常驻可见**
   （复杂度红线 ④：不加 hover 才知道能点的）。表头写「客户详情」当图例、单元格写「详情」；
   窄窗**不砍这一列** —— 砍掉入口就是把功能删了，而不是"适配"。
   ⚠ 订单详情入口改在**平台订单号**（`.ono.xod`）上，行本身**不再可点**（不再给整行 pointer）。 */
.xe-tbl thead th.xe-tdc{width:1%;white-space:nowrap;text-align:right;color:var(--t3)}
.xe-tbl tbody td.xe-tdc{width:1%;white-space:nowrap;text-align:right;color:var(--t3)}
/* ── 勾选列（2026-09-23，最左一列）──────────────────────────────────
   ⚠ 列宽 `1%` + `nowrap`：这一列的全部内容就一个 13px 的勾选框，
     让它参与剩余宽度分配会把另外 13 列的宽度全挤歪。
   ⚠ `accent-color` 用 token —— 四主题各自取色，不用为深色主题另写一套
     （勾选框是原生控件，`background` 改不动它，只有 `accent-color` 有效）。 */
.xe-tbl thead th.xe-tds{width:1%;white-space:nowrap;padding-right:0}
.xe-tbl tbody td.xe-tds{width:1%;white-space:nowrap;padding-right:0}
.xe-ck{width:13px;height:13px;margin:0;cursor:pointer;vertical-align:middle;
  accent-color:var(--accent-text);flex:none}
/* ── 订单详情（抽屉 · 2026-10-17 起，原行内展开已撤）──────────────────────
   详情体 `.xe-dtl` 现在塞进 `#xeodtl` 抽屉的 `.dtl-bd` 里（见 index.html）。
   旧的 `.xe-tgl`/`tr.xe-op`/`tr.xe-oc`/`.xe-detc`（行内展开的箭头、高亮、详情行、
   「收起」头）已随行内展开一起下线。 */
.xe-dtl{display:flex;flex-direction:column;gap:12px;padding:12px 13px 13px}
/* ★ 订单详情抽屉（2026-10-17）：`.xe-dtl` 塞进客户抽屉的 `.dtl-bd` 里时，
   `.dtl-bd` 已给内边距 ⇒ 去掉 `.xe-dtl` 自带的那层，否则双重缩进。 */
.dtl-bd > .xe-dtl{padding:0}
/* 抽屉头「来源 / 单号」里的等宽串：`.mono` 是 `.xe-tbl` 作用域，抽屉头不在表里 ⇒
   这里补一份（等宽 = 订单号位数可读）。 */
.dtl-hd .dh-st .mono{font-family:var(--font-num);font-size:var(--fs-micro);color:var(--t2)}
/* 交付判定条：把本站恒等式（小鹅通订单号非空 ⟺ 领课成功）印在屏上 ——
   列表里的「已交付/未交付/无法判」徽**不给理由**，这里给。 */
.xe-vd{display:flex;align-items:baseline;gap:8px;padding:7px 10px;border-radius:var(--r-sm);
  border:1px solid var(--line);border-left-width:3px;background:var(--e0);
  font-size:var(--fs-micro);color:var(--t2);line-height:1.65}
.xe-vd b{flex:none;font-size:var(--fs-caption);font-weight:500}
/* 状态圆点：`currentColor` ⇒ 一条规则跟着 `.ok/.no/.na` 各自变色（写三份 = 同族散落）。 */
.xe-vd b::before{content:'';display:inline-block;width:7px;height:7px;
  border-radius:var(--r-full);background:currentColor;margin-right:6px;vertical-align:middle}
.xe-vd.ok{border-color:var(--accent-line);border-left-color:var(--accent);
  color:var(--accent-text);background:var(--accent-wash)}
.xe-vd.no{border-color:var(--danger-line);border-left-color:var(--danger);
  color:var(--danger-text)}
.xe-vd.na{border-style:dashed}
/* ⚠★ 由 `--hairline` 改 `--line`：`--hairline` 在 A/B 是 `transparent` ⇒
   深色主题下**详情区的 5 个分区之间没有任何分隔线**，字段糊成一片。
   （与表体行线同一个根因、同批修 —— 见 `.xe-tbl tbody td` 那条注释。） */
.xe-dsec{border-top:1px solid var(--line);padding-top:10px}
/* 分节标题 + 尾随横线（2026-09-24 美化）：`订单 ──────────` 这种形态让 5 个分区
   在长详情里形成清晰的"章节"节奏（此前是一行灰字，与字段标签同语气、读不出层级）。 */
.xe-dsec > .h{display:flex;align-items:center;gap:8px;font-size:var(--fs-micro);
  color:var(--t3);margin-bottom:8px}
.xe-dsec > .h::after{content:'';flex:1 1 auto;height:1px;background:var(--line)}
.xe-fg{display:grid;gap:8px 10px;grid-template-columns:repeat(auto-fill,minmax(168px,1fr))}
/* 字段卡化（2026-09-24 美化）：每个字段从"标签 + 值两行裸文本"改成一张浅卡。
   底用 `--e1` —— 它在四主题都**比所在层（`.dtl-bd` 的 `--e1`）深一档** ⇒ 恒定读作"凹陷"，
   "哪个标签配哪个值"因此不用靠留白去猜。
   ⚠ 边框保留 `--hairline` 是**刻意的**：层次已由底色表达，这一道边只是给 C/D 两主题
     补一条细线，深色主题不该再多一个框（同一属性在两个主题下有无，是这里唯一的例外）。 */
.xe-f{min-width:0;padding:6px 9px;border-radius:var(--r-sm);background:var(--e1);
  border:1px solid var(--hairline)}
.xe-f i{display:block;font-style:normal;font-size:var(--fs-micro);color:var(--t3);
  margin-bottom:3px}
.xe-f b{display:block;font-weight:400;font-size:var(--fs-caption);color:var(--t1);
  line-height:1.5;word-break:break-all}
.xe-f b .mono{font-family:var(--font-num);font-size:var(--fs-micro);color:var(--t2)}
.xe-f .w{display:block;font-size:var(--fs-micro);color:var(--t3);margin-top:1px}
.xe-f.dim b{color:var(--t3)}
/* ★ 三态之二（**不许与 `.dim` 的 `—` 同形**）：上游压根没有这一列 ——
   虚线灰字。与 `.dim` 的 `—`（有这列、这行为空）分开：
   前者要去找平台要这一列，后者是这条单本身如此。 */
.xe-f.na b{color:var(--t3);font-size:var(--fs-micro);display:inline-block;
  border-bottom:1px dashed var(--line-strong)}

/* 徽（平台 / 状态 / 交付）*/
.xe-bi{display:inline-block;font-size:var(--fs-micro);padding:1px 6px;border-radius:var(--r-xs);
  border:1px solid var(--line);color:var(--t2);white-space:nowrap;background:var(--e0)}
.xe-bi.pf{border-color:var(--accent-line);color:var(--accent-text)}
/* ★ 交付徽**三态**：已交付 / 未交付 / 无法判（上游没给领课列）。
   「无法判」不许画成「未交付」—— 那是拿一个不存在的维度当结论。 */
.xe-bi.ok{border-color:var(--accent-line);color:var(--accent-text);background:var(--accent-wash)}
.xe-bi.no{border-color:var(--danger-line);color:var(--danger-text)}
.xe-bi.na{border-style:dashed;color:var(--t3)}
.xe-bi.st-done{border-color:var(--accent-line);color:var(--accent-text)}
.xe-bi.st-paid{color:var(--t2)}
.xe-bi.st-shipped{border-color:var(--amber-line);color:var(--amber)}
.xe-bi.st-canceled,.xe-bi.st-refunded{border-color:var(--danger-line);color:var(--danger-text)}
/* ★ 领课状态徽的**中间态**（2026-09-21 第二批）：上游原值「链接已点击未领取」——
   客户进过领课链接、但没领到手。**不许**并进 `.no`：这批人是最该去追的
   （有意向、卡在最后一步），与「链接未点击」的处置完全不同。 */
.xe-bi.mid{border-color:var(--amber-line);color:var(--amber)}

/* ★ 列表单元格的「没数据」三态（2026-09-21 第二批）—— 与详情格 `.xe-f.na` /
   `.xe-f .w` **同一套语义**，但这里是**列表形态**：一格一值、放不下"整列未填"那行
   小字 ⇒ 区别靠**下划线**做，全文解释交给 `title`（见 `naCell()`）。
   ⚠ `.hard`（上游压根没这一列）用虚线，与普通 `—`（有这一列、这行为空）**不同形**；
     合并的话，读者会把"平台不给这个维度"读成"这一单漏填了"。 */
.xe-tbl .xe-na{color:var(--t3)}
.xe-tbl .xe-na.hard{border-bottom:1px dashed var(--line-strong);cursor:help}
/* ★ 平台订单号列（第 5 列）：等宽 + 不折行 —— 26 位串一旦折行，**位数就读不出来了**。
   上限 186px 只在**异常长**时生效（实测该列宽 90px）⇒ 正常订单号**永远完整**。 */
.xe-tbl .ono{display:inline-block;max-width:186px;overflow:hidden;
  text-overflow:ellipsis;vertical-align:bottom}
/* ★ 平台订单号 = 订单详情抽屉入口（2026-10-17）：可点提示用 accent 色 + 手型 + 悬停下划线
   （本仓既有"这里能点"语言，见 `.crm .ftbl .op`）。不靠 hover 才发现能点。 */
.xe-tbl .ono.xod{cursor:pointer;color:var(--accent-text)}
.xe-tbl .ono.xod:hover{text-decoration:underline}
.xe-tbl .ono.xod:focus-visible{outline:2px solid var(--focus);outline-offset:1px}
/* ★ 「客户详情」入口（原「详情」列 · 2026-10-17）：与 `.xod` 同一套可点语言。 */
.xe-tbl .xe-ccrm{color:var(--accent-text);cursor:pointer;font-size:var(--fs-caption);
  white-space:nowrap}
.xe-tbl .xe-ccrm:hover{text-decoration:underline}
.xe-tbl .xe-ccrm:focus-visible{outline:2px solid var(--focus);outline-offset:1px}
/* ★ 长串兜底（2026-09-21 第二批）：上游偶有 32 位脱敏串落在「下单人 / 手机号」列
   （实测 `小红书:56` 一行，两列都是 `#pDEkQ68t6z…`），把这两列从 ~80px 撑到
   237 / 226px。**只在超长时**才套它（阈值在 `longw()` 里，14 字）——
   正常值走原路径 ⇒ 11 位手机号不会被截断。 */
.xe-tbl .lw{display:inline-block;max-width:118px;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom;cursor:help}

/* ── 分页条（2026-09-24 新增 · 用户原话「加个分页，20，50.100 的分页，
      默认小鹅通打开 20 分页」）────────────────────────────────────────
   ★ 放在**表格下方**（`.xe-tw` 之外）：上面那一行是"筛选唯一一行"（红线 ③）已满编，
     而 `.xe-tw` 本身是**横向滚动容器** ⇒ 页码条放里面会跟着横滚跑掉。
   ★ 沿用 `.xe-fbar` 的**同一套**横向滚动策略（窄窗横滚、不换行堆高）：
     它承载的是"每页多少行 + 当前位置 + 总数"三件事，挤成一列反而读不出来。
   ⚠ 只许用令牌（本文件纪律 1：不得出现字面色值）。 */
.xe-pager{display:flex;align-items:center;gap:6px;flex:none;flex-wrap:nowrap;
  margin:9px 0 0;padding:6px 2px 0;border-top:1px solid var(--hairline);
  overflow-x:auto;font-size:var(--fs-micro);color:var(--t3)}
/* ★ 区间 + 总数**必须**在一起（`显示 1–20 / 共 3089 单`）：
   只写"每页 20"看不出后面还有多少；只写总数看不出当前在哪一段。
   分页天然会把行藏起来 ⇒ 这两件事是"我为什么只看到这些"的全部解释。 */
.xe-pginfo{flex:none;white-space:nowrap;color:var(--t2)}
.xe-pginfo b{font-family:var(--font-num);color:var(--t1);font-weight:600}
/* 页码胶囊化（2026-09-24 美化）：`第 N/M 页` 混在一行灰字里最不显眼，而它恰恰是
   "我在哪一页"的唯一读数 ⇒ 给一枚 `--e3` 胶囊把它顶出来。 */
.xe-pgno{flex:none;white-space:nowrap;font-family:var(--font-num);color:var(--t2);
  padding:2px 9px;border-radius:var(--r-full);background:var(--e3)}
.xe-pgno b{color:var(--t1);font-weight:600}
/* 每页档位按钮：与平台分段钮（`.xe-p`）**刻意不同形**（方角小钮而非胶囊）——
   两者都是"选一个"，但一个改筛选结果集、一个只改显示密度，同形会被当成同一件事。
   ★ 2026-09-24 美化：三档**粘连成一个段控件**（`.xe-pgps` 包一层 —— CSS 与 `pagerHtml()`
     同批改，缺任一半都会退化成"三枚方角小钮挤在一起"）。
     三枚独立小钮读起来像三个无关按钮；粘连后「20 50 100」读作一件事（选显示密度）。
   ⚠ `margin-left:-1px` 让相邻边框叠成一条；`.on`/`:hover` 抬 `z-index` 保证自己的边框
     在上，否则选中态的左/右边框会被相邻那枚盖掉（看着像"边框缺了半条"）。 */
.xe-pgps{display:inline-flex;flex:none;align-items:center}
.xe-psb{flex:none;height:22px;padding:0 8px;border-radius:0;margin-left:-1px;
  border:1px solid var(--line);background:var(--e0);color:var(--t2);cursor:pointer;
  font-family:var(--font-num);font-size:var(--fs-micro);
  transition:color var(--dur-1),background var(--dur-1),border-color var(--dur-1)}
.xe-pgps .xe-psb:first-child{border-radius:var(--r-xs) 0 0 var(--r-xs);margin-left:0}
.xe-pgps .xe-psb:last-child{border-radius:0 var(--r-xs) var(--r-xs) 0}
.xe-psb:hover{border-color:var(--line-strong);color:var(--t1);background:var(--e2);
  position:relative;z-index:1}
.xe-psb.on{background:var(--accent-wash);border-color:var(--accent-line);
  color:var(--accent-text);font-weight:600;position:relative;z-index:1}
/* 边界态（第 1 页的「上一页」/ 末页的「下一页」）：用 `disabled` 真禁用，
   **不是**画成灰但还能点 —— "点了没反应"与"到头了"是两件事。 */
.xe-pager .xe-btn:disabled{opacity:.45;cursor:default}
.xe-pager .xe-btn:disabled:hover{border-color:var(--line-strong);color:var(--t1)}

/* ── 课程卡（课程管理）────────────────────────────────────────────── */
.xe-cgrid{display:grid;gap:9px;grid-template-columns:repeat(auto-fill,minmax(268px,1fr))}
.xe-cc{border:1px solid var(--line);border-radius:var(--r-md);background:var(--e0);
  padding:10px 11px;display:flex;flex-direction:column;gap:7px;min-width:0;
  box-shadow:0 1px 2px var(--sh-1);
  transition:border-color var(--dur-1),box-shadow var(--dur-1)}
/* 悬停抬起（2026-09-24 美化）：课程卡是"可扫读的一组"，有悬停反馈才读作"卡"。
   ⚠ 只改边框色与阴影，**刻意不动 `transform`** —— 位移会带来亚像素错位
     （长课程名换行时尤其明显），也会牵动 `.xe-cgrid` 的整体重排。 */
.xe-cc:hover{border-color:var(--line-strong);box-shadow:0 2px 6px var(--sh-1)}
.xe-cc .tt{display:flex;align-items:flex-start;gap:6px}
.xe-cc .cn{flex:1 1 auto;min-width:0;font-size:var(--fs-small);color:var(--t1);
  font-weight:600;line-height:1.4;word-break:break-all}
.xe-cc .meta{display:flex;flex-wrap:wrap;gap:5px}
/* 行内细线（2026-09-24 美化）：6 行「标签 …… 值」此前只靠行距分组，加线后每行自成一条
   （最后一行去线，避免与卡片下内边距叠成"双线"）。 */
.xe-cc .rows{display:flex;flex-direction:column;gap:0;font-size:var(--fs-micro);color:var(--t2)}
.xe-cc .rows .r{display:flex;justify-content:space-between;gap:8px;
  padding:3px 0;border-bottom:1px solid var(--line)}
.xe-cc .rows .r:last-child{border-bottom:0;padding-bottom:0}
.xe-cc .rows .r b{font-family:var(--font-num);color:var(--t1);font-weight:600}
.xe-cc .bar{height:6px;border-radius:var(--r-full);background:var(--e3);overflow:hidden}
.xe-cc .bar i{display:block;height:100%;background:var(--accent);border-radius:var(--r-full)}
/* 疑似非课程 / 交付无法判：左缘 3px —— 与 `.xe-vd`、`.xe-err` 同一口径（语义条一律在左缘）。 */
.xe-cc .gd{border:1px dashed var(--danger-line);border-left-width:3px;color:var(--danger-text);
  font-size:var(--fs-micro);padding:3px 7px;border-radius:var(--r-xs);line-height:1.5}

/* ── 导入视图 ─────────────────────────────────────────────────────── */
.xe-imp{display:flex;flex-direction:column;gap:9px}
.xe-step{border:1px solid var(--line);border-radius:var(--r-md);background:var(--e0);
  padding:10px 11px;box-shadow:0 1px 2px var(--sh-1)}
.xe-step > .h{display:flex;align-items:center;gap:7px;margin-bottom:8px}
/* 步骤号（2026-09-24 美化）：18 → 20px + **外光圈**。
   ⚠ 光圈刻意不用 `--accent-wash`：它与徽章**自身**的底色同值 ⇒ 光圈会在底色里消失
     （"加了个看不见的东西"，属于本仓最忌讳的形态）。`--sel` 是四主题齐备的淡染，
     在深色与浅色下都能与 `--accent-wash` 拉开一档。 */
.xe-step > .h .i{flex:none;width:20px;height:20px;border-radius:var(--r-full);
  background:var(--accent-wash);border:1px solid var(--accent-line);color:var(--accent-text);
  font-family:var(--font-num);font-size:var(--fs-micro);font-weight:600;display:flex;
  align-items:center;justify-content:center;box-shadow:0 0 0 3px var(--sel)}
.xe-step > .h .t{font-size:var(--fs-small);color:var(--t1);font-weight:600}
.xe-step > .h .d{font-size:var(--fs-micro);color:var(--t3);flex:1 1 auto;min-width:0}
.xe-ippf{display:flex;flex-wrap:wrap;gap:6px}
.xe-ta{width:100%;min-height:118px;resize:vertical;border:1px solid var(--line);
  border-radius:var(--r-sm);background:var(--e2);color:var(--t1);padding:8px 9px;
  font-family:var(--font-num);font-size:var(--fs-micro);line-height:1.6;outline:0;
  transition:border-color var(--dur-1),box-shadow var(--dur-1)}
/* 焦点环：与 `.xe-sbox:focus-within` 同一口径（`--sel` 淡染）——
   这一页的粘贴框是**主要输入面**，焦点可见性比筛选条那一行更要紧。 */
.xe-ta:focus{border-color:var(--accent-line);box-shadow:0 0 0 3px var(--sel)}
.xe-ta::placeholder{color:var(--t3)}
.xe-acts{display:flex;align-items:center;gap:7px;flex-wrap:wrap;margin-top:8px}
.xe-btn{font-family:var(--font-ui);font-size:var(--fs-caption);color:var(--t1);
  padding:4px 12px;border-radius:var(--r-sm);border:1px solid var(--line-strong);
  background:var(--e0);cursor:pointer}
.xe-btn:hover{border-color:var(--accent-line);color:var(--accent-text)}
.xe-btn.pri{background:var(--accent-wash);border-color:var(--accent-line);
  color:var(--accent-text);font-weight:500}
/* 筛选行里的紧凑按钮（重置 / 刷新 / 复制…）—— 与 `.xe-dtl .xe-btn` 同一个思路：
   这一行的高度预算只有 24px，用默认 `padding:4px 12px` 会把整条撑高。
   `flex:none` + `nowrap` 同 `.go` 那条：宁可不换行，也不许被压成竖排两行。 */
.xe-btn.sm{height:24px;padding:0 9px;font-size:var(--fs-micro);border-radius:var(--r-full);
  flex:none;white-space:nowrap}
.xe-file{font-family:var(--font-ui);font-size:var(--fs-micro);color:var(--t3)}
.xe-map{display:flex;flex-wrap:wrap;gap:5px}
.xe-m{display:inline-flex;align-items:center;gap:5px;font-size:var(--fs-micro);
  padding:2px 7px;border-radius:var(--r-xs);border:1px solid var(--accent-line);
  color:var(--accent-text);background:var(--accent-wash)}
.xe-m.un{border-color:var(--line);border-style:dashed;color:var(--t3);background:none}
.xe-m .f{font-family:var(--font-num);color:var(--t3)}
.xe-plangrid{display:grid;gap:7px;grid-template-columns:repeat(auto-fill,minmax(158px,1fr))}
/* 左缘 3px **实色**语义条（2026-09-24 美化）：八格预检读数里 new/warn/bad 三态原先只差
   **边框色**，而边框色是 `*-line`（26–30% 淡染）—— 八格并排时扫读极弱。
   ⚠ 左缘必须用**实色**（`--accent` / `--amber` / `--danger`）：拿 `*-line` 做 3px 条
     会糊在底色里，等于没加（"加了个看不见的东西"）。
   ★ 与 `.xe-vd` / `.xe-err` / `.xe-cc .gd` 同一口径：**语义条一律在左缘、一律实色**。 */
.xe-pl{border:1px solid var(--line);border-left:3px solid var(--line);
  border-radius:var(--r-sm);background:var(--e1);padding:8px 9px}
.xe-pl .l{font-size:var(--fs-micro);color:var(--t3)}
.xe-pl .v{font-family:var(--font-num);font-size:var(--fs-num);color:var(--t1);
  font-weight:600;margin-top:2px}
.xe-pl .v.z{color:var(--t3);font-weight:400}
.xe-pl.new{border-color:var(--accent-line);border-left-color:var(--accent);
  background:var(--accent-wash)}
.xe-pl.warn{border-color:var(--amber-line);border-left-color:var(--amber)}
.xe-pl.bad{border-color:var(--danger-line);border-left-color:var(--danger)}
.xe-cta{margin-top:9px;padding:8px 10px;border-radius:var(--r-sm);
  border:1px solid var(--amber-line);background:var(--e0);font-size:var(--fs-micro);
  color:var(--t2);line-height:1.7}
.xe-cta b{color:var(--t1);font-weight:500}

/* ── 空态 / 错态 / 忙态（★ 三个类，绝不合并）────────────────────────
   2026-09-24 美化：三者各补一个"形状"，让它们在一屏里**一眼可辨** ——
   此前三张脸都是"一段灰字"，差别只在文字内容。 */
/* 空态：一枚虚线圈当图标位。
   ⚠ 用 `::before` 而非插一段内联 SVG：三处 `.xe-empty` 都由 JS 生成，改 JS 会多一处
     落点，而伪元素是**零结构改动**（判据只数 `.xe-empty` 的个数、不查子树）。 */
.xe-empty{margin:26px 0;text-align:center;color:var(--t3);font-size:var(--fs-caption);
  line-height:1.9}
.xe-empty::before{content:'';display:block;width:34px;height:34px;margin:0 auto 10px;
  border:1.5px dashed var(--line-strong);border-radius:var(--r-full)}
.xe-empty .big{display:block;font-size:var(--fs-small);color:var(--t1);font-weight:600;
  margin-bottom:4px}
/* 错态：左缘实色条（与 `.xe-vd.no` / `.xe-pl.bad` 同一口径）。
   ⚠ 用把同一条边加宽、而不是叠一层 `box-shadow`：错态本就有一条红边，
     加宽它最省，也不会与框内 `<b>`（"取数失败"）抢注意力。 */
.xe-err{margin:12px 0;padding:9px 11px;border-radius:var(--r-sm);
  border:1px solid var(--danger-line);border-left:3px solid var(--danger);
  background:var(--e0);color:var(--danger-text);
  font-size:var(--fs-caption);line-height:1.7}
/* 忙态：脉冲圆点（全文件**唯一**带动画的地方）。
   ⚠ 动画只许改 `opacity`（不动尺寸/位移）：出图脚本靠"等目标元素出现"取图，
     凡改布局的动画都会让截图可能落在两个状态之间（图看着"歪了一点"，且不报错）。 */
.xe-busy{margin:26px 0;text-align:center;color:var(--t3);font-size:var(--fs-caption)}
.xe-busy::before{content:'';display:inline-block;width:7px;height:7px;margin-right:8px;
  border-radius:var(--r-full);background:var(--accent);vertical-align:middle;
  animation:xe-pulse 1.3s ease-in-out infinite}
@keyframes xe-pulse{0%,100%{opacity:.22}50%{opacity:1}}
.xe-snap{margin-top:9px;font-size:var(--fs-micro);color:var(--t3);line-height:1.7}
.xe-snap b{color:var(--t2);font-weight:500}

/* ── 滚动条（2026-09-24 新增 · 本站此前是**唯一漏做**的站）──────────────
   其余 4 个站各自定义过 `::-webkit-scrollbar`（chat / customers / shell…），本站漏了 ⇒
   深色主题下列表用的是**系统亮色滚动条**，与整片深色割裂 —— 而 `.xe-body` 是全站
   **唯一纵向滚动容器**、出现频率最高，这一处漏得最显眼。
   颜色只用 `--scroll`（四主题齐备：深色 .14 白 / 浅色 .26 深）。
   ⚠ 三条横向容器（筛选行 / 分页条 / 表格）写 `height` 而非 `width`。 */
.xe-body::-webkit-scrollbar{width:9px}
.xe-body::-webkit-scrollbar-thumb{background:var(--scroll);border-radius:5px}
.xe-body::-webkit-scrollbar-track{background:transparent}
.xe-fbar::-webkit-scrollbar,.xe-pager::-webkit-scrollbar,.xe-tw::-webkit-scrollbar{height:9px}
.xe-fbar::-webkit-scrollbar-thumb,.xe-pager::-webkit-scrollbar-thumb,
.xe-tw::-webkit-scrollbar-thumb{background:var(--scroll);border-radius:5px}
.xe-fbar::-webkit-scrollbar-track,.xe-pager::-webkit-scrollbar-track,
.xe-tw::-webkit-scrollbar-track{background:transparent}
/* 分页条的撑开位（2026-09-24 修——**意图一直在、CSS 漏了**）：
   `pagerHtml()` 一直在渲染 `<span class="sp"></span>`（意图 = 左信息 / 右控件分组），
   而全文件只有 `.xe-hd .sp{flex:1 1 auto}` 一条 ⇒ 分页条里那个 `.sp`
   **拿不到任何样式**、不撑开，于是信息、翻页钮、每页档位全部挤在左边。
   症状与"本来就该这么排"完全同形（不报错、不缺失、只是难看）——正是本仓最防的一类。
   ⚠ 用直接子选择器 `>`：`.xe-hd .sp` 是后代选择器、在窄窗被 `display:none`，
     两者必须各自独立（否则改一处会影响另一处）。 */
.xe-pager > .sp{flex:1 1 auto}

/* ★★ 2026-09-27 宽档兜底（≤1300）：**把宽度还给「课程」列** + 收回多余的内边距
   【两条声明为什么必须成对】下限（`min-width:116px`）会让 14 列的最小宽度涨约 116px ⇒
   在 1200 档本来就会**新增一条横滚条**、并把末列「详情」推出可视区
   —— 那正是 `data.js` 记的 v2 血例形态（末列被推 ⇒ 行操作**点不到**、屏幕上看不出报错）。
   同段把水平内边距 9 → 6（14 列共让出 84px）正好抵消 ⇒ 档位回到"零横溢"。
   【为什么上界取 1300 —— 实测过的数，不是拍的】
     · `每页 20 行`：1440→230px · 1300→126px（**下限在此已免费**，本列本来就 >116）
     · `每页 100 行`：1300→下限生效后横溢 84 → **74（比改前还小）** ⇒ 免费
     · 而 **1440 × 每页 100**：下限会把整表顶过预算（横溢 0 → 9px）⇒ **有代价**
     ⇒ 安全的切点落在 1300 与 1440 之间；**取实测免费侧的上界 1300**（保守），
       1301–1439 维持原行为（不改）。
   【实测收益（`_probe_xefix.mjs`，全程零落盘 · 7 视口宽 × 2 每页档）】
     · 1440（两个每页档）**逐项完全不变** ⇒ 默认宽度零回归
     · 1300/1240：课程列 126/81 → **188/149**、折行 3–4 → **2**、表高 1284/1658 → **987**
     · 1200：课程列 51 → **123**、折行 10 → **3**、行高 185 → **64**、表高 3392 → **1327**
     · 1100/1024：课程列 51 → **116**、折行 10 → **3**、表高 3401 → **1336**
     · `每页 100 行 @1024`：表高 **12183 → 6456**、内容总高 12586 → 6859
     · 949/900：上限那个视觉缺陷同样修好（课程列 47 → 116、折行 10 → 3）；
       代价 = 横溢 +44px（**这两档本来就横滚、末列本来就够不着**，非新增形态）
   【★ 与「表格不横滚」那条决定（原 605 行）】口径不冲突 ——
     ① 该决定的原意是**不许嵌套两层滚动容器**（见 `shell.css` 窄宽兜底那段：
        "`.crmmode` 已有 `.tblwrap` 自身横滚，再叠一层会出双横滚条"），本段不嵌套任何容器；
     ② 本段在 1440/1300/1240/1200 档**不新增任何一条横滚条**（逐字对照过）。
   【⚠ 内边距为什么从 ≤949 段搬到这里】≤949 段原有一条 `.xe-tbl thead th,…{padding:6px 7px}`
     —— 与本段区间重叠且**特异性相同** ⇒ 会退化成"靠源顺序决胜"（本仓明确防的一类）。
     故把它**上移**到本段、值收成 6/6，≤949 段里那条**已删**（全件只此一处声明）。
   【回滚】删掉本段整块，并把 ≤949 段那里的内边距声明恢复为 `padding:6px 7px`。 */
@media (max-width:1300px){
  .xe-tbl .cr{min-width:116px}
  .xe-tbl thead th,.xe-tbl tbody td{padding:6px 6px}
}

/* ── 窄窗兜底（≤949，与其余站同一断点）────────────────────────────── */
@media (max-width:949px){
  .xe-hd{flex-wrap:wrap;height:auto;padding:7px 12px;gap:7px}
  .xe-hd .sp{display:none}
  .xe-sbox{order:9;flex:1 1 100%}
  .xe-sbox input{width:100%;min-width:0}
  /* 筛选行：窄窗**只压内边距与下拉宽度，不换行**（红线 ③：筛选只有一行）——
     横向滚动由本就存在的 `overflow-x:auto` 承担（这张 14 列宽表在任何窗口都要横滚）。 */
  .xe-fbar{padding:5px 12px}
  .xe-sel{max-width:118px}
  /* 分卡组在窄窗换两列（间隙由 `.xe-kpi` 的 `gap` 提供）。
     ⚠ 删掉旧的 `border-bottom:1px solid var(--hairline)`：分卡后每格自带四边，
       再加一条底边会与下巴叠成"双线"；而且 `--hairline` 在 A/B 还是透明的 ⇒
       它**只在 C/D 生效**，等于凭空多一处四主题不一致。 */
  .xe-kpi{flex-wrap:wrap;margin:8px 12px 0;gap:8px}
  .xe-k{flex:1 1 46%}
  .xe-body{padding:8px 12px 14px}
  .xe-note{margin:8px 12px 0}
  /* 分页条：窄窗**照样横滚、不换行**（与 `.xe-fbar` 同一策略）——
     它比筛选行短得多（3 个档位 + 2 个翻页钮），实测 577px 宽下无需滚动，
     这条只是把内边距对齐，别再往下压字号（它会成为"数字看不清"的来源）。 */
  .xe-pager{gap:5px;padding-top:5px}
  .xe-cgrid{grid-template-columns:1fr}
  .xe-plangrid{grid-template-columns:1fr 1fr}
  /* ★ 表格不横滚：窄窗把最宽的「课程」列收窄，宁可换行也不引入第二条横向滚动条
       （R：客户站/假站那次的实测结论 —— 双横滚条是本项目明确排除的形态）。 */
  .xe-tbl .cr{max-width:none}
  /* ★ 本段原有的 `.xe-tbl thead th,…{padding:6px 7px}` 已**上移**到上面那条
     `@media (max-width:1300px)`（值收成 6/6）—— 两段区间重叠且特异性相同，
     留在两处就是"靠源顺序决胜"；全件只留一处声明。
     回滚时要把它恢复到这里。 */
  /* ⚠ 窄窗**不要**再压「平台订单号」列（2026-09-21 第二批试过 `max-width:76px`，
     量出来只省 14px，却会把 19 位订单号截成"6929507…"）——
     本趟的既定口径是"入口与信息都不砍，异常长串才省略"（靠 `.lw` 的 14 字阈值）。 */
  /* ★ 详情区收成**两列**（382px 宽下每列 ~170px，放得下"上游未给该列"这种短值）。
     ⚠ 「详情」那一列与它的表头文字**都保留** —— 窄窗砍入口 = 删功能，不是适配。 */
  .xe-dtl{padding:10px}
  .xe-fg{grid-template-columns:1fr 1fr;gap:8px 10px}
}

/* ══════════════════════════════════════════════════════════════════
   订单分配设置面板（2026-10-17）
   用户令：「把小鹅通订单按下单顺序来分配给教练…可以在小鹅通那加个配置」。

   纪律沿用本文件头注：
     · **不出现字面色值**，一律四主题齐备的 var() 令牌（--amber / --danger-text 都在用）
     · 「待办」不用危险红（`.xe-bi.todo` 用 amber）：还没加微信是**正常待办**，
       不是告警；全表飘红会让真正异常的那几处看不见
     · 面板是 `position:fixed` 的对话框，**不参与表格布局** ——
       放进 `.xe-tw`（横向滚动容器）里会被裁，且会把列宽算进去
   ══════════════════════════════════════════════════════════════════ */
.xe-bi.asg{border-color:var(--line-strong);color:var(--t1);background:var(--e2)}
.xe-bi.todo{border-color:var(--amber-line);color:var(--amber)}

.xe-amask{position:fixed;inset:0;background:var(--veil);z-index:60}
.xe-ap{position:fixed;z-index:61;left:50%;top:50%;transform:translate(-50%,-50%);
  width:min(660px,calc(100vw - 28px));max-height:min(86vh,780px);
  display:flex;flex-direction:column;
  background:var(--e1);color:var(--t1);
  border:1px solid var(--line-strong);border-radius:var(--r-md);box-shadow:var(--sh-1);
  font-family:var(--font-ui);font-size:var(--fs-caption)}
.xe-ap-h{display:flex;align-items:center;gap:8px;padding:11px 14px;flex:none;
  border-bottom:1px solid var(--line)}
.xe-ap-h b{font-size:var(--fs-small)}
.xe-ap-sub{color:var(--t3);font-size:var(--fs-micro)}
.xe-ap-b{padding:12px 14px;flex:1 1 auto;min-height:0;overflow:auto}
.xe-ap-f{display:flex;align-items:center;gap:8px;padding:10px 14px;flex:none;
  border-top:1px solid var(--line)}
.xe-ap-on{display:flex;align-items:center;gap:6px;margin-bottom:10px;cursor:pointer}
.xe-ap-on .dim{color:var(--t3);font-size:var(--fs-micro)}
.xe-ap-grid{display:grid;grid-template-columns:auto 96px 1fr;gap:7px 8px;align-items:center}
.xe-ap-grid label{color:var(--t2)}
.xe-ai,.xe-as{height:26px;padding:0 7px;border:1px solid var(--line-strong);
  border-radius:var(--r-xs);background:var(--e0);color:var(--t1);
  font-family:var(--font-ui);font-size:var(--fs-caption)}
.xe-ai{width:96px;font-family:var(--font-num)}
/* ★ 起始下单时间用 `datetime-local`：默认 96px 装不下 `2026-10-17 12:00`，
   会被浏览器截成只看得见日期 —— 而这一项最怕的就是"看起来对、其实看不全"。 */
#aestart{width:178px;font-family:var(--font-num)}
.xe-ap-row{display:flex;align-items:center;gap:6px;padding:7px 0 0}
.xe-ai:focus,.xe-as:focus{outline:none;border-color:var(--accent-line);background:var(--e1)}
.xe-ap-note{margin:9px 0 2px;color:var(--t3);font-size:var(--fs-micro);line-height:1.7}
.xe-ap-sec{margin:14px 0 6px;font-weight:600;color:var(--t1)}
.xe-ap-sec .dim{margin-left:6px;font-weight:400;color:var(--t3);font-size:var(--fs-micro)}
.xe-ap-rule,.xe-ap-ord{display:flex;align-items:center;gap:6px;padding:4px 0}
.xe-ap-rule .dim,.xe-ap-ord .dim{color:var(--t3);font-size:var(--fs-micro)}
.xe-ap-ord .n{width:18px;text-align:right;color:var(--t3);
  font-family:var(--font-num);font-size:var(--fs-micro)}
.xe-ap-ord .nm{min-width:76px}
.xe-ap-empty{padding:2px 0;color:var(--t3);font-size:var(--fs-micro)}
.xe-ap-warn{margin-top:8px;padding:6px 8px;border:1px solid var(--amber-line);
  border-radius:var(--r-xs);color:var(--amber);font-size:var(--fs-micro);line-height:1.7}
.xe-ap-kv{display:flex;flex-wrap:wrap;gap:16px;color:var(--t2)}
.xe-ap-kv b{font-family:var(--font-num);color:var(--t1)}
.xe-ap-res{margin-top:8px;padding:6px 8px;border:1px dashed var(--line-strong);
  border-radius:var(--r-xs);color:var(--t2);font-size:var(--fs-micro);line-height:1.7}
.xe-ap-tip{color:var(--t3);font-size:var(--fs-micro)}
.xe-ap-err{margin-bottom:8px;color:var(--danger-text);line-height:1.7}
.xe-ap-busy{color:var(--t3)}
