/* @@SPLIT_HEADER@@
   css/components.css —— 通用组件：状态条 / 表格 / 商品悬浮卡 / 列设置 / 分页 / 底栏 / 打印浮层 /
      由 redesign2.html 拆分而来（原行号 495-1322），业务逻辑原样搬运；加载顺序见 index.html / README.md */
/* ==========================================================================
   8. 状态条（温馨提示 + 工具行合并，见文件头说明）
   ◆ 左：两条温馨提示（可「查看」、可关闭）；右：自动同步 + 两个开关 + 两个文字入口
   ========================================================================== */
.statusbar{flex:none;display:flex;align-items:center;gap:10px;padding:3px 12px;min-height:32px;font-size:12px}
.notice{display:flex;align-items:center;gap:5px;min-width:0;color:var(--text-2);flex-wrap:wrap}
.notice .t{display:inline-flex;align-items:center;gap:5px;font-weight:600;color:var(--text);white-space:nowrap}
.notice .t .i{color:var(--accent)}
.notice .n{font-weight:600;color:var(--text);font-variant-numeric:tabular-nums}
.notice .lnk{color:var(--accent);cursor:pointer}
.notice .lnk:hover{text-decoration:underline}
.notice .x{
  display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;margin-left:2px;
  border:0;background:none;border-radius:5px;color:var(--faint);cursor:pointer;padding:0;
}
.notice .x:hover{background:var(--bg);color:var(--text)}
.statusbar .divider{width:1px;height:16px;background:var(--line);flex:none}
.tools{margin-left:auto;display:flex;align-items:center;gap:14px;white-space:nowrap}
.sync{display:inline-flex;align-items:center;gap:6px;color:var(--text-2);font-size:12px}
.live{width:6px;height:6px;border-radius:50%;background:#10b981;box-shadow:0 0 0 3px rgba(16,185,129,.15);flex:none}
.sw-wrap{display:inline-flex;align-items:center;gap:6px;color:var(--text-2);font-size:12px;cursor:pointer}
/* 开关：30×17 胶囊 */
.sw{width:30px;height:17px;border-radius:var(--r-pill);background:#d1d5db;position:relative;transition:background .15s;flex:none}
.sw::after{content:"";position:absolute;top:2px;left:2px;width:13px;height:13px;border-radius:50%;background:var(--card);box-shadow:0 1px 2px rgba(0,0,0,.2);transition:left .15s}
.sw.on{background:var(--accent)}
.sw.on::after{left:15px}
.tlink{color:var(--mut);font-size:12px;cursor:pointer;white-space:nowrap}
.tlink:hover{color:var(--accent)}

/* ==========================================================================
   9. 表格卡片
   ◆ 白底 + 12px 圆角；表头 sticky + 白底 + 底部细线 + 极轻阴影（允许的 3 处之一）
   ◆ 行 hover 浅蓝、选中行更明显、无斑马纹
   ========================================================================== */
.tablecard{flex:1;min-height:0;display:flex;flex-direction:column;overflow:hidden}
/* ★ 2026-10-26：用户解除「不许横向滚动」硬约束（原话「10那还是不要限制横滚算了，
   我打可以横滚只是我设置的不需要横滚，抱歉」），按用户拍板的方案 A 改：
   · overflow-x:auto —— 列宽按 min 自然取，装不下就出横向滚动条；不再像以前那样
     把超出的右侧几列**静默裁掉**（「操作列点不到」就是这么来的）。
   · scrollbar-gutter:stable —— 给竖向滚动条**永远预留**那 15px。
     ★ 这个坑踩过一次：竖滚条一出现/消失，容器 clientWidth 就跳 15px，列宽跟着重算，
       滚动时整张表左右抖。预留住就是恒定宽度。
   ◆ 改动前原文（完整保留，回退时照抄这一行即可）：
     .tablewrap{flex:1;min-height:0;overflow:auto;overflow-x:hidden}
   ◆ 为什么把 overflow-y 也显式写出来：只写 overflow-x:auto 时 overflow-y 会被隐式
     改成 auto，虽然这里本来就 auto，写明白免得以后改一半又把 sticky 表头弄失效。 */
.tablewrap{flex:1;min-height:0;overflow:auto;overflow-y:auto;overflow-x:auto;scrollbar-gutter:stable}
table.grid{width:100%;table-layout:fixed;border-collapse:separate;border-spacing:0;font-size:13px}
/* 表头 */
.grid thead th{
  position:sticky;top:0;z-index:5;height:40px;padding:3px 6px;
  background:var(--card);border-bottom:1px solid var(--line);
  box-shadow:0 1px 3px rgba(0,0,0,.06);
  /* ★ 2026-10-26 用户要求「表头全部居中」：原来 text-align:left，
     22 个表头全部贴着各自列的左边缘（实测文字左偏移 = padding 6px），
     列变宽以后看起来像"文字靠左空白在右"，很散。
     改成 center —— 只影响表头，数据单元格的对齐（数字右/文字左）不动。 */
  font-size:12px;font-weight:600;color:var(--text-2);text-align:center;vertical-align:middle;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.grid thead th.c-chk{padding-left:12px}
.th-txt{display:inline-block;vertical-align:middle;line-height:18px}
/* 表头小图标：齿轮/箭头默认很淡，hover 或激活才明显（降噪） */
/* 表头齿轮（每列的显示设置入口）
   ⚠️ 原来 color:#cbd5e1 + 11px —— 在白底上几乎看不见（用户实测反馈「完全看不清楚」）。
      改成 #94a3b8 + 13px：对比度够、又不抢标题的注意力。
   ★ 为什么不用更深的 #64748b：22 个齿轮同时变深，表头会一片黑点，反而看不清标题文字。 */
.th-gear{color:var(--faint);margin-left:4px;width:13px;height:13px;vertical-align:-2px}
.th-gear:hover{color:var(--accent);transform:scale(1.12)}
/* 窄列（重量/体积/订单状态/订单时间）的齿轮：绝对定位在右上角，
   不占标题文字宽度；平时透明，鼠标移到该列才出现（复刻版 8 个齿轮入口全部保留） */
/* 绝对定位版（窄列用，不占标题文字宽度）
   ⚠️ 原来 opacity:0 —— 鼠标不移上去就等于不存在，用户根本不知道那里能点。
      改成默认 0.45（看得见但不刺眼），hover 到 1。
   位置也从 right:2/top:2 挪到 right:3/top:3，并给 th 留出右内边距避免压住文字。 */
.th-gear.abs{position:absolute;right:3px;top:3px;margin:0;width:12px;height:12px;
  opacity:.45;transition:opacity .12s,transform .12s}
.grid thead th:hover .th-gear.abs{opacity:1}
.grid thead th:has(> .th-gear.abs){padding-right:18px}
/* 表头下面的副链接（商品的「快速选择商品」、操作的「展开」）。
   ★ 2026-10-26：表头文字居中后，这两条副链接还是贴左（display:flex 默认 justify-content:flex-start），
     看起来和上面的标题不对齐。加 justify-content:center 一起居中。 */
.th-sub{display:flex;align-items:center;justify-content:center;gap:2px;margin-top:0;
  font-size:11px;font-weight:400;line-height:13px;color:var(--faint)}
.th-link{color:var(--accent);cursor:pointer}
.th-link:hover{text-decoration:underline}
.th-sort{cursor:pointer;user-select:none;padding-right:16px;position:relative}
.th-sort:hover{background:var(--card);color:var(--accent)}
/* 排序箭头：绝对定位在右缘，不占标题文字宽度（窄列标题才不会被挤断）；
   默认透明，只在 hover 或当前排序列出现 */
.arrow{position:absolute;right:4px;top:50%;margin-top:-5.5px;width:11px;height:11px;color:var(--faint);opacity:0;transition:opacity .12s}
.th-sort:hover .arrow{opacity:.7}
.th-sort.asc .arrow,.th-sort.desc .arrow{opacity:1;color:var(--accent)}
.th-sort.asc .arrow{transform:rotate(180deg)}
/* 表头第二列：三个状态小图标 —— 已随「打印时间列」一起删掉（那一列现在是
   「状态/时间」文字表头，不再用一排看不出区别的绿勾）。.th-icons 不再有引用。 */
/* 数据行 */
.grid tbody td{
  height:52px;padding:3px 6px;vertical-align:middle;
  border-bottom:1px solid var(--line);color:var(--text-2);
  overflow:hidden;
}
.grid tbody td.c-chk{padding-left:12px}
.grid tbody tr:last-child td{border-bottom:none}
.grid tbody tr:hover td{background:var(--hover)}
.grid tbody tr.sel td{background:var(--sel)}
.grid tbody tr.closed td{color:#94a3b8}
.grid tbody tr.closed .oid,.grid tbody tr.closed .wb{color:#94a3b8}
/* 勾选框：统一 14px、蓝色 accent；窄屏（1280）左内边距压到 8px，
   否则 2.6% 的列（约 28px）减去 18px 内边距就装不下 14px 的勾选框 */
.cb{width:14px;height:14px;accent-color:var(--accent);cursor:pointer;margin:0;vertical-align:middle}
/* 序号列（本轮从勾选列里独立出来，才能整列拖动换位） */
.c-idx{padding-left:8px!important}
.seq2{font-size:10px;color:#cbd5e1;font-variant-numeric:tabular-nums}
/* ★ 选中行的序号要能看见：浅灰 #cbd5e1 在选中行蓝底（--sel = #e7f0ff）上
   对比度只有 **1.29:1**，基本等于看不见（用户截图里那行序号像是空的）。
   选中时换深色 #475569 → 对比度 6.61:1（自测里用真浏览器量的）。
   ⚠️ 只对「选中行」改：序号是辅助定位用的，未选中的行应该很淡（降噪初衷），
   不能一刀切把 .seq2 全改深 —— 那样 20 行全都变深，列表会变吵。
   真实的选中行 class 名就是 "sel"：render() 拼 <tr class="sel ...">，
   点勾选框时走 tr.classList.toggle('sel')，两处同一个名字。
   （售后表 .as-table 也有 tr.sel，但它没有序号列，所以这里不用管。） */
.grid tbody tr.sel .seq2{color:var(--mut);font-weight:600}
/* ==========================================================================
   状态/时间列（原来「三个绿勾列 + 打印时间列」合并成这一列）
   ◆ 为什么合并：三枚绿勾长得一模一样，用户看不出哪个是「已打发货单」、
     哪个是「已打快递单」、哪个是「已发货」；打印时间又单独占一整列、
     时间戳前面还是个一样的绿勾，两列的勾谁也说明不了谁。
   ◆ 为什么用颜色区分：需求指定 —— 蓝=已打发货单、红=已打快递单、黑=已发货。
     没发生的状态**不画**（不画灰勾：灰勾会让人以为"有这个状态但没做"）。
   ◆ 一行 = 「勾 + 时间」同一个 flex 容器（gap:4px 垂直居中），最多 3 行；
     3 × 13px + 2 × 1px ≈ 41px，52px 行高塞得下。字号 10px 是为了塞进 10.2% 的列宽。
   ========================================================================== */
.st-line{display:flex;align-items:center;gap:4px;min-width:0;line-height:13px}
.st-line + .st-line{margin-top:1px}
.st-line .st-ck{width:11px;height:11px;flex:none}
.st-ck-inv{color:#2d8cf0}    /* 已打发货单 = 蓝 */
.st-ck-wb{color:#ed4014}     /* 已打快递单 = 红 */
.st-ck-ship{color:#1f2937}   /* 已发货 = 近黑 */
.st-time{font-size:10px;color:var(--mut);font-variant-numeric:tabular-nums;letter-spacing:-.2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.st-time.none{color:#cbd5e1}
/* 分类 / 智能快递这类「一格一句话」的纯文本 */
.cell-txt{display:block;max-width:100%;font-size:12px;color:var(--text-2);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.dash-val{color:#cbd5e1}
/* 订单编号：19 位必须完整显示（少一位就认不了单）。
   ◆ 字号分两档：>1620px 用 12px（实测 19 位数字宽 125px，列内容宽 129~156px）；
     ≤1620px 用 9.5px + 字距 -0.3（实测 ≈93px，1280 下列内容宽 98.8px）。
     分档而不是一路缩小：大屏没必要牺牲可读性，小屏才压字号。
   ◆ 复制按钮改成纯图标 + 单独一行：同号行里再塞 14px 图标，1280 下就放不下 19 位了。 */
.oidrow{display:flex;flex-direction:column;align-items:flex-start;gap:0;min-width:0}
.oid{font-size:12px;font-weight:500;color:var(--text);letter-spacing:-.3px;
  font-variant-numeric:tabular-nums;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}
.copy{display:inline-flex;align-items:center;line-height:13px;font-size:10px;color:var(--accent);cursor:pointer}
.copy .i{width:10px;height:10px}
.copy:hover{color:#1d4ed8}
@media (max-width:1620px){
  .oid{font-size:9px;letter-spacing:-.3px}
  .copy .i{width:9px;height:9px}
}
/* 快递模板列：已打印 = 运单号 + 模板名；未打印 = 灰色「禁用框」 */
.wb{font-size:12px;font-weight:600;color:var(--text);font-variant-numeric:tabular-nums;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.wb-tpl{font-size:10px;color:var(--faint);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;line-height:13px}
.wb-empty{
  display:block;padding:2px 4px;border:1px dashed var(--line-strong);border-radius:6px;
  background:var(--hover);color:#a8b0bb;font-size:10px;line-height:16px;text-align:center;
  white-space:nowrap;overflow:hidden;cursor:not-allowed;
}
/* 收件人 */
.rcpt{display:flex;align-items:center;gap:3px;font-size:12px;font-weight:500;color:var(--text);
  white-space:nowrap;min-width:0;overflow:hidden}
.rcpt .rcpt-n{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rcpt .i{width:10px;height:10px;color:var(--faint);flex:none}
.nick{display:block;max-width:100%;font-size:11px;color:var(--accent);cursor:pointer;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.nick:hover{text-decoration:underline}
@media (max-width:1500px){
  .rcpt .i{display:none}     /* 1280 下 3.70% 只有 33px：先保住收件人姓名 */
/* 「解密」小按钮（2026-10-26）：只在没解密的行出现，点一次花 1 次额度。
   做成极小的一行文字按钮，不挤占收件人列（那一列在 1280 下只有 33px）。 */
.rcpt-dec{display:block;margin-top:1px;padding:0;border:0;background:none;cursor:pointer;
  font-family:inherit;font-size:10px;line-height:1.2;color:var(--accent);text-align:left}
.rcpt-dec:hover{text-decoration:underline}
}
/* 商品：每个商品一行，行内 [缩略图][名称（完整显示，自动换行）][已发货角标]
   ◆ 为什么缩略图从 14px 放大：14px 是**还没有真图**、用渐变色块占位时定的尺寸；
     接上真实商品图之后，14px 连"这是碗还是盘子"都看不出来（用户原话「图片这么小？」）。
   ◆ 为什么尺寸走 CSS 变量：用户要求「图片大小跟着间距变动」—— 以后要调大小只改
     --thumb-size 一个值，行高、间距、角标位置全部跟着走，不用满文件找 14/28/30。
   ◆ 为什么名称不缩略（不 clamp、不省略号）：用户原话「商品名字不要缩略」。
     宁可把这一行撑高（竖向滚动用户说无所谓），也不能让老板猜这是什么商品。
   ◆ 行高：不再写死。`.grid tbody td` 上的 height:52px 在表格里**本来就是最小高度**
     （CSS 表格的行高计算把它当 min-height 用），多商品 / 长名字的行会自然变高。 */
.prod{display:flex;align-items:flex-start;gap:var(--thumb-gap);
  min-height:var(--thumb-size);margin-bottom:var(--prod-gap)}
.prod:last-child{margin-bottom:0}
.thumb{width:var(--thumb-size);height:var(--thumb-size);border-radius:5px;flex:none;
  border:1px solid rgba(15,23,42,.06);background-size:cover;background-position:center;
  overflow:hidden;display:inline-block}
/* 图挂了由 JS 摘掉 <img>，露出 span 自己的渐变底色（尺寸/圆角不变，行高不抖） */
.thumb img{width:100%;height:100%;object-fit:cover;display:block;border-radius:4px}
/* 商品名：完整显示，允许换行，不许省略号 */
.pname{flex:1 1 auto;min-width:0;font-size:12px;color:var(--text-2);line-height:1.4;
  white-space:normal;overflow:visible;text-overflow:clip;
  word-break:break-all;overflow-wrap:anywhere}
.pqty{font-style:normal;font-size:11px;color:var(--faint);margin-left:2px;font-variant-numeric:tabular-nums}
/* 「已发货」小角标：低调的淡绿胶囊，不用橙色三角 */
.shipped{flex:none;font-size:10px;line-height:13px;padding:0 4px;border-radius:var(--r-pill);background:var(--green-bg);color:var(--green)}
/* ==========================================================================
   商品悬浮详情卡（悬停约 1.5 秒出现，见 bindSkuCard）
   ◆ 全局只有一个节点：#skuCard 挂在 body 末尾，不受表格裁剪/层叠上下文影响。
   ◆ z-index 200：高于表格（sticky 表头 5）、下拉菜单（120/130）、底栏（80），
     低于弹窗遮罩（300）—— 打开弹窗时不该有卡片飘在上层。
   ========================================================================== */
#skuCard{position:fixed;left:0;top:0;z-index:200;width:240px;padding:10px;
  border:1px solid var(--line);border-radius:10px;background:var(--card);
  box-shadow:0 12px 32px rgba(15,23,42,.16);display:none;font-size:12px;color:var(--text-2)}
#skuCard.show{display:block}
#skuCard .sk-img{width:160px;height:160px;margin:0 auto 8px;border-radius:6px;overflow:hidden;
  background:var(--bg);display:flex;align-items:center;justify-content:center}
/* ★ object-fit:contain 而不是 cover：商品是陶瓷盘/碗，cover 会把盘子边缘裁掉一圈，
   看起来像"缺角的次品"。contain 留白就用 #f1f5f9 底兜住，不丑。 */
#skuCard .sk-img img{width:100%;height:100%;object-fit:contain;display:block}
#skuCard .sk-fail{font-size:11px;color:var(--faint)}
#skuCard .sk-title{font-size:12px;font-weight:600;color:var(--text);line-height:16px;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
  margin-bottom:6px;word-break:break-all}
#skuCard .sk-row{display:flex;gap:8px;line-height:18px;font-size:11.5px}
#skuCard .sk-k{flex:none;width:56px;color:var(--faint)}
#skuCard .sk-v{flex:1;min-width:0;color:var(--text-2);word-break:break-all}
/* 订单时间 */
/* 窄列里的 nowrap 文本一律「自己裁剪 + 省略号」：
   单元格 overflow:hidden 只是视觉裁掉，scrollWidth 仍会报溢出（自测 K2 抓的就是这个），
   让内容自己 ellipsis 才是真正不溢出。 */
.otime{font-size:12px;color:var(--mut);font-variant-numeric:tabular-nums;white-space:nowrap;
  display:block;max-width:100%;overflow:hidden;text-overflow:ellipsis}
/* 收件信息：地址单行 nowrap + 省略号；手机号单独一行、绝不换行。
   ◆ 为什么地址不再两行：列宽收到 6.30% 后两行会把「138****0011」挤到下一屏外
     （用户截图里就是「1 *** ****0011」被拆成两行），宁可地址省略——全文在 title 里。
   ◆ 手机号绝不换行：它是「搜后 4 位」时唯一能核对的东西，拆行就读不出来了。
   ★ 2026-10-26 改（对照「我打」截图）：未解密时地址是「省市区 + ****」，
     而 **** 是**唯一能说明"这里脱敏了"的信号** —— 不能被省略号吃掉。
     做法：拆成「可省略的省市区」+「永不省略的 ****」两个 flex 子项：
       省略号只发生在省市区那一段，**** 永远留在可视区里。 */
.addr{
  font-size:12px;line-height:15px;color:var(--text-2);
  white-space:nowrap;overflow:hidden;
}
/* ★ width:0 + min-width:100% + overflow:hidden = 「最小内容宽按 0 算」的标准写法。
   为什么必须要它：表格列宽是百分比，但浏览器在算列宽时还会看单元格的
   **最小内容宽**（min-content）——眼睛按钮 flex:none + 11 位手机号 nowrap，
   两者加起来在 1280 下比 6.3% 的列宽还大，整张表就会被顶宽 15px，
   最后一列（操作）被 .tablewrap 的 overflow:hidden 静默裁掉（正好是历史踩过的坑）。
   这一行让单元格「内容再宽也只报 0」，列宽完全由百分比决定。 */
.addr-cell{width:0;min-width:100%;overflow:hidden}
.addr-line{display:flex;min-width:0;white-space:nowrap;overflow:hidden}
.addr-region{min-width:0;overflow:hidden;text-overflow:ellipsis}
/* **** 永不省略（flex:none）+ 灰一点：一眼能看出「这是脱敏占位，不是真地址」 */
.addr-mask{flex:none;font-style:normal;color:var(--faint);margin-left:1px}
/* 解密后的详址：和普通文字一样会省略（但整串仍是明文，title 里有全文） */
.addr-real{min-width:0;overflow:hidden;text-overflow:ellipsis;color:var(--text)}
.addr-sub{display:flex;align-items:center;gap:3px;font-size:10px;line-height:13px;color:var(--faint);
  white-space:nowrap;overflow:hidden;max-width:100%;min-width:0}
.addr-sub .i{width:9px;height:9px;flex:none}
/* 手机号可缩（缩的时候出省略号）：它比眼睛「可牺牲」——号码后 3 位在搜索里也能用，
   而眼睛是**唯一的解密入口**，丢了就没法解密。 */
.addr-sub .ph{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis}
/* 虚拟号（解密后才出现）：可拨的号 + 分机。★ 也要可缩 ——
   实测「18400902398 分机 9109」在 1280 下比列宽还长，不让它缩同样会顶宽表格。 */
.addr-sub .vno{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;
  color:#0f766e;font-size:9.5px;
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}
/* 眼睛按钮（解密入口，对照「我打」）：三种状态用 data-st 区分
     on   未解密、可点（深色眼睛，悬停变蓝）
     done 已解密（绿色勾，不可点）
     off  额度用完/状态不支持（灰色，仍可点 —— 让用户看到失败原因，
          但按钮样式是 disabled 的样子，点下去也不会花额度：前端先判断额度） */
.eye-btn{flex:none;display:inline-flex;align-items:center;justify-content:center;
  width:16px;height:16px;padding:0;border:0;border-radius:4px;background:none;
  cursor:pointer;color:var(--text-2);line-height:1}
.eye-btn svg{width:13px;height:13px;display:block}
.eye-btn:hover{background:var(--accent-weak);color:#2563eb}
.eye-btn[data-st="done"]{color:var(--green);cursor:default}
.eye-btn[data-st="done"]:hover{background:none;color:#16a34a}
.eye-btn[data-st="off"]{color:#cbd5e1;cursor:not-allowed}
.eye-btn[data-st="off"]:hover{background:none;color:#cbd5e1}
@media (max-width:1500px){
  /* 1280 下 6.30% 只有 65px 内容宽：锁图标会让手机号被裁，直接让位给号码本身 */
  .addr-sub .i{display:none}
  .addr-sub{font-size:9.5px}
  /* ★ 1280 下眼睛按钮保留：它是唯一的解密入口，比锁图标重要得多 */
}
/* 留言备注：单行省略，悬停看全文（52px 行高放不下两行 + 其他内容） */
.n-remark{display:block;font-size:12px;color:var(--text-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* 数字列：右对齐 + tabular-nums */
.num{text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap}
.n-count{font-size:12px;color:var(--text-2)}
.n-money{font-size:12px;font-weight:600;color:var(--text)}
.n-freight{font-size:12px;color:var(--mut)}
.n-weight,.n-volume{font-size:12px;color:var(--text-2)}
/* 订单状态胶囊：柔和底色 + 深色字
   ◆ 五种真实状态要一眼分开（打单场景最关心"还有哪些活没干"）：
       待发货 = 蓝底加粗（**最醒目**，这就是今天要干的活）
       待收货 = 绿（已经发出去了，不用管）
       已完成 = 灰（正常结案）
       已退款 = 橙红（异常，钱退了但货可能已发）
       已取消 = 极浅灰（无效单，视觉上"退到后面去"）
   ◆ 为什么不用同一个色系的深浅：深浅区分在 11px 小胶囊上几乎看不出来，
     色相不同才是一眼可辨。 */
.pill{display:inline-block;max-width:100%;padding:0 8px;border-radius:var(--r-pill);
  font-size:11px;line-height:18px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;vertical-align:middle}
.pill-wait{background:var(--sel);color:var(--accent-hover);font-weight:600}   /* 待发货 = 蓝（最醒目） */
.pill-sent{background:var(--green-bg);color:var(--green)}      /* 待收货 / 已发货 = 绿 */
.pill-done{background:var(--bg);color:#4b5563}                   /* 已完成 = 灰 */
.pill-refund{background:var(--danger-bg);color:#be123c}                 /* 已退款 = 橙红（异常） */
.pill-closed{background:var(--hover);color:#9ca3af}                 /* 已取消 / 已关闭 = 极浅灰（无效） */
/* 平台（打单表第 19 列 / 售后表第 3 列）：图标 14 + 两个字，同一行垂直居中
   ◆ 为什么这一列原来是「店铺」现在是「平台」：这套系统是自用，只对接微信 / 抖音
     两个来源，店铺名（不同店铺名各不相同）反而不需要在这一列区分 ——
     用户原话「这个店铺，弄成平台名字，我们是自用不是开发给别人用」。
     所以 .shop / .mini-tag 两条样式随「店铺」列一起删掉：店铺名不再渲染，留着
     就是死代码（规矩 3.5）。数据里的 shop / shopTag 字段没删，只是不再展示。
   ◆ 为什么不做彩色底块：用户要的是「带图标」，图标着色就够了；12px 的两个字再
     套一个彩色胶囊，在 22 列的表格里太吵，反而看不清哪列是平台。 */
.plat{display:inline-flex;align-items:center;gap:4px;max-width:100%;min-width:0;font-size:12px;color:var(--text-2);white-space:nowrap}
.plat .pi{width:14px;height:14px;flex:none;display:block;fill:currentColor;stroke:none}
.plat .pn{min-width:0;overflow:hidden;text-overflow:ellipsis}
/* 图标着色：微信绿 / 抖音黑（需求指定值）。图标用 currentColor 取色，
   文字保持深灰 —— 平台一眼能分开，又不至于整列五颜六色 */
.pi-wx{color:#07c160}
.pi-dy{color:#161823}
/* 标识：星标 + 红框标签（需求指定红框） */
.flag{display:inline-flex;align-items:center;gap:3px;max-width:100%;overflow:hidden}
.flag .i.star{width:12px;height:12px;color:#f59e0b;flex:none}
.flag-tag{display:inline-block;max-width:100%;padding:0 5px;border:1px solid var(--danger-line);
  border-radius:6px;background:var(--card);color:var(--danger);font-size:10px;line-height:15px;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;vertical-align:middle}
/* 操作列图标按钮 */
/* 操作列图标按钮
   ⚠️ 必须 border:0;background:none;padding:0 —— <button> 的浏览器默认样式
      会画出一个灰色方框，实测和「我打」对比就是这个方框显得特别丑。
      平时透明，只有 hover 才给浅底（降噪：22 列里这一列不该抢眼）。 */
.icon-btn{
  width:20px;height:20px;display:inline-flex;align-items:center;justify-content:center;
  border:0;background:none;padding:0;font:inherit;appearance:none;
  border-radius:5px;color:var(--faint);cursor:pointer;
}
.icon-btn:hover{background:var(--accent-weak);color:var(--accent)}
.icon-btn:active{background:#e2e8f0}
.icon-btn .i{width:13px;height:13px}
/* 空态 */
.empty{padding:48px 0;text-align:center;color:var(--mut);font-size:13px}

/* ==========================================================================
   9.5 列宽拖拽 —— 挤压式：总宽恒 100%，永远不出现横向滚动
   ◆ 热区 4px：再宽会吃掉表头文字的可点区域（表头有 3 列要排序），再窄鼠标
     要瞄两次才命中（实测 2px 命中率很差）。热区透明，只 hover 时淡淡发蓝。
   ◆ 为什么这里不给容器加 overflow-x:auto 兜底：这一版所有列宽都是百分比、
     和恒等于 100%，本来就不该有溢出。真溢出了也**不能**靠 overflow 藏起来 ——
     自测是直接量 table.scrollWidth 与「各表头宽度之和」，容器兜不住假象。
   ◆ 拖动中整列高亮用 !important：要压过表头白底（.grid thead th）和行 hover
     底色（tr:hover td），否则拖动时看不出调的是哪一列。
   ========================================================================== */
.col-resize{position:absolute;top:0;right:0;width:4px;height:100%;z-index:6;cursor:col-resize;background:transparent}
.col-resize:hover{background:rgba(37,99,235,.22)}
.grid thead th.col-hot,.grid tbody td.col-hot,
.as-table thead th.col-hot,.as-table tbody td.col-hot{background:#e8f1ff!important}
/* 拖动期间：不许选中文字（否则一拖就把整行文字刷蓝），鼠标整页变列宽光标 */
body.col-resizing{cursor:col-resize;user-select:none;-webkit-user-select:none}
body.col-resizing *{cursor:col-resize!important}

/* ==========================================================================
   9.6 列换位（拖表头主体）—— 和上面 9.5 的「拖右边缘调宽」是两套手势
   ◆ 可拖的 th 给 cursor:grab + hover 浅底，一眼知道「这块能拖」；
     固定列（勾选 / 序号 / 操作）不加这个类。
   ◆ 拖动中：被拖的列半透明（.dragging，opacity .5），落点是 2px 蓝竖线
     （.drop-before / .drop-after 的伪元素，高度 = 表头高度）。
   ========================================================================== */
.grid thead th.draggable,.as-table thead th.draggable{cursor:grab}
.grid thead th.draggable:hover,.as-table thead th.draggable:hover{background:#f8fbff}
.grid thead th.dragging,.as-table thead th.dragging{opacity:.5;cursor:grabbing}
.grid thead th.drop-before::before,.grid thead th.drop-after::after,
.as-table thead th.drop-before::before,.as-table thead th.drop-after::after{
  content:"";position:absolute;top:0;bottom:0;width:2px;background:var(--accent);z-index:7;
}
.grid thead th.drop-before::before,.as-table thead th.drop-before::before{left:0}
.grid thead th.drop-after::after,.as-table thead th.drop-after::after{right:0}
body.col-dragging{cursor:grabbing;user-select:none;-webkit-user-select:none}
body.col-dragging *{cursor:grabbing!important}

/* ==========================================================================
   9.7 智能搜索的结果提示条（表格卡片内的顶栏；没有搜索词时整条隐藏）
   ========================================================================== */
.hintbar{flex:none;display:none;align-items:center;gap:8px;height:30px;padding:0 12px;
  border-bottom:1px solid var(--line);background:var(--hover);font-size:12px;color:var(--mut);}
.hintbar.show{display:flex}
.hintbar .htxt{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  font-variant-numeric:tabular-nums}
.hintbar .htxt b{color:var(--text);font-weight:600}
.hintbar .btn-link{height:22px;font-size:12px;flex:none}
/* 收件信息列里的脱敏手机号：等宽数字，好对「后 4 位」；绝不换行 */
.addr-sub .ph{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  font-variant-numeric:tabular-nums;letter-spacing:-.2px;color:var(--faint);white-space:nowrap;flex:none}


/* 隐藏列后可能出现的末尾留白列：只占宽、不画内容 */
.grid td.col-filler,.as-table td.col-filler{border-bottom:none}
.subtable td.col-filler{border-bottom:none}

/* ==========================================================================
   16. 列设置面板（工具行「列表设置」/ 售后筛选行齿轮）
   ◆ 420px 宽、最多 70vh 高、内部可滚：打单 20 个可勾项，一屏放不下。
   ◆ 定位用 fixed + JS 按按钮矩形算：按钮在页面顶部（状态条），面板放它下面；
     如果下面放不下（窗口矮），再翻到按钮上方 —— 总之不裁。
   ◆ 勾选框用页面统一的 .cb（accent-color 蓝），不用浏览器默认样式。
   ========================================================================== */
.colset-pop{
  display:none;position:fixed;z-index:160;width:420px;max-height:70vh;
  background:var(--card);border:1px solid var(--line);border-radius:12px;
  box-shadow:0 16px 40px rgba(15,23,42,.18),0 2px 8px rgba(15,23,42,.06);
  flex-direction:column;
}
.colset-pop.show{display:flex}
.cs-hd{flex:none;height:40px;display:flex;align-items:center;padding:0 14px;
  border-bottom:1px solid var(--line);font-size:13px;font-weight:600;color:var(--text)}
.cs-body{flex:1;min-height:0;overflow:auto;padding:10px 14px 6px}
/* 列设置面板顶部：列宽模式（自动 / 手动 N 列）+ 一键恢复自动 */
.cs-widthrow{display:flex;align-items:center;gap:8px;margin:0 0 10px;
  padding:7px 9px;border:1px solid var(--line);border-radius:8px;background:var(--card);
  font-size:12px;color:var(--text-2)}
.cs-widthrow span{flex:1 1 auto;min-width:0}
.cs-widthrow .btn{flex:none}
.cs-group{margin-bottom:12px}
.cs-ghd{font-size:11px;color:var(--faint);margin:2px 0 4px}
.cs-items{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:2px 8px}
.cs-item{display:flex;align-items:center;gap:6px;height:28px;padding:0 4px;border-radius:6px;
  font-size:12px;color:var(--text-2);cursor:pointer;min-width:0}
.cs-item:hover{background:#f3f4f6}
.cs-item span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cs-ft{flex:none;display:flex;align-items:center;gap:8px;padding:10px 14px;border-top:1px solid #f1f3f6}
.cs-ft .btn{height:28px}
.cs-ft .grow{flex:1}

/* ==========================================================================
   10. 分页（在表格卡片内底部）
   ========================================================================== */
.pager{
  flex:none;height:30px;display:flex;align-items:center;justify-content:flex-end;gap:6px;
  padding:0 12px;border-top:1px solid var(--line);font-size:12px;color:var(--mut);
}
.pager .total{margin-right:auto;font-variant-numeric:tabular-nums}
.pager .total b{color:var(--text);font-weight:600}
.pg{
  min-width:26px;height:24px;padding:0 8px;border:1px solid var(--line);border-radius:6px;
  background:var(--card);color:var(--text-2);font-size:12px;cursor:pointer;
}
.pg:hover:not(:disabled){border-color:var(--accent);color:var(--accent)}
.pg.on{background:var(--accent);border-color:var(--accent);color:#fff;font-weight:600}
.pg:disabled{color:#cbd5e1;cursor:not-allowed;background:#fafbfc}
.pager .dd .ctl{height:24px;padding:0 7px;font-size:12px;border-radius:6px}
.pager .dd .dd-menu{top:auto;bottom:30px}

/* ==========================================================================
   11. 底部固定工具栏
   ◆ 白底 + 顶部细线 + 向上极轻阴影（不用深色渐变）
   ◆ 打印快递单 = 蓝色主按钮（带打印机图标）；打印发货单 = 次一级白底描边
   ◆ 本轮：整条按钮组水平居中（justify-content:center + 等宽左右 padding），
     左右留白对称。三个视图各有一套按钮组，同屏存在、按视图显隐 ——
     这样每套都能独立保持「居中」，不用把按钮搬来搬去。
   ◆ 「已选 0 单」放在按钮组内部的左端（不单独贴左）：贴左会让整组视觉重心
     偏右，和「按钮主体居中」的要求冲突；放组内左端既保留语义，组也仍是居中块。
   ========================================================================== */
.bottombar{
  position:fixed;left:0;right:0;bottom:0;z-index:80;height:52px;
  display:flex;align-items:center;justify-content:center;gap:8px;padding:0 16px;
  background:var(--card);border-top:1px solid var(--line);
  box-shadow:0 -1px 3px rgba(0,0,0,.06);
}
/* 每个视图一套按钮组；.on 的那套才显示 */
.bb-group{display:none;align-items:center;gap:8px}
.bb-group.on{display:flex}
/* 首页不需要底部栏：隐藏底栏并把它占的 52px 还给内容区 */
body.no-bb .bottombar{display:none}
body.no-bb .app{padding-bottom:0}
.bbtn{
  height:32px;display:inline-flex;align-items:center;gap:5px;padding:0 12px;
  border:1px solid var(--line-strong);border-radius:var(--r-sm);background:var(--card);
  font-size:12px;font-weight:500;color:var(--text-2);cursor:pointer;white-space:nowrap;
  transition:border-color .12s,background .12s,color .12s;
}
.bbtn:hover{border-color:var(--accent);color:var(--accent)}
.bbtn .i{width:13px;height:13px}
/* 主操作：打印快递单 */
.bbtn-primary{background:var(--accent);border-color:var(--accent);color:#fff;font-weight:600;padding:0 14px}
.bbtn-primary:hover{background:var(--accent-hover);border-color:var(--accent-hover);color:#fff}
/* 次操作：打印发货单（白底描边 + 深色字，和主按钮区分） */
.bbtn-secondary{color:var(--text);border-color:var(--line-strong);font-weight:500}
.bbtn-secondary .i{color:var(--text-2)}
.bbtn-icon{width:32px;padding:0;justify-content:center}
/* 录屏扫描发货（原 AI 打单）：淡蓝描边 —— 比「打印快递单」弱、比普通次按钮醒。
   ◆ 底色只用近乎白的 #f8fbff，不铺 --accent-weak：整条底栏里蓝色块太多会抢
     主按钮的注意力；描边用 --accent-line 保持和主按钮同一色系但低一档。 */
.bbtn-scan{color:var(--accent);border-color:var(--accent-line);background:var(--hover);font-weight:600}
.bbtn-scan:hover{background:#eef6ff;border-color:var(--accent);color:var(--accent)}
.bbtn-scan .i{color:var(--accent)}
.selinfo{font-size:12px;color:var(--mut);margin-left:4px;white-space:nowrap;font-variant-numeric:tabular-nums}
.selinfo b{color:var(--accent);font-weight:600}
.bb-divider{width:1px;height:20px;background:var(--line);flex:none;margin:0 2px}
/* 底栏下拉往上弹 */
.bottombar .dd-menu{top:auto;bottom:38px}
.bottombar .ctl{background:#fff}

/* ==========================================================================
   11.5 打印设置浮层（底栏「打印快递单 ▾ / 打印发货单 ▾」）
   ◆ 结构：.pset 包住「触发按钮 + 浮层」，.pset 是 position:relative ——
     浮层用 bottom:calc(100% + 8px) 就正好贴在按钮上方 8px，不会盖住按钮
     （底栏贴着窗口下沿，往下弹会被裁掉，所以只能往上）。
   ◆ 宽度 340px 是需求指定值；水平居中于按钮（left:50% + translateX(-50%)），
     这样两个按钮的浮层看起来一样稳，不会一个偏左一个偏右。
   ◆ z-index 140：高于底栏（80）、低于弹窗遮罩（300）—— 打印前点的通用弹窗
     要能盖住它。
   ========================================================================== */
.pset{position:relative;display:inline-flex}
.pset-pop{
  display:none;position:absolute;left:50%;transform:translateX(-50%);
  bottom:calc(100% + 8px);z-index:140;width:340px;
  background:var(--card);border:1px solid var(--line);border-radius:12px;
  box-shadow:0 12px 32px rgba(15,23,42,.16),0 2px 8px rgba(15,23,42,.08);
}
.pset.open .pset-pop{display:block}
.pset-hd{padding:12px 14px 9px;font-size:13px;font-weight:600;color:var(--text);border-bottom:1px solid #f1f3f6}
.pset-body{padding:11px 14px}
.pset-row{display:flex;align-items:center;gap:10px;margin-bottom:8px}
.pset-row:last-child{margin-bottom:0}
.pset-row .k{flex:none;width:52px;font-size:12px;color:var(--mut)}
.pset-row .dd{flex:1;min-width:0}
.pset-row .dd .ctl{width:100%;height:30px}
.pset-row .dd .val{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0}
.pset-sep{height:1px;background:var(--bg);margin:10px 0}
.pset-lab{font-size:12px;color:var(--mut);margin-bottom:2px}
.pset-chk{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--text-2);margin:7px 0;cursor:pointer}
.pset-chks{display:flex;flex-wrap:wrap;gap:2px 14px}
.pset-chks .pset-chk{width:calc(50% - 7px)}
.pset-ft{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:10px 14px 12px;border-top:1px solid #f1f3f6}
.pset-ft .btn{height:30px}
/* ★ 2026-10-25：发货单浮层的底排变成 4 个按钮（打 / 看 / 查 / 存）。
   宽度不够时 flex 会把最后一个挤到第二行，看起来像「保存为默认」跟别人不是一组；
   这里只给 #popInvoice 放宽 + 收紧按钮左右内边距（快递单浮层只有 2 个按钮，不动）。 */
#popInvoice{width:372px}
#popInvoice .pset-ft{gap:6px}
#popInvoice .pset-ft .btn{padding:0 9px}
/* 浮层里的下拉菜单向上展开（浮层本身已经在按钮上方，往下开会挡住底栏） */
.pset-pop .dd-menu{top:auto;bottom:34px}
/* ---- 本地打印组件（agent/print_agent.py，8771）接入用的小控件 ----
   ◆ .pset-mini：打印机旁的「刷新」按钮（比 .btn 小一档，不抢「直接打印」）
   ◆ .pset-note：组件没启动时的提示条；连上后变绿并显示打印机数量
   ◆ 颜色用现成的 --accent / --line-strong，不新造变量 */
.pset-mini{flex:none;height:30px;padding:0 10px;font-size:12px;border:1px solid var(--line-strong);border-radius:var(--r-sm);background:var(--card);color:var(--text-2);cursor:pointer;white-space:nowrap;transition:border-color .12s,color .12s}
.pset-mini:hover{border-color:var(--accent);color:var(--accent)}
.pset-mini:disabled{opacity:.5;cursor:not-allowed}
.pset-note{display:none;margin:0 14px 10px;padding:7px 10px;font-size:11.5px;line-height:1.55;border-radius:8px;background:var(--warn-bg);border:1px solid var(--warn-line);color:#9a3412}
.pset-note.show{display:block}
.pset-note.ok{background:var(--green-bg);border-color:#bbf7d0;color:#166534}

.btn:disabled{cursor:not-allowed;background:var(--bg);border-color:var(--line);color:var(--faint)}
.btn:disabled:hover{background:var(--bg);border-color:var(--line);color:var(--faint)}

/* ==========================================================================
   12.9 订单行交互（2026-10-26 新增）
   --------------------------------------------------------------------------
   ① 行展开明细面板       ② ≡ 单行「更多操作」菜单
   ③ 订单锁定（锁图标）    ④ 标识列彩色标签
   ⑤ 快捷勾选 / 其他操作面板 ⑥ 底部功能展示设置
   ⑦ 真分页（每页条数）
   ★ 所有弹出层都挂 document.body + position:fixed：.tablewrap 是 overflow:auto，
     卡片/底栏也有 overflow，放进 <td> 或底栏里的面板一定被裁（上一轮角标踩过）。
   ========================================================================== */

/* ---- ① 行展开 ---- */
/* ❗ 展开行是「一个 td 跨 N 列」：列数必须动态算（用户可能用「列表设置」藏了列），
   写死 22 就会在藏列后右边空一大块。见 expandRowHTML()。 */
.grid tbody tr.expand-tr > td.ex-td{
  height:auto;padding:0;background:var(--card);
  border-bottom:1px solid var(--line);overflow:visible;
}
/* 展开行不参与 hover 高亮（它本来就不是一条"数据"） */
.grid tbody tr.expand-tr:hover > td{background:#fbfcfe}

.ex-wrap{padding:12px 14px 14px;font-size:12px;color:var(--text-2);text-align:left}
.ex-hd{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:8px}
.ex-hd .t{font-size:13px;font-weight:600;color:var(--text)}
.ex-hd .mono{font-variant-numeric:tabular-nums;letter-spacing:.2px}
.ex-hd .paid{margin-left:auto;font-size:13px;font-weight:600;color:#dc2626}
.ex-meta{display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin-bottom:10px;color:var(--mut)}
.ex-meta b{color:var(--text-2);font-weight:600}
.ex-prods{border:1px solid var(--line);border-radius:10px;background:var(--card);overflow:hidden}
.ex-prow{display:flex;align-items:flex-start;gap:10px;padding:8px 10px;border-bottom:1px solid #f1f5f9}
.ex-prow:last-child{border-bottom:0}
.ex-prow .thumb{width:38px;height:38px;border-radius:6px;flex:none;overflow:hidden;display:inline-block}
.ex-prow .thumb img{width:100%;height:100%;object-fit:cover;display:block}
.ex-prow .nm{flex:1;min-width:0}
.ex-prow .nm .n1{color:var(--text);font-size:12.5px;line-height:1.45;word-break:break-all}
.ex-prow .nm .n2{margin-top:2px;color:var(--faint);font-size:11.5px;line-height:1.45;word-break:break-all}
.ex-prow .nm .n3{margin-top:2px;color:var(--faint);font-size:11px}
.ex-prow .money{flex:none;text-align:right;min-width:104px;font-variant-numeric:tabular-nums}
.ex-prow .money .u{color:var(--text-2)}
.ex-prow .money .s{color:var(--text);font-weight:600}
.ex-sum{display:flex;align-items:center;gap:16px;flex-wrap:wrap;margin-top:10px;color:var(--mut)}
.ex-sum b{color:var(--text);font-weight:600}
.ex-sum .paid b{color:#dc2626}
.ex-sum .warn{color:#b45309}
.ex-recv{margin-top:10px;display:grid;grid-template-columns:64px 1fr;gap:4px 10px;line-height:1.6}
.ex-recv .k{color:var(--faint)}
.ex-recv .v{color:var(--text-2);word-break:break-all}
.ex-notes{margin-top:10px;display:grid;grid-template-columns:132px 1fr;gap:8px 10px;align-items:center}
.ex-notes .k{color:var(--faint);font-size:11.5px;line-height:1.4}
.ex-notes .k i{font-style:normal;color:#b45309}
.ex-notes input{
  height:28px;padding:0 8px;font-size:12px;color:var(--text);background:var(--card);
  border:1px solid var(--line-strong);border-radius:7px;width:100%;max-width:520px;
}
.ex-notes input:focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 2px var(--accent-weak)}
.ex-notes input.saved{border-color:#86efac;box-shadow:0 0 0 2px #ecfdf5}
.ex-ft{display:flex;align-items:center;gap:8px;margin-top:12px;padding-top:10px;border-top:1px dashed var(--line)}
.ex-ft .right{margin-left:auto;display:flex;gap:8px}
.ex-ft .btn{font-size:12px;height:28px}

/* 收起状态：图标转 90°（一个图标两态，不用再加一份 SVG） */
.icon-btn.ex-open .i{transform:rotate(180deg);color:var(--accent)}
.icon-btn .i{transition:transform .12s}

/* ---- ③ 锁定图标（钉在勾选列右侧，绝对定位：列只有 2.6%，塞不下两件） ---- */
.c-chk{position:relative}
.lockbtn{
  position:absolute;right:1px;top:50%;margin-top:-8px;width:16px;height:16px;padding:0;
  display:inline-flex;align-items:center;justify-content:center;border:0;background:none;
  border-radius:4px;cursor:pointer;color:#cbd5e1;
}
.lockbtn .i{width:11px;height:11px}
.lockbtn:hover{background:#e8eef7;color:var(--accent)}
.lockbtn.on{color:var(--accent)}
.lockbtn.on .i{width:12px;height:12px}
/* 锁定行：左侧 2px 深色竖条（比整行变色克制，22 列已经够密） */
.grid tbody tr.locked > td:first-child{box-shadow:inset 2px 0 0 #2563eb}

/* ---- ④ 标识列彩色标签 ---- */
.flagwrap{display:flex;align-items:center;gap:3px;flex-wrap:wrap;overflow:hidden;max-height:40px}
.ftag{
  display:inline-block;flex:none;font-size:10px;line-height:15px;padding:0 4px;border-radius:4px;
  border:1px solid transparent;white-space:nowrap;max-width:100%;overflow:hidden;text-overflow:ellipsis;
}
.ftag.flag-present{background:#fce7f3;color:#be185d;border-color:#fbcfe8}
.ftag.flag-flash{background:var(--warn-bg);color:var(--warn);border-color:#fed7aa}
.ftag.flag-presale{background:var(--warn-bg);color:var(--warn);border-color:#fde68a}
.ftag.flag-discount{background:#cffafe;color:#0e7490;border-color:#a5f3fc}
.ftag.flag-card{background:#ede9fe;color:#6d28d9;border-color:#ddd6fe}
.ftag.flag-merge{background:var(--accent-weak);color:#7e22ce;border-color:#e9d5ff}
.ftag.flag-local{background:var(--accent-weak);color:var(--mut);border-color:#e2e8f0}
.ftag.fmore{background:var(--bg);color:var(--mut);border-color:#e5e7eb}

/* ---- ⑤⑥⑦ 通用弹出面板（挂 body + fixed） ---- */
.ppop{
  position:fixed;z-index:320;background:var(--card);border:1px solid var(--line);border-radius:10px;
  padding:4px;box-shadow:0 12px 32px rgba(15,23,42,.14),0 2px 8px rgba(15,23,42,.06);
  max-height:70vh;overflow:auto;text-align:left;
}
.pp-item{
  display:flex;align-items:center;gap:6px;width:100%;height:30px;padding:0 10px;border:0;
  border-radius:6px;background:none;font-size:12px;color:var(--text-2);
  white-space:nowrap;cursor:pointer;text-align:left;
}
.pp-item:hover{background:#f3f4f6}
.pp-item.off,.pp-item:disabled{color:var(--faint);cursor:not-allowed;background:none}
.pp-item.danger{color:#dc2626}
.pp-item.danger:hover{background:#fef2f2}
.pp-item .pp-t{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis}
.pp-item .pp-caret{flex:none;color:var(--faint);font-size:10px}
/* 齿轮面板里选项标题后面的「?」说明图标。
   ⚠️ 原来写的是字面量 `[?]`（三个字符），用户看到的就是「一行展示 [?]」——
     像坏掉的占位符。改成一个圆底的问号，鼠标悬停显示 hint 全文。 */
.pp-item .hint-q{flex:none;display:inline-flex;align-items:center;justify-content:center;
  width:13px;height:13px;border-radius:50%;background:var(--sel);color:var(--mut);
  font-size:9px;font-weight:700;line-height:1;cursor:help;margin-left:2px;
  font-style:normal;vertical-align:1px}
.pp-item .hint-q:hover{background:#cbd5e1;color:#334155}
.pp-sep{height:1px;margin:4px 6px;background:var(--line)}
.pp-hd{padding:4px 10px 6px;font-size:11px;color:var(--faint);border-bottom:1px solid var(--line);margin-bottom:3px}

/* 快捷勾选：带输入框的那一行 */
.pp-inrow{display:flex;align-items:center;gap:6px;padding:4px 8px;font-size:12px;color:var(--text-2);white-space:nowrap}
.pp-inrow input{
  width:56px;height:24px;padding:0 6px;font-size:12px;text-align:center;color:var(--text);
  border:1px solid var(--line-strong);border-radius:6px;
}
.pp-inrow input:focus{outline:none;border-color:var(--accent)}
.pp-inrow .go{
  height:24px;padding:0 8px;font-size:11px;border:1px solid var(--line-strong);border-radius:6px;
  background:var(--card);color:var(--text-2);cursor:pointer;
}
.pp-inrow .go:hover{border-color:var(--accent);color:var(--accent)}

/* ---- 弹窗（自有，不用浏览器 prompt：CDP/无障碍都能测） ---- */
.odlg-mask{
  position:fixed;inset:0;z-index:330;background:rgba(15,23,42,.34);
  display:flex;align-items:center;justify-content:center;
}
.odlg{
  width:420px;max-width:calc(100vw - 40px);max-height:80vh;display:flex;flex-direction:column;
  background:var(--card);border-radius:var(--r-lg);box-shadow:0 24px 64px rgba(15,23,42,.22);overflow:hidden;
}
.odlg.wide{width:560px}
.odlg-hd{display:flex;align-items:center;padding:13px 16px 0;font-size:14px;font-weight:600;color:var(--text)}
.odlg-x{margin-left:auto;width:24px;height:24px;border:0;background:none;border-radius:6px;color:var(--faint);cursor:pointer;font-size:13px;line-height:1}
.odlg-x:hover{background:var(--bg);color:var(--text)}
.odlg-bd{padding:12px 16px;overflow:auto;font-size:12px;color:var(--text-2);line-height:1.7}
.odlg-bd .lab{display:block;margin:8px 0 4px;color:var(--faint);font-size:11.5px}
.odlg-bd input,.odlg-bd select,.odlg-bd textarea{
  width:100%;font-size:12px;color:var(--text);padding:6px 8px;border:1px solid var(--line-strong);
  border-radius:7px;background:var(--card);font-family:inherit;
}
.odlg-bd textarea{min-height:64px;resize:vertical}
.odlg-bd input:focus,.odlg-bd select:focus,.odlg-bd textarea:focus{outline:none;border-color:var(--accent)}
.odlg-bd .hint{margin-top:6px;color:var(--faint);font-size:11.5px}
.odlg-ft{display:flex;justify-content:flex-end;gap:8px;padding:0 16px 16px}
.odlg-ft .btn{font-size:12px;height:30px}
/* 事件时间线 */
.ev-list{max-height:46vh;overflow:auto;border:1px solid var(--line);border-radius:8px;background:#fff}
.ev-row{display:flex;gap:8px;padding:6px 10px;border-bottom:1px solid var(--line);font-size:12px}
.ev-row:last-child{border-bottom:0}
.ev-row .ts{flex:none;color:var(--faint);font-variant-numeric:tabular-nums}
.ev-row .kd{flex:none;width:38px;text-align:center;border-radius:4px;font-size:10px;line-height:16px;height:16px;margin-top:2px}
.ev-row .dt{flex:1;min-width:0;color:var(--text-2);word-break:break-all}
.ev-k-sync{background:var(--accent-weak);color:#475569}
.ev-k-print{background:var(--info-bg);color:#1d4ed8}
.ev-k-note{background:var(--warn-bg);color:#b45309}
.ev-k-tag{background:var(--green-bg);color:#047857}
.ev-k-decode{background:var(--info-bg);color:#6d28d9}
.ev-k-status{background:var(--danger-bg);color:#b91c1c}
.ev-k-lock{background:#e0f2fe;color:#0369a1}

/* 底部功能展示设置：清单 */
.cfg-sec{margin-bottom:14px}
.cfg-hd{display:flex;align-items:center;gap:8px;font-size:12px;font-weight:600;color:var(--text);margin-bottom:6px}
.cfg-hd .n{font-size:11px;font-weight:400;color:var(--faint)}
.cfg-list{border:1px solid var(--line);border-radius:8px;overflow:auto;max-height:26vh;background:#fff}
.cfg-row{display:flex;align-items:center;gap:8px;padding:4px 10px;border-bottom:1px solid var(--line);font-size:12px;color:var(--text-2)}
.cfg-row:last-child{border-bottom:0}
.cfg-row .nm{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cfg-row .mv{display:flex;gap:2px}
.cfg-row .mv button{
  width:20px;height:20px;border:1px solid var(--line);border-radius:4px;background:var(--card);
  color:var(--mut);font-size:10px;line-height:1;cursor:pointer;padding:0;
}
.cfg-row .mv button:hover:not(:disabled){border-color:var(--accent);color:var(--accent)}
.cfg-row .mv button:disabled{opacity:.35;cursor:not-allowed}
.cfg-row.off .nm{color:var(--faint);text-decoration:line-through}

/* ---- 真分页 ---- */
.pager .pg-nums{display:inline-flex;align-items:center;gap:2px}
.pager .pg.on{cursor:default}

/* ---- 订单时间列：下单 / 已付款时长 / 剩余倒计时 / 进度条 ---- */
/* ★ 三行加起来约 46px，仍在 52px 行高内：不让它撑高整行（22 列的表格一旦
   行高不一致就非常难扫读）。 */
.ot-cell{display:flex;flex-direction:column;gap:1px;line-height:1.28;min-width:0}
.ot-cell .ot-time{font-size:11.5px;color:var(--text-2);font-variant-numeric:tabular-nums;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ot-cell .ot-paid{font-size:10.5px;color:var(--faint);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ot-cell .ot-left{font-size:10.5px;color:var(--mut);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ot-cell .ot-left.warn{color:#b45309}
.ot-cell .ot-left.urgent{color:var(--danger);font-weight:600}
.ot-bar{height:3px;border-radius:2px;background:var(--accent-weak);overflow:hidden;margin-top:1px}
.ot-bar i{display:block;height:100%;width:0;border-radius:2px;background:#cbd5e1;transition:width .3s}
.ot-bar.warn i{background:#f59e0b}
.ot-bar.urgent i{background:#e11d48}

/* 商品列里可选的「规格 / 商家编码」小字（只显示一行，超出省略） */
/* 规格 / 商家编码 那一行。
   ⚠️ 2026-10-26 用户反馈「规格的字体的颜色不对」：
      原来 var(--faint)（#94a3b8 级）+ 10.5px —— 在浅色行上几乎看不清。
      关掉「商品名称」后规格是这一格唯一的内容，必须有正常可读性。
      改成 var(--text-2) + 11.5px：比正文浅一档（保持从属关系），但能看清。 */
.prod .pspec,.prod .pcode{display:block;font-style:normal;font-size:11.5px;line-height:1.3;color:var(--text-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

/* 表头「操作 · 展开/收起」：可点的副链接 + 箭头翻转 */
.th-sub .th-link[data-subact]{cursor:pointer}
.th-sub .th-link[data-subact]:hover{color:var(--accent);text-decoration:underline}
.th-sub .i.is-open{transform:rotate(180deg)}

/* 列设置面板里的单选组 */
.pp-radio{display:flex;flex-direction:column;gap:1px;padding:1px 0 3px}
.pp-opt{
  display:flex;align-items:center;width:100%;height:26px;padding:0 10px;border:0;border-radius:6px;
  background:none;font-size:12px;color:var(--text-2);cursor:pointer;text-align:left;white-space:nowrap;
}
.pp-opt:hover{background:#f3f4f6}
.pp-opt.on{color:var(--accent);font-weight:600}
/* 收件信息列的风险标签 */
.rc-flag{display:inline-block;flex:none;font-size:9px;line-height:14px;padding:0 4px;border-radius:4px;margin-left:4px}
.rc-flag.multi{background:var(--danger-bg);color:#b91c1c}
.rc-flag.remote{background:var(--warn-bg);color:#c2410c}
.addr-cell.remote .addr-region,.addr-cell.remote .addr-real{color:#c2410c}
/* 商品列排布（一行 1/2/4 个） */
.prods.grid2{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:2px 6px}
.prods.grid4{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:2px 4px}
.prods.grid2 .prod,.prods.grid4 .prod{min-width:0}
.prod .more-n{font-size:10px;color:var(--faint);cursor:default}

/* ==========================================================================
   12. 弹窗 / 轻提示
   ========================================================================== */
#mask,#scanMask{position:fixed;inset:0;z-index:300;background:rgba(15,23,42,.34);display:none;align-items:center;justify-content:center;backdrop-filter:blur(1px)}
#mask.show,#scanMask.show{display:flex}
.modal{width:380px;max-width:calc(100vw - 40px);background:var(--card);border-radius:var(--r-lg);box-shadow:0 24px 64px rgba(15,23,42,.22);overflow:hidden}
.modal-hd{display:flex;align-items:center;padding:14px 16px 0;font-size:14px;font-weight:600;color:var(--text)}
.modal-x{margin-left:auto;width:24px;height:24px;display:inline-flex;align-items:center;justify-content:center;border:0;background:none;border-radius:6px;color:var(--faint);cursor:pointer;padding:0}
.modal-x:hover{background:var(--bg);color:var(--text)}
.modal-bd{padding:14px 16px 18px;text-align:center}
.modal-bd .big{font-size:14px;font-weight:600;color:var(--text)}
.modal-bd .sub{margin-top:6px;font-size:12px;color:var(--mut);line-height:1.6}
.modal-ft{display:flex;justify-content:flex-end;gap:8px;padding:0 16px 16px}
#toast{
  position:fixed;left:50%;bottom:68px;transform:translateX(-50%) translateY(6px);
  background:#0f172a;color:#fff;font-size:12px;padding:7px 14px;border-radius:var(--r-pill);
  z-index:400;opacity:0;pointer-events:none;transition:opacity .18s,transform .18s;
  box-shadow:0 8px 24px rgba(15,23,42,.18);white-space:nowrap;
}
#toast.show{opacity:1;transform:translateX(-50%) translateY(0)}
