/* ============================================================
   JobBee/ERP 统一后台 UI 套件 (精简 SaaS 风)
   各后台(recruitadmin/monsteradmin/erp...)共用: index 引本文件即得设计系统 + 壳 + 组件。
   - 设计变量在 :root, 换主色/圆角改这里。
   - 同时覆盖常用 Bootstrap 类(.card/.btn/.table/.modal/.badge/.form-*), 让存量 Bootstrap 页面零改动继承 SaaS 观感。
   - 移动端断点 <=768px: 侧栏抽屉 / 统计卡 2 列 / 表格横滚 / 客服台单栏。
   载入顺序: 放在 bootstrap.min.css 之后(覆盖生效)。
   ============================================================ */

:root{
  --bg:#f6f7f9; --surface:#fff; --surface-2:#fafbfc; --hover:#f4f5f8; --border:#e7e9ee; --border-2:#eef0f4;
  --text:#1a1f2b; --muted:#6b7385; --faint:#9aa1b1;
  --primary:#4263eb; --primary-weak:#eef1fe; --primary-hover:#3651c9;
  --ok:#12b76a; --ok-weak:#e7f7ee; --warn:#f79009; --warn-weak:#fef3e2; --danger:#f04438; --danger-weak:#fdeceb;
  /* 描边按钮专用的两个语义色(2026-09-05 主人: 「多来点别的颜色, 每个颜色要扣题」)。
     ‼️ 不能直接用 --warn(#f79009) 和 Bootstrap 的 info(#0dcaf0) —— 压白底分别只有
        **2.35** 和 **1.96**, 描边款的字和边一样读不了(实测, 不是估的)。
     这两个值压白底 5.43 / 5.36, 和 primary(4.98) · success(5.85) · muted(4.76) 同档。
     --warn 本身不动: 它还给预售 pill 那种"深字压浅底"用, 没有这个问题。 */
  --warn-deep:#b54708;   /* 琥珀: 改价 / 改库存 —— 动数字 */
  --info:#0e7490;        /* 青:   改文字 —— 标题 / 描述 / 规格 */
  /* 圆角整体收小(2026-08-20 用户: "border radius 现在值太大, 降低一点, 不管是按钮还是 tags")。
     这三个 token 覆盖站内绝大多数圆角; 下面那三行 --bs-* 是覆盖 bootstrap 自己的 ——
     .btn / .badge / .form-control 走的是 bootstrap 变量, 不改它们光改上面这三个是不够的。 */
  --r-lg:8px; --r:6px; --r-sm:4px;
  --r-modal:12px;   /* 弹窗/大面板专用: 保持原来的大圆角, 不跟小控件一起收 */
  --bs-border-radius:var(--r); --bs-border-radius-sm:4px; --bs-border-radius-lg:8px;
  --bs-border-radius-xl:10px; --bs-border-radius-2xl:12px;
  --sh-sm:0 1px 2px rgba(16,24,40,.06); --sh:0 4px 16px rgba(16,24,40,.07); --sh-lg:0 12px 32px rgba(16,24,40,.12);
  --sidebar:248px;
  /* ---------- 层号表(2026-09-05) ----------
     弹窗并成一套之后, 面板从 Bootstrap 的 1055 抬到了 UKDlg 栈的 19990 起
     (dialog.js 的 Z_BASE/Z_STEP, 每叠一层 +20)。**凡是"必须盖在弹窗之上"的东西都得跟着抬**,
     否则会出现"保存时转圈藏在面板后面""结果提示弹了但看不见"这种查都不好查的毛病。
     ‼️ 改这里之前先看 dialog.js 的 Z_BASE —— 两处必须对得上。 */
  --z-drawer:1050;    /* 手机侧栏抽屉: 在弹窗之下 */
  --z-dlg:19990;      /* 弹窗栈基准 = dialog.js Z_BASE(那边是权威, 这里只是记着) */
  --z-busy:30000;     /* 转圈 / 全屏 loading: 盖住弹窗(保存的时候正在弹窗里转) */
  --z-gate:30050;     /* 图形验证码: 是道闸, 谁都盖不住它 */
  --z-toast:30100;    /* 结果提示: 最上面 */
  --font:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue","PingFang SC","Microsoft YaHei",sans-serif;
}
*{box-sizing:border-box}
html,body{margin:0;height:100%}
/* 全局 90% 视觉密度(2026-07-10 用户: 90% 缩放观感更好, 默认即如此)。zoom 与浏览器缩放同引擎, 布局/JS 测量一致; 只作用桌面, 移动端保持 100%。
   ⚠ vh 不随 zoom 缩放: 100vh 的壳被 zoom .9 压成视觉 90vh → 整站底部空 10% 白条, 侧栏 foot 够不着屏底
   (2026-07-11 用户实锤"没上下定格")→ 壳高按 zoom 反除补偿。 */
@media (min-width:769px){html{zoom:.9}}
body{font-family:var(--font);background:var(--bg);color:var(--text);font-size:14px;line-height:1.5;-webkit-font-smoothing:antialiased}
a{color:inherit;text-decoration:none}
[x-cloak]{display:none!important}
::-webkit-scrollbar{width:9px;height:9px}
::-webkit-scrollbar-thumb{background:#d3d7e0;border-radius:var(--r)}

/* ---------- 布局壳 ---------- */
.uk-app{display:flex;height:100vh;overflow:hidden}
/* zoom .9 的 vh 补偿(必须排在基础规则之后, 同特异性靠后胜): 见文件头 ⚠ 注释 */
@media (min-width:769px){.uk-app{height:calc(100vh / .9)}}
.uk-sidebar{width:var(--sidebar);flex:none;background:var(--surface);border-right:1px solid var(--border);display:flex;flex-direction:column;padding:16px 12px}
.uk-brand{display:flex;align-items:center;gap:10px;padding:6px 10px 14px;font-weight:700;font-size:17px;letter-spacing:-.01em}
.uk-brand .logo{width:30px;height:30px;border-radius:var(--r-lg);background:linear-gradient(135deg,var(--primary),#7c8cf7);display:flex;align-items:center;justify-content:center;color:#fff;font-size:16px;flex:none}
/* ‼️ 导航项多到超过一屏时, overflow:auto 会在侧栏里画一条竖线(2026-09-12 主人:
   "谁他妈让你在这加个竖线了, 别的地方都没有")。滚动能力保留(滚轮/触控照旧), 只是不画那根条。 */
.uk-nav{flex:1;overflow:auto;margin-top:4px;list-style:none;padding:0;scrollbar-width:none}
.uk-nav::-webkit-scrollbar{width:0;height:0}
.uk-nav .nav-group{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.06em;color:var(--faint);padding:14px 12px 6px}
.uk-nav .nav-item{display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:var(--r);color:var(--muted);cursor:pointer;font-weight:500;position:relative;margin-bottom:3px;transition:background .12s,color .12s}
/* 相邻两项要留缝(2026-08-11 用户): 它们各自有圆角底色, 贴在一起时 hover/选中态会连成一整块,
   看不出是两个可点区域。用 margin-bottom 而不是 .uk-nav{gap}: 这个容器里还混着 .nav-group
   分组标题, gap 会把标题本就有的 14px 上留白再撑大一截。 */
.uk-nav .nav-item .ico{width:18px;text-align:center;font-size:15px;opacity:.9;flex:none}
.uk-nav .nav-item:hover{background:var(--hover);color:var(--text)}
.uk-nav .nav-item.active{background:var(--primary-weak);color:var(--primary);font-weight:600}
.uk-nav .nav-item.active::before{content:"";position:absolute;left:-12px;top:8px;bottom:8px;width:3px;border-radius:0 3px 3px 0;background:var(--primary)}
/* 子项(nav-child): 靠左侧一条竖线表达从属, 不靠留白 —— 纯缩进在窄侧栏里读不出层级。
   图标位保留但空着(对齐父项文字), 子项自己不配图标: 一列图标里混进几个明显不同量级的
   概念反而更乱。 */
.uk-nav .nav-child{padding-left:24px;font-size:13px}
.uk-nav .nav-child::after{content:"";position:absolute;left:14px;top:4px;bottom:4px;width:1px;background:var(--border-2)}
.uk-nav .nav-child .ico{display:none}
.uk-nav .nav-child.active::after{background:var(--primary)}
.uk-nav .nav-child.active::before{display:none}   /* 左侧那条高亮竖条归父级层次用, 子项用自己的线 */
.uk-nav .nav-item .badge{margin-left:auto;background:var(--danger);color:#fff;font-size:11px;font-weight:600;padding:1px 7px;border-radius:20px}
/* 退出 = 导航最后一项(2026-09-18 主人: 不要底部常驻按钮); 上面空一截和业务项分开 */
.uk-nav .uk-logout{margin-top:14px}
/* 语言下拉在用户区右端: 名字那一格吃掉剩余宽度(长名字省略), 下拉按内容宽 */
.uk-user-nm{flex:1;min-width:0}
.uk-user-nm .nm{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.uk-user .uk-lang{flex:none;width:auto;font-size:12px;padding:2px 26px 2px 8px;background-position:right 7px center;cursor:pointer}
.uk-user{display:flex;align-items:center;gap:10px;padding:6px 10px}
/* 用户区置顶形态(2026-07-10 用户: 去品牌行, 用户名放侧栏最上): 直属 sidebar 的 uk-user 带分隔线 */
.uk-sidebar>.uk-user{padding:8px 10px 14px;border-bottom:1px solid var(--border-2);margin-bottom:4px;flex:none}
.uk-sidebar>.uk-user .nm{font-size:14px}
.uk-user .ava{width:32px;height:32px;border-radius:50%;background:var(--primary);color:#fff;display:flex;align-items:center;justify-content:center;font-weight:600;font-size:13px;flex:none}
.uk-user .ava.logo{background:none;border-radius:0}
.uk-user .ava.logo svg{width:32px;height:32px;display:block}
.uk-user .nm{font-weight:600;font-size:13px} .uk-user .rl{font-size:11px;color:var(--faint)}

.uk-main{flex:1;display:flex;flex-direction:column;overflow:hidden}
.uk-topbar{height:60px;flex:none;background:var(--surface);border-bottom:1px solid var(--border);display:flex;align-items:center;gap:14px;padding:0 22px}
.uk-topbar .title{font-size:18px;font-weight:700;letter-spacing:-.01em}
.uk-topbar .spacer{flex:1}
.uk-search{display:flex;align-items:center;gap:8px;background:var(--bg);border:1px solid var(--border);border-radius:var(--r);padding:7px 12px;width:260px;color:var(--muted)}
.uk-search input{border:0;background:transparent;outline:0;flex:1;font-size:13px;color:var(--text)}
.uk-icon-btn{width:36px;height:36px;border-radius:var(--r);border:1px solid var(--border);background:var(--surface);display:flex;align-items:center;justify-content:center;cursor:pointer;font-size:15px}
.uk-icon-btn:hover{background:var(--hover)}
/* 内联 SVG 图标基类(feather 风 24 viewBox, stroke=currentColor 随文字色/激活态变色) */
.uk-i{width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;flex:none;vertical-align:-2px}
.uk-topbar-actions{display:flex;gap:8px;align-items:center}
.uk-content{flex:1;overflow:auto;padding:22px}

/* 汉堡 + 遮罩(桌面隐藏) */
.uk-hamb{display:none;width:38px;height:38px;border-radius:var(--r);border:1px solid var(--border);background:var(--surface);align-items:center;justify-content:center;cursor:pointer;font-size:18px}
.uk-scrim{display:none;position:fixed;inset:0;background:rgba(16,24,40,.4);z-index:1040}
/* 桌面端侧栏可收起(2026-09-19 主人:「左侧栏可以动画收回隐藏, 默认打开」)。
   opt-in: renderShell({collapsible:true}) 给 .uk-app 打 uk-collapsible(目前只 ERP 开), 收起 = .uk-side-off。
   负 margin 把侧栏整个推出去, 主区(flex:1)自然变宽, .uk-app 的 overflow:hidden 负责裁掉; 宽度含 padding/边框
   (border-box), 所以 -var(--sidebar) 正好推干净。只在桌面宽度生效 —— 窄屏仍是下面那套抽屉, 两套互不干扰。 */
/* 开关 = 侧栏右边沿外侧的半圆把手(2026-09-19 主人: 顶栏汉堡不好看, 要「跟左侧栏连着的箭头」)。
   把手压住侧栏那 1px 右边框、自己不画左边框 -> 和侧栏连成一体; 侧栏推出去后它停在屏幕左边沿(0~17px)。
   展开 = 左箭头(点了收回), 收起 = 旋转 180° 成右箭头。
   放在顶栏(60px)下面一点的灰底内容区: 白把手压在灰底上才看得出是从侧栏伸出来的; 放顶栏里是白对白, 只剩一圈细线。
   宽 16px 小于内容区左内边距 22px, 和卡片之间还留 6px, 收起后也不压内容。 */
.uk-side-tab{display:none}
@media (min-width:769px){
  .uk-app.uk-collapsible .uk-sidebar{position:relative;z-index:30;transition:margin-left .22s ease}
  .uk-app.uk-side-off .uk-sidebar{margin-left:calc(-1 * var(--sidebar))}
  .uk-app.uk-collapsible .uk-side-tab{display:flex;position:absolute;top:74px;right:-16px;width:16px;height:44px;padding:0;
    align-items:center;justify-content:center;background:var(--surface);color:var(--muted);cursor:pointer;
    border:1px solid var(--border);border-left:none;border-radius:0 12px 12px 0;box-shadow:3px 2px 8px rgba(16,24,40,.08);
    transition:color .15s,background .15s}
  .uk-app.uk-collapsible .uk-side-tab:hover{color:var(--primary);background:var(--primary-weak)}
  .uk-app.uk-collapsible .uk-side-tab:focus-visible{outline:none;box-shadow:0 0 0 1px var(--primary),0 0 0 4px var(--primary-weak)}
  .uk-side-tab .uk-i{width:14px;height:14px;stroke-width:2.4;transition:transform .22s ease}
  .uk-app.uk-side-off .uk-side-tab .uk-i{transform:rotate(180deg)}
}
@media (prefers-reduced-motion:reduce){.uk-app.uk-collapsible .uk-sidebar,.uk-side-tab .uk-i{transition:none}}

/* ---------- 组件: 统计卡 ---------- */
.uk-stats{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:22px}
.uk-stat{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-lg);padding:18px;box-shadow:var(--sh-sm)}
.uk-stat .lbl{color:var(--muted);font-size:13px;font-weight:500;display:flex;align-items:center;gap:8px}
.uk-stat .lbl .si{width:30px;height:30px;border-radius:var(--r-lg);display:flex;align-items:center;justify-content:center;font-size:15px}
.uk-stat .num{font-size:27px;font-weight:750;letter-spacing:-.02em;margin-top:12px}
.uk-stat .delta{font-size:12.5px;font-weight:600;margin-top:5px}
.uk-up{color:var(--ok)} .uk-down{color:var(--danger)}

/* ---------- 组件: 状态 pill / 头像单元格 ---------- */
/* ‼️ white-space:nowrap —— 标签是一个整体, 断成两行就不像标记像句子了
   (2026-09-05 实测: 窄窗口下 "Merchant ✓" 的 ✓ 被甩到第二行, 整枚标变成两层楼)。
   放不下就让它挤出格子/换整枚到下一行, 都比把自己的字拆开强。 */
.uk-pill{display:inline-flex;align-items:center;gap:5px;padding:3px 10px;border-radius:var(--r-lg);font-size:12px;font-weight:600;white-space:nowrap}
.uk-pill::before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor}
/* 预售天数那枚不要圆点(2026-10-01 主人:「前面加个点是何意味?」): 圆点是状态灯, 天数不是状态 */
.uk-preo .uk-pill::before{display:none}
.uk-pill.ok{background:var(--ok-weak);color:var(--ok)} .uk-pill.warn{background:var(--warn-weak);color:var(--warn)} .uk-pill.dng{background:var(--danger-weak);color:var(--danger)}
/* mute = 已归档/已删除等"不再活跃"的终态。不能借 dng —— 红色是"出问题了", 而这类是正常结束。 */
.uk-pill.mute{background:var(--hover);color:var(--muted)}
.uk-cell-user{display:flex;align-items:center;gap:10px}
.uk-cell-user .ava{width:32px;height:32px;border-radius:50%;color:#fff;display:flex;align-items:center;justify-content:center;font-weight:600;font-size:12px;flex:none}

/* ---------- 组件: 原生表格(ERP 新页用; 存量 DataTables 见下方 Bootstrap 覆盖) ---------- */
.uk-tbl{width:100%;border-collapse:collapse;font-size:13.5px}
.uk-tbl th{text-align:left;color:var(--muted);font-weight:600;font-size:12px;text-transform:uppercase;letter-spacing:.03em;padding:11px 14px;border-bottom:1px solid var(--border-2);background:var(--surface-2)}
.uk-tbl td{padding:12px 14px;border-bottom:1px solid var(--border-2)}
/* 紧凑表(opt-in, 2026-09-15): 列多的表里 14px 左右内边距 x 12 列 = 264px 纯空白。
   ‼️ 不改全局 `.uk-tbl td` —— 这份 CSS 是各产品共用的。 */
.uk-tbl-tight th,.uk-tbl-tight td{padding-left:8px;padding-right:8px}
/* 列宽范式(2026-09-15 主人定): **除吸收列外, 列宽由内容决定** —— 没内容自然就窄, 不写死 px。
   ‼️ 实测(Chrome, table-layout:auto, 订单表商品列自然宽 618):
        th{max-width:200}        -> 618  完全无效
        th+td{max-width:200}     -> 287  压不住
        内层容器 max-width+截断  -> 303  压不住
        th{width:200}            -> 180  有效
        th{min-width:160}        -> 生效
      所以 **max-width 不是列的上限, width 才是**; min-width 照样生效。
   ‼️ 还有一条更要命: 表是 width:100%, **余量必须有人吃**。没有吸收列时余量平摊到各列,
      "上限"就成了空话(上面那个 303 就是这么来的)。所以 .uk-tbl-auto 里**必须**至少有一个
      .uk-grow 列。
   用法: <table class="uk-tbl uk-tbl-auto">, 然后
        .uk-grow  = 吸收列/自由文本列(宽度自然生长, 吃余量)
        不挂类     = 缩到内容刚好(width:1% + 表头不换行)
        .uk-ckcell = 勾选列, 不吃统一下限 */
.uk-tbl-auto th{min-width:56px}
.uk-tbl-auto th:not(.uk-grow){width:1%;white-space:nowrap}
.uk-tbl-auto th.uk-ckcell{min-width:0}
/* 一般列表的列宽范式(2026-09-26 主人:「列宽用自然宽度, 别给 fix 宽度, 但是每一列都有一个最小宽度, 看 order table;
   这些规则要适用于所有这种形式的 table」)。用法: <table class="uk-tbl uk-tbl-nat">, 表头**不写 px 宽度**。
   各列按内容自然宽(auto 布局按各列内容宽度比例分富余: 短的列自然窄, 不会全灌进一列, 右边也不留空洞);
   下限 = 表头文字不换行 + 统一 56px, 个别列要更宽的在 th 上写 min-width。
   和订单表 .uk-tbl-auto 的区别: 订单表有 30% 的商品列兜富余, 所以别的列能缩到 1%; 一般列表没有这种列。 */
/* ‼️ 2026-09-26 同日主人:「整个 admin 通用的 table 也都这么搞」—— 这条下限升成**全后台所有表格的默认**
   (ERP / recruitadmin / monsteradmin 共用本文件): 原生 .uk-tbl、Bootstrap .table、DataTables 表头一律
   不换行 + 至少 56px; 列宽不写 px, 按内容自然宽。uk-tbl-nat 现在只剩下面两条输入框宽度。
   DataTables 另要在建表时关 autoWidth —— 它默认会量一遍把每列 px 宽写死到 th 上。 */
.uk-tbl th,.table > thead > tr > th,table.dataTable > thead > tr > th{min-width:56px;white-space:nowrap}
.uk-tbl th.uk-ckcell,.uk-tbl th.uk-spacer,.uk-tbl th.uk-draghead{min-width:0}
/* 表里的数字输入框不撑满格子: Bootstrap .form-control 是 width:100%, 自然宽的列一分到富余, 框就跟着拉到三四百 px
   (2026-09-26 定价页倍率/加减额框被拉到 380px 实测)。定一个够放 8 位数的宽度。 */
.uk-tbl-nat td input[type=number].form-control{width:110px;display:inline-block}
/* 文字框同理(编辑页规格矩阵新建档的 SKU 框): 不给宽度就在自动布局里被压成一条缝, 给了 100% 又被富余拉长 */
.uk-tbl-nat td input.form-control:not([type]),.uk-tbl-nat td input[type=text].form-control{width:150px;display:inline-block}
/* 定长短值(时间/金额/单号这类)的**格子**也不许换行 —— 范式只给 th 加了 nowrap,
   td 不管的话列一窄就被压成 "2026-/09-15/18:44" 三行(2026-09-15 订单表实测)。
   ‼️ 别把它加成"所有非 .uk-grow 列"的默认: 状态列下面挂着运单号那种长单串, 一 nowrap 就把表撑爆。 */
.uk-tbl td.uk-nw{white-space:nowrap}
/* 平台芯片并进店铺格 / 预期回款并进金额格(2026-09-15; 平台 09-17 拆回单列, 2026-09-20 主人又要合) */
/* 平台标排在店铺标**上面**(2026-09-20 主人), 所以是下外边距不是上外边距 */
.uk-tbl td.uk-shopcell .od-pf{margin-bottom:3px}
.uk-tbl td.od-amt{white-space:nowrap}
.uk-tbl td.od-amt .od-payout{color:var(--muted);margin-top:2px}
.uk-tbl tr:last-child td{border-bottom:0}
.uk-tbl tr:hover td{background:var(--surface-2)}
.uk-tbl-scroll{overflow-x:auto;-webkit-overflow-scrolling:touch}

/* ============================================================
   Bootstrap 覆盖: 让存量 .card/.btn/.table/.modal/.form-* 页面继承 SaaS 观感
   ============================================================ */
.card{border:1px solid var(--border)!important;border-radius:var(--r-lg)!important;box-shadow:var(--sh-sm)!important;background:var(--surface)!important;color:var(--text);
      /* Bootstrap 拿 --bs-card-border-radius(默认 6px)算标题栏/页脚的内圆角(5px), 不知道上面改成了 --r-lg(8px)。
         标题栏是方一点的角, 它的底色就盖在卡片那段弧形边框上 -> 四角边框看着变细(主人 2026-10-05 截图)。
         两个变量都要对齐: 编译后的 Bootstrap 里内圆角直接引 --bs-border-radius, 不跟 --bs-card-border-radius 走。 */
      --bs-card-border-radius:var(--r-lg)!important;--bs-card-inner-border-radius:calc(var(--r-lg) - 1px)!important}
.card-header{background:var(--surface)!important;border-bottom:1px solid var(--border-2)!important;font-weight:700}
/* ‼️‼️ 按钮的颜色**只改 Bootstrap 自己的 --bs-btn-* 变量, 一个 !important 都不要写**。
   2026-09-05 事故: 这里原来写 `.btn-outline-primary{color:var(--primary)!important}` +
   只补了 :hover。Bootstrap 的 :active / :focus / .btn-check:checked+.btn / .show 会把背景
   填成主色并同时把字色换成 `--bs-btn-active-color`(白) —— 而那个 !important 把白字压回蓝字,
   于是**蓝底蓝字, 一个字都看不见**(主人报的 "Copy to Shops" 就是它)。
   变量写法为什么不会再犯: 每个状态自带**成对**的 color + bg, 换就一起换, 不存在只压住一半。
   ‼️ 不需要 !important: ui-kit.css 在 bootstrap 之后加载(erp/index.jsp:41-43, recruitadmin 同),
      同特异性靠后者胜。写了 !important 反而把后面各状态的 hook 一起焊死。 */
.btn{border-radius:var(--r)!important;font-weight:600;font-size:13.5px}
.btn-primary{--bs-btn-bg:var(--primary);--bs-btn-border-color:var(--primary);
  --bs-btn-hover-bg:var(--primary-hover);--bs-btn-hover-border-color:var(--primary-hover);
  --bs-btn-active-bg:var(--primary-hover);--bs-btn-active-border-color:var(--primary-hover);
  --bs-btn-disabled-bg:var(--primary);--bs-btn-disabled-border-color:var(--primary)}
.btn-outline-primary{--bs-btn-color:var(--primary);--bs-btn-border-color:var(--primary);
  --bs-btn-hover-color:#fff;--bs-btn-hover-bg:var(--primary);--bs-btn-hover-border-color:var(--primary);
  --bs-btn-active-color:#fff;--bs-btn-active-bg:var(--primary);--bs-btn-active-border-color:var(--primary);
  --bs-btn-disabled-color:var(--primary);--bs-btn-disabled-border-color:var(--primary)}
/* danger 的描边款不覆写会掉回 Bootstrap 的 #dc3545 —— 和 --danger(#f04438) 差一截,
   而"建/改/删"三个按钮是并排的, 只有它不是一家的颜色, 一眼看得出来。 */
.btn-danger{--bs-btn-bg:var(--danger);--bs-btn-border-color:var(--danger);
  --bs-btn-hover-bg:var(--danger-hover,#d92d20);--bs-btn-hover-border-color:var(--danger-hover,#d92d20);
  --bs-btn-active-bg:var(--danger-hover,#d92d20);--bs-btn-active-border-color:var(--danger-hover,#d92d20);
  --bs-btn-disabled-bg:var(--danger);--bs-btn-disabled-border-color:var(--danger)}
/* 填充红同样压深一档: 白字压在 --danger(#f04438) 上只有 3.76(实测), 换 #d92d20 到 4.8。
   描边态的字色仍用 --danger —— 那是深字压白底, 没这个问题。 */
.btn-outline-danger{--bs-btn-color:var(--danger);--bs-btn-border-color:var(--danger);
  --bs-btn-hover-color:#fff;--bs-btn-hover-bg:#d92d20;--bs-btn-hover-border-color:#d92d20;
  --bs-btn-active-color:#fff;--bs-btn-active-bg:#d92d20;--bs-btn-active-border-color:#d92d20;
  --bs-btn-disabled-color:var(--danger);--bs-btn-disabled-border-color:var(--danger)}
/* success 同理: 不覆写会掉回 #198754, 和 --ok(#12b76a) 是两个绿。 */
/* ‼️ 填充绿用**深一档**的 #087443, 不用 --ok(#12b76a): 白字压在 #12b76a 上对比只有 2.62
   (2026-09-05 在真页面上量的), 那已经是"看得见但费劲"。#087443 是调色板里已有的绿, 白字 5.3。
   --ok 本身不动 —— 它还给状态点/浅底 pill 用, 那些是深字压浅底, 没有这个问题。 */
.btn-success{--bs-btn-bg:#087443;--bs-btn-border-color:#087443;
  --bs-btn-hover-bg:#066037;--bs-btn-hover-border-color:#066037;
  --bs-btn-active-bg:#066037;--bs-btn-active-border-color:#066037;
  --bs-btn-disabled-bg:#087443;--bs-btn-disabled-border-color:#087443}
.btn-outline-success{--bs-btn-color:#087443;--bs-btn-border-color:#087443;
  --bs-btn-hover-color:#fff;--bs-btn-hover-bg:#087443;--bs-btn-hover-border-color:#087443;
  --bs-btn-active-color:#fff;--bs-btn-active-bg:#087443;--bs-btn-active-border-color:#087443;
  --bs-btn-disabled-color:#087443;--bs-btn-disabled-border-color:#087443}
/* ‼️ 上面这条给所有输入控件加了 !important 的圆角, 于是 **Bootstrap 抹掉 input-group
   内侧圆角的规则被盖掉了** —— 三个控件各自带着 6px 圆角顶在一起, 中间显出一个豁口
   (2026-09-04 主人在筛选行指出"margin 不对", 实测三个控件 x 是 -1px 相接的, 问题只在圆角)。
   这里把内侧圆角补抹掉: 首个只留左圆角, 末个只留右圆角, 中间全平。 */
.input-group > :not(:first-child){border-top-left-radius:0!important;border-bottom-left-radius:0!important}
.input-group > :not(:last-child){border-top-right-radius:0!important;border-bottom-right-radius:0!important}

.form-control,.form-select{border-radius:var(--r)!important;border-color:var(--border)!important;font-size:13.5px;background-color:var(--surface);color:var(--text)}
/* ‼️ 描边按钮**只有一种风格**, 只是颜色不同(2026-09-05 主人:「为什么这些按钮你都要搞的
   风格差距那么大? 要用就用一种风格, 只是颜色不同」)。
   那一种风格的定义是 primary/danger/success 三家共同遵守的那条: **边框色 = 文字色**。
   secondary 原来破了例 —— 字用 --muted(#6b7385) 而边框用 --border(#e7e9ee),
   后者对白底只有 **1.15:1**, 等于没有边框; 并排放着就成了「有框」和「没框」两种东西。
   实测对比度: primary 5.00 · secondary(改后) 4.82 · danger 3.77 —— 视觉重量这才对齐。
   ‼️ hover/active/disabled 的边框色**必须一起换**, 否则鼠标一碰又掉回淡边。
   ‼️ 别为了「次要动作要轻一点」把边框留淡: 轻重交给**颜色**(灰 vs 蓝 vs 红)去表达,
      不是交给「有没有边框」—— 后者读起来是两套设计语言, 不是主次。

   ‼️‼️ **交互模式一律照 Bootstrap 原生, 不许自己发挥**(2026-09-05 主人:「谁他妈让你覆盖了,
      你就用原生的」)。原生 outline-* 的 hover/active 就是**填自己的色 + 白字**, 三家都这样;
      secondary 一度被我改成「填 --hover 淡灰 + 深字」, 结果鼠标划过去几乎看不出变化,
      和旁边蓝/红按钮的反白填充成了两种交互。
      界线记死: **换颜色值 = 主题定制(可以)**; **换交互模式 = 自己发挥(不可以)**。
      白字压 --muted(#6b7385) = 4.82:1, 与 primary(5.00) / danger(4.8) 同档, 过 AA。 */
/* 琥珀 / 青: 写法和 primary·danger·success 一模一样(边框色 = 文字色, hover 填自己的色 + 白字),
   只是颜色不同 —— 这正是主人要的"一种风格, 只是颜色不同"。 */
.btn-outline-warning{--bs-btn-color:var(--warn-deep);--bs-btn-border-color:var(--warn-deep);
  --bs-btn-hover-color:#fff;--bs-btn-hover-bg:var(--warn-deep);--bs-btn-hover-border-color:var(--warn-deep);
  --bs-btn-active-color:#fff;--bs-btn-active-bg:var(--warn-deep);--bs-btn-active-border-color:var(--warn-deep);
  --bs-btn-disabled-color:var(--warn-deep);--bs-btn-disabled-border-color:var(--warn-deep)}
.btn-outline-info{--bs-btn-color:var(--info);--bs-btn-border-color:var(--info);
  --bs-btn-hover-color:#fff;--bs-btn-hover-bg:var(--info);--bs-btn-hover-border-color:var(--info);
  --bs-btn-active-color:#fff;--bs-btn-active-bg:var(--info);--bs-btn-active-border-color:var(--info);
  --bs-btn-disabled-color:var(--info);--bs-btn-disabled-border-color:var(--info)}
.btn-outline-secondary{--bs-btn-color:var(--muted);--bs-btn-border-color:var(--muted);
  --bs-btn-hover-color:#fff;--bs-btn-hover-bg:var(--muted);--bs-btn-hover-border-color:var(--muted);
  --bs-btn-active-color:#fff;--bs-btn-active-bg:var(--muted);--bs-btn-active-border-color:var(--muted);
  --bs-btn-disabled-color:var(--muted);--bs-btn-disabled-border-color:var(--muted)}
.text-muted{color:var(--muted)!important}
.form-control:focus,.form-select:focus{border-color:var(--primary)!important;box-shadow:0 0 0 3px var(--primary-weak)!important}
/* 弹窗圆角**单独保留原来的 12px**(2026-08-20 用户: "popup 的 border radius 复原, 之前那样好看,
   button/tags 的改动保留")。所以这里用 --r-modal 而不是跟着 --r-lg 一起变小 ——
   大面板的圆角和小控件的圆角本来就不该是同一个值: 面板大, 圆角小了显得生硬。 */
/* 宽大弹窗(订单详情这类内容多的): 宽高都吃满屏幕, 上下**等边距**。
   ‼️ 必须给 .modal-dialog **固定 height** —— 只给 .modal-body 一个 max-height 是
   "内容多高就多高, 最多不超过这么高", 内容不够长时弹窗照样矮着, 看起来像没改。
   放在 css 而不是 js 里写内联样式: css 有 ?v= 缓存戳, 改了立刻生效;
   app.js 没有版本号(build.xml:785 记着是用户当初的要求), 改了要强刷才看得到。 */
.uk-modal-tall .modal-dialog{max-width:min(1500px,96vw);width:96vw;height:calc(100vh - 1.5rem);margin:.75rem auto}
/* ‼️ zoom .9 的 vh 补偿 —— 与 .uk-app 那条同一个坑同一套解法(见文件头 ⚠ 注释):
   html{zoom:.9} 而 **vh 不随 zoom 缩放**, 所以 100vh 的弹窗被压成视觉 90vh, 底部空 10%。
   实测正是这个: 视口 1026 时下边距 116(≈11%), 上边距却只有 10。反除 .9 补回来。
   (排在上面那条之后, 同特异性靠后胜。) */
@media (min-width:769px){.uk-modal-tall .modal-dialog{height:calc((100vh - 1.5rem) / .9)}}
.uk-modal-tall .modal-content{height:100%}
.uk-modal-tall .modal-body{flex:1 1 auto;overflow:auto}
.modal-content{border:0!important;border-radius:var(--r-modal)!important;box-shadow:var(--sh-lg)!important;background:var(--surface);color:var(--text)}
/* Bootstrap 遮罩用 100vw/100vh, 不随 html zoom .9 缩放 -> zoom 后只铺 90% 露右/下白边(2026-07-14 用户报);
   改成 inset:0 四边锚定(与 .uk-scrim 同法, 不依赖 zoom 具体值), 永远铺满视口. 三后台共用 ui-kit 一处修. */
.modal-backdrop{inset:0!important;width:auto!important;height:auto!important}
.badge.bg-danger{background:var(--danger)!important} .badge.bg-primary{background:var(--primary)!important} .badge.bg-success{background:var(--ok)!important}
table.dataTable thead th{color:var(--muted);font-weight:600;font-size:12px;text-transform:uppercase;letter-spacing:.03em;background:var(--surface-2);border-bottom:1px solid var(--border-2)}
table.dataTable td{border-color:var(--border-2)}
table.dataTable td.dtr-control:before{background-color:var(--primary)!important}
/* 存量 Bootstrap/DataTables 表格观感对齐 .uk-tbl(2026-07-10 用户: 字太大/太挤/按钮太大): 字号/密度/行悬停/表内按钮收小。
   密度规则同选择器后置覆盖 bootstrap 的 .table 与 .table-sm, 全后台统一。 */
.table{font-size:13.5px}
.table thead th{color:var(--muted);font-weight:600;font-size:12px;text-transform:uppercase;letter-spacing:.03em;background:var(--surface-2);border-bottom:1px solid var(--border-2)}
.table{color:var(--text)}
.table>:not(caption)>*>*{padding:.6rem .75rem;vertical-align:middle;background-color:transparent}
.table tbody tr:hover>*{background:var(--surface-2)}
.table .btn-sm{font-size:12px;padding:.2rem .6rem;font-weight:500}
/* 列表页表格区包成卡片面(留白呼吸感, 不顶满内容区; 配合上面的贴底 flex 链) */
.uk-content>.dataTables_wrapper{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-lg);padding:12px 16px;box-shadow:var(--sh-sm)}
.metric-num{font-size:1.8rem;font-weight:700}

/* ---------- 翻页器紧凑 + 分页行贴底(全后台统一) ---------- */
/* 所有 .pagination 缩小(含 DataTables bs5 翻页器), 配色跟设计变量 */
.pagination{--bs-pagination-padding-x:.6rem;--bs-pagination-padding-y:.22rem;--bs-pagination-font-size:12.5px;margin-bottom:0}
.pagination .page-link{color:var(--muted);border-color:var(--border);background-color:var(--surface)}
.pagination .page-item.active .page-link{background:var(--primary);border-color:var(--primary);color:#fff}
.dataTables_info{font-size:12.5px;color:var(--muted)!important}
/* 数据不满一屏时把"信息+翻页"行挤到内容区底部: 有表格的页面内容区变列 flex, 表格所在 .dt-row(col-sm-12 的父行)撑满。
   :has() 老浏览器不识别则整段忽略, 布局回到现状(渐进增强)。 */
.uk-content:has(.dataTables_wrapper){display:flex;flex-direction:column}
.uk-content:has(.dataTables_wrapper)>*{flex:0 0 auto}
.uk-content .dataTables_wrapper{display:flex;flex-direction:column;flex:1 0 auto}
.uk-content .dataTables_wrapper>.row{flex:0 0 auto}
.uk-content .dataTables_wrapper>.row.dt-row{flex:1 1 auto}
/* 列表卡 .uk-listcard(2026-10-02 主人: 表格照 ERP 那套; 内容不满也要顶满 flex-grow:1, 每页条数在右下角)。
   卡 = .uk-tbl-scroll(表) + .uk-listpager(翻页器)。同上面 DataTables 那条链: 内容区变列 flex, 卡撑满, 翻页器贴底。
   只圈挂了这个类的卡, 不动 .uk-content 本身(三后台共用)。 */
.uk-content:has(.uk-listcard){display:flex;flex-direction:column}
.uk-content:has(.uk-listcard)>*{flex:0 0 auto}
.uk-content .uk-listcard{display:flex;flex-direction:column;flex:1 0 auto}
.uk-listcard>.uk-tbl-scroll{flex:1 1 auto}
.uk-listcard>.uk-listpager{flex:0 0 auto}

/* ---------- toast / loading / 动作面板(承 recruitadmin.css, 收进套件) ---------- */
.toast-wrap{position:fixed;top:1rem;right:1rem;left:1rem;z-index:var(--z-toast);display:flex;flex-direction:column;align-items:flex-end;gap:.5rem;pointer-events:none}
.ra-toast{max-width:90vw;padding:.6rem 1rem;border-radius:var(--r);color:#fff;box-shadow:var(--sh);font-size:.9rem}
.ra-toast.ok{background:var(--ok)} .ra-toast.err{background:var(--danger)} .ra-toast.info{background:var(--primary)}
#loadingMask{display:none;position:fixed;inset:0;z-index:var(--z-busy);background:rgba(255,255,255,.5);align-items:center;justify-content:center}
#loadingMask.show{display:flex}
.ra-actions .modal-title{font-size:1rem}
.ra-actions .btn{padding:.65rem 1rem;font-size:1rem}
@media (max-width:575.98px){
  .ra-actions .modal-dialog{margin:0;position:fixed;left:0;right:0;bottom:0;max-width:100%}
  .ra-actions .modal-content{border-radius:1rem 1rem 0 0}
}

/* ---------- 客服台 ---------- */
.cs-wrap{display:flex;gap:16px}
.cs-list{width:300px;flex:none;background:var(--surface);border:1px solid var(--border);border-radius:var(--r-lg);overflow:auto}
.cs-item{display:flex;align-items:center;gap:11px;padding:13px 14px;cursor:pointer;border-bottom:1px solid var(--border-2)}
.cs-item:hover{background:var(--surface-2)} .cs-item.on,.cs-item.active{background:var(--primary-weak)}
.cs-ava{width:38px;height:38px;flex:none;border-radius:50%;color:#fff;display:flex;align-items:center;justify-content:center;font-weight:600}
.cs-nm{font-weight:600;font-size:13.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} .cs-tm{font-size:11.5px;color:var(--faint)}
.cs-dot{width:8px;height:8px;border-radius:50%;background:var(--danger);margin-left:auto;flex:none}
/* 头像 + 下方店铺标(ERP 客服): 整行顶对齐; 列定宽, 长别名在标签里折行不撑宽 */
.cs-item.cs-top{align-items:flex-start} .cs-item.cs-top .cs-dot{margin-top:6px}
/* 双击侧栏「客服」跳到的那条未读会话闪一下(2026-09-19), 眼睛好找 */
.cs-item.cs-flash{animation:csFlash 1.4s ease}
@keyframes csFlash{0%,35%{background:var(--danger-weak)}100%{background:transparent}}
/* 客服页搜索框(ERP, 2026-09-29 学微信): 框钉在会话列顶上不随列表滚, 下面 .cs-scroll 才滚;
   结果分「联系人 / 聊天记录」两段, 命中词黄底; 从搜索点进会话, 那条消息闪一下 */
.cs-list.cs-has-search{display:flex;flex-direction:column;overflow:hidden}
.cs-has-search>.cs-scroll{flex:1;min-height:0;overflow:auto}
.cs-search{position:relative;flex:none;padding:10px 12px;border-bottom:1px solid var(--border-2)}
.cs-search input{padding-right:28px}
.cs-search input::-webkit-search-cancel-button{display:none}
.cs-search-x{position:absolute;right:18px;top:50%;transform:translateY(-50%);border:0;background:none;color:var(--faint);font-size:18px;line-height:1;padding:0 4px;cursor:pointer}
.cs-search-x:hover{color:var(--text)}
.cs-sec{padding:8px 14px 4px;font-size:12px;color:var(--faint);font-weight:600;background:var(--surface-2)}
.cs-smore,.cs-sback{padding:9px 14px;font-size:12.5px;color:var(--primary);cursor:pointer;border-bottom:1px solid var(--border-2)}
.cs-sback{font-weight:600;position:sticky;top:0;background:var(--surface);z-index:1}
.cs-smore:hover,.cs-sback:hover{background:var(--surface-2)}
.cs-snip{font-size:13px;line-height:1.45;margin-top:2px;word-break:break-word;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}
mark.cs-hl{background:#fde68a;color:inherit;padding:0 1px;border-radius:2px}
.cs-nm .cs-wrapnm{white-space:normal;word-break:break-all}
.cs-osn{margin-top:2px;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-variant-numeric:tabular-nums} .cs-osn-n{color:var(--faint)}
.cs-osn.cs-osn-none{color:var(--faint);font-style:italic}
.cs-sys{opacity:.6}
.cs-row.cs-hit .cs-bub{animation:csHit 2.4s ease}
.cs-sys.cs-hit{animation:csHitSys 2.4s ease}
@keyframes csHit{0%,55%{box-shadow:0 0 0 3px #f7b309}100%{box-shadow:0 0 0 3px transparent}}
@keyframes csHitSys{0%,55%{background:#fde68a;opacity:1}100%{background:transparent}}
.cs-side{flex:none;width:60px;display:flex;flex-direction:column;align-items:center;gap:8px}
.cs-side .cs-ava{width:32px;height:32px;font-size:13px}
.cs-shop{max-width:60px;text-align:center;line-height:1}
.cs-shop .nm{font-size:11px;color:var(--muted);word-break:break-word}
.cs-shop .uk-shoptag{white-space:normal;word-break:break-word;font-size:10.5px;line-height:1.25;padding:3px 5px}
/* 会话摘要最多两行, 第二行还放不下才出省略号(line-clamp; 老 WebKit 前缀版三件套缺一不可) */
.cs-pv{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;overflow:hidden;word-break:break-word;margin-top:2px}

/* ===== 通用红点(2026-08-07 用户要求"做个通用的, position absolute 放元素右上角") =====
   用法: 宿主元素加 .uk-dot-host(负责 position:relative), 里面放 <i class="uk-dot"></i>;
        要带数字就 <i class="uk-dot uk-dot-num">3</i>。宿主可以是按钮/下拉/菜单项/头像等任意元素。
   注意: 不能用在 <option> 上 —— option 里放不了子元素也不吃背景色, 那种场景只能退回字符标记。 */
.uk-dot-host{position:relative}
.uk-dot{
    position:absolute; top:0; right:0; z-index:3;
    width:9px; height:9px; border-radius:50%;
    background:var(--danger);
    /* 描边: 压在深色/彩色宿主上也能看清边界(不描边时红点会糊进背景) */
    box-shadow:0 0 0 2px var(--surface);
    pointer-events:none;   /* 别挡住宿主的点击 */
}
/* 行内版(2026-08-07 用户定): 不绝对定位, 跟着 flex 行走 —— margin-left:auto 推到最右 + 垂直居中,
   与会话列表的 .cs-dot 同款观感。用在"一行一项"的列表/菜单项里(宿主是 flex 且 align-items:center)。
   注意: 用了这个就不需要 .uk-dot-host, 它不参与定位。 */
.uk-dot-inline{
    position:static; margin-left:auto; flex:none;
    box-shadow:none;      /* 行内不压在别的元素上, 不需要描边 */
}
/* 带数字版: 宽度随位数撑开, 仍锚右上角 */
.uk-dot-num{
    width:auto; height:16px; min-width:16px; border-radius:var(--r);
    top:-7px; right:-7px; padding:0 5px;
    color:#fff; font-size:11px; font-weight:700; line-height:16px;
    text-align:center; font-style:normal;
}
.cs-main{flex:1;display:flex;flex-direction:column;background:var(--surface);border:1px solid var(--border);border-radius:var(--r-lg);overflow:hidden}
.cs-hd{padding:15px 18px;border-bottom:1px solid var(--border-2);font-weight:700;display:flex;align-items:center}
.cs-msgs{flex:1;overflow:auto;padding:18px;background:var(--bg);display:flex;flex-direction:column;gap:9px}
.cs-row{display:flex} .cs-row.me,.cs-row.mine{justify-content:flex-end}
.cs-bub{max-width:70%;padding:9px 13px;border-radius:14px;font-size:13.5px;line-height:1.45;word-break:break-word;white-space:pre-wrap}
.cs-row:not(.me):not(.mine) .cs-bub{background:var(--surface);border:1px solid var(--border);border-bottom-left-radius:4px}
.cs-row.me .cs-bub,.cs-row.mine .cs-bub{background:var(--primary);color:#fff;border-bottom-right-radius:4px}
.cs-bub.pending{opacity:.55} .cs-bub.failed{background:var(--danger);color:#fff}
.cs-ft{display:flex;gap:10px;padding:14px;border-top:1px solid var(--border-2);position:relative}
.cs-ft input{flex:1;border:1px solid var(--border);border-radius:var(--r);padding:9px 13px;outline:0;font-family:inherit;font-size:13.5px}
.cs-ft input:focus{border-color:var(--primary)}
.cs-emoji-btn{flex:none;font-size:1.3rem;line-height:1;border:1px solid var(--border);background:var(--surface);border-radius:var(--r-lg);padding:0 12px;cursor:pointer}
.cs-emoji-btn:hover{background:var(--hover)}
.cs-emoji{position:absolute;bottom:calc(100% + 8px);left:14px;width:300px;max-height:210px;overflow:auto;background:var(--surface);border:1px solid var(--border);border-radius:var(--r-lg);box-shadow:var(--sh-lg);padding:10px;display:flex;flex-wrap:wrap;gap:4px;z-index:20}
.cs-emoji span{width:34px;height:34px;display:flex;align-items:center;justify-content:center;font-size:1.25rem;cursor:pointer;border-radius:var(--r)}
.cs-emoji span:hover{background:var(--hover)}
.cs-back{display:none;width:34px;height:34px;border-radius:var(--r-sm);border:0;background:transparent;font-size:18px;cursor:pointer;margin-right:4px}
.cs-empty{flex:1;display:flex;align-items:center;justify-content:center;color:var(--faint);flex-direction:column;gap:10px}

/* ============================================================
   P0 打磨层(2026-07-10 "基座艺术品化"第一批, 纯 CSS 全后台白得):
   微交互 / 焦点可达性 / 数字排版 / 排序图标 / 空态 / toast 动效 / 骨架屏
   ============================================================ */
/* 微交互: 按钮过渡+按压反馈, 行悬停渐变 */
/* ⛔ 这里原来还有 `.btn:active{transform:translateY(.5px)}` —— **原生按钮按下不位移**,
   那是我自己加的(ROADMAP §369 那批"艺术品化"的产物)。2026-09-05 主人:「就用原生的,
   别他妈自己发挥」-> 撤掉; transition 里的 transform 一并去掉, 免得留个没人用的过渡。
   ‼️ 交互反馈**照 Bootstrap 原生那套**就够: hover 填色 / active 加深 / focus-visible 焦点环。 */
.btn{transition:background-color .15s,border-color .15s,color .15s,box-shadow .15s}
.uk-tbl td,.table td{transition:background-color .12s}
/* 焦点可达性: 键盘可见焦点环(主色), 覆盖 bootstrap 默认 */
.btn:focus-visible,.uk-icon-btn:focus-visible,.uk-nav .nav-item:focus-visible,.uk-hamb:focus-visible{outline:none;box-shadow:0 0 0 1px var(--primary),0 0 0 4px var(--primary-weak)}
/* 数字排版: 表格数字等宽对齐; .uk-num 给数值列右对齐用(ID/金额/数量) */
.uk-tbl,.table{font-variant-numeric:tabular-nums}
th.uk-num,td.uk-num{text-align:right}
/* 数值不换行: 金额/数量断成两行没法读。放在这里而不是逐个 th 写 nowrap ——
   ‼️ nowrap 写在 th 上会让**表头文字**成为列宽下限, 那个"窄列"就是假的
      (2026-09-03: VARIATION IMAGE 一个表头把整列顶到一百多 px)。 */
td.uk-num{white-space:nowrap}
/* DataTables 排序图标: 缩小调淡, 激活方向主色 */
table.dataTable thead>tr>th.sorting:before,table.dataTable thead>tr>th.sorting:after,table.dataTable thead>tr>th.sorting_asc:before,table.dataTable thead>tr>th.sorting_asc:after,table.dataTable thead>tr>th.sorting_desc:before,table.dataTable thead>tr>th.sorting_desc:after{font-size:.55em;opacity:.18;right:6px}
table.dataTable thead>tr>th.sorting_asc:before,table.dataTable thead>tr>th.sorting_desc:after{opacity:.9;color:var(--primary)}
/* 空态: DataTables 空表 + 通用 .uk-empty 组件 */
.dataTables_empty{padding:48px 0!important;color:var(--faint)}
/* 采集器页的「去采集」面板(ERP 2026-09-23 主人:「换个底色区分开」)。
   只用主题变量调和, 深浅色都成立; 下面的列表卡片保持纯白, 一眼分得出"在这儿动手"和"这是结果"。 */
/* ‼ 上面那条 `.card{background:var(--surface)!important}` 带 !important —— 底色不加 !important 压不过它
   (第一版就是这么白给的: 类加上了, 颜色一点没变)。 */
.card.uk-scrape{background:color-mix(in srgb, var(--primary) 9%, var(--surface))!important;
           border-color:color-mix(in srgb, var(--primary) 26%, var(--border))!important}
.card.uk-scrape>.card-header{background:color-mix(in srgb, var(--primary) 6%, var(--surface))!important;
           border-bottom-color:color-mix(in srgb, var(--primary) 18%, var(--border-2))!important}
.uk-scrape .form-control,.uk-scrape .form-select{background:var(--surface)}
/* 采集方式: 两个可点的方块, 比一排药丸看得清自己在哪一种 */
.uk-mode{display:inline-flex;align-items:center;gap:8px;padding:9px 14px;border:1px solid var(--border);
         border-radius:var(--r-lg);background:var(--surface);color:var(--text);font-size:13.5px;cursor:pointer}
.uk-mode:hover{border-color:color-mix(in srgb, var(--primary) 45%, var(--border))}
.uk-mode.active{border-color:var(--primary);color:var(--primary);font-weight:650;
         box-shadow:0 0 0 2px color-mix(in srgb, var(--primary) 16%, transparent)}
.uk-mode .uk-i{width:15px;height:15px}

.uk-empty{padding:48px 20px;text-align:center;color:var(--faint)}
.uk-empty .ic{display:block;font-size:28px;margin-bottom:8px;opacity:.55}
/* toast: 滑入动效 + 类型图标 */
@keyframes uk-toast-in{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:none}}
.ra-toast{animation:uk-toast-in .18s ease;pointer-events:auto}
.ra-toast::before{font-weight:700;margin-right:.45rem}
.ra-toast.ok::before{content:"✓"} .ra-toast.err::before{content:"✕"} .ra-toast.info::before{content:"ℹ"}
/* loading 遮罩: 轻磨砂 */
#loadingMask{background:rgba(255,255,255,.6);backdrop-filter:blur(2px)}
/* 骨架屏(留给页面局部加载用): <div class="uk-skeleton" style="height:14px"> */
.uk-skeleton{position:relative;overflow:hidden;background:var(--border-2);border-radius:var(--r-sm)}
.uk-skeleton::after{content:"";position:absolute;inset:0;background:linear-gradient(90deg,transparent,rgba(255,255,255,.65),transparent);animation:uk-shimmer 1.2s infinite}
@keyframes uk-shimmer{from{transform:translateX(-100%)}to{transform:translateX(100%)}}
/* 细节: 选区色/占位符色/输入悬停/滚动条悬停 */
/* ‼️ 不要自定义文本选中色(2026-09-05 主人): 淡色背景在输入框里看不清选中了哪一段。
   浏览器默认那个蓝是系统级高对比配色, 保持默认。 */
.form-control::placeholder{color:var(--faint)!important;opacity:1}
/* ⛔ 这里原来有 `.form-control:hover:not(:focus){border-color:#d3d7e0!important}` ——
   **原生输入框没有 hover 态**, 那是我自己加的(而且 #d3d7e0 是硬编码, 不在调色板里)。
   2026-09-05 主人:「你就用原生的, 别他妈自己发挥」-> 撤掉。 */
::-webkit-scrollbar-thumb:hover{background:#b9bfcc}
/* 动效偏好: 用户系统关动画则全部静止 */
@media (prefers-reduced-motion:reduce){*,*::before,*::after{transition:none!important;animation:none!important}}

/* ============================================================
   P1/P2 批(2026-07-10 用户令"全做"): 暗色主题 / 密度切换 / 表头钉住+卡内滚动
   ============================================================ */
/* 暗色主题: html[data-theme=dark](进页前置脚本从 localStorage['admin_theme'] 打标, 防闪白) */
[data-theme="dark"]{
  --bg:#101218; --surface:#181b23; --surface-2:#1e222c; --hover:#242a37;
  --border:#2a3040; --border-2:#232837;
  --text:#e7eaf2; --muted:#9aa3b7; --faint:#697184;
  --primary:#5b78f0; --primary-weak:#20294a; --primary-hover:#6f88f3;
  --ok-weak:#143223; --warn-weak:#33290f; --danger-weak:#3a1d1a;
  /* 暗底上要反过来取**亮版** —— #b54708 / #0e7490 这种深色压在暗底上等于看不见。
     (--danger / --ok / --warn 暗色下没重定义, 是因为它们本来就够亮。) */
  --warn-deep:#fdb022; --info:#38bdf8;
  --sh-sm:0 1px 2px rgba(0,0,0,.4); --sh:0 4px 16px rgba(0,0,0,.5); --sh-lg:0 12px 32px rgba(0,0,0,.6);
}
[data-theme="dark"] #loadingMask{background:rgba(8,10,14,.6)}
[data-theme="dark"] ::-webkit-scrollbar-thumb{background:#39404f}
[data-theme="dark"] .btn-light{--bs-btn-color:var(--text);--bs-btn-bg:var(--hover);--bs-btn-border-color:var(--border);--bs-btn-hover-color:var(--text);--bs-btn-hover-bg:var(--surface-2);--bs-btn-hover-border-color:var(--border);--bs-btn-active-color:var(--text);--bs-btn-active-bg:var(--surface-2);--bs-btn-active-border-color:var(--border)}
[data-theme="dark"] .close,[data-theme="dark"] .btn-close{filter:invert(1) opacity(.7)}
/* 密度切换: html[data-dense="1"](localStorage['admin_dense']) 表格更紧 */
[data-dense="1"] .table>:not(caption)>*>*{padding:.35rem .6rem}
[data-dense="1"] .uk-tbl td,[data-dense="1"] .uk-tbl th{padding:8px 12px}
/* 表头钉住 + 滚动权交给表格卡内部(桌面): 长表滚动时表头/筛选/分页都不跑 */
@media (min-width:769px){
  .uk-content:has(.dataTables_wrapper){overflow:hidden}
  .uk-content .dataTables_wrapper{flex:1 1 auto;min-height:0}
  .uk-content .dataTables_wrapper>.row.dt-row{overflow:auto;min-height:0}
  .uk-content .dataTables_wrapper table.dataTable thead th{position:sticky;top:0;z-index:2}
  /* 列表卡同款: 滚动只在卡里, 表头钉住, 翻页器永远在卡底 */
  .uk-content:has(.uk-listcard){overflow:hidden}
  .uk-content .uk-listcard{flex:1 1 auto;min-height:0}
  .uk-listcard>.uk-tbl-scroll{overflow:auto;min-height:0}
  .uk-listcard .uk-tbl>thead th{position:sticky;top:0;z-index:2}
}

/* ============================================================
   移动端 <=768px
   ============================================================ */
@media (max-width:768px){
  /* 抽屉用 transform 位移, 不用 left(2026-08-06 移动端实测改):
     left 是**布局属性**, 动画每帧触发重排 —— 低端安卓上抽屉会顿, 而卖家多在手机上开店。
     transform 走合成层, 不碰布局。顺带解决一个测不了的问题: 浏览器面板不在合成时
     压根不重算 left(内联 left:0 都不生效, 实测), 而 transform 照常工作 ⇒ 换成它之后这条路径可验证。 */
  .uk-sidebar{position:fixed;top:0;bottom:0;left:0;transform:translateX(-100%);z-index:1050;transition:transform .22s ease;box-shadow:var(--sh-lg);will-change:transform}
  .uk-sidebar.open{transform:translateX(0)}
  .uk-scrim.open{display:block}
  .uk-hamb{display:flex}
  .uk-topbar{padding:0 14px;gap:10px}
  .uk-topbar .title{font-size:16px}
  .uk-topbar .uk-search{display:none}
  .uk-content{padding:14px}
  .uk-stats{grid-template-columns:repeat(2,1fr);gap:12px;margin-bottom:16px}
  .uk-stat{padding:14px} .uk-stat .num{font-size:22px}
  .cs-wrap{position:relative}
  .cs-list{width:100%}
  .cs-main{display:none;position:absolute;inset:0}
  .cs-wrap.chatting .cs-list{display:none}
  .cs-wrap.chatting .cs-main{display:flex}
  .cs-back{display:flex}
}

/* ==== 下拉菜单弹层现代化(2026-07-11 用户: 原生 select 弹层丑) ====
   appearance:base-select 渐进增强: Chrome/Edge 135+ 把 option 弹层交给页面 CSS 接管,
   Firefox/Safari 自动回退原生弹层(闭合态样式不受影响)。零 JS 零 markup, 老浏览器无感。 */
/* ⚠ 必须点名 .form-select: Bootstrap 的 .form-select{appearance:none}(类选择器)压过裸 select 的 opt-in,
   漏掉它=全后台下拉一个没修(2026-07-11 用户实锤); !important 防加载序漂移。不支持的浏览器丢弃该值回退原生。 */
select,
.form-select,
::picker(select){appearance:base-select!important}
/* base-select 自带 ::picker-icon 箭头, 会与 Bootstrap .form-select 的背景图箭头叠成双箭头 → 藏掉自带的 */
.form-select::picker-icon{display:none}
::picker(select){
  border:1px solid var(--border);border-radius:var(--r-lg);background:var(--surface);
  box-shadow:0 8px 24px rgba(16,24,40,.14);padding:4px;margin-top:4px
}
select option{
  font-size:13.5px;color:var(--text);padding:6px 12px;border-radius:var(--r);cursor:pointer
}
select option:hover,select option:focus{background:var(--hover,#f4f5f8)}
select option:checked{background:var(--primary-weak);color:var(--primary);font-weight:600}
select option::checkmark{color:var(--primary)}


/* ============ 对话框(替代原生 alert/confirm/prompt) ============
   原生弹窗是浏览器画的("xxx says"), 样式不受控、手机上难看、放不下单选和多行说明,
   而且同步阻塞整页 JS。这一套由 JS 的 ui.alert/confirm/prompt/choice 驱动(见各后台 app.js)。
   z-index 压在 toast 之下: 弹框开着时的操作结果提示要能盖在它上面。 */
.uk-dlg-mask{
  position:fixed;inset:0;z-index:1080;display:flex;align-items:center;justify-content:center;
  background:rgba(16,24,40,.45);padding:16px/* 进出场动画归 shared/js/dialog.js(照登录页精校那套); 这里再挂一条会两套叠着跑 */
}
.uk-dlg{
  width:100%;max-width:420px;background:var(--surface);border-radius:var(--r-lg);
  box-shadow:var(--sh-lg);overflow:hidden/* 同上: 原来这条是带回弹过冲的 cubic-bezier(.2,.9,.3,1.2), 和新动画叠着跑, 观感很差 */
}
.uk-dlg-hd{padding:14px 18px 0;font-weight:650;font-size:15px;color:var(--text)}
/* ‼️ 高度上限跟着**视口**走, 不是写死的 60vh(主人 2026-09-10:「页面这么大, 你为什么一定要
   把弹窗搞这么小然后让用户去拖 scrollbar」)。60vh 在 1080p 上就是 648px —— 内容 700px 就
   开始滚, 而弹窗上下还空着一大片。150px 是给标题+页脚+上下外边距留的量; 只有真的装不下
   才出滚动条。 */
.uk-dlg-bd{padding:10px 18px 4px;max-height:calc(100vh - 150px);overflow:auto}
.uk-dlg-msg{color:var(--muted);font-size:13.5px;line-height:1.6;white-space:pre-wrap;word-break:break-word}
.uk-dlg-ft{display:flex;gap:8px;justify-content:flex-end;padding:14px 18px 16px}
.uk-dlg-input{margin-top:10px}
/* 单选: 整块可点(不是只有那个小圆点), 手机上尤其重要 */
.uk-dlg-choices{display:flex;flex-direction:column;gap:8px;margin-top:12px}
.uk-dlg-choice{
  display:flex;align-items:center;gap:10px;padding:10px 12px;cursor:pointer;
  border:1px solid var(--border);border-radius:var(--r);transition:background .12s,border-color .12s
}
.uk-dlg-choice:hover{background:var(--hover)}
.uk-dlg-choice.on{border-color:var(--primary);background:var(--primary-weak)}
.uk-dlg-choice .lbl{font-weight:600;font-size:14px}
.uk-dlg-choice .hint{margin-left:auto;color:var(--faint);font-size:12.5px}
@keyframes uk-dlg-fade{from{opacity:0}to{opacity:1}}
@keyframes uk-dlg-pop{from{opacity:0;transform:translateY(8px) scale(.98)}to{opacity:1;transform:none}}
@media (max-width:768px){
  /* 手机上贴底出现, 拇指够得到; 按钮拉满宽 */
  .uk-dlg-mask{align-items:flex-end;padding:0}
  /* 上滑动画归 shared/js/dialog.js —— 它按这里的 align-items:flex-end 认出抽屉形态 */
  .uk-dlg{max-width:none;border-radius:var(--r-lg) var(--r-lg) 0 0}
  .uk-dlg-ft .btn{flex:1}
}
@keyframes uk-dlg-up{from{transform:translateY(100%)}to{transform:none}}

/* ============ 面板(大弹窗)= .uk-pmask ============
   2026-09-05 三套弹窗并成一套(主人:「合并到一起, 做成最通用最好看的, 放到 js/shared 里全项目通用」)。
   骨架和基础尺寸在 www/shared/js/dialog.js 里自带(那份要零依赖, 独立能跑);
   **这里只上皮肤** —— 后台的设计变量、密度、分隔线。前台不引 ui-kit.css, 拿到的就是朴素版。

   ‼️ 里面沿用 Bootstrap 的 .modal-header/.modal-body/.modal-footer 类名是**故意的**:
      36 处调用点的 `$m.find('.modal-body')` 因此原样能用, Bootstrap 的纯样式规则也继续生效。
      我们扔掉的只是它的 JS(z-index/backdrop/body 锁/focus trap) —— 那才是当年打架的部分。
   ‼️ 竖向内距一律交给 `.py-2`(panel() 生成时就带, 老 markup 本来也带) ——
      那是 !important 的工具类, 在这里再写 padding 的上下值只会写了不算。所以只写左右。 */
.uk-pmask{background:rgba(16,24,40,.5)}
.uk-pmask .modal-content{background:var(--surface);color:var(--text)}
.uk-pmask .modal-header{
  padding-left:16px;padding-right:16px;
  border-bottom:1px solid var(--border-2);background:var(--surface)
}
.uk-pmask .modal-header .modal-title{font-size:15px;font-weight:650;color:var(--text)}
/* ✕ 自己是按钮, 不该继承标题栏那个 move 光标(拖拽是按住标题栏空白处) */
.uk-pmask .modal-header .btn-close{--bs-btn-close-opacity:.45;padding:.4rem;margin:0;flex:none;cursor:pointer}
.uk-pmask .modal-header .btn-close:hover{--bs-btn-close-opacity:.9}
.uk-pmask .modal-footer{
  padding-left:16px;padding-right:16px;
  border-top:1px solid var(--border-2);background:var(--surface-2)
}
/* 面板里的滚动条收细, 和站内别处一致(默认那条又粗又抢眼) */
.uk-pmask .modal-body::-webkit-scrollbar{width:10px;height:10px}
.uk-pmask .modal-body::-webkit-scrollbar-thumb{
  background:#d3d7e0;border-radius:var(--r);border:3px solid transparent;background-clip:content-box
}

/* 弹窗里的表单栅格: 两列, 加 .fw 的占整行。
   窄字段(金额上下限/平台/店铺)两个并排一行, 名称和备注这种长的独占一行 ——
   全挤一列会把框拉得老长, 全并排又放不下长输入。 */
.uk-dlg-form{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:6px}
.uk-dlg-form>label{display:flex;flex-direction:column;gap:5px;font-size:12.5px;color:var(--muted);font-weight:600}
/* ‼️ `.fw` 不该只认 label —— 说明文字/按钮行这些是 div, 原来没法跨列, 一律被塞进
   两列网格的一格里挤成竖条(2026-09-10 截图看出来的)。 */
.uk-dlg-form>label.fw,.uk-dlg-form>.fw,.uk-dlg-form>hr{grid-column:1 / -1}
.uk-dlg-form>hr{margin:2px 0;border:0;border-top:1px solid var(--border)}
.uk-dlg-form .hint{font-weight:400;color:var(--faint);font-size:11.5px;line-height:1.4}
@media (max-width:560px){.uk-dlg-form{grid-template-columns:1fr}}
/* 颜色色块选择器(2026-08-20, 建标签弹窗用): 原来是个 <select>, 选项文字就是 #4263eb 这种十六进制
   —— 用户挑的是颜色不是编码, 下拉里那一行行色号根本看不出选的是啥。选中态用双层 box-shadow
   画外圈(不占布局, 不会让色块跳位), 再叠一个 ✓ 保证色盲用户也分得清选没选。 */
.uk-swatches{display:flex;flex-wrap:wrap;gap:9px;padding:3px 0}
.uk-swatch{width:26px;height:26px;border-radius:var(--r-sm);cursor:pointer;position:relative;
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.10);transition:transform .12s}
.uk-swatch:hover{transform:scale(1.1)}
.uk-swatch.on{box-shadow:inset 0 0 0 1px rgba(0,0,0,.10),0 0 0 2px var(--surface),0 0 0 4px var(--primary)}
.uk-swatch.on::after{content:'✓';position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
  color:#fff;font-size:14px;font-weight:700;text-shadow:0 1px 2px rgba(0,0,0,.4)}

/* ===== 逐品批量编辑抽屉(erp §8, 2026-08-06; EasyBoss 式 Before/After) =====
   全部新类名 .pe-*, 不复用/不覆盖任何共享类 —— r691 .scroll-view 的教训: 改共享类静默砸别页。 */
.pe-mask{position:fixed;inset:0;background:var(--bg,#f6f7fb);z-index:1060;display:flex;flex-direction:column}
.pe-hd{display:flex;align-items:center;gap:10px;padding:10px 16px;border-bottom:1px solid var(--border);background:var(--card,#fff);flex-wrap:wrap}
.pe-hd .pe-title{font-weight:700;font-size:15px;margin-right:6px}
/* 字段页签(.pe-tabs/.pe-tab)已于 2026-09-04 撤掉 —— 编辑器改成一页, 见 .pe-one */
.pe-bd{flex:1;overflow:auto;padding:12px 16px}
.pe-tbl{width:100%;border-collapse:collapse;background:var(--card,#fff);border:1px solid var(--border);border-radius:var(--r-lg);overflow:hidden}
/* 行之间**不画分隔线**(2026-09-04 主人: 每行之间那个分割线删掉)。
   这张表一行里有七八个输入框, 本身就靠留白分段; 再加一条横线只是多一道噪音。
   表头下面那条留着 —— 它分的是标题行和数据, 是另一回事。 */
.pe-tbl th,.pe-tbl td{padding:8px 10px;font-size:12.5px;vertical-align:top;text-align:left}
.pe-tbl th{border-bottom:1px solid var(--border)}
.pe-tbl th{background:var(--bg-soft,#f3f4f8);color:var(--muted);font-weight:600;white-space:nowrap}
.pe-item{display:flex;gap:8px;align-items:flex-start;min-width:180px;max-width:260px}
.pe-item img{width:40px;height:40px;object-fit:cover;border-radius:var(--r);flex:none}
.pe-item .nm{font-size:12px;line-height:1.35;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}
/* 一页版编辑器(2026-09-04)。一个品一行, 这个品能改的东西全在这一行里 ——
   原来是"字段页签 + Before/After 两列", 改一个品的标题和价要切两次页签, 还看不见另一样。
   现值直接填在输入框里, 所以也不需要 Before 那一列了。 */
.pe-one{min-width:1180px}          /* 列多, 窄屏让 .pe-bd 横向滚, 别把每列压成一条缝 */
.pe-one textarea{width:100%;font-size:12.5px;resize:vertical}
.pe-one .pe-cnt{color:var(--faint);font-size:11px;text-align:right;line-height:1.2;margin-top:2px}
.pe-one .pe-cnt.over{color:var(--danger,#d6336c);font-weight:700}
/* AI 按钮上边距**两处必须同一个值**(2026-09-04 主人: 改成一个值, 别太近别太远)。
   标题那格 textarea 和按钮中间夹着字数计数, 描述那格没有 —— 各自 2px 的话看着一近一远。 */
.pe-one .pe-ai{margin-top:6px}
.pe-one .pe-ratio-warn:empty{display:none}
.pe-one td{vertical-align:top}
/* 商品那一格: 品名三行截断, 但**平台标签和 SKU 不参与截断** ——
   它俩在 .nm 里的时候被长标题直接顶掉了(2026-09-04 自己截图才看见)。 */
.pe-itemtxt{min-width:0}
.pe-itemtxt .nm{display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden;
  font-size:12px;line-height:1.35}
.pe-itemmeta{margin-top:3px;font-size:11px;display:flex;flex-wrap:wrap;gap:4px;align-items:center}
.pe-itemshop{margin-top:3px;font-size:11px;line-height:1.3}
/* 保存结果标在商品格里(2026-09-04 主人: 别为它单开一列)。
   平台原话可能很长, 允许换行 —— 宁可这一行高一点, 也不能把报错截没。 */
.pe-rowst{margin-top:4px;font-size:11px;line-height:1.35;word-break:break-word}
.pe-rowst.ok{color:var(--success,#2b8a3e);font-weight:600}
.pe-rowst.err{color:var(--danger,#d6336c);font-weight:600}
/* 价格框前面那个货币符号: 不占一列, 跟着输入框走 */
.pe-pv .cur{color:var(--muted);font-size:11px;margin-right:2px}
.pe-dim{display:flex;gap:6px;align-items:center}
.pe-dim input{width:60px}
.pe-st{font-size:12px;white-space:nowrap}
.pe-st.ok{color:var(--ok,#2b8a3e)}
.pe-st.err{color:var(--danger,#d6336c);white-space:normal;max-width:220px;display:inline-block}
.pe-ft{display:flex;align-items:center;gap:8px;padding:10px 16px;border-top:1px solid var(--border);background:var(--card,#fff);flex-wrap:wrap}
.pe-ft .pe-gap{flex:1}
@media (max-width:768px){
  .pe-bd{padding:8px}
  /* 窄屏不再压列宽: 一页版列多, 压完每一列都没法填 —— 让它横向滚, 至少每格是能用的 */
  .pe-item{min-width:140px}
}

/* ===== 客服页顶到底(2026-08-09 用户: "flex grow=1, 顶到底") =====
   原来靠 JS 量 window.innerHeight 反算 px 高度, 底部总留一条缝, 而且横幅出现/消失、
   窗口缩放、浏览器缩放都要重算 —— 算出来的数永远慢半拍。改成纯 flex 链交给浏览器。

   ⚠ 用 :has(#csRoot) 精确圈定客服页, **不动 .uk-content 本身** ——
   它是三后台所有页面共用的容器, 改共享类会静默砸别的页(r691 .scroll-view 的教训)。
   本文件第 143 行的 .uk-content:has(.dataTables_wrapper) 是同款先例。
   min-height:0 不能省: flex 子项默认 min-height:auto, 不清零的话内部 overflow:auto 不生效, 会被内容撑破。 */
.uk-content:has(#csRoot){display:flex;flex-direction:column;overflow:hidden}
#csRoot{flex:1;display:flex;flex-direction:column;min-height:0}
#csRoot>.cs-wrap{flex:1;min-height:0}

/* 订单列表的品名/规格(erp, 2026-08-11 用户: 列表要和详情页一样看到 product + classification)。
   品名两行截断: 汽配标题动辄上百字, 不截会把整行撑成一屏; title 属性给全文。
   规格用主色加粗 —— 拣错规格就是发错货, 它比品名更该被一眼看到。 */
/* ⚠ 商品列必须给**定宽容器**(2026-08-11): 表格是 auto 布局, 列宽按内容的**内在最大宽度**算,
   而 -webkit-line-clamp 只是视觉裁剪, 撑列的力还在 —— 只做截断的话汽配标题(动辄上百字符)
   会把这一列撑到几百 px, 把店铺/金额/状态/时间全挤成竖排。给内层 div 一个确定宽度,
   列的内在宽度就被钉死, 标题在里面自然换行。 */
/* 缩略图垂直居中(2026-08-21 用户): 原来 flex-start 让图顶在第一行行首,
   而右边是"标题两行 + 规格"的一叠, 图孤零零吊在左上角。
   gap 7 -> 12(2026-08-21 用户"绿色处margin加大"): 图和文字贴得太近。 */
/* 缩略图那一列的占位宽度 = 图宽 + gap。预售徽章要靠它往右让, 才能和标题/规格对齐 ——
   徽章挂在所有商品行之后(它是**整单**的属性, 不能塞进某一件商品里), 所以不在 .txt 的缩进里,
   不补这个偏移就会贴着格子最左边(2026-08-21 用户: "为什么preorder顶到前面去了")。
   ⚠ --od-thumb 必须和 app.js 里 itemImg(l.image, 30) 那个 30 一致, 改一处要改两处。 */
/* ‼️‼️ 宽度**必须是 100%**, 不能靠自定义属性从 th 传下来 ——
   **CSS 自定义属性只沿 DOM 继承, 而 th 不是 td 的祖先**。在 th 上写 --uk-prodw 一点作用都没有,
   商品格会一直用回落值(340px), 列一旦比它宽, 右边就空一条(2026-09-03 用户两次指着问
   "中间为什么这么大空隙" —— 第一次在商品页, 第二次在订单页, 同一个病)。
   列宽由 th 控制, 格子只管填满自己那一格, 两边各管各的。 */
.uk-prodcell{display:flex;align-items:center;gap:var(--od-gap,12px);width:100%;min-width:0}
/* 多品单: 每件一行, 第二件起用一条细线隔开 —— 不隔开会读成"一件商品名换行了" */
.uk-tbl{--od-thumb:36px;--od-gap:12px}
.od-lines>.uk-prodcell+.uk-prodcell{margin-top:7px;padding-top:7px;border-top:1px dashed var(--border-2)}
/* 复合单(同一商品买了几个规格, 2026-09-19 主人: 标题只显示一次): 标题一行 + 每个规格一行。
   组和别的商品之间照样画虚线; 组内不画 —— 画了又读成几件不同的商品。
   标题前的空占位和缩略图同宽, 标题就和下面各行的规格左对齐。 */
.od-lines>.od-grp+.uk-prodcell,.od-lines>.uk-prodcell+.od-grp,.od-lines>.od-grp+.od-grp{margin-top:7px;padding-top:7px;border-top:1px dashed var(--border-2)}
.od-grp-title>.sp{width:var(--od-thumb,36px);flex:none}
.od-grp>.uk-prodcell+.uk-prodcell{margin-top:6px}
/* 订单弹窗的买家 / 费用两张表(2026-09-19 主人): 左列字段名不许被挤, 右列值负责换行。
   平台掩码的地址是一长串不带空格的 ****, 不许断行时它把整张表撑宽, 左列被压成一字一行的竖排。 */
/* ‼️ 要压过 .uk-tbl tbody td:last-child{white-space:nowrap}(操作列那条, 特异性 0,2,2), 所以带上 .uk-tbl 和 tbody */
.uk-tbl.bi-tbl tbody td:first-child{white-space:nowrap;width:130px}
.uk-tbl.bi-tbl tbody td:last-child{white-space:normal;overflow-wrap:anywhere;word-break:break-word}
/* 数量 >1 才出现(2026-09-19 员工: 一单 20 件同款要一眼看出来, 照 EasyBoss 的红字 ×20) */
.od-qty{color:var(--danger);font-weight:700;font-size:15px;white-space:nowrap}
/* 订单表行间隔(2026-09-19 主人:「每一行的间隔明显一点, 先改订单我看看效果, 我点头之后同步到所有」)。
   第一版只挂在订单表(当时叫 .od-tbl, 已并入 .uk-rowgap); 原来行与行只隔一条 1px 的 --border-2, 多品单一长就分不清哪几行是一单。
   画一道 8px 的空档, 每单看着像一张独立的卡片。
   ‼️ 09-19 主人:「可以加深一点」—— 第一版用页面底色 --bg(#f6f7f9), 压在白表上几乎看不出。
      单独给一个更深的灰; 暗色主题要另给(比 --bg 更暗), 否则会变成一道亮条。 */
/* ‼️ 09-19 主人点头:「效果不错, 同步到项目里所有的类似报表, 尤其是那种共享的 admin 报表」。现在两种表自动带:
      · .uk-tbl.uk-rowgap —— 自己画的列表/报表, 在 JS 里逐张挂(弹窗里的键值表、编辑网格不挂: 那不是"一行一条记录");
      · .table.table-hover —— monsteradmin / recruitadmin 的 DataTables 列表和 erp 的销售报表, 这几处 table-hover
        恰好只用在"一行一条记录"的列表上(键值表是 table-sm / table-borderless / table-bordered, 不带 hover), 所以按类名一条规则全覆盖。
   ‼️ 商品表是「一个品 = 首行 uk-prow + 若干规格子行 uk-vrow, 左边一排 rowspan 格」: 间隔只能画在**品与品之间**
      (uk-prow-end 那一行 + 首行里的 rowspan 格, 它俩的底边就是这个品的底边), 规格子行之间保持原来的细线,
      否则一个品被切成好几张卡片, 分组反而看不出来。
   ‼️ DataTables 响应式展开的子行(tr.child)属于上一行: 展开时上一行(tr.dt-hasChild)底边退回细线。 */
.uk-tbl.uk-rowgap,.table.table-hover{--tbl-row-gap:#e2e5eb}
[data-theme="dark"] .uk-tbl.uk-rowgap,[data-theme="dark"] .table.table-hover{--tbl-row-gap:#0a0c10}
/* ‼️ 末行不画: 排除写进选择器本身(:not(:last-child)), 不另写一条「末行清零」——
      :not(.uk-prow):not(.uk-vrow) 抬高了权重, 另写的清零条压不过它, 实测末行照样多一道 8px 灰条。 */
.uk-tbl.uk-rowgap>tbody>tr:not(.uk-prow):not(.uk-vrow):not(:last-child)>td,
.uk-tbl.uk-rowgap>tbody>tr.uk-prow-end:not(:last-child)>td,
.uk-tbl.uk-rowgap>tbody>tr.uk-prow>td[rowspan],
.table.table-hover>tbody>tr:not(:last-child)>td{border-bottom:8px solid var(--tbl-row-gap)}
.table.table-hover>tbody>tr.dt-hasChild>td{border-bottom:1px solid var(--border-2)}
/* 最后一个品的 rowspan 格: 它所在的首行不是 last-child, 上一条管不到。单独一条 —— :has 不认的浏览器只丢这一条, 不连累上面 */
.uk-tbl.uk-rowgap>tbody>tr.uk-prow:not(:has(~tr.uk-prow))>td[rowspan]{border-bottom:0}
/* 勾选列和商品列之间收紧(2026-08-21 用户"红色处margin减小"): 两个单元格各 14px 内边距
   叠出 28px 的空档, 而勾选框本身只有 16px 宽, 看着像商品列被推开了。 */
/* ‼️ 2026-09-03 从 #odBody 解锁到全项目(用户: 订单表精调过的那些,
   系统里所有 table 都要跟上)。判据从"第 1/2 列"改成"**勾选格及其右邻**" ——
   按列序号的话, 没有勾选列的表(模板/日志)会被莫名其妙地收紧头两列。 */
/* 勾选格: 方框**真正居中**。三件事缺一不可 ——
   ① 两边内边距对称(上一版左 8 右 4, 于是方框整体偏左, 看着像没居中)
   ② td/th 自己 text-align:center
   ③ ‼️ Bootstrap 的 .form-check-input 自带 margin-top:.25em + float, 不清掉它会往下沉半格,
      在 41px 高的行里一眼就能看出来。用 vertical-align:middle 让它跟着行高居中。
   这条挂在 .uk-ckcell 上而不是"第一列", 所以**所有表都吃**(商品表的勾选格也是同一个问题)。 */
.uk-tbl th.uk-ckcell,.uk-tbl td.uk-ckcell{padding-left:6px;padding-right:6px;text-align:center}
.uk-tbl .uk-ckcell input[type=checkbox]{margin:0;float:none;vertical-align:middle}

/* 自由列: 不给宽度 = auto 布局下吃富余宽度。**挂几列就几列平分**, 相当于表格版的 flex-grow:1。
   min-width 是硬闸: 光靠 auto, 内容短的那列会被别人挤没(实测标签列只剩两个字符宽)。 */
.uk-tbl th.uk-grow{width:auto;min-width:150px}
/* 垫片列: 末尾一个空列, **富余宽度全归它**, 真实列各自按内容/指定宽度。
   ‼️ 为什么需要它: 表格 width:100% 而其余列都是 width:1% 时, 富余只能灌给唯一那个
      有正常宽度的列 —— 实测把"说明"撑到 1128px、"显示名" 1211px、"水印文字" 1190px。
      给那列写 width 没用(**指定宽度是下限不是上限**), 写 max-width 也没用(auto 布局忽略)。
   用法: 内容整体都短的表, 在 thead 末尾加一个 <th class="uk-spacer"></th>。
        真有长内容的表用 .uk-grow, 别用垫片。
   ‼️‼️ **每行必须有对应的 <td>**。这里原来写的是"行里不用加对应的 td(HTML 允许行少一格)",
        **那是错的**: HTML 确实允许, 但行分隔线是下面 `.uk-tbl td{border-bottom}` 由**格子**
        画的 —— 垫片列没有格子就没人画那一段, 于是表头灰底铺满整张卡片, 而每行的横线在最后
        一个真实列右边就断掉。2026-09-04 主人指着店铺授权页说"UI 完全不正常", 九张用了垫片
        的表全是这个病。
        补 td 这件事**不用调用方记**: shared_admin/js/ui.js 的 fixSpacerCells() 会自动补齐,
        重渲染后也会再补。 */
.uk-tbl th.uk-spacer{width:auto;padding:0}
.uk-tbl td.uk-spacer{padding:0}
/* 操作列不许换行: 两个按钮一旦上下摞起来, 行高直接翻倍(实测模板页 ACTIONS 只有 77px,
   两个按钮摞成 77px 高的行)。**行里最后一格就是操作列** —— 垫片只加在 thead, 行里没有对应的 td。 */
/* 合并格(rowspan)一律**顶对齐**(2026-09-03 用户: "这种多行规格的情况, 让标题 align top 别居中")。
   一个品四档规格时, 商品格被垂直居中会浮在四行的正中间, 和第一档对不上 ——
   眼睛要先找"这块属于哪几行"。顶对齐后, 商品名和它的第一档在同一条水平线上。
   ‼️ 挂在 [rowspan] 上而不是某一列: 店铺/平台/状态/时间那些合并格同理, 一起顶对齐才整齐。 */
/* 逐档行压矮(2026-09-03 用户: "让规格行稍微再矮一点")。
   42px 是这么来的: 上下各 12px 内边距 + 20.25px 行高。内边距收到 6px。
   ‼️ 光收内边距不够 —— **档位图会顶着行高**(34px 的图 + 12px 内边距 = 46px, 比文字行还高),
      所以图也要跟着小一号, 否则收了内边距行高纹丝不动。 */
.uk-tbl tr.uk-vrow > td,.uk-tbl td[data-vari]{padding-top:6px;padding-bottom:6px}
.uk-tbl td[data-vari] .uk-thumb{width:26px !important;height:26px !important}
.uk-tbl td[rowspan]{vertical-align:top}
.uk-tbl td[rowspan] .uk-prodcell{align-items:flex-start}
.uk-tbl tbody td:last-child{white-space:nowrap}
/* 操作列竖排(2026-09-05 主人: 让按钮竖着排列)。
   两个按钮横着放要占 ~200px, 而这一列在商品表里排在最右边, 横着摆会把前面的列挤窄;
   竖排之后这一列只要一个按钮的宽度。
   ‼ 这里**不能只靠 white-space** —— 上面那条 nowrap 管的是换行, 管不了摆放方向;
     要竖排必须让格子本身变成纵向 flex。
   ‼ 按钮 stretch 成同宽: 两个按钮文字长短不同(Quick edit / Formula Price),
     不拉齐就是左对齐的锯齿边。
   ‼ 清掉按钮自带的 me-1(横向间距), 否则竖排时右边多出一截空白。 */
.uk-tbl td.uk-actcol{white-space:normal}
.uk-tbl td.uk-actcol > .btn{display:block;width:100%;margin:0 0 4px 0}
.uk-tbl td.uk-actcol > .btn:last-child{margin-bottom:0}
.uk-tbl td.uk-actcol .btn + .btn{margin-left:0}
.uk-tbl td .btn + .btn{margin-left:4px}
/* 可点格子: 一行里有几种点法就要有几种颜色(§7.40)。这一格点下去做的事和"开详情"不同,
   所以悬停时把行的灰底收回去, 给它自己的浅紫。 */
/* 点了有功能的一律小手(2026-09-03 用户点名)。‼️ 光有小手不够, **还要 title 说清楚
   点下去会发生什么** —— 小手只说"这儿能点", 不说"点了会怎样"。 */
.uk-tbl td.uk-clickcell,.uk-tbl td.uk-ckcell,.uk-tbl th.uk-ckcell,.uk-tbl td.uk-copycell{cursor:pointer}
/* 可点的格子: hover 时**只染它自己**, 同时把整行的 hover 压平(一行里同时亮两块很乱)。
   ‼️ 压平那条必须写 `td:not(:hover)`, 不能写 `td` 也不能写 `td.uk-clickcell`:
      · 写 `td`  -> :has() 的特异性按最具体的参数算 (0,3,3), 盖过下面那条 (0,3,1),
        连**被 hover 的那一格自己**都压成透明 = "这一列根本没有 hover"(主人连报两次);
      · 写 `td.uk-clickcell` -> 选中的是这一行**所有**可点格, 而商品表里 规格/图/价/库存/状态
        全是 .uk-clickcell, 于是 hover 规格列, 状态列跟着一起绿(主人: "为什么我hover
        variation列, status列也染色?")。
      `:not(:hover)` 才是"除了鼠标下面那一格"这个意思。
   ‼️ 底色**浅绿**: 淡蓝是"勾选"、浅橙是"复制"(表格交互规范), 绿留给"点开一个编辑框"。 */
.uk-tbl tr:has(td.uk-clickcell:hover) > td:not(:hover){background:transparent}
.uk-tbl td.uk-clickcell:hover{background:#d3f9d8}
/* ‼️‼️ **th 上的 max-width 管不住表格列** —— auto 布局把富余宽度发给"没定宽的那些列",
   max-width 直接被忽略(2026-09-03 实测: 加了 max-width:320px 之后, 发布任务的 ERROR
   仍然是 627px, 店铺的 ACTIONS 仍然是 1071px)。
   所以模型是: **一张表最多留一个 .uk-grow(内容最值钱的那列, 通常是标题), 其余列一律显式给宽**。
   留两个自由列 -> 它们按**内容比例**分而不是平分; 留错列 -> 操作列吃掉一千像素。
   ‼️ **内容本来就短的表(店铺/模板)干脆一个自由列都不留** —— 设了它照样吃满(店名列实测 963px)。
      auto 布局里**指定宽度是下限不是上限**, 富余按各列指定宽度成比例摊, 均摊反而好看。 */

/* 标题完整显示(2026-09-03 用户: "禁止省略标题, 标题必须都展示完整") —— 全站现在都用这个。
   ‼️ 仍要 overflow-wrap:anywhere(基类里有) —— 汽配标题是长串斜杠不带空格, 不加就顶破列宽。
   ‼️ 别在这儿写 text-overflow:ellipsis 之类的"优雅省略": 卖家要靠标题认出是哪个品,
      省略号后面藏的往往正是区分两个品的那几个字(年份/左右/高低配)。 */
.uk-prodtitle.uk-prodtitle-full{display:block;-webkit-line-clamp:none;overflow:visible}
/* 规格名: 完整显示, 不再单行省略(它就是这一行的身份) */
.uk-tbl td.uk-varname .v{white-space:normal;max-width:none}
.uk-tbl td.uk-ckcell:first-child+td,.uk-tbl th.uk-ckcell:first-child+th{padding-left:8px}
.uk-prodcell>.txt{flex:1;min-width:0}
/* 商品标题(2026-09-15 员工反馈看不清): 12 -> 14, 颜色从 muted 提到正文色 —— “看不清”是小和灰两件事, 只改字号只解一半。 */
.uk-prodtitle{font-size:14px;line-height:1.35;color:var(--text);margin-top:2px;
  overflow-wrap:anywhere;   /* 汽配标题常是长串斜杠不带空格, 不加这条会顶破容器 */
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
/* 窄屏不再另给宽度: 列宽由 th 的 min-width 决定, 格子恒等于列宽 */
/* 列宽配比(2026-08-11 用户): 店铺收窄+小字; 状态/平台/金额/标签/时间用 width:1%+nowrap
   缩到内容刚好; 省下的宽度自然流给备注列。商品列已定宽, 所以剩余全归备注。 */
/* 店铺格: 店名和别名各一行, 都不换行(2026-08-21 用户"这块UI被挤的太窄了")。
   原来是一整串 + overflow-wrap:anywhere, 窗口一窄就被拆成一字一行的竖排(六行高), 整行跟着炸。
   min-width 是硬闸: 光有 th 的 width 在 auto 布局里只是建议, 挤起来照样被压扁。 */
.uk-shopcell-th{width:104px;min-width:96px}
/* 店铺格: 任何表都能用(2026-09-03 解锁) */
.uk-tbl td.uk-shopcell{font-size:12px;line-height:1.35;color:var(--muted);min-width:130px}
/* ‼️ 店名那行不换行(它是主标识); **别名那行允许换行** —— 别名常是
   "(PH7SS8624A) (laz3pf2)" 这种长串, 它一 nowrap 就成了整列的硬下限,
   th 上写 width:104px 也压不下去(实测被顶到 137px)。 */
.uk-tbl td.uk-shopcell .nm,.uk-tbl td.uk-shopcell .al{display:block}
.uk-tbl td.uk-shopcell .nm{white-space:nowrap}
.uk-tbl td.uk-shopcell .al{opacity:.75}
/* 预售徽章: 平台事实, 和状态 pill 并排。用中性蓝而不是警示色 —— 它是属性不是异常 */
/* 预售徽章用橙(2026-08-21 用户)。走现成的 --warn 变量对, 而不是写死色值 ——
   深色主题下 --warn-weak 会自动换成深底色, 写死的话夜里就是一块刺眼的亮斑。 */
.uk-pill.pre{background:var(--warn-weak);color:var(--warn);margin-left:4px}
/* 标签芯片右上角的改/删角标(2026-08-21 用户)。芯片本体 = 给这一单挂/摘标,
   角标 = 改/删标签本身 —— 两个完全不同量级的动作, 热区必须分开且一眼能分辨,
   所以角标坐在角上而不是并排, 颜色也用红/蓝分开。
   芯片要 position:relative 才托得住绝对定位的角标; 芯片本身有 padding, 角标往外挪半格
   才真在"右上角"而不是压在文字上。 */
.tag-chip{position:relative;overflow:visible}
.tag-corner{position:absolute;top:-7px;right:-7px;width:16px;height:16px;line-height:15px;
  border-radius:50%;font-size:11px;font-weight:700;text-align:center;cursor:pointer;
  border:1px solid #fff;box-shadow:0 1px 3px rgba(0,0,0,.25)}
.tag-corner.del{background:var(--danger);color:#fff}
.tag-corner.edit{background:var(--primary);color:#fff}
.tag-corner:hover{transform:scale(1.15)}
/* 改/删模式下芯片之间要拉开: 角标向外凸 7px, 平常那 4px 间距会让它压在隔壁芯片上。
   row-gap 给得更大 —— 角标是往**上**凸的, 换行后会压到上一排。 */
.tag-mode{gap:14px 12px!important}
/* 自成一行时不要那 4px —— 它是给"跟在状态 pill 后面并排"用的间隔,
   留着会让徽章比标题/规格右移 4px(2026-08-21 量出来的)。 */
.od-pre .uk-pill.pre{margin-left:0}
/* 金额/状态不许竖排 —— 它们已经缩到内容宽度, 再换行就是一字一行。
   ‼️ 2026-09-17 从 nth-child 改成按 class 选。原来写的是 `td:nth-child(5/6/7/8/11)`, 列序还停在 08-11 的 11 列版
      (1勾选 2商品 3订单号 4店铺 5平台 6金额 7预期回款 8状态 9标签 10备注 11时间);
      09-15 平台/回款并进别的格、09-17 加了承运商列, 两次都没人回来改这里 ——
      结果第 7 列(承运商)被强制不换行, Lazada `Pickup: J&T Cargo PH, Delivery: J&T Cargo PH` 撑宽整张表;
      而"状态列运单号可断行"那条落到了标签列上。**按序号选列, 加减一列就全错位**。
   时间格自带 .uk-nw, 不用在这里管。 */
#odBody td.od-amt,#odBody td.od-st{white-space:nowrap}
/* 订单行全顶对齐(2026-09-20 主人; 09-19 只给了多件单, 被退回来一次)。
   行高由商品格/操作列擑着, 居中的话订单号/金额/状态全漂到中间, 和第一件商品对不上。
   ‼️ 备注行(od-note-row)排除在外: 那一条绿带里的字是主人 09-19 特意让我居中的。 */
#odBody > tr:not(.od-note-row) > td{vertical-align:top}
/* 标签列: 给个上限让它换行, 不给的话 auto 布局会按"所有芯片排成一行"的内在宽度撑列。
   芯片之间用 gap 而不是 me-1, 换行后行间也才有间距。 */
/* min-width 是必须的: max-width 不是下限, auto 布局会把这一列压到 97px(实测),
   于是四个标签排成四行, 比不换行还难看。160 刚好放得下两个常见长度的芯片。 */
/* ⚠ th 在 thead 里, **不在 #odBody(tbody)下** —— 写 #odBody th 永远选不中,
   而列宽是表头那一行定的, 所以 min-width 必须落在 th 上才算数。 */
/* 标签列不再封顶(2026-09-03 用户: Tags/Notes 都 flex-grow=1) —— 宽度交给 .uk-grow 去分。
   保留 min-width: 芯片是块状的, 太窄会一个一行。 */
/* ‼️ 2026-09-20 主人:「action 和 tags 列做成竖向排列节省横向空间」—— 芯片改**一个一行**,
   下限从 150(放得下两个芯片并排)收到 84(放得下一个短芯片)。 */
.od-tags-th,#odBody td.od-tags{min-width:84px}
#odBody td.od-tags{white-space:normal}
/* 订单表标签的上下留白加大一档(2026-09-05 主人)。
   裸 .badge 走的是 Bootstrap 默认 padding(.35em .65em), 竖向偏紧;
   这一列一行常挂两三个标, 挤在一起读起来累。
   ‼ 只加**上下**, 左右不动 —— 左右已经够, 加了会把这一列撑宽(它是定宽 180px)。 */
#odBody td.od-tags .badge{margin:0;padding-top:.45em;padding-bottom:.45em}
#odBody td.od-tags{display:table-cell}
/* 竖排(2026-09-20 主人)。align-items:flex-start 是必须的: 不给的话芯片被拉成整列宽的色条,
   一列全是等宽色块反而更占地方、也看不出标签长短。 */
.od-tags-wrap{display:flex;flex-direction:column;align-items:flex-start;gap:4px}
/* 状态列里的运单号仍要能断行: 它比"Cancelled"长, 不断的话会把这一列重新撑开 */
#odBody td.od-st .small{white-space:normal;word-break:break-all}
/* 操作格小按钮(2026-09-17 主人:「action 列太宽, 按钮调小」)。按钮高 30 -> 22。
   容器在 app.js odActCell 里只给 min-width:124px, 跟着格子宽度排: 宽屏一排 5 个 / 中等 3+2 / 窄屏 2+2+1。 */
#odBody td.od-act .btn{padding:1px 6px;font-size:12px;line-height:1.5;border-radius:4px}
/* ‼️ 2026-09-19 主人:「按钮高度都不一样」。只给 line-height 管不住高度: 中文字在 --font 里逐字回退
   (Segoe UI 没中文 -> 系统按字挑字体), 不同回退字体的上下伸部不一样, 行盒被撑高 ——
   同一格里「隔离」22.7px、「预检」20px(实测), 同一排上沿就错开。定死高度 + flex 居中, 字体怎么回退都不改框。 */
#odBody td.od-act .btn{height:22px;line-height:1;display:inline-flex;align-items:center;justify-content:center}
/* ‼️ 2026-09-19 主人:「为什么两行对不起」。通用的 `.uk-tbl td .btn + .btn{margin-left:4px}` 在这里和 flex 的 gap:4px 叠加:
   按钮间距成了 8px, 而且折到第二排的第一个按钮还带着那 4px 左外边距 —— 第二排整体比第一排往右缩进 4px(实测 1564 vs 1560.4)。
   间距只交给 gap, 外边距清零。 */
#odBody td.od-act .btn{margin:0}
/* 竖排(2026-09-20 主人): 一个按钮一行, 宽度由最长的那个定, 其余撑满 —— 不撑满就是一列锯齿边。
   ‼️ 按钮自带 display:inline-flex(上面那条定高用的), width:100% 才生效。 */
#odBody td.od-act .od-actbox{align-items:stretch}
#odBody td.od-act .btn{width:100%}
/* 店铺授权页操作列(2026-09-26 主人:「action 里跟 order 那边一样, 竖向排列, 2 列」):
   同订单页的小号定高按钮(22px, 12px 字), 两列网格, 每个按钮撑满自己那一格; 间距只交给 gap。 */
/* 店铺授权页整行顶对齐(2026-09-26 主人:「表格学习 order 那边, align flex start」), 同 #odBody。 */
#shopBody > tr > td{vertical-align:top}
/* 关键指标: 固定两列网格, 每家店同一项在同一个位置(主人:「key metrics 这一列排列这么乱」)。
   minmax(max-content,1fr): 两列等宽, 但不会窄过最长的那个 pill(窄了会压到隔壁)。 */
#shopBody .shop-kpi{display:grid;grid-template-columns:repeat(2,minmax(max-content,1fr));gap:4px 6px;justify-items:start}
#shopBody .shop-kpi .uk-pill{margin:0}
/* contain:inline-size: 这一长条不参与算列宽(否则整列被它撑到 800px, 上面两列 pill 被拉开), 在两列宽度里自己折行 */
#shopBody .shop-kpi .shop-kpi-bad{grid-column:1 / -1;white-space:normal;line-height:1.4;contain:inline-size;justify-self:stretch}
#shopBody .shop-kpi .shop-kpi-at{grid-column:1 / -1;font-size:11px;color:var(--muted)}
#shopBody td.shop-act .shop-actbox{display:grid;grid-template-columns:1fr 1fr;gap:4px;min-width:210px}
#shopBody td.shop-act .btn{height:22px;line-height:1;padding:1px 6px;font-size:12px;border-radius:4px;margin:0;width:100%;
  display:inline-flex;align-items:center;justify-content:center;white-space:nowrap}
/* 预期回款: 终值正常色加粗, 预估灰色带 ≈ —— 两者可信度不同, 视觉上必须能分开 */
#odBody td.od-payout{text-align:right}
.od-est{color:var(--muted)}
/* 我们自己算的估算(2026-09-20 主人): 和平台给的预估长得不一样 ——
   虚线底框 + 后面一个小「估」字, 一眼看得出这不是平台的数字。 */
.od-est-own{border-bottom:1px dashed var(--border);cursor:help}
.od-est-own i{font-style:normal;font-size:11px;opacity:.75;margin-left:2px}
/* 备注挪进商品格规格下面(2026-09-19 主人): 和规格那行同字号; 只有「备注」这一小块可点, 自己的浅绿 hover(同原来那一格) */
/* 第二版(同日主人):「左侧跟商品图对齐, margin top 大一点, 宽度横跨多列, 不属于这一行而是额外一行」——
   每单下面单起一个 tr.od-note-row(从商品列横跨到最右)。订单行底下不再画行间隔灰条, 挪到备注行下面;
   两行一起 hover(看着是同一单)。上边距 = 订单行自己的下内边距(12px), 备注行不再加。 */
/* ‼️ 只有跟着备注块一起结束的那两格(勾选+商品)不画底线 ——
   第 3 列起的格子 rowspan=2, 它们本来就一直画到备注块底下, 行间隔灰条要留着。 */
#odBody>tr.od-hasnote>td:not([rowspan]){border-bottom:0}
/* 备注行上下留白相等, 字在浅绿条里上下居中(2026-09-19 主人:「让文字上下居中」); 原来上 0 下 10, 字贴着顶边。
   订单行底部少留 4px, 商品和备注之间的距离保持原样(4 + 8 = 原来的 12)。 */
#odBody>tr.od-hasnote>td{padding-bottom:4px}
#odBody>tr.od-note-row>td{padding-top:8px;padding-bottom:8px;vertical-align:middle}
/* 备注那一块浅绿 hover、点哪都开备注框(同日主人第三版): 它和订单行是两个动作, 不再一起变灰。
   ‼️ 2026-09-20 主人把范围收到**勾选列 + 商品列**那一块(「不要新起一行…除了第一/二列之外, 就正常高度」):
      右边那个合并格子 .od-note-rest 不上色 —— 连通用的 `.uk-tbl tr:hover td` 那一档灰也要压住,
      否则鼠标一过右边一整条还是会变色, 看着又成了一整行。 */
#odBody>tr.od-note-row:hover>td{background:#d3f9d8}
/* 买家图片那一格(2026-10-05, 备注右边从订单号列到最右): 它不是备注, 不跟着变绿、点了也不开备注框(app.js 拦了点击) */
#odBody>tr.od-note-row:hover>td.od-pics-cell{background:transparent}
/* 鼠标在图片那一格上时, 左边备注那格也别变绿 —— 绿色的意思是「点了改备注」, 这时点的是图 */
#odBody>tr.od-note-row:has(td.od-pics-cell:hover)>td{background:transparent}
/* 这一页最后一单(2026-10-05 主人截图:「把 ui 搞坏了」): 末行不画行间隔灰条, 但最后一单的备注行才是末行 ——
   订单行里 rowspan 的那几格不是末行, 照样在底下画 8px 灰条, 备注那一格却没有, 看着像备注漏出了卡片。一起不画。 */
#odBody>tr.od-hasnote:nth-last-child(2)>td[rowspan]{border-bottom:0}
.od-noteline{margin:0}
.od-note-hit{font-size:12px;line-height:1.4;cursor:pointer;border-radius:4px;padding:1px 4px;margin-left:-4px;max-width:100%;
  overflow-wrap:anywhere;display:-webkit-inline-box;-webkit-line-clamp:6;-webkit-box-orient:vertical;overflow:hidden}
/* 备注里本来就换了行的, 这里也照着换行(2026-09-19 主人); 行数上限从 2 放到 6, 多出来的看悬停提示 */
.od-note-hit .v{white-space:pre-line}
.od-note-hit .k{color:var(--muted)}
/* 订单商品标题: r5096 改成「单击复制、双击开商品页」后不再是链接, 链接自带的悬停变色+下划线跟着没了(主人:「标题的 hover 效果怎么拿掉了」)。
   照原来链接的样子补回来 —— 看得出这一块是能点的。 */
#odBody .od-title:hover{color:var(--primary);text-decoration:underline}
/* 规格编辑器: 新规格的图 + 选图小窗(2026-09-19) */
.uk-veimg{display:inline-flex;width:30px;height:30px;border-radius:4px;overflow:hidden;vertical-align:middle;cursor:pointer;
  border:1px solid var(--border-2);align-items:center;justify-content:center}
.uk-veimg img{width:100%;height:100%;object-fit:cover}
.uk-veimg.need{border:2px solid var(--danger)}
.uk-vepick{display:flex;flex-wrap:wrap;gap:8px}
.uk-vepick-one{padding:0;border:2px solid transparent;border-radius:6px;background:none;line-height:0}
.uk-vepick-one img{width:76px;height:76px;object-fit:cover;border-radius:4px}
.uk-vepick-one:hover{border-color:var(--primary-weak,#cfe0ff)}
.uk-vepick-one.on{border-color:var(--primary)}
/* 新版本提示条(2026-09-19): 顶上居中, 不挡操作 */
.erp-newver,.uk-newver{position:fixed;top:10px;left:50%;transform:translateX(-50%);z-index:3000;background:var(--primary);color:#fff;
  padding:8px 10px 8px 16px;border-radius:8px;box-shadow:0 6px 24px rgba(0,0,0,.18);font-size:13px;display:flex;align-items:center}
.uk-vepick-one{position:relative}
.uk-vepick-one .cap{position:absolute;left:2px;bottom:2px;font-size:10px;line-height:1.6;padding:0 4px;border-radius:3px;
  background:rgba(0,0,0,.62);color:#fff}
#odBody td.od-note-td{white-space:normal}
.od-note{font-size:12px;line-height:1.35;
  overflow-wrap:anywhere;   /* 备注常是没有空格的长串(单号/链接), 不加这条会顶破列宽 */
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
/* 规格: "Variation:" 前缀用和列标题一样的灰, 真正的值用蓝 —— 值才是要看的东西(2026-08-11 用户) */
.uk-prodsub{font-size:12px;line-height:1.35;margin-top:1px}
/* 预售徽章单起一行(跟在全部商品行之后): 它是**整单**的事实, 不是某一件商品的,
   所以不塞进任何一件里。它自己就是一个 .uk-prodcell 行, 第一格是和缩略图同宽的空占位 ——
   这样它和上面每一行共用同一个 gap, **结构上**就和标题/规格左对齐, 不靠算偏移。 */
/* ‼️ 只认 div: 操作列「预检」按钮也叫 .od-pre, 不限定会被推下 3px, 和同排按钮上沿错开(2026-09-19 主人:「不对齐」) */
div.od-pre{margin-top:3px}
.od-pre>.sp{width:var(--od-thumb,30px);flex:none}
.uk-prodsub .k{color:var(--muted);font-weight:400}
.uk-prodsub .v,.uk-prodsub-v{color:var(--primary);font-weight:600}
/* 订单号点击复制(2026-08-11 用户: 点这一格任意位置都复制, 不用精准点那串字)。
   热区=整个单元格, 所以 .od-sn 挂在 td 上; 悬停才提示可点, 平时不抢视觉。 */
td.od-sn{white-space:nowrap}
/* 点整格即复制的单元格。**全项目通用**, 挂 .uk-copycell 就有(2026-08-26 用户)。
   ‼️ 底色用**浅橙**而不是主色浅蓝: 这一格点下去是"复制", 与同一行里点了会**跳转/打开**的
      蓝色链接是两种不同的动作, 颜色分开才不会让人以为点了会跳走。用户指定的色系。 */
.uk-tbl td.uk-copycell{cursor:pointer;transition:background .12s}
.uk-tbl td.uk-copycell:hover{background:#ffe8cc}
.uk-tbl td.uk-copycell:active{background:#ffd8a8}
/* 行内一小段文字点击复制(.uk-copytext, 2026-09-27; 订单商品格里的规格): 和复制格同一套颜色, 只是范围是那几个字 */
.uk-copytext{cursor:pointer;border-radius:3px;transition:background .12s}
.uk-copytext:hover{background:#ffe8cc}
.uk-copytext:active{background:#ffd8a8}

/* 订单页的标签筛选钮(erp)。原来用 .btn-outline-secondary + .active, Bootstrap 的 active
   是深灰底白字, 把标签自己的颜色盖没了 —— 选中后是一块看不出文字的灰疙瘩(2026-08-11 用户反馈)。
   这里只给中性底色和边框, 选中态的配色由 JS 按该标签的颜色内联设置。 */
.od-tagchip{border:1px solid var(--border);background:transparent;color:var(--muted);font-size:12.5px;
  padding:3px 10px;border-radius:999px;transition:background .12s,border-color .12s,color .12s}
.od-tagchip:hover{border-color:var(--muted);color:var(--text)}
.od-tagchip .dot{display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:5px;vertical-align:baseline}
.od-tagchip.on .dot{background:#fff!important}   /* 选中后底色已是标签色, 色点再同色就看不见了 */
.od-tagchip:focus,.od-tagchip:focus-visible{outline:none;box-shadow:0 0 0 3px var(--primary-weak)}
/* 标签筛选条默认一行 + 右侧展开钮(2026-09-19 主人)。收起时的高度由 JS 按第一个标签的实际高度设(fitTagsBar),
   不在这里写死 —— 字号/缩放一变写死的高度就会切掉半行或露出第二行的上沿。 */
.od-tagsbar{display:flex;align-items:flex-start;gap:6px}
.od-tagsbar>#odTags{flex:1;min-width:0}
.od-tagsmore{flex:none;border:1px dashed var(--border);background:var(--surface);color:var(--primary);font-size:12.5px;
  padding:3px 10px;border-radius:999px;white-space:nowrap}
.od-tagsmore:hover{border-color:var(--primary);background:var(--primary-weak);color:var(--primary)}

/* 非阻塞 loading(2026-08-24): 顶部居中一颗药丸里的转圈。
   ‼️ pointer-events:none 是这个东西存在的意义 —— 它绝不能挡住任何操作,
      否则就和 utils.loading 那个全屏遮罩没区别了。 */
/* 居中(2026-08-24 用户: 照 monster Unity 项目 Data/Remote.cs 的做法 —— 那边是
   uicenter.loadingIcon 一个**屏幕中央**的图标, 请求开始后延迟显示、完成即隐藏)。
   ‼️ 仍然 pointer-events:none: 用户前面明确说过不要 block UI。所以它只是"在转",
      不像 utils.loading 那样铺一层遮罩把点击吃掉。 */
.uk-busy{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);z-index:var(--z-busy);
  pointer-events:none;background:rgba(255,255,255,.94);border-radius:14px;padding:16px;display:flex;
  box-shadow:0 6px 24px rgba(0,0,0,.18)}
.uk-busy i{width:34px;height:34px;display:block;border:3px solid rgba(0,0,0,.13);
  border-top-color:#0d6efd;border-radius:50%;animation:uk-spin .8s linear infinite}
@keyframes uk-spin{to{transform:rotate(360deg)}}
/* 行内小转圈(2026-09-05): 发布进度那一屏每家店一个。和 .uk-busy 共用 uk-spin,
   区别是它不铺遮罩、不定位到屏幕中央 —— 它属于**那一行**, 不是整页在忙。 */
.uk-busy-inline{display:inline-block;width:15px;height:15px;vertical-align:middle;
  border:2px solid var(--border);border-top-color:var(--primary);border-radius:50%;
  animation:uk-spin .8s linear infinite}

/* 会换行的表格单元(状态标记 / 一排操作按钮)。原来只靠空格和 me-1 撑横向间距,
   一换行就上下贴死, 所以要给横纵两个方向都补间距。

   ‼️‼️ **这里绝对不能写 `display:flex`**。这个类只贴在 `<td>` 上(erp 店铺授权页两处),
      而 `display:flex` 会把这一格从 table-cell 变成 flex 容器 —— 它**就不再跟着行拉伸了**。
      2026-09-05 主人「这一列 UI 乱了」, 量出来是:
          行高 51 · 别的格 51 · **这一格 44**, 而且顶部比行顶低 4px。
      后果有两个, 都很难一眼归因到 CSS:
        · 它那条 `border-bottom` 停在行的**中间**, 画出一个和行错位的框;
        · 整行 hover 的灰底在这一列**缺一块**(那块只有 44px 高)。
      第一版是我用 flex+gap 图省事, gap 确实好使 —— 但代价是把格子踢出了表格布局。

   ‼️ 间距改用 margin。`.uk-pill` 是 inline-flex、`.btn` 是 inline-block,
      两者都是 atomic inline-level 盒子, **纵向 margin 会撑开行盒**, 换行时不会上下贴死
      (纯 inline 元素才不会 —— 这也是为什么下面那条全局 `.uk-pill{margin-bottom:3px}` 有效)。 */
.uk-wrapcell{vertical-align:middle}
.uk-wrapcell > .uk-pill,.uk-wrapcell > .badge{margin-right:6px}
.uk-wrapcell > .uk-pill:last-child,.uk-wrapcell > .badge:last-child{margin-right:0}
/* 按钮横向靠自带的 me-1, 这里只补换行后的纵向间距。
   ‼️ vertical-align:middle 不能省: inline-block 默认贴**基线**, 行盒底下会白留一截
      给字母降部(g/y 那一截)的空间, 换行时每行都多几个 px, 行越多越明显。 */
.uk-wrapcell > .btn{margin-bottom:4px;vertical-align:middle}

/* ---------- 换行的 tag 组: 纵向间距(2026-08-24 用户: 所有这种 tag 换行都要有小 margin) ----------

   根因: .uk-pill 和 .badge 都是**行内级**盒子(inline-flex / inline-block), 一换行上下就贴死 ——
   横向靠空格或 me-1 撑着, 纵向什么都没有。

   ‼️ 为什么从 tag 本身治, 而不是逐个给容器打 flex+gap:
      uk-pill 光 erp 一家就有 34 处、badge 14 处, 逐个找必漏, 而且**以后新加的还会漏**
      —— 那种"改了但下次又出现"的修法不算修好。行内盒子的纵向 margin 是会撑开行盒的,
      所以给 tag 自己加 margin-bottom 就够, 容器一个都不用动。

   ‼️ 代价说明白: 单行的格子也会多 3px 高。表格是 table-sm, 3px 看不出来,
      换来的是**再也不用管哪个容器会换行**。

   ‼️ **不能给 .badge 全局加**。那是 Bootstrap 的通用类, 全站还用在**页签上的计数角标**
      (od-tab-n / it-tab-n / cl-tab-n / pt-tab-n)—— 给它们加纵向 margin 会把页签文字顶歪。
      所以只管 .uk-pill(我们自己的类, 只用在状态/标记)和明确是 tag 芯片的那两种 badge。

   ‼️ 已经用 flex+gap 的容器要把它清掉, 否则 gap 和 margin 叠加变成 7px。
      下面那串选择器是全站现有的 flex-wrap 容器(grep flex-wrap:wrap 得来),
      新增这类容器时记得加进来。 */
.uk-pill,.badge.tag-chip{margin-bottom:3px;vertical-align:middle}
/* ‼️ .uk-pftag 也要 vertical-align:middle: 它默认是 baseline, 和旁边的 .uk-pill 一行放着时
   两个标签**差 2px**(2026-09-04 主人在商品详情弹窗指出"没有居中")。 */
.uk-pftag{vertical-align:middle}
/* 标签芯片的圆角(2026-09-03 用户: "圆角小一点")。写在这里而不是各处内联 style 里 ——
   tag-chip 在 erp 有多处渲染(标签管理 / 自动打标 / 订单详情), 逐处改必漏。
   ‼️ 订单列表那一列的标签是**光秃秃的 .badge**(没有 tag-chip 类), 所以要单列一条
      td.od-tags .badge —— 只写 .tag-chip 的话截图里那一列一点变化都没有。 */
.badge.tag-chip,td.od-tags .badge,.uk-tagpick .badge{border-radius:var(--r-sm)}
/* ‼️ `.uk-wrapcell` 2026-09-05 从这份名单里**移走了**: 它不再是 flex 容器(见上面那段),
   换行的纵向间距正是靠 `.uk-pill` 自己那 3px margin-bottom 撑的, 清零就又贴死了。 */
.od-tags-wrap .uk-pill,.od-tags-wrap .badge,
.pe-hd > .uk-pill,.pe-ft > .uk-pill{margin-bottom:0}
/* ‼️ 上面那串是**逐个列举**出来的, 新加的 flex 容器必漏 —— 2026-09-04 就漏了商品详情
   弹窗头部的 `d-flex align-items-center gap-2`: .uk-pill 带着 margin-bottom:3px,
   在 align-items:center 的行里外框比 .uk-pftag 高 3px, 于是平台标比状态标低 2px,
   主人一眼看出"没有居中"。
   改成按 Bootstrap 的 .d-flex 通配: 这个类就是全站 flex 行的标记, 不用再一处处补选择器。 */
.d-flex > .uk-pill,.d-flex > .badge.tag-chip{margin-bottom:0}

/* 批量打标弹窗里的标签多选(2026-08-24)。一行摆几个, 换行有间距 ——
   标签几十个的时候纵向排会把弹窗撑得很长。 */
/* ‼️ 不再写 `max-height:46vh;overflow:auto`(2026-09-10 主人:「屏幕空间足够大就别随便加
   scroll」): ①46vh 和屏幕多大无关, 放得下也照样出滚动条; ②弹窗里再套一层滚动 =
   一个框两条滚动条, 滚哪一层全看指针在哪。装不下由弹窗正文那一层兜底就够了。 */
.uk-tagpicks{display:flex;flex-wrap:wrap;gap:8px;padding:2px}
.uk-tagpick{display:inline-flex;align-items:center;gap:6px;cursor:pointer;margin:0;
  border:1px solid var(--border);border-radius:999px;padding:4px 10px 4px 8px;user-select:none}
.uk-tagpick:hover{background:var(--hover)}
.uk-tagpick .badge{margin:0}

/* ===== 平台品牌色按钮(2026-08-25 用户: 绑店选平台时按各家品牌色)=====
   ‼️ 五态必须一起写全: 默认 / hover / focus-visible / active / disabled。
      只写默认态的话 hover 会退回 Bootstrap 的 primary 蓝, 视觉直接跳变;
      而且 btn-outline-* 的 hover **会反转前景色**, 按钮里任何写死颜色的子元素都会瞎。
      —— 这条是用户点名的老毛病, 别再犯。 */
.uk-pf{--pf:#6c757d;--pf-ink:#fff;
  color:var(--pf);border:1px solid var(--pf);background:transparent;
  font-weight:600;transition:background-color .12s,color .12s,border-color .12s}
.uk-pf:hover,.uk-pf:focus-visible,.uk-pf.active{background:var(--pf);color:var(--pf-ink);border-color:var(--pf)}
.uk-pf:active{background:var(--pf);color:var(--pf-ink);filter:brightness(.9)}
.uk-pf:focus-visible{outline:2px solid var(--pf);outline-offset:2px;box-shadow:none}
.uk-pf:disabled,.uk-pf.disabled{opacity:.5;background:transparent;color:var(--pf)}
/* --pf = 品牌底色(按钮实心态的底 / 芯片的底) · --pf-ink = 压在底色上的字色。
   ‼️ 品牌色**只在这三行**写, 别处一律消费变量 —— 写两份就会改一处另一处不动。
   ‼️ 字色由用户定版(2026-09-01): 虾皮橙底**黑字**、lazada 深蓝底白字、tiktok **深灰黑**(不是纯黑)底白字。
      橙底配黑字不是笔误 —— 橙的明度高, 白字在上面发飘。 */
/* ‼️ 不是官方那个 #ee4d2d —— 用户 2026-09-01: "太红了, 要橘黄色"。
   色相从 ~10°(橙红) 挪到 ~32°(橘黄), 明度也上来了, 配黑字更稳。别照着品牌手册改回去。 */
/* 待办告警条的入场(2026-09-05 主人: "每次切到 overview, 上面这些 warning 会瞬间渲染出来"
   "把 UI 顶下去, 体验非常差")。
   ‼️ 这块是**异步**填的(erpTodo.do 回来才有内容), 内容一到高度从 0 跳到几百 px,
      下面的看板整体被弹下去, 人眼里就是"页面抽了一下"。
   ‼️ 不能用 max-height 猜一个大数做过渡 —— 条数不定(1~6 条), 猜大了动画尾巴空转、
      猜小了直接截断内容。用 grid-template-rows 0fr -> 1fr, 它按**真实内容高度**过渡,
      不需要事先知道高度。外层要 overflow:hidden, 否则收起时内容会漏出来。
   ‼️ 尊重 prefers-reduced-motion: 关掉动画而不是留一个慢半拍的空壳。 */
.uk-todo-anim{display:grid;grid-template-rows:0fr;overflow:hidden;
  transition:grid-template-rows .34s cubic-bezier(.22,.61,.36,1)}
.uk-todo-anim > *{min-height:0}
.uk-todo-anim.on{grid-template-rows:1fr}
@media (prefers-reduced-motion:reduce){
  .uk-todo-anim{transition:none}
}
/* Shopee 橘黄 + 黑字。2026-09-05 主人两次嫌深: 先压到 .8, 还是深 -> .6。
   ‼️ 压的是**整块的 opacity** 而不是换一个浅一点的 --pf: 这个类同时给平台标(实心底)
      和 .uk-pf 那个筛选**按钮**(描边)用, 只调底色的话按钮那边不跟着淡, 两处就对不上了。
   ‼️ 这一条**只管得到按钮**。平台标那边被下面 `.uk-pftag{opacity:.9}` 盖掉了 ——
      同是一个类的特异性, 而它排在后面。加深一档的那条写在那条规则旁边(搜 uk-pftag.uk-pf-shopee)。
      第一次压到 .8 时我没看这个顺序, 结果标上一点没变, 主人只好再说一次。 */
.uk-pf-shopee{--pf:#fa8c16;--pf-ink:#000;opacity:.8}
/* Lazada 蓝 + 白字。2026-09-03 用户: 原来的 #0f146d(品牌深藏蓝)在小尺寸标签上
   糊成一团黑, 提亮到 #2f5bd4 —— 白字对比度仍有 5.3:1, 远超 4.5 的门槛。 */
.uk-pf-lazada{--pf:#2f5bd4;--pf-ink:#fff}
.uk-pf-tiktok{--pf:#2b2e35;--pf-ink:#fff}      /* TikTok 深灰黑 + 白字 */

/* 平台品牌色**芯片**(2026-09-01 用户: 订单列表 platform 那一列做成 tag 样式)。
   实心填充、**无边框**(用户定版)。不带 .uk-pill 那个 ::before 圆点:
   平台不是状态, 不需要指示灯; 而且实心底上再点一个同色点也看不见。
   认不出的平台走 fallback(灰底), 仍然是芯片 —— 见 app.js pfTag() 的注释。 */
.uk-pftag{display:inline-flex;align-items:center;padding:3px 10px;border-radius:var(--r-lg);
  font-size:12px;font-weight:600;line-height:1.5;white-space:nowrap;border:0;
  color:var(--pf-ink,var(--muted));background:var(--pf,var(--hover));
  /* 用户 2026-09-01: 整枚芯片压到 0.9 —— 实心品牌色在一列里连着排太抢眼, 压一档让表格重心
     回到商品和金额上。用 opacity 而不是给背景加 alpha: 后者字是全实的, 压不下来那股冲劲。 */
  opacity:.9}
/* Shopee 那枚再压一档(2026-09-05 主人: 橙色太深, 给 .6)。
   ‼️ **两个类**写在一起才压得住上面那条 `.uk-pftag{opacity:.9}` —— 特异性比它高一级,
      不用靠"谁写在后面"。橙底本来就比蓝底/黑底跳, 同样 .9 在一列里看着重得多。 */
.uk-pftag.uk-pf-shopee{opacity:.8}
/* ‼ 别给某个芯片手调上下 padding 去"对齐"(2026-09-05 试过又删了, 主人拍板)。
     现象: Shopee 看着上松下紧。真因**不是 padding 写错** —— 三家 padding 都是 3px/10px,
     盒模型完全一致; 是**字体的下伸部**: 同样 12px/600 实测
         Shopee  actualBoundingBoxDescent = 3  (那个 p 挂到基线以下)
         Lazada / TikTok / Live / Sold Out = 0
     芯片按基线对齐是排版上正确的做法, 下伸部本来就该挂下去。
     为什么不补: 一个常量补偿**只能照顾一类词** —— 给全体加 1.5px, 带下伸的差从 2.81
     降到 1.31, 没下伸的却从 0.19 涨到 1.69, 总错误没少, 只是摊平。只补一个词又是魔数,
     换字体/字号就失效且没人知道它怎么来的。
     真要根治只有两条路: ① 芯片文字全大写(大写没有下伸部, 纯 CSS 零运行时);
     ② 在 shared 的 ui.js 里用 canvas measureText 逐个芯片量 actualBoundingBoxDescent
     再设 padding(所有词自动生效, 换字体也跟着变)。两条都要先定, 别再手调。 */

/* 暗色: 只把**本来就深**的那两个提亮 —— `#0f146d` / `#2b2e35` 压在 #181b23 的卡片上
   基本糊成一片, 芯片和背景分不开。橙的明度够高, 原样不动。
   ‼️ 这一条同时修好了 .uk-pf 那个**按钮**在暗色下几乎看不见的老毛病(它也吃 --pf)。 */
[data-theme="dark"] .uk-pf-lazada{--pf:#5670e0}
[data-theme="dark"] .uk-pf-tiktok{--pf:#59606e}

/* 绑店时"选哪家店"的按钮。按钮里有一行次要说明(app_key), 必须**跟随父色**:
   写死 text-muted 的话 hover 反色后就是深底灰字, 基本看不见(2026-08-25 用户截图指出)。 */
.uk-pick{display:block;width:100%;text-align:left;
  color:var(--pf,#0d6efd);border:1px solid var(--pf,#0d6efd);background:transparent;
  transition:background-color .12s,color .12s}
.uk-pick:hover,.uk-pick:focus-visible,.uk-pick.active{background:var(--pf,#0d6efd);color:#fff}
.uk-pick:focus-visible{outline:2px solid var(--pf,#0d6efd);outline-offset:2px;box-shadow:none}
.uk-pick .uk-pick-sub{color:inherit;opacity:.7;font-size:.8em}

/* ===== 表格行: "点了不开详情"的热区, 悬停时收掉整行灰底 =====
   2026-08-25 先只在订单表做了; 2026-08-26 用户指出这套是通用的("你需要同步到项目里所有的 table"),
   于是从 #odBody 改成挂在 .uk-tbl 上 —— **全项目每张表都吃, 新表不用再抄一遍**。
   整行变灰 = 在暗示"点哪都开详情", 但这四处点下去分别是:
   勾选 / 开大图 / 开平台商品页 / 复制订单号。
   所以悬停它们时把行底色收回透明, 各自给自己的 hover, 让人一眼看出这一下点的是什么。

   ‼️ 用 :has() 实现 —— 它是"父元素跟着子元素状态变"的唯一纯 CSS 手段。
      老浏览器不认这条规则会整条跳过, 退回原来的整行 hover, **不会坏**, 只是没这个提示。
   ‼️ 收回的是 transparent 不是某个具体色: .uk-tbl 没有斑马纹, td 正常态本来就没底色,
      写死一个色反而会在暗色主题下露馅。 */
/* ‼️ 被悬停的那一格必须 :not() 排除掉 —— 否则这条把**整行包括它自己**刷成透明,
      而 `tr:has(X:hover) > td` 的优先级高于 `X:hover`,
      结果就是下面那句底色永远出不来。2026-08-25 第一版就是这么写坏的。
      图片/标题那两条不用排除: 悬停目标在 td **里面**, td 本来就该透明。 */
/* ‼️ 最后那条用的是通用的 `a:hover` 而不是 `.uk-prodtitle a:hover` ——
      "这一行里有链接被悬停"本身就说明点下去是跳链接而不是开详情, 与是哪张表、哪一列无关。
      商品表/采集箱的标题也走同一个 titleLink(), 于是一并生效, 不用逐表加规则。 */
/* ‼️ 排除用 `:not(:hover)` 而不是 `:not(.uk-copycell)` —— 后者把**整行所有**同类格子
      一起排除掉, 于是一行里有两个复制格时(退货表: 退货单号 + 订单号)会一起亮,
      分不清点的是哪个。`:not(:hover)` 只排除鼠标正下方那一格, 天然各管各的。
      2026-08-26 第一版就是这么写坏的。
      图片/链接那两条不用排除: 悬停目标在 td **里面**, 那个 td 本来就该透明。 */
.uk-tbl tr:has(.uk-ckcell:hover) > td:not(:hover),
.uk-tbl tr:has(.uk-copycell:hover) > td:not(:hover),
.uk-tbl tr:has(.uk-thumb:hover) > td,
.uk-tbl tr:has(a:hover) > td,
.uk-tbl tr:has(.uk-titlecopy:hover) > td{background:transparent}

/* ‼️ 选择器必须带上 `td`/`th` —— 行 hover 那条是 `.uk-tbl tr:hover td`(0,2,2),
      不带元素名的 `.uk-tbl .uk-ckcell:hover` 只有 (0,2,0), 会被它压住, 底色出不来。
      2026-08-26 橙色迟迟不显示就是栽在这。 */
.uk-tbl td.uk-ckcell,.uk-tbl th.uk-ckcell{cursor:pointer}
/* ‼️ 勾选格不能再用 var(--surface-2) —— 那正是行 hover 的同一个灰, 等于没区分(用户 2026-08-26)。
   三种动作三种颜色: 灰=点了开详情(整行) / 淡蓝=点了勾选 / 浅橙=点了复制。 */
.uk-tbl td.uk-ckcell:hover,.uk-tbl th.uk-ckcell:hover{background:var(--primary-weak)}
.uk-tbl .uk-thumb:hover{outline:2px solid var(--primary);outline-offset:1px}
.uk-tbl td a:hover{color:var(--primary);text-decoration:underline}
/* 商品标题(2026-09-19): 单击复制 / 双击开商品页, 见 ui.js titleLink。表格外(订单详情、商品编辑弹窗)也用它, 所以不挂 .uk-tbl 前缀 */
.uk-titlecopy{cursor:copy}
/* 有链接的标题 2026-09-20 改成了真的 <a>(主人要右键复制链接) ——
   平常要长得和普通标题一样, 所以把链接自带的蓝字+下划线压回去, 悬停时才变蓝。 */
a.uk-titlecopy{color:inherit;text-decoration:none}
.uk-titlecopy:hover{color:var(--primary);text-decoration:underline}

/* 逐品编辑那张表用的是 .pe-tbl 不是 .uk-tbl, 单独带上它(勾选格是同一套 .uk-ckcell) */
.pe-tbl tr:has(.uk-ckcell:hover) > td:not(:hover){background:transparent}
.pe-tbl td.uk-ckcell,.pe-tbl th.uk-ckcell{cursor:pointer}
.pe-tbl td.uk-ckcell:hover,.pe-tbl th.uk-ckcell:hover{background:var(--primary-weak)}
/* 订单号那格**不在这里重复定义** —— 上面 `td.od-sn:hover` 早就有了
   (整格 var(--primary-weak) 淡蓝底 + 小手光标), 正好是要的效果。
   它以前出不来纯粹是被那条 :has 盖住, 现在 :not() 排除掉就自然生效了。
   2026-08-25 我一度在这儿又写了一条 rgba 硬编码的, 属于重复且绕开设计系统变量, 已删。 */

/* ============================================================
   账号中心(shared_admin/js/account.js)
   在这之前登录进后台只有一个"退出" —— 改密码/看绑定邮箱/看自己权限一律做不到
   (2026-09-01 用户提)。信息架构抄 torrent 前台 account.jsp:
   总览页只列"能做什么去哪里", 条目**整行可点**(小按钮在手机上最难点中),
   验证不预先做、提交撞 155 才弹。
   ‼️ 遮罩用 inset:0 四边锚定, 不用 100vw/100vh —— html{zoom:.9} 下 vw/vh 不缩放,
      会露出右/下白边(2026-07-14 用户报过 bootstrap 遮罩的同一个坑)。
   ============================================================ */
/* ⛔ 这里原来有一整套自造的壳: .uk-acct-mask / .uk-acct-box(+.sm) / .uk-acct-head /
   .uk-acct-title / .uk-acct-x, 外加给验证窗压层用的 z-index:1086。
   2026-09-06 主人:「为什么窗口跟其他弹窗不一样? 为何不能拖动」—— 根因就是这套:
   它是站里的**第四套**弹窗实现, 拖动/叠栈/统一外观都在 UKDlg 里而它一样没接。
   两个窗都改走 `UKDlg.panel()` 后这些 DOM 不存在了, 整段删掉;
   遮罩 / 圆角 / 阴影 / 进出场动画 / 压层顺序**全部由 UKDlg 提供**。 */
/* 只保留宽度: 主窗 460、验证窗 380, 和改造前一致(bootstrap 默认 500 会显得空) */
.uk-acct-panel .modal-dialog{max-width:460px}
.uk-acct-vm .modal-dialog{max-width:380px}
/* 返回键仍然由 account.js 自己插进 .modal-header, 样式留着 */
.uk-acct-back{
  border:1px solid var(--border);background:var(--surface);color:var(--muted);
  border-radius:var(--r-sm);cursor:pointer;font-size:13px;padding:3px 9px;line-height:1.5
}
.uk-acct-back:hover{background:var(--hover);color:var(--text)}
.uk-acct-sub{margin:0 0 14px;font-size:12.5px;color:var(--muted);line-height:1.6}

/* 资料区: dt/dd 两列。用 dl 而不是 table —— 这是"名称:值"的语义, 且窄屏能自然折 */
.uk-acct-kv{margin:0 0 16px;border:1px solid var(--border-2);border-radius:var(--r);overflow:hidden}
.uk-acct-kv>div{display:flex;gap:12px;padding:8px 12px;font-size:13px;border-bottom:1px solid var(--border-2)}
.uk-acct-kv>div:last-child{border-bottom:0}
.uk-acct-kv>div:nth-child(odd){background:var(--surface-2)}
.uk-acct-kv dt{flex:0 0 92px;margin:0;color:var(--muted)}
.uk-acct-kv dd{flex:1;margin:0;color:var(--text);word-break:break-all}

/* 条目清单: <a> 撑满整格 */
.uk-acct-list{list-style:none;margin:0;padding:0;border:1px solid var(--border-2);border-radius:var(--r);overflow:hidden}
.uk-acct-list li{border-bottom:1px solid var(--border-2)}
.uk-acct-list li:last-child{border-bottom:0}
.uk-acct-list a{display:block;padding:11px 13px;text-decoration:none;color:var(--text)}
.uk-acct-list a:hover{background:var(--hover)}
.uk-acct-list .t{display:block;font-size:13.5px;font-weight:600}
.uk-acct-list .d{display:block;margin-top:2px;font-size:12px;color:var(--muted)}
.uk-acct-list li.danger a{color:var(--danger)}
.uk-acct-list li.danger a:hover{background:var(--danger-weak)}

/* 表单件。故意不用 .form-control —— 本套件要能在没引 bootstrap 的页面上照常长得对 */
.uk-acct-lb{display:block;margin:12px 0 5px;font-size:12.5px;color:var(--muted)}
.uk-acct-in{
  padding:9px 11px;border:1px solid var(--border);border-radius:var(--r);
  background:var(--surface);color:var(--text);font-size:13.5px;font-family:var(--font);width:auto;flex:1;min-width:0
}
.uk-acct-in.blk{display:block;width:100%}
.uk-acct-in:focus{outline:none;border-color:var(--primary);box-shadow:0 0 0 3px var(--primary-weak)}
.uk-acct-hint{margin:6px 0 0;font-size:11.5px;color:var(--faint)}
.uk-acct-row{display:flex;gap:8px;align-items:center}
.uk-acct-act{display:flex;gap:8px;justify-content:flex-end;margin-top:16px}
.uk-acct-btn{
  padding:9px 16px;border:1px solid var(--primary);background:var(--primary);color:#fff;
  border-radius:var(--r);font-size:13.5px;font-weight:600;cursor:pointer;font-family:var(--font);white-space:nowrap
}
.uk-acct-btn:hover{background:var(--primary-hover);border-color:var(--primary-hover)}
.uk-acct-btn.ghost{background:var(--surface);color:var(--muted);border-color:var(--border)}
.uk-acct-btn.ghost:hover{background:var(--hover);color:var(--text)}
.uk-acct-btn:disabled{opacity:.6;cursor:default}

/* 提示条: 占位高度固定, 出现/消失时表单不跳 */
.uk-acct-tip{min-height:18px;font-size:12.5px;line-height:1.5;margin:2px 0 4px;word-break:break-word}
.uk-acct-tip.err{color:var(--danger)}
.uk-acct-tip.ok{color:var(--ok)}

.uk-acct-priv{display:flex;flex-wrap:wrap;gap:6px;margin-top:6px}
.uk-acct-chip{
  display:inline-block;padding:3px 9px;border-radius:var(--r-sm);
  background:var(--primary-weak);color:var(--primary);font-size:12px;font-weight:600
}

/* 侧栏用户区变成账号入口: 得看着能点 */
.uk-sidebar>.uk-user{cursor:pointer;border-radius:var(--r)}
.uk-sidebar>.uk-user:hover{background:var(--hover)}

@media (max-width:768px){
  .uk-acct-mask{align-items:flex-end;padding:0}
  .uk-acct-box,.uk-acct-box.sm{max-width:100%;max-height:92vh;border-radius:var(--r-modal) var(--r-modal) 0 0}
  .uk-acct-kv>div{flex-direction:column;gap:2px}
  .uk-acct-kv dt{flex:none}
}

/* ---- 图形验证码弹窗的后台兜底样式 ----
   ‼️ captcha.js(www/shared/js)只带行为不带样式, 它的 CSS 至今分散在四处
      (shared_admin/login.jsp、erp/login.jsp、appstore/css/app.css、torrent/css/torrent.css)
      —— 而**后台主页 index.jsp 一处都没有**。服务端在发码失败后会随机布防, 之后的请求回 147
      就要弹图形码, 在后台里弹出来就是一坨没有样式的裸 HTML。这里补上。
   ‼️ login.jsp 那份不能删: 它是独立登录页, **不引 ui-kit.css**, 删了它自己就先坏了。
      两边各一份是必然, 不是手拷贝漂移。这份改用设计变量, 因此自动跟随暗色主题。 */
.cap-mask{
  position:fixed;inset:0;background:rgba(15,18,24,.55);backdrop-filter:blur(2px);
  z-index:var(--z-gate);display:none;align-items:center;justify-content:center;padding:16px
}
.cap-mask.on{display:flex}
.cap-card{
  background:var(--surface);border:1px solid var(--border);border-radius:var(--r-modal);
  box-shadow:var(--sh-lg);padding:20px 22px;width:100%;max-width:320px;text-align:center;font-family:var(--font)
}
.cap-hd{font-size:16px;font-weight:700;color:var(--text)}
.cap-sub{font-size:12.5px;color:var(--muted);margin:6px 0 14px;line-height:1.5}
.cap-img{
  width:200px;height:52px;border:1px solid var(--border);border-radius:var(--r);
  cursor:pointer;object-fit:cover;background:var(--surface-2)
}
.cap-hint{font-size:11.5px;color:var(--muted);margin:6px 0 10px}
.cap-in{
  width:100%;padding:11px 12px;border:1px solid var(--border);border-radius:var(--r);
  font-size:15px;text-align:center;letter-spacing:2px;background:var(--surface);color:var(--text);font-family:var(--font)
}
.cap-in:focus{outline:none;border-color:var(--primary);box-shadow:0 0 0 3px var(--primary-weak)}
.cap-tip{min-height:16px;font-size:12px;color:var(--danger);margin:7px 0 2px;opacity:0}
.cap-tip.on{opacity:1}
.cap-btns{display:flex;gap:10px;margin-top:10px}
.cap-btns button{
  flex:1;padding:11px 0;border-radius:var(--r);font-size:14px;font-weight:600;
  cursor:pointer;border:1px solid var(--border);font-family:var(--font)
}
.cap-no{background:var(--surface);color:var(--muted)}
.cap-ok{background:var(--primary);color:#fff;border-color:var(--primary)}
.cap-ok:disabled{opacity:.6;cursor:default}

/* 商品表: 一个品一大行 + 每档一子行(2026-09-03 用户拍板)。
   ‼️ 分组靠**品的第一行画上边线**, 而不是给子行画下边线 —— 后者在最后一个品下面会多一条,
      而且 rowspan 的格子被切成一段一段, 视觉上分不清哪几行属于同一个品。
   ‼️ 子行不重画左边那些 rowspan 的格子, 所以行 hover 时整个品会一起亮 —— 这是对的:
      悬停时你要看清"这一大块是同一个品"。 */
/* 一个品是一整块: 首行加上内边距、末行加下内边距(2026-09-03 用户: "商品行整体的上下 padding 加大")。
   ‼️ 不能只加首行的上内边距 —— 那样留白全归上面那个品的下方看起来还行, 但**最后一档会贴着下一条分隔线**。
      上下各给一份, 每个品才是一块完整的卡片感。 */
.uk-tbl tr.uk-prow > td{border-top:2px solid var(--border-2);padding-top:14px}
.uk-tbl tr.uk-prow-end > td{padding-bottom:14px}
.uk-tbl tr.uk-vrow > td{border-top:1px dashed var(--border-2)}
/* 规格行也要 hover 高亮(2026-09-05 主人)。整表的 .uk-tbl tr:hover td 对它不生效 ——
   一个多规格品是**一大行套多条规格子行**, 鼠标停在某一档上时高亮的是整个商品行,
   十几档的品根本看不出指着哪一档。这里单独给子行一层更明显的底色。 */
/* 档位格的 hover: **整档四格(规格/图/价/库存)一起亮**, 第一档和后面几档完全一样。

   ‼️ 触发必须是 `:has(td[data-vari]:hover)`, 不能是 `tr:hover`(2026-09-05 主人第二次报:
      '我鼠标在别的地方, 为什么第一个规格行要显示被 hover 的颜色?')。
      结构上 tr.uk-prow **不只装第一档** —— 它还装着跨全品高度的 rowspan 格(勾选 / 商品名 /
      预售 / 店铺 / 平台 / 状态 / 分组 / 时间 / 操作)。写 `tr.uk-prow:hover` 的话, 鼠标停在
      那些格子上(哪怕是完全空白的预售格)条件照样成立, 第一档就无缘无故亮了;
      而第二档起各自独占一个 tr.uk-vrow, 没有这些干扰 —— **两档行为因此不一致**。
      ⛔ 上一版 `.uk-tbl tr.uk-prow:hover:hover > td[data-vari]` 就是这么错的, 已作废。

   ‼️ 权重必须 > `.uk-tbl tr:has(td.uk-clickcell:hover) > td:not(:hover){background:transparent}`
      的 (0,4,3) —— 那条只留鼠标底下那一格, 会把同档另外三格压平。
      这里 .uk-tbl(1) + .uk-prow/.uk-vrow(1) + :has(td[data-vari]:hover)(2) + [data-vari](1) = b:5,
      元素 tr + td + has 里的 td = c:3 -> **(0,5,3)**, 稳赢, 不靠源码顺序。
      (顺带也压过 `tr:has(a:hover) > td{transparent}` 和 `td.uk-clickcell:hover{#d3f9d8}`。)

   实测判据(patchright + getComputedStyle, 不是看截图颜色):
      鼠标在空白预售格 -> 第一档四格必须是 rgba(0,0,0,0), 不是 rgb(244,245,248)。 */
/* ‼️ 先把整行 hover 的底色从档位格上摘掉, 再单独给它们上色 —— 顺序不能反。
      第 125 行 `.uk-tbl tr:hover td{background:var(--surface-2)}` 是**整行**规则,
      而第一档那四格物理上就长在 tr.uk-prow 里, 于是鼠标停在同一行的任何非可点格
      (空白预售格 / 平台格 / 时间格 …)上时, 第一档跟着变色而第二档起是白的 ——
      还是那句「鼠标在别的地方, 第一个规格行却亮了」, 只是颜色淡一点。
      (0,4,2) > 125 行的 (0,2,2), 稳压。
      ‼️ 这条只对 uk-prow 写: uk-vrow 一行就是一档, 整行 hover 本来就等价于档位 hover。 */
.uk-tbl tr.uk-prow:hover > td[data-vari]{background:transparent}
.uk-tbl tr.uk-prow:has(td[data-vari]:hover) > td[data-vari],
.uk-tbl tr.uk-vrow:has(td[data-vari]:hover) > td[data-vari]{background:var(--hover,#f4f5f8)}
/* 规格名: 与订单表的规格同色(主色), 一眼分得出这是"档"不是普通文本 */
.uk-tbl td.uk-varname .v{color:var(--primary);font-weight:600;font-size:12px;
  display:inline-block;max-width:170px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  vertical-align:middle}
/* 标题下面那行真 SKU: 小、灰、可复制。它不是规格, 只是要拿去平台后台搜的那串 */
.uk-prodsku{font-size:11px;line-height:1.3;color:var(--muted);margin-top:2px;
  overflow-wrap:anywhere;cursor:pointer}

/* ==== 商品图网格(2026-09-04, 商品编辑弹窗)====
   ‼️ 固定 96px 方格而不是让图片自己撑: 商品图尺寸五花八门, 不定死的话一行高矮不齐,
      而员工要做的就是"扫一眼看哪张不对", 参差不齐正好毁掉这件事。
   ‼️ object-fit: contain 不是 cover —— cover 会把图裁掉一部分, 而这里正是要看清整张图。 */
.uk-imgcell { width: 96px; }
.uk-imgbox {
    position: relative; width: 96px; height: 96px;
    border: 1px solid var(--border); border-radius: 6px; overflow: hidden;
    background: #fff; display: flex; align-items: center; justify-content: center;
}
.uk-imgbox img { max-width: 100%; max-height: 100%; object-fit: contain; }
/* 加号格(2026-09-04 主人: "要一个最后一张图右侧的正方形, 中心有个加号那种的更通用")。
   和缩略图同尺寸同圆角, 跟在最后一张图右边 —— 这是网格式图片管理的通用手势,
   比另起一个"上传图片"按钮少一次找。 */
.uk-imgadd {
    width: 96px; height: 96px; display: flex; align-items: center; justify-content: center;
    border: 1px dashed var(--border); border-radius: 6px; cursor: pointer;
    color: var(--txt-2, #6b7280); background: var(--surface, #fff); margin: 0;
    transition: border-color .12s, color .12s;
}
.uk-imgadd:hover { border-color: var(--primary); color: var(--primary); }
.uk-imgadd span { font-size: 30px; line-height: 1; font-weight: 300; }
.uk-imgchk { position: absolute; top: 4px; left: 4px; z-index: 2; }
/* 主图角标: 放右上, 和左上的勾选框错开 */
.uk-imgmain {
    position: absolute; top: 0; right: 0; z-index: 2;
    background: var(--accent, #4263eb); color: #fff;
    font-size: 10px; line-height: 1; padding: 3px 5px; border-radius: 0 6px 0 6px;
}
.uk-imgsize { text-align: center; font-size: 11px; margin-top: 2px; }
/* 操作按钮(2026-09-04 主人: "这个左右箭头也太不明显了")。原来是无边框透明的 .btn,
   在浅灰底上等于隐形。改成描边按钮 + 32px 见方的热区: 这一排要天天点, 认得出、点得中比省地方重要。
   到头的方向键直接 disabled —— 点了没反应比灰着更让人困惑。 */
.uk-imgops { display: flex; justify-content: center; gap: 3px; margin-top: 3px; }
.uk-imgops .btn {
    padding: 0; width: 21px; height: 21px; font-size: 12px; line-height: 1;
    display: inline-flex; align-items: center; justify-content: center;
}
.uk-imgops .btn:disabled { opacity: .3; }
/* 图标是内联 SVG(2026-09-05): 用 currentColor 描边, 所以放进 btn-outline-danger 自动变红。
   ‼️ svg 要 display:block —— 行内元素会按基线对齐, 在 21px 的方按钮里天生偏下几像素。 */
.uk-imgops .btn svg { display: block; }

/* 拖拽排序(商品图)。把手压在缩略图右下角, 光标 grab; 拖起来的格子压暗, 落点画一条竖线。
   ‼️ 图本身 draggable=false: 不禁的话浏览器会去拖那张图(半透明鬼影), 看着就像"拖了没反应"。 */
.uk-imgcell { cursor: grab; }
.uk-imgcell:active { cursor: grabbing; }
.uk-imgdrag {
    position: absolute; right: 2px; bottom: 2px; z-index: 2;
    background: rgba(255,255,255,.86); border: 1px solid var(--border);
    border-radius: 4px; font-size: 11px; line-height: 1; padding: 2px 3px; color: var(--txt-2, #6b7280);
}
.uk-imgcell.dragging { opacity: .4; }
.uk-imgcell.dragover .uk-imgbox { border-color: var(--primary); box-shadow: -3px 0 0 var(--primary); }

/* 拖拽排序(规格表)。把手用 grab 光标, 拖起来的行压暗, 落点画一条线 —— 三样缺一样都会让人
   不知道自己拖到哪了。行本身 draggable, 但只在把手上给 grab 光标(别让整行看起来都能拖)。 */
.uk-tbl td.uk-draghandle{cursor:grab;color:var(--faint);padding-left:6px;padding-right:2px;width:1%}
.uk-tbl td.uk-draghandle:active{cursor:grabbing}
.uk-tbl tr.uk-dragging{opacity:.45}
.uk-tbl tr.uk-dragover > td{border-top:2px solid var(--primary)}

/* 规格图: 可点换。没有图的行给一个 + 占位 —— 没图的恰恰最需要补图, 不能只在有图时给入口 */
.uk-skuimg { display: inline-block; cursor: pointer; line-height: 0; }
.uk-skuimg:hover { outline: 2px solid var(--accent, #4263eb); outline-offset: 1px; border-radius: 4px; }
.uk-skuimg-empty {
    display: inline-flex; align-items: center; justify-content: center;
    width: 34px; height: 34px; border: 1px dashed var(--border); border-radius: 4px;
    color: var(--txt-3, #9aa4b2); font-size: 16px; line-height: 1;
}
/* 规格图的删除角标(2026-09-12): 只在这一档真有图时出现, 平时淡, 悬停变红 */
.uk-skuimgbox { position: relative; display: inline-block; line-height: 0; }
.uk-skuimg-del {
    position: absolute; top: -6px; right: -6px; width: 16px; height: 16px; padding: 0;
    border: 1px solid var(--border); border-radius: 50%; background: var(--bg-1, #fff);
    color: var(--txt-3, #9aa4b2); font-size: 12px; line-height: 14px; cursor: pointer;
}
.uk-skuimgbox:hover .uk-skuimg-del { color: var(--danger, #e03131); border-color: var(--danger, #e03131); }

/* ==== 手工批量编辑弹窗(2026-09-04)====
   一个商品一大行(rowspan), 一个规格一行, 每格都是输入框。 */
.uk-prodcell-sm { max-width: 320px; }
.uk-prodcell-sm .nm { font-size: 13px; line-height: 1.35; }
.uk-prodcell-sm .sh { font-size: 11px; }
#beGrid td { vertical-align: middle; padding: 5px 8px; }
/* ‼️ 合并格(商品名 / 预售)必须顶对齐(2026-09-04 主人: "前两列不要居中, 排在开头")。
   表格单元格默认垂直居中, 而这两格是 rowspan=档数 —— 二十档的品就把内容浮在
   半屏之下, 和它对应的第一档差着十几行, 看着完全不知道在说哪个品。
   通用规则 .uk-tbl td[rowspan]{vertical-align:top} 本来就有, 是被上面这条
   #beGrid td 的 id 选择器压掉了 —— 权重更高, 所以要在这里再写一次。 */
#beGrid td[rowspan] { vertical-align: top; }
/* 快速编辑里标题可改(2026-09-04)。textarea 不是 input: 汽配标题动辄 130+ 字,
   单行框只看得见开头一截, 改的时候不知道自己在改什么。 */
#beGrid .be-title { width: 100%; min-width: 300px; resize: vertical; line-height: 1.35; }
#beGrid .be-ttcnt { text-align: right; margin-top: 2px; }
#beGrid input.form-control-sm { height: 28px; padding: 1px 6px; }
/* 预售: 开关和天数**横排**一格。开关本身不占标签文字 —— 列头已经写着"预售"了,
   每一行再重复一遍是噪音, 而且会把这一格撑宽。 */
.be-pocell { white-space: nowrap; }
.be-po { display: flex; align-items: center; gap: 8px; }
.be-po .form-switch { padding-left: 2.2em; }
.be-pod { width: 62px; }
/* 禁用态要看得出来是"现在不能填", 不是"坏了" */
.be-pod:disabled, .be-nm:disabled { background: var(--surface-2, #eef1f5); color: var(--txt-3, #9aa4b2); }
/* 预售那一格是整品级(rowspan), 给一条左边线把它和逐档的三列分开 —— 否则人会以为能一档一档设 */
#beGrid td:nth-child(2) { border-left: 1px solid var(--border); border-right: 1px solid var(--border); }

/* 逐品编辑的「价格/库存/预售」逐档表(2026-09-04: 价格/库存/预售三个页签合一)。
   一个规格一行, 名/价/库存并排 —— 员工要的就是"一屏把这一档填完", 而不是切三次页签。 */
.pe-pv{width:100%;border-collapse:collapse}
.pe-pv td{padding:2px 3px;vertical-align:middle}
/* 规格名给足宽度(汽配的档名动辄 Left (Driver),Front), 价和库存固定窄列 */
/* 规格名定宽而不是 auto: auto 会让这一列把整行的富余全吃掉(主人 2026-09-04 指出),
   而汽配的档名再长也就 "Left (Driver),Front" 那个量级, 200px 够看, 超了框内滚。 */
.pe-pv td:first-child{width:240px}
.pe-pv td:nth-child(2),.pe-pv td:nth-child(3){width:125px}
.pe-pv input{width:100%}
/* 币种标签和价格框**必须在同一行**(2026-09-04 主人: "都没对齐, 很丑")。
   ‼️ 之前 .cur 是裸 inline span, 而同格的 input 是 width:100% —— 一行放不下两个,
      标签被挤到上一行, 于是价格框比同一档的"规格名/库存"低 8~9px(实测 108 vs 116),
      整个规格块又比标题/描述/包裹低 10px。整张表看着全是错位就是这一条。
   修法: 标签定宽 inline-block, 价格框宽度扣掉标签占的位置。
   实测修后: 名/价/存三个框顶边同为 99/219/390, 各列首控件顶收敛到 98~100。 */
.pe-pv td:nth-child(2){white-space:nowrap}
/* 币种和价格框之间留够气口(2026-09-04 主人: php 跟右侧的 margin 稍微加大) */
.pe-pv .cur{display:inline-block;width:20px;text-align:right;vertical-align:middle;margin-right:6px}
.pe-pv td:nth-child(2) input{width:calc(100% - 30px);display:inline-block;vertical-align:middle}
.pe-pv input{min-width:0}
/* 预售在这一格最上面: 它是商品级的, 不跟着档走 —— 所以和下面的表拉开一条线 */
.pe-pvpre{display:flex;align-items:center;gap:6px;padding-bottom:4px;margin-bottom:4px;
          border-bottom:1px dashed var(--border,#e5e7eb)}
.pe-pvpre .form-check{display:flex;align-items:center;gap:4px}

/* 批量按钮条的簇分隔线(2026-09-04)。十几个按钮平铺一排, 谁跟谁是一类看不出来 ——
   一条竖线比加空隙好: 空隙大了会被当成"这个按钮不属于这一排"(主人原话
   「为什么 delete items 跟左边离那么远?」), 小了又看不出分组。 */
.uk-btnsep{display:inline-block;width:1px;align-self:stretch;margin:2px 4px;
  background:var(--border)}

/* 商品标题底下那排数据(销量/收藏/浏览/评分, 照 Lazada 官方后台)。
   ‼ flex-wrap 必需: 商品列是 uk-grow 吃富余宽度, 窄屏时这排要折行, 不能把列撑破。
   ‼ .off = 没测到, 画得更淡 —— 它和 0 是两件事, 不能长得一样。 */
/* 位置: 钉在商品格**底部**(主人 2026-09-04 圈的位置)。多规格品标题只占两行、下面一大片空,
   数据行贴着标题会浮在半空; 钉底之后一行行扫下去四个图标是竖着对齐的一列, 好比较。
   ‼ 靠 height:100% + margin-top:auto 把它推下去 —— td 撑不满时它自然退回标题下面, 不会错位。 */
/* ‼ height:1px 是给 td 一个"确定"高度的已知解法 —— 实际高度仍由内容撑, 但子元素的
   height:100% 这才解析得出来(不给的话数据行钉不到底, 实测差 59px)。 */
.uk-tbl td.uk-prodtd{height:1px}
.uk-tbl td.uk-prodtd .uk-prodcell{height:100%;align-items:stretch}
/* 缩略图不跟着拉伸: stretch 会把它抻成一整列的高度 */
.uk-tbl td.uk-prodtd .uk-prodcell > .uk-thumb,
.uk-tbl td.uk-prodtd .uk-prodcell > a{align-self:flex-start}
.uk-tbl td.uk-prodtd .uk-prodcell > .txt{display:flex;flex-direction:column;flex:1;min-width:0}
/* 和标题拉开(主人 2026-09-04: 贴太紧)。短标题的行 margin-top:auto 收不出空间,
   所以间距靠 padding-top 给 —— 长短标题两种情况下都稳定。 */
.uk-tbl td.uk-prodtd .uk-statrow{margin-top:auto;padding-top:12px}
.uk-statrow{display:flex;flex-wrap:wrap;gap:4px;margin-top:8px}
/* 每格定一个下限宽度 -> 四个格子上下行之间**左右对齐**, 不会因为数字位数不同而参差。 */
/* ‼ 图标和数字都设成 display:block + line-height:1 —— 只写 align-items:center 是不够的:
   居中的是**元素盒子**, 字形在盒子里的位置由 line-height 决定, 两边行高不一样就差半格
   (主人 2026-09-04: "跟图标不在一条线上")。 */
.uk-statrow .uk-stat{display:inline-flex;align-items:center;justify-content:center;gap:4px;
  min-width:44px;padding:2px 7px;
  border:1px solid var(--border);border-radius:var(--r-sm);background:var(--surface-2);
  font-size:10.5px;line-height:1;color:var(--muted);white-space:nowrap;cursor:default}
.uk-statrow .uk-stat i{display:block;font-style:normal;line-height:0;flex:none}
.uk-statrow .uk-stat svg{display:block;width:12px;height:12px;opacity:.6}
.uk-statrow .uk-stat b{display:block;font-size:11px;font-weight:600;line-height:1;color:var(--text)}
/* 没数据: 只有图标, 整块调淡 + 虚线框。**不写 — 也不写 0** —— 0 的意思是"没人看过"。 */
.uk-statrow .uk-stat.off{border-style:dashed;background:transparent;opacity:.45;min-width:30px}

/* 分组管理弹窗(2026-09-04 主人: 下拉最多 10 个, 其余走「更多…」)。
   一个地方把 看全部组 / 建 / 删 / 点一个组按它筛 四件事做完 ——
   原来这四件事散在筛选行的两个按钮和一个下拉里。 */
.uk-grpmgr-add{display:flex;gap:6px;margin-bottom:8px}
.uk-grpmgr-add input{flex:1}
.uk-grpmgr-tbl{width:100%;table-layout:auto}
.uk-grpmgr-tbl td{padding:6px 8px;border-bottom:1px solid var(--border)}
.uk-grpmgr-tbl tr:last-child td{border-bottom:0}
/* ‼️ 名字这一格 width:100% —— 不给的话三格都按内容收缩, 名字和件数之间空出一大块
   (2026-09-04 主人: "为什么右侧空出那么多")。件数和按钮那两格按内容走。 */
.uk-grpmgr-tbl td.gm-name{width:100%;font-weight:600}
.uk-grpmgr-tbl td.gm-cnt,.uk-grpmgr-tbl td.gm-act{white-space:nowrap;width:1%}
/* 整行可点 = 按这个组筛选, 所以**整行**小手 + 整行 hover(主人两条都提了)。
   删除按钮自己 stopPropagation, 点它不会顺带筛选。 */
.uk-grpmgr-tbl tr{cursor:pointer}
/* 整行可点(点一行开详情)的表: 小手 + 行高亮, 和商品列表的手感一致 */
.uk-tbl tr.uk-rowlink{cursor:pointer}
.uk-tbl tr.uk-rowlink:hover>td{background:var(--surface-2,#f4f5f8)}
/* ‼️ 别用 var(--surface-2): 实测它解析成 rgb(250,251,252), 在白底上肉眼几乎看不出来
   (主人: "名字鼠标移上去没有 hover 效果" —— 其实有, 只是太淡)。写死一个看得见的浅灰蓝。 */
/* 悬停整行高亮。‼️ 圆角要加在**首尾两格**上, 不能加在 tr 上 ——
   表格行的 border-radius 不生效(渲染的是每个 td 的背景)。 */
.uk-grpmgr-tbl tr:hover > td{background:#eef2f7}
.uk-grpmgr-tbl tr:hover > td:first-child{border-top-left-radius:6px;border-bottom-left-radius:6px}
.uk-grpmgr-tbl tr:hover > td:last-child{border-top-right-radius:6px;border-bottom-right-radius:6px}
.uk-grpmgr-tbl tr:hover .gm-name{color:var(--primary)}

/* ==== 增删规格弹窗(2026-09-05)====
   上半每一维一块选项表, 下半是组合出来的档位矩阵。三种行要一眼分得出来:
   已有档=白底 / 新增=绿底 / 待删=划掉压暗 / 平台上没有的空组合=灰字。
   ‼️ 靠颜色**和**文字两条线表达, 不只靠颜色 —— 打印和色弱都要看得懂。 */
.uk-varedit .uk-vdim{border:1px solid var(--border);border-radius:8px;padding:8px 10px;margin-bottom:6px}
.uk-varedit .uk-vdim-hd{display:flex;align-items:baseline;gap:8px;margin-bottom:6px}
.uk-varedit .uk-vopts{display:flex;flex-wrap:wrap;gap:6px}
.uk-varedit .uk-vopt{display:inline-flex;align-items:center;gap:6px;padding:3px 6px 3px 10px;
    border:1px solid var(--border);border-radius:14px;background:var(--surface);font-size:12.5px}
.uk-varedit .uk-vopt .x{border:0;background:transparent;color:var(--faint);line-height:0;
    padding:3px;border-radius:50%;cursor:pointer}
.uk-varedit .uk-vopt .x:hover{background:var(--danger-weak);color:var(--danger)}
.uk-varedit .uk-vaddopt{border:1px dashed var(--border);background:transparent;color:var(--muted);
    border-radius:14px;padding:3px 12px;font-size:12.5px;cursor:pointer}
.uk-varedit .uk-vaddopt:hover{border-color:var(--primary);color:var(--primary)}
/* 矩阵行的三种状态 */
.uk-varedit tr.uk-vrow-new > td{background:var(--ok-weak)}
.uk-varedit tr.uk-vrow-del > td{background:var(--danger-weak);text-decoration:line-through;opacity:.7}
.uk-varedit tr.uk-vrow-hole > td{color:var(--muted);background:var(--hover)}
.uk-varedit .uk-tbl td{vertical-align:middle}

/* ==== 店铺彩标(2026-09-05)====
   多店时店名是一串很像的英文(EZTradingPH / EZTrading0.ph / EZTradingSVIP), 得逐个读字才分得清;
   平台标本来就是彩色的, 店铺标跟着上色, 一眼扫得出这行属于哪家。
   ‼️ 底色/字色是行内样式(逐店不同, 写不进 class), 这里只管形状。
   ‼️ inline-block: 它套在 display:block 的 .nm 里, 不这么写会拉成整列宽的一条色带。 */
/* ‼️ 2026-09-20 主人:「店铺alias的标签让它样式跟平台标签样式一样」——
   内边距/圆角/字号/透明度全抄 .uk-pftag(搜它看原件)。
   ‼ 仍是 inline-block 而不是 pftag 那个 inline-flex: 店名长了要截成省略号,
     inline-flex 的子项吃不到 text-overflow。底色是逐店的行内样式, 这里不管色。 */
.uk-shoptag{display:inline-block;max-width:100%;padding:3px 10px;border-radius:var(--r-lg);
    font-weight:600;font-size:12px;line-height:1.5;vertical-align:middle;border:0;
    overflow:hidden;text-overflow:ellipsis;white-space:nowrap;opacity:.9}
.uk-tbl td.uk-shopcell .nm .uk-shoptag{margin-bottom:2px}
/* 色板里的"不上色": 白底 + 一道斜杠(照取色器的惯例); 没有它就只能靠再点一次取消, 那不叫入口 */
.uk-swatch-none{background:var(--surface);
    background-image:linear-gradient(to top left, transparent calc(50% - 1px),
        var(--danger,#e5484d) calc(50% - 1px), var(--danger,#e5484d) calc(50% + 1px), transparent calc(50% + 1px))}

/* 店铺标的**一行版**(chip / 弹窗预览): 表格里是两行(列窄), 但在一行宽度不缺的地方,
   把真名接在彩标右边更顺眼(2026-09-05 主人: "详情页的括号移到一行去")。
   ‼️ 一行版的 .al-inline 不挑外层(2026-09-26 主人: 总览「店铺分布」彩标和真名贴在一起) ——
      原来只认 .uk-shopcell 里面的, 放进普通表格格子就没了间距。 */
.al.al-inline,.uk-shop-inline .al{display:inline;margin-left:6px;white-space:nowrap}
.uk-shop-inline .nm{display:inline}
.uk-shop-inline{display:inline-flex;align-items:center;gap:0}

/* ==== 商品表(一个品跨好几行)的 hover ====
   2026-09-05 被主人连报四次才对, 四版的错法都记在这, 别再走一遍:
     v1 逐行 `tr:hover`               -> **rowspan 的跨行格长在第一行里**, 鼠标停在它们上面
                                         (甚至停在两行之间的空白)第一档就亮 —— "鼠标在别处却亮着"
     v2 JS 打类"整块一起亮"           -> 方向反了, 主人要的是"各行独立, 不传导到父类"
     v3 `tr:hover > td{transparent}`  -> 整行 hover 被一刀切没了("原本整行的hover又没了?")
     v4 = 现在: 按**鼠标压在哪一类格子上**分情形, 三条规则作用域互不重叠:

       鼠标在跨行格(商品名/店铺/时间/空白预售格) -> 整行照亮(商品块), 第一档那四格**不亮**
            前半 = 第 125 行的 `.uk-tbl tr:hover td`; 后半 = 下面 §档位 那条 prow transparent
       鼠标在某一档的四格                        -> **只亮那一档**, 不往父块传 = 本节这条
       两行之间 / 表格空白                       -> 什么都不亮

   ‼️ 档位高亮本身(`:has(td[data-vari]:hover) > td[data-vari]{var(--hover)}`)写在**上面**
      §档位格的 hover 那一段里 —— 别再另写一套(2026-09-05 我重复造过一次)。
   ‼️ 特异性 (0,5,3), 压得住 `.uk-tbl tr:hover td`(0,2,2)。 */
.uk-tbl.uk-vhover tr:has(> td[data-vari]:hover) > td:not([data-vari]){background:transparent}
/* 档位格点了有事(改这一档的价/库存), 所以要小手。‼️ 它们**不挂 .uk-clickcell**:
   通用的 `tr:has(td.uk-clickcell:hover) > td.uk-clickcell` 会把同一行所有 clickcell 一起染绿,
   连跨行的状态格也跟着亮(见 app.js 那段注释)。高亮和点击都认 `data-vari` 这个属性。 */
.uk-tbl td[data-vari]{cursor:pointer}

/* ---- 单图编辑器(2026-09-09): 左边预览, 右边一条控制栏 ---- */
.uk-imgopen{cursor:zoom-in}
.uk-imged{display:flex;gap:16px;align-items:flex-start}
.uk-imged-view{flex:1 1 auto;min-width:0}
/* 预览格高度**跟视口走**: 写死 360px 等于在 1440p 上也只给一小格。留一个上限免得图太高把
   控制栏挤出屏幕; 高度固定(不是 auto)是故意的 —— 换一张别的比例的图, 整个弹窗不该跳一下。 */
.uk-imged-canvas{display:flex;align-items:center;justify-content:center;height:min(58vh,560px);
  background:var(--bg-soft,#f5f6f8);border:1px solid var(--line,#e3e6eb);border-radius:6px}
.uk-imged-canvas img{max-width:100%;max-height:100%;object-fit:contain}
/* 渲染中把上一张压暗, 别让人以为"点了没反应"—— 但**不清空**, 空白比旧图更像坏了 */
.uk-imged-canvas img.loading{opacity:.35;filter:blur(1px)}
/* ‼️ 控制栏**不自己加 overflow**(主人 2026-09-10)。宽屏上排**两列**, 高度直接减半,
   根本用不着滚; 真窄了才靠弹窗自己那层兜底。 */
.uk-imged-side{flex:0 0 460px;display:grid;grid-template-columns:1fr 1fr;
  gap:0 14px;align-content:start}
/* 一块 = 一个网格单元(块内部纵向排), 两列切的是"块"不是"控件" */
.uk-imged-grp{min-width:0;padding:8px 10px;border:1px solid var(--line,#e9ebf0);border-radius:6px;
  margin-bottom:12px}
.uk-imged-grp>*:last-child{margin-bottom:0!important}
/* "复位"跨满两列 —— 它管的是整块面板, 不属于任何一块 */
.uk-imged-side [data-act=reset]{grid-column:1/-1}
.uk-imged-side .form-range{margin:0}
.uk-imged-side .form-control-color{width:38px;padding:2px}
/* 按钮之间要有间隔(主人 2026-09-10): 所以**不用** btn-group —— 它的定义就是把按钮拼成
   一条(负 margin), 给它加 gap 等于跟它的本意对着干。这里是普通 flex + gap。 */
.uk-imged-btns{display:flex;gap:6px;flex-wrap:wrap}
@media (max-width:900px){.uk-imged{flex-direction:column}
  .uk-imged-side{flex:1 1 auto;width:100%}}

/* 表格上面还有大块内容的页(2026-09-24, recruitadmin 装机渠道: 汇总 + 按天 + 明细): 桌面默认让表格卡撑满剩余高度、
   只在卡里滚(第 503 行), 上面内容一多表格就被挤成 0 行。页面里放一个 .uk-page-flow = 这页整页滚, 表格按自然高度排。
   只圈带这个标记的页, 不动 .uk-content 本身(三后台共用)。 */
@media (min-width:769px){
  .uk-content:has(.uk-page-flow){overflow:auto}
  .uk-content:has(.uk-page-flow) .dataTables_wrapper{flex:0 0 auto}
  .uk-content:has(.uk-page-flow) .dataTables_wrapper>.row.dt-row{overflow:visible}
  .uk-content:has(.uk-page-flow) .uk-listcard{flex:0 0 auto}
  .uk-content:has(.uk-page-flow) .uk-listcard>.uk-tbl-scroll{overflow-y:visible;flex:0 0 auto}
}

/* 订单详情: 平台结算 / 订单信息排版(2026-10-02): 标签-值两两一组, 宽屏一行两组, 窄屏一组 */
.op-blk{margin-top:14px}
.op-h{font-weight:600;font-size:14px;margin-bottom:4px}
.op-sub{font-size:12px;color:var(--muted);font-weight:600;margin:10px 0 4px}
.op-grid{display:grid;grid-template-columns:max-content minmax(0,1fr) max-content minmax(0,1fr);gap:4px 14px;font-size:13px}
.op-k{color:var(--muted);white-space:nowrap}
.op-v{word-break:break-word}
@media (max-width:768px){.op-grid{grid-template-columns:max-content minmax(0,1fr)}}
