/* 定价系统样式（从 index.html 拆出） */
:root{
    /* ═══════════════════════════════════════════════════════════════════
       第 1 层 原始值 primitive —— **全站唯一允许出现裸 hex 的地方**
       ═══════════════════════════════════════════════════════════════════ */
    --navy-900:#071224; --navy-800:#0B1F3A; --navy-700:#122C4D; --navy-600:#12305A;
    --gold-700:#8A6415; --gold-600:#996E1A; --gold-500:#C9922D; --gold-400:#D4A63F;
    --gold-300:#F0D9AB; --gold-200:#F0E2C4;
    --red-700:#8A3A30;  --red-600:#B23B36;  --red-500:#C0392B;
    --red-200:#F2C4BD;  --red-100:#FDECEA;
    --green-700:#1A7D36; --green-600:#1F8A4C; --green-200:#CFE8D0; --green-100:#E6F4EA;
    --brown-800:#5D4410; --brown-700:#976500; --brown-200:#FDF3DD;
    --blue-600:#1D5FB0;  --blue-200:#C9D2E0;  --blue-100:#EAF0F7; --blue-100l:#BCD6F5;
    --ink-500:#3D4B63;   --gray-600:#646A77;  --gray-500:#6B6A63;  --gray-400:#9CA3AF;
    --slate-500:#68778D; --slate-400:#A8A29A; --slate-300:#CFCAC2;
    --paper-0:#FFFFFF; --paper-1:#FDFBF6; --paper-2:#F7F5F0; --paper-3:#F0EFE9;
    --paper-4:#E9E5DC; --paper-warm:#FDF8EE;
    --line-warm:#ECE6DA; --line-cool:#E2E4E9; --line-gold:#F0E2C4;
    --unknown-text:#8A7A5C; --unknown-line:#E6DCC6;
    --status-none:#5B6472; --status-none-bg:#EEF0F3;
    --warn-date:#B98A3A;

    /* ═══════════════════════════════════════════════════════════════════
       第 2 层 语义令牌 semantic —— **组件只准用这一层**
       ═══════════════════════════════════════════════════════════════════ */
    --color-brand:var(--navy-800);
    --color-brand-deep:var(--navy-900);
    --color-brand-700:var(--navy-700);
    --color-accent:var(--gold-500);
    --color-on-brand:var(--paper-0);        /* 压深底的白字 */
    --color-bg:#FAF7F0;                     /* 规范 0.1 的页面底（原 #FAF8F4 差 2 级，已对齐）*/
    --color-surface:var(--paper-0);
    --color-surface-alt:var(--paper-1);
    --color-surface-sunken:var(--paper-3);
    --color-border:var(--line-warm);
    --color-border-soft:var(--line-gold);
    --color-border-cool:var(--line-cool);

    --color-text:var(--navy-800);
    --color-text-soft:var(--ink-500);
    --color-text-muted:var(--gray-600);     /* 白 5.43:1 · band-3 4.56:1（v77d 压暗，见第 1 层注释）*/
    --color-text-dim:var(--gray-500);       /* 5.43:1 */
    --color-text-faint:var(--gray-400);     /* 2.54:1 —— ⚠️ 仅图标/装饰，禁当正文 */
    --color-slate:var(--slate-500);         /* 4.55:1  ← 原 #6B7A90 4.36:1 */
    --color-text-ghost:var(--slate-400);    /* 缺价格灰字，刻意淡 */
    --color-text-ghost-2:var(--slate-300);  /* 不适用格灰字，刻意淡 */
    --color-status-none:var(--status-none);
    --color-unknown-text:var(--unknown-text);
    --color-unknown-line:var(--unknown-line);

    --color-danger:var(--red-500);          /* 填充/徽标 */
    --color-danger-text:var(--red-600);     /* 5.88:1 文字 */
    --color-danger-deep:var(--red-700);
    --color-danger-bg:var(--red-100);
    --color-danger-line:var(--red-200);

    --color-success:var(--green-600);       /* ⚠️ 4.38:1 —— 只够块/徽标底，别当正文 */
    --color-success-text:var(--green-700);  /* 5.21:1 ← 正文用这个 */
    --color-success-bg:var(--green-100);
    --color-success-line:var(--green-200);

    --color-warning:var(--gold-500);        /* ⚠️ 2.75:1 —— 只够块/徽标底，别当正文 */
    --color-warning-text:var(--brown-700);  /* 5.03:1 ← 正文用这个 */
    --color-warning-deep:var(--brown-800);
    --color-warning-bg:var(--brown-200);
    --color-warning-line:var(--gold-300);
    --color-warning-date:var(--warn-date);

    --color-info:var(--blue-600);
    --color-info-bg:var(--blue-100);
    --color-info-line:var(--blue-200);
    --color-info-light:var(--blue-100l);

    /* 焦点环（规范第 11 层：焦点指示必须可见）—— 本项目做法是「边框变琥珀 + 极淡环」*/
    --ring-amber:rgba(201,146,45,.15);
    --ring-amber-soft:rgba(201,146,45,.12);
    --ring-bad:rgba(192,57,43,.14);

    /* 矩阵色阶四档 —— ⚠️ `verify_freshness` 断言四档底色互不相同 → 值不许动 */
    --band-1:#8FD6AD; --band-2:#BFE6CE; --band-3:#DCF0E4; --band-4:#EEF8F2;
    --band-1-h:#7DCA9D; --band-2-h:#AEDCC0; --band-3-h:#CCE8D7; --band-4-h:#E2F2E8;
    --band-text:#4A7A62;

    /* 组件级底色 —— ⚠️ `verify_freshness` 断言行悬停 ≠ #F8FAFD → 值不许动 */
    --tint-hover:#F8FAFD;
    --tint-edit:#FFFDF5;
    --tint-fold:#F1EFE9;
    /* ⚠️⚠️ 下面 8 个是 v77 第一轮「裸 hex → var()」误伤的**修复**：
       替换时把 3 位简写 `#FFF` 当成了 6 位色值的前缀 —— `#FFF5f4` 被切成
       `var(--color-surface)` 再挂一个裸尾巴 `5f4`，于是那句 background 成了**无效声明**，
       底色整条丢失（共 15 处）。这里按 v77 前的原值补成令牌，**值一字不改**，纯属恢复原状。
       ⚠️ 本轮同时给校验器补了这类「var() 后拼 hex」的检查，见 _tmp/vspec_verify_css.py ③。 */
    --tint-danger:#FFF5F4;        /* 校验未过格 / 错误块底 */
    --tint-danger-soft:#FFF7F6;   /* 字段级错误底 */
    --tint-warn:#FFF5E5;          /* 警示徽标底 */
    --tint-warn-soft:#FFF8E8;     /* 提示条底 */
    --tint-warn-mid:#FFF7E8;      /* 状态块底 */
    --tint-warn-faint:#FFFBF3;    /* 按钮悬停底 */
    --tint-warn-ghost:#FFFBF0;    /* 极淡警示底 */
    --tint-note:#FFFDF6;          /* 矩阵备注 / 警示行底 */

    --font:'Inter','Noto Sans SC',system-ui,-apple-system,"PingFang SC","Microsoft YaHei",sans-serif;
    --mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;

    /* 圆角 / 阴影（规范 0.4：圆角统一 6px · 阴影只用一种轻投影）*/
    --radius:6px; --radius-sm:6px; --radius-lg:6px;
    --shadow:0 1px 3px rgba(0,0,0,.08);

    /* ═══════════════════════════════════════════════════════════════════
       第 3 层 兼容别名 —— 老变量名继续可用，一律指向语义令牌
       （这样 481 处 var() 引用不用逐个改；新代码请直接用第 2 层）
       ═══════════════════════════════════════════════════════════════════ */
    --navy:var(--color-brand); --navy-deep:var(--color-brand-deep);
    /* ⚠️ 这里**不能**再写 --navy-700:var(--color-brand-700) —— 第 1 层已有 --navy-700，
       而 --color-brand-700 又指回 --navy-700，两条构成**相互引用环** → 双双失效。
       （v77 第一轮引入；因 thead th 的 color 靠继承侥幸没露馅，v77b 修）*/
    --amber:var(--color-accent); --amber-600:var(--gold-600); --amber-400:var(--gold-400);
    --cream:var(--color-bg); --bg:var(--color-bg); --card:var(--color-surface);
    --border:var(--color-border-cool); --line:var(--color-border); --muted:var(--color-text-muted);
    --ok:var(--color-success); --warn:var(--color-warning); --bad:var(--color-danger);
    --blue:var(--color-info); --slate:var(--color-slate);
    /* ⚠️ 下面 3 个原本**从没定义过**（v70 起就是），属于静默 bug，这次补上：
       `.spec-v{color:var(--text)}` → 无效值 → 颜色靠继承侥幸没露馅；
       `.gap-chip.plain:hover{border-color:var(--navy-600)}` → 无效值 → **悬停边框一直没变色**；
       `.must-copybox{background:var(--soft)}` → 无效值 → 底色一直是透明。 */
    --text:var(--color-text);
    --soft:var(--paper-1);
  }

  /* 暗色令牌双套（规范 0.1「令牌天生双套」）
     ⚠️ **备用 · 未接线** —— 只在 `<html data-theme="dark">` 时生效，当前没有任何切换入口，
        所以对现有观感零影响。只覆盖语义层；组件级 tint 尚未配套。 */
  [data-theme="dark"]{
    --color-bg:#12151A;
    --color-surface:#1A1F27;
    --color-surface-alt:#212733;
    --color-surface-sunken:#0E1116;
    --color-border:#2E3542;
    --color-border-cool:#333B49;
    --color-text:#E8E4DA;
    --color-text-soft:#C3C8D2;
    --color-text-muted:#9AA3B2;
    --color-text-dim:#8C93A0;
    --color-text-faint:#6B7280;
    --color-on-brand:#0B1F3A;
    --tint-hover:#232A36;
    --tint-edit:#2A2418;
    --tint-fold:#20252E;
  }
  *{box-sizing:border-box;margin:0;padding:0}
  /* ══ 规范第 2.1 / 11 层：尊重「减少动态效果」系统偏好（v77 新增）══ */
  @media (prefers-reduced-motion: reduce){
    *,*::before,*::after{
      animation-duration:.01ms !important; animation-iteration-count:1 !important;
      transition-duration:.01ms !important; scroll-behavior:auto !important}
  }

  /* ══ 规范第 9 层「费茨定律」：可点目标 ≥36×36（v77 → v77b → v77c）══
     ⚠️⚠️ 这个 36px 热区踩过**两个坑**，都记下来别再犯：
       ① `outline:10px solid transparent` —— ❌ **没用**：outline 只画、不参与命中测试，
          点击区实测还是 13×13。
       ② `padding:10px` + `box-sizing:content-box` —— ❌ **也没用**：Chromium 对
          **替换元素**（input[type=checkbox]/radio）**直接丢弃 padding**，计算值就是
          `padding:0px`。最小对照实测：同写法的 text 框 40×40/pad=10px，checkbox 16×16/pad=0px。
     ✅ 正解 = 外面套一个 36×36 的 `<label class="plck-hit">`：label 天生把点击转发给
        内嵌控件，可点面积 16→36；而**原生渲染 / accent-color / :indeterminate 半选态
        全部保留**（自绘 `appearance:none` 就得自己画勾和半选态，不划算）。
     ⚠️ 该列 `td/th` 的内距归 0，让 36px 的 label 自己定高 —— 否则内距叠加会把行高顶高。 */
  .plck-hit{display:inline-flex;align-items:center;justify-content:center;
    width:36px;height:36px;cursor:pointer;vertical-align:middle}
  .plck{width:16px;height:16px;flex:none;margin:0;cursor:pointer;accent-color:var(--color-brand)}
  .plck:focus-visible{outline:2px solid var(--color-accent);outline-offset:2px}
  td:has(> .plck-hit),th:has(> .plck-hit){padding:0;text-align:center}

  /* ══ 规范第 9 层：全站可点目标 ≥36×36 兜底（v77b 新增）══
     实测改造前 1293 个偏小，集中在三处：地名库行内按钮 498（`.btn-ghost`/`.btn-danger`
     被行内 style="height:28px" 压成 28）、角色下拉 249（`.pl-role` 28）、价格输入 16（`.st-th` 32）。
     ⚠️ 用 `min-height` 而不是去改行内样式 —— `min-height` **优先于**同一元素上的 `height`，
     所以这一条就把全站兜住了，app.js 里的行内 height 不用逐个动。
     ⚠️ 刻意**不写裸 `button`** —— 那会把 `.rev-b`（12px 图标钮）一起撑大。══ */
  .btn-ghost,.btn-primary,.btn-danger,.btn-mini,.btn-skip,.btn-exit,
  .sr-edit,.sr-hold,.sr-del,.sr-lines-btn,.sr-fold-hd,.pl-tip-btn,.pl-role,
  .st-th,
  .ed-table button,.ed-table input,.ed-table select,
  .fld input:not([type=checkbox]):not([type=radio]),.fld select,
  .up-zone .up-chip .rw{min-height:36px}
  /* 图标钮 / 徽标钮 / 复选框除外 —— 显式钉回小尺寸，别被上面那条误伤 */
  .rev-b,.rev-chg,.mn-badge,.cbx-close,.pl-tip-x{min-height:0}

  /* ══ 规范第 9 层：状态全套 —— 补「激活（按下）」态（v77 新增；此前 :active 出现 0 次）══ */
  .btn-primary:active{opacity:1;transform:translateY(1px);background:var(--color-brand-deep)}
  .btn-ghost:active{transform:translateY(1px);background:var(--paper-3)}
  .btn-danger:active,.del:active,.ed-del:active,.sr-del:active{transform:translateY(1px);
    background:var(--color-danger-bg);border-color:var(--color-danger)}
  .mn-btn:active,.chip:active,.type-btn:active{transform:translateY(1px)}
  .btn-primary:disabled,.btn-ghost:disabled,.btn-danger:disabled{opacity:.45;cursor:not-allowed;
    transform:none}
  @media (prefers-reduced-motion: reduce){
    .btn-primary:active,.btn-ghost:active,.btn-danger:active,.del:active,
    .ed-del:active,.sr-del:active,.mn-btn:active,.chip:active,.type-btn:active{transform:none}
  }

  body{font-family:var(--font);
    background:var(--cream);color:var(--navy);font-size:14px;line-height:1.6;padding:32px;
    -webkit-font-smoothing:antialiased}
  .wrap{max-width:1200px;margin:0 auto}
  header{margin-bottom:24px}
  .topbar{background:var(--navy);color:var(--color-on-brand);border-radius:var(--radius-lg);
    padding:16px 24px;display:flex;align-items:center;gap:16px;box-shadow:var(--shadow)}
  .logo{width:40px;height:40px;border-radius:6px;background:var(--amber);color:var(--navy);
    font-weight:800;font-size:16px;letter-spacing:.5px;display:flex;align-items:center;justify-content:center;flex:none}
  .brand-txt{display:flex;flex-direction:column;line-height:1.15}
  .brand-txt b{font-size:16px;font-weight:700;letter-spacing:.5px}
  .brand-txt span{font-size:12px;letter-spacing:1.5px;opacity:.72;margin-top:1px}
  .brand-sub{margin-left:auto;font-size:13px;opacity:.9;text-align:right;font-weight:500;line-height:1.4}
  .brand-sub b{color:var(--amber-400);font-weight:700}
  /* 登录级别牌（三级权限：一级定底线 / 二级定报价 / 三级只拿去卖）——颜色区分职责 */
  .role-chip{margin-left:16px;flex:none;font-size:12px;font-weight:700;letter-spacing:.3px;
    padding:4px 16px;border-radius:999px;white-space:nowrap;border:1px solid transparent}
  .role-chip.rol-L1{background:rgba(201,146,45,.18);color:var(--amber-400);border-color:rgba(201,146,45,.55)}
  .role-chip.rol-L2{background:rgba(90,150,220,.16);color:var(--color-info-light);border-color:rgba(90,150,220,.5)}
  .role-chip.rol-L3{background:rgba(255,255,255,.1);color:rgba(255,255,255,.88);border-color:rgba(255,255,255,.3)}
  .card{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);
    padding:24px 24px;margin-bottom:16px;box-shadow:0 1px 3px rgba(11,31,58,.05)}
  .card h2{font-size:14px;font-weight:600;margin-bottom:16px;color:var(--navy);
    display:flex;align-items:center;gap:8px}
  .card h2::before{content:"";width:4px;height:14px;background:var(--amber);border-radius:6px}

  /* 一级导航：价格录入 | 价格看板 */
  .mainnav{display:flex;gap:8px;margin-bottom:16px}
  .mn-btn{appearance:none;border:1px solid var(--line);background:var(--color-surface);color:var(--navy);
    font-family:var(--font);font-size:16px;font-weight:700;letter-spacing:1px;
    padding:8px 32px;border-radius:999px;cursor:pointer;transition:.15s;
    box-shadow:0 1px 2px rgba(11,31,58,.04)}
  .mn-btn:hover{border-color:var(--amber);color:var(--amber-600)}
  .mn-btn.active{background:var(--navy);border-color:var(--navy);color:var(--color-on-brand);
    box-shadow:0 3px 10px rgba(11,31,58,.22)}
  .mn-btn.active:hover{color:var(--color-on-brand)}

  /* 类型选择 */
  .type-pick{display:flex;gap:16px;flex-wrap:wrap;margin-bottom:16px}
  .type-btn{flex:1;min-width:240px;border:1px solid var(--line);background:var(--color-surface);border-radius:var(--radius);
    padding:16px 24px;cursor:pointer;display:flex;align-items:center;gap:16px;transition:.15s;box-shadow:0 1px 2px rgba(11,31,58,.04)}
  .type-btn:hover{border-color:var(--amber);box-shadow:0 4px 14px rgba(11,31,58,.08)}
  .type-btn .ic{width:42px;height:42px;border-radius:6px;display:flex;align-items:center;justify-content:center;
    font-size:20px;font-weight:700;color:var(--color-on-brand)}
  .type-btn.trade .ic{background:var(--navy)}
  /* 白字压 #C9922D 只有 2.75:1（任何字号都不够）→ 琥珀底上改用 navy 字，6.07:1 */
  .type-btn.rent .ic{background:var(--amber);color:var(--color-brand)}
  .type-btn .tt{font-size:16px;font-weight:600}
  .type-btn .td{font-size:12px;color:var(--muted)}
  .type-btn.active{border-color:var(--navy);box-shadow:0 0 0 2px rgba(11,31,58,.12)}
  .type-btn.rent.active{border-color:var(--amber);box-shadow:0 0 0 2px var(--ring-amber)}
  .type-btn.arb .ic{background:var(--ok)}
  .type-btn.arb.active{border-color:var(--ok);box-shadow:0 0 0 2px rgba(31,138,76,.15)}
  .type-btn.batch .ic{background:var(--blue)}
  .type-btn.batch.active{border-color:var(--blue);box-shadow:0 0 0 2px rgba(29,95,176,.15)}
  .arb-pos{color:var(--ok);font-weight:700}
  .arb-neg{color:var(--bad);font-weight:700}
  .arb-zero{color:var(--muted)}

  .filters{display:flex;gap:16px;flex-wrap:wrap;align-items:flex-end}
  .fld{display:flex;flex-direction:column;gap:4px}
  .fld label{font-size:12px;color:var(--muted);font-weight:500}
  .fld input,.fld select{height:36px;border:1px solid var(--border);border-radius:6px;
    padding:0 8px;font-size:13px;color:var(--navy);background:var(--color-surface);outline:none;transition:.15s;min-width:120px}
  .fld input:focus,.fld select:focus{border-color:var(--amber);box-shadow:0 0 0 2px var(--ring-amber)}
  .btn-ghost{border:1px solid var(--border);background:var(--color-surface);color:var(--navy);border-radius:6px;
    height:36px;padding:0 16px;font-size:13px;cursor:pointer}
  .btn-ghost:hover{border-color:var(--amber)}
  .btn-primary{background:var(--navy);color:var(--color-on-brand);border:none;border-radius:6px;height:36px;
    padding:0 16px;font-size:13px;cursor:pointer;font-weight:600}
  .btn-primary:hover{opacity:.9}
  button:disabled{opacity:.5;cursor:not-allowed}

  /* ===== v54 市场行情筛选：地点下拉（可搜）+ 报价日期时间段 ===== */
  /* 地点下拉：输入框 + 浮层列表。点选=精确、打字=包含匹配（口径见 app.js 顶部注释） */
  .cbx{position:relative;display:flex;align-items:center}
  .cbx input{padding-right:32px}
  .cbx-x{display:none;position:absolute;right:5px;width:20px;height:20px;border:none;
    background:transparent;color:var(--muted);font-size:12px;line-height:1;padding:0;
    border-radius:50%;cursor:pointer}
  .cbx-x:hover{background:var(--paper-3);color:var(--navy)}
  .cbx.has-val .cbx-x{display:block}
  .cbx-list{display:none;position:absolute;top:calc(100% + 5px);left:0;z-index:60;
    min-width:100%;max-height:264px;overflow-y:auto;background:var(--color-surface);
    border:1px solid var(--border);border-radius:6px;padding:4px;
    box-shadow:0 10px 26px rgba(11,31,58,.14)}
  .cbx.open .cbx-list{display:block}
  .cbx-opt{display:flex;align-items:center;justify-content:space-between;gap:16px;
    padding:8px 8px;font-size:13px;color:var(--navy);border-radius:6px;
    cursor:pointer;white-space:nowrap}
  .cbx-opt:hover{background:var(--color-bg)}
  .cbx-opt.on{background:var(--navy);color:var(--color-on-brand)}
  .cbx-opt .n{font-size:12px;color:var(--muted)}
  .cbx-opt.on .n{color:var(--color-info-line)}
  .cbx-empty{padding:8px 8px;font-size:13px;color:var(--muted)}

  /* 时间段：独占一行（flex-basis:100% 强制换行，省得再动 f_trade/f_rent 的显隐切换） */
  .f-time{flex-basis:100%}
  .time-row{display:flex;flex-wrap:wrap;gap:8px;align-items:center}
  .chip{height:36px;padding:0 16px;border:1px solid var(--border);background:var(--color-surface);
    color:var(--navy);border-radius:6px;font-size:13px;cursor:pointer;transition:.15s}
  .chip:hover{border-color:var(--amber)}
  .chip.on{background:var(--navy);color:var(--color-on-brand);border-color:var(--navy);font-weight:600}
  .time-row input[type=date]{height:36px;width:152px;min-width:0;padding:0 8px;
    border:1px solid var(--border);border-radius:6px;background:var(--color-surface);
    font-size:13px;color:var(--navy);outline:none;transition:.15s}
  .time-row input[type=date]:focus{border-color:var(--amber);box-shadow:0 0 0 2px var(--ring-amber)}
  .time-or{font-size:13px;color:var(--muted)}
  .time-hint{font-size:13px;color:var(--amber);font-weight:500}
  .count{margin-left:auto;color:var(--muted);font-size:13px;align-self:center}
  .count b{color:var(--color-warning-text)}

  /* 录入模块 */
  .entry-card{padding:16px 16px}
  .sub-h{font-size:13px;font-weight:600;color:var(--muted);margin-bottom:8px}
  .entry{display:flex;gap:16px;flex-wrap:wrap;align-items:flex-end}
  .batch-inline{margin-bottom:8px}
  .batch-head{display:flex;align-items:baseline;gap:8px;margin-bottom:8px}
  .batch-title{font-size:13px;font-weight:600;color:var(--navy)}
  .batch-hint{font-size:12px;color:var(--muted)}

  table{width:100%;border-collapse:collapse;font-size:13px;margin-top:16px}
  /* v59 表头吸顶（Donny 2026-09-17）：「这个页面滑动起来的时候，上面那个头头它也一起划上去了，
     导致看这些实际数据的时候不知道这些表头是什么」→ 页面滚动时把列名钉在视口顶部。
     ⚠️ 这里只需要 position/top/z-index 三个词，**底色与分隔线本来就是现成的**（见下面那行
        `background:var(--cream)` + `border-bottom:2px solid var(--line)`）——
        如果哪天把它俩删了，吸顶的表头就会**透出滚过去的行**，必须补回来。
     ⚠️ `z-index:3` 用来压住表里滚动的内容。**`.mtx` 那张是例外**：它的角格自己带 `pl`，
        `table.mtx th.pl{z-index:2}` 特异性更高 → 角格 computed 仍是 2，跟吸左的行头同值。
        现在不穿帮（`.mtx-wrap` 只横滚不竖滚，两者不会重叠）；**但若哪天给 `.mtx-wrap` 加上
        max-height 竖滚，必须同时把角格提到 4**，否则行头会盖住「地点」这个表头格。
     ⚠️ sticky 生效的前提是**祖先链上没有 overflow**。v59.1 逐张实测全站 36 张 thead：
        31 张干净（滚到视口上方 300px 后 top=0，真吸住）、5 张被 overflow 祖先框住、只在自己框里吸 ——
        `.modal-body{overflow:auto}`（3 张弹窗表，**只该在弹窗内吸，这是对的**）
        + `.mtx-wrap`（2 张总览矩阵，最长 21 行 905px —— v59.2 已给它定 `max-height`，改成
        **框内竖滚、表头吸框顶**，见下面 `.mtx-wrap` 那条）。
        ⚠️ 记牢机制：`overflow-x:auto` 会把 `overflow-y` 的计算值也变成 auto → 横滚容器里的表
        写 `top:0` **吸不动**（不是写错，是机制如此），除非去掉横滚或给框定高变成框内竖滚。 */
  thead th{text-align:left;color:var(--navy-700);font-weight:600;font-size:12px;
    padding:8px 16px;border-bottom:2px solid var(--line);background:var(--cream);white-space:nowrap;
    position:sticky;top:0;z-index:3}
  tbody td{padding:12px 16px;border-bottom:1px solid var(--line);vertical-align:middle}
  tbody tr:hover{background:var(--paper-2)}
  .tag{display:inline-block;padding:2px 8px;border-radius:6px;font-size:12px;font-weight:600}
  .t-trade{background:var(--color-info-bg);color:var(--navy)}
  .t-rent{background:var(--color-warning-bg);color:var(--amber-600)}
  .route-line{font-weight:600}
  .route-line .arr{color:var(--amber);margin:0 4px}
  .amt{font-weight:700;font-variant-numeric:tabular-nums}
  .cur{color:var(--muted);font-size:12px;margin-left:2px}
  .muted{color:var(--muted)}
  .cell-sub{font-size:12px;color:var(--muted);margin-top:4px;line-height:1.35;font-weight:400}
  .del{border:1px solid var(--border);background:var(--color-surface);color:var(--bad);border-radius:6px;
    height:30px;padding:0 16px;font-size:12px;cursor:pointer}
  .del:hover{background:var(--color-danger-bg);border-color:var(--bad)}
  .empty{text-align:center;color:var(--muted);padding:32px 0}
  .hint{color:var(--muted);font-size:12px;margin-top:8px}
  .hint code{background:var(--color-info-bg);padding:2px 8px;border-radius:6px;font-size:12px;color:var(--navy);
    font-family:ui-monospace,Menlo,Consolas,monospace;margin:0 2px}
  textarea{width:100%;border:1px solid var(--border);border-radius:6px;padding:16px;font-size:13px;
    font-family:ui-monospace,Menlo,Consolas,monospace;color:var(--navy);resize:vertical;outline:none;line-height:1.6}
  textarea:focus{border-color:var(--amber);box-shadow:0 0 0 2px var(--ring-amber)}
  .batch-stat{font-size:13px;align-self:center;margin-left:auto;color:var(--muted)}
  .batch-stat b{color:var(--ok)}
  .batch-stat .bad{color:var(--bad)}
  .ed-table{width:100%;border-collapse:collapse;font-size:13px;margin-top:8px}
  .ed-table th{text-align:left;color:var(--muted);font-weight:600;font-size:12px;padding:8px 8px;
    border-bottom:2px solid var(--line);white-space:nowrap}
  .ed-table td{padding:8px 8px;border-bottom:1px solid var(--line);vertical-align:middle}
  .ed-table input,.ed-table select{height:32px;border:1px solid var(--border);border-radius:6px;
    padding:0 8px;font-size:12px;color:var(--navy);background:var(--color-surface);outline:none;width:100%;min-width:70px}
  .ed-table input:focus,.ed-table select:focus{border-color:var(--amber);box-shadow:0 0 0 2px var(--ring-amber-soft)}
  /* 校验未通过就地标红（v15）：地点不在城市清单 / 箱型箱况没选。红框 + 极淡红底，不改布局不跳动 */
  .ed-table input[data-miss],.ed-table select[data-miss]{border-color:var(--bad);background:var(--tint-danger)}
  .ed-table input[data-miss]:focus,.ed-table select[data-miss]:focus{
    border-color:var(--bad);box-shadow:0 0 0 2px var(--ring-bad)}
  .ed-table .col-m{width:90px}
  .ed-table .col-sm{width:78px}
  /* 箱型/箱况是下拉（v15）：字比手输短，但「CW马士基」得放得下 → 给个最小宽度别被挤断 */
  .ed-table select.col-sm{width:auto;min-width:94px}
  .ed-table .rowidx{color:var(--muted);font-variant-numeric:tabular-nums}
  .ed-del{border:1px solid var(--border);background:var(--color-surface);color:var(--bad);border-radius:6px;height:30px;
    padding:0 8px;font-size:12px;cursor:pointer}
  .ed-del:hover{background:var(--color-danger-bg);border-color:var(--bad)}
  .bad-box{background:var(--tint-danger);border:1px solid var(--color-danger-line);border-radius:6px;padding:16px 16px;margin-top:16px}
  .bad-box h3{font-size:13px;color:var(--bad);margin-bottom:8px}
  .bad-box pre{white-space:pre-wrap;font-size:12px;color:var(--color-danger-deep);font-family:ui-monospace,Menlo,Consolas,monospace;
    background:var(--color-danger-bg);padding:8px 8px;border-radius:6px;margin-bottom:8px}
  #net_err{background:var(--color-danger-bg);border:1px solid var(--color-danger-line);color:var(--color-danger-deep);border-radius:var(--radius-sm);
    padding:8px 16px;margin-bottom:16px;font-size:13px}
  #net_err a{color:var(--bad)}
  /* ===== v9 免登录模式提示条（只在开关打开时由模板渲染出来）===== */
  #skip_banner{background:var(--tint-warn-soft);border:1px solid var(--color-warning-line);border-left:3px solid var(--amber);
    color:var(--gold-700);border-radius:var(--radius-sm);padding:8px 16px;margin-bottom:16px;font-size:13px;line-height:1.6}
  #skip_banner b{color:var(--color-warning-deep)}
  /* ===== v10 询价待办（缺哪些价格该去问）===== */
  .todo-actions{display:flex;gap:8px;align-items:center;flex:none}
  .todo-sec{margin-top:16px}
  .todo-sec h3{margin:0;font-size:14px;color:var(--navy);display:flex;align-items:center;gap:8px}
  .todo-n{background:var(--color-danger-bg);color:var(--bad);border:1px solid var(--color-danger-line);border-radius:999px;
    padding:2px 8px;font-size:12px;font-weight:700}
  .todo-ok{color:var(--color-success-text);font-size:12px;font-weight:600}
  .todo-tb{width:100%;border-collapse:collapse;font-size:13px}
  .todo-tb th{text-align:left;color:var(--muted);font-weight:600;font-size:12px;
    padding:8px 8px;border-bottom:1px solid var(--line)}
  .todo-tb td{padding:8px 8px;border-bottom:1px solid var(--line);vertical-align:middle}
  .todo-tb tr:last-child td{border-bottom:0}
  .todo-ref{color:var(--navy);font-weight:600}
  .todo-ref-none{color:var(--muted)}
  .todo-warn-price{color:var(--color-warning-text);font-weight:700}
  /* ── v53：待办页「分类 + 折叠」（Donny 2026-09-17：「分类排列显示可以折叠」「默认全收起」）──
     折叠头沿用「待配买租差」那套视觉语言（箭头转 90°、同一个按钮来回切 = 交互对称）。
     两层：`.todo-cat` = 大类（箱价 / 租箱价）；`.todo-fold` = 组（地点 / 目的地）。 */
  .todo-tools{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin:2px 0 8px}
  .todo-cat{margin-top:16px}
  .todo-cat h4{margin:0 0 2px;font-size:13px;font-weight:700;color:var(--navy);
    display:flex;align-items:center;gap:8px;border-bottom:1px solid var(--line);padding-bottom:8px}
  .todo-fold{margin-left:2px}
  .todo-fold-hd{display:block;width:100%;background:none;border:0;padding:8px 4px;text-align:left;
    font-family:inherit;font-size:13px;color:var(--navy);cursor:pointer;line-height:1.6;
    display:flex;align-items:center;gap:8px;border-bottom:1px solid var(--line)}
  .todo-fold-hd:hover{color:var(--amber-600);background:var(--paper-1)}
  .todo-fold-hd .todo-fold-tt{display:flex;align-items:center;gap:8px;flex-wrap:wrap;min-width:0}
  .todo-fold-arw{display:inline-block;width:12px;flex:none;color:var(--muted);transition:transform .15s}
  .todo-fold-hd[aria-expanded="true"] .todo-fold-arw{transform:rotate(90deg)}
  .todo-fold-bd{padding:2px 0 8px 16px}
  /* 折叠头里的小字与徽标都是 flex 项，去掉 .cell-sub 的 margin-top（否则整行会被顶歪） */
  .todo-fold-hd .cell-sub,.todo-cat h4 .cell-sub{margin-top:0}
  /* 时效标记（行情表内）：临期黄 / 过期红 / 正常灰 */
  .age{font-size:12px;white-space:nowrap}
  .age-ok{color:var(--muted)}
  .age-warn{color:var(--color-warning-text);font-weight:700}
  .age-old{color:var(--bad);font-weight:700}
  .ref-line{font-size:12px;color:var(--muted);line-height:1.5}
  .ref-line b{color:var(--color-warning-text)}
  /* 整批共用信息区（批量录入时只填一次，应用到整批） */
  .shared-box{border:1px solid var(--line);border-left:3px solid var(--amber);border-radius:var(--radius);padding:16px 16px;margin-top:16px;background:var(--card)}
  .shared-title{font-size:12px;font-weight:600;color:var(--navy);margin-bottom:8px;letter-spacing:.3px}
  /* 三合一上传区：点击 / 拖拽 / Ctrl+V 粘贴 */
  .up-zone{border:1px dashed var(--line);border-radius:var(--radius-sm);padding:8px;background:var(--paper-1);
    transition:.15s;cursor:pointer;min-width:150px}
  .up-zone:hover{border-color:var(--amber)}
  .up-zone.drag{border-color:var(--navy);background:var(--color-info-bg);box-shadow:0 0 0 2px rgba(11,31,58,.10)}
  .up-zone .up-tip{font-size:12px;color:var(--muted);text-align:center;padding:8px 4px;user-select:none;line-height:1.5}
  .up-zone .up-chip{display:flex;align-items:center;gap:8px;background:var(--color-surface);border:1px solid var(--border);
    border-radius:6px;padding:4px 8px;font-size:12px;margin-top:8px}
  .up-zone .up-chip .nm{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--navy)}
  /* 删除 × 悬浮在缩略图/文件图标右上角（红点徽章，先进交互：图上直接删） */
  .up-zone .up-chip .thumb-wrap{position:relative;flex:none;display:inline-flex}
  .up-zone .up-chip .thumb-x{position:absolute;top:-6px;right:-6px;width:16px;height:16px;border:none;
    border-radius:50%;background:var(--bad);color:var(--color-on-brand);font-size:12px;line-height:1;cursor:pointer;
    box-shadow:0 0 0 2px var(--color-surface);z-index:3;display:flex;align-items:center;justify-content:center;padding:0}
  .up-zone .up-chip .thumb-x:hover{filter:brightness(.85)}
  .up-zone input[type=file]{display:none}
  /* 粘贴落点：透明文本域盖住整个上传区——右键菜单只有对可编辑元素才显示「粘贴」 */
  .up-zone{position:relative}
  .up-zone .paste-catcher{position:absolute;inset:0;width:100%;height:100%;opacity:0;border:0;resize:none;
    background:transparent;outline:none;cursor:pointer;overflow:hidden;z-index:1;font-size:12px;color:transparent}
  .up-zone .up-chip{position:relative;z-index:2}
  .up-zone .up-chip .sz{color:var(--muted);font-size:12px;margin-left:4px;font-weight:400}
  .up-zone .up-chip .rw{border:1px solid var(--border);background:var(--color-surface);color:var(--navy);border-radius:6px;height:22px;
    padding:0 8px;font-size:12px;cursor:pointer;flex:none}
  .up-zone .up-chip .rw:hover{border-color:var(--amber);color:var(--amber-600)}
  /* chip 缩略图 / 文件图标 / 上传中 / 失败态（规范 3.1 即时缩略图 + 3.9 失败重试） */
  .up-zone .up-chip .up-thumb{width:40px;height:40px;object-fit:cover;border-radius:6px;border:1px solid var(--border);
    background:var(--color-surface);cursor:zoom-in;flex:none;transition:.15s}
  .up-zone .up-chip .up-thumb:hover{border-color:var(--amber);box-shadow:0 0 0 2px rgba(201,146,45,.18)}
  .up-zone .up-chip .up-ficon{width:40px;height:40px;flex:none;display:flex;align-items:center;justify-content:center;
    border-radius:6px;border:1px solid var(--border);background:var(--color-surface);color:var(--muted)}
  .up-zone .up-chip .up-ficon.bad{color:var(--bad);border-color:var(--color-danger-line)}
  .up-zone .up-chip.fail{border-color:var(--bad);background:var(--color-danger-bg)}
  .up-zone .up-chip .spin{width:14px;height:14px;flex:none;border:2px solid var(--line);border-top-color:var(--amber);
    border-radius:50%;animation:spin .8s linear infinite}
  @keyframes spin{to{transform:rotate(360deg)}}

  /* ===== 定价策略页 ===== */
  .st-formula{font-size:13px;color:var(--muted);background:var(--paper-warm);border:1px solid var(--color-border-soft);
    border-radius:6px;padding:8px 16px;margin:16px 0 4px;line-height:1.6}
  /* 公式与策略说明（口径显性列出，方便对照调整） */
  .st-spec{background:var(--paper-warm);border:1px solid var(--color-border-soft);border-radius:6px;padding:8px 16px;margin:16px 0 4px}
  .spec-row{display:flex;gap:8px;align-items:baseline;padding:4px 0}
  .spec-row+.spec-row{border-top:1px dashed var(--color-border-soft)}
  .spec-k{flex:none;width:64px;font-size:12px;font-weight:700;color:var(--gold-700)}
  .spec-v{font-size:13px;color:var(--text);line-height:1.55}
  .spec-v b{color:var(--gold-700)}
  .st-th{width:96px;height:32px;border:1px solid var(--border);border-radius:6px;padding:0 8px;
    font-size:13px;text-align:right}
  .st-th:focus{outline:none;border-color:var(--amber)}
  .rt-cell{white-space:nowrap}          /* 起讫地不折行：中文最小宽度会被压成一字一行 */
  .nb{white-space:nowrap}               /* 金额/日期整体换行，不从中间拆开 */
  .prov{display:inline-block;max-width:170px;overflow:hidden;text-overflow:ellipsis;
    white-space:nowrap;vertical-align:bottom}   /* 列表「报价公司」：偏长就省略，title 悬停看全文 */
  .st-ok,.st-no,.st-risk,.st-none,.st-flat{display:inline-block;font-size:12px;font-weight:700;border-radius:999px;padding:4px 16px;white-space:nowrap}
  .st-ok{background:var(--color-success-bg);color:var(--color-success-text)}
  .st-risk{background:var(--color-warning-bg);color:var(--color-warning-text)}
  .st-none{background:var(--color-info-bg);color:var(--navy)}   /* 未设买租差：中性提示色，不是错也不是好 */
  .st-flat{background:var(--paper-3);color:var(--color-text-dim)}       /* 缺市场租价：灰色待补录 */
  /* v106：st-no 红改灰 ——「做不了 / 触底超卖价」是**结论**不是错误（数据不够/没空间），
     灰色=平静的负面；红色只留给真危险操作（删除等）。与 st-flat 同族。 */
  .st-no{background:var(--paper-3);color:var(--color-text-dim)}
  /* 报价档位（可报租价在市场低/均/高里的位置），跟着结论芯片一起出现在单元格里 */
  .tier-best,.tier-good,.tier-warn,.tier-any{font-size:12px;font-weight:700;white-space:nowrap}
  .tier-best{color:var(--color-success-text)}
  .tier-good{color:var(--color-success-text)}
  .tier-warn{color:var(--color-warning-text)}
  .tier-any{color:var(--bad)}
  /* 线路没优势：该目的地组合下 5 个以上起点都做不了 */
  .tag-noedge{display:inline-block;font-size:12px;font-weight:700;color:var(--bad);
              border:1px solid var(--bad);border-radius:6px;padding:1px 8px;margin-right:4px}
  /* v95：报价「已取整」小标 —— 报价被吸附到 30/50/80 尾数时才打（没取整的行不打，免得满屏标签）。
     刻意做得**轻**（灰字细边 11px）：它只回答「为什么报价跟买租差算出来的差一点点」，
     是解释、不是警告，**不许**跟「线路没优势」那种红标抢注意力。 */
  .tag-snap{display:inline-block;font-size:11px;font-weight:600;color:var(--muted);
            border:1px solid var(--line);border-radius:5px;padding:0 5px;margin-left:4px;
            vertical-align:1px;cursor:help}
  .net-over{color:var(--bad)}
  /* v106 视觉降噪（Donny「视觉从新设计 不要过劳」）：琥珀文字链按钮 → 白底灰边幽灵按钮。
     为什么：一行里「货源 ▾」「特价」「换回均价」全是琥珀实心字 = 每行两三处都在喊。
     幽灵化后：平时灰字灰边不抢眼，hover 才亮琥珀；开启态（sp-on）仍琥珀描边。
     ⚠️ 全站同一类（行情表货源▾/详情、子行货源▾/特价/回政策值/换回均价）一起变，保持一致。 */
  .st-drill-btn{display:inline-flex;align-items:center;gap:3px;border:1px solid var(--border);
    background:var(--color-surface);color:var(--color-text-soft);font-size:12px;font-weight:600;
    cursor:pointer;padding:1px 9px;border-radius:999px;white-space:nowrap;vertical-align:middle;line-height:1.5}
  .st-drill-btn:hover{border-color:var(--amber);color:var(--gold-700);background:var(--tint-warn-faint);text-decoration:none}
  .st-drill td{background:var(--paper-1);padding:8px 16px}
  /* v106 同行租价折叠带（rt-drill）：与货源折叠带（st-drill）同款视觉，独立类名避免撞车 */
  .rt-drill>td{background:var(--paper-1);padding:8px 16px}
  /* v95：参数页「进阶 ▾」—— 一年改不了一次的参数收进这里，首页只留他天天动的。
     做成**一行低调的按钮**（不是卡片、不占高度）：它本身也不该抢注意力。 */
  /* v95：排序块折叠头的样式（与「进阶 ▾」同一套低调做法） */
  .pn-ord-hd{border:none;background:none;font:inherit;font-size:12px;font-weight:700;
    color:var(--navy);cursor:pointer;padding:2px 0;display:inline-flex;align-items:center;gap:6px}
  .pn-ord-hd:hover{text-decoration:underline}
  .pn-ord-arw{font-size:11px;color:var(--muted)}
  .pn-ord-fold{margin-bottom:6px}
  .pn-ord-bd{margin-top:4px}
  .pn-adv-btn{border:none;background:none;font:inherit;font-size:12px;font-weight:700;
    color:var(--navy);cursor:pointer;padding:2px 0}
  .pn-adv-btn:hover{text-decoration:underline}
  .pn-adv-bd{margin-top:6px;padding-left:10px;border-left:2px solid var(--line)}
  /* ══ v95 货源详情卡（Donny 2026-09-23）—— 「按需填」的那张卡 ══════════════
     刻意做得**平**（不用卡片阴影、不边框套边框）：它挂在下钻表里，本来就三层深了，
     再堆视觉层级就是信息过载。分隔只靠浅底 + 一条虚线。 */
  .drill-tbl .cf-cell{white-space:nowrap}
  .cf-cell .st-drill-btn{padding-left:8px}
  .cf-sum{font-weight:600;color:var(--navy)}
  tr.card-row>td{background:var(--paper-2);padding:6px 14px 10px}
  .card-fm{border-top:1px dashed var(--line);padding-top:8px}
  .cf-hd{margin-bottom:6px;font-size:13px}
  .cf-row{display:flex;flex-wrap:wrap;gap:8px 14px;margin-bottom:6px}
  .cf-f{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--muted)}
  .cf-f>span{white-space:nowrap}
  .cf-f input.st-th{width:150px}
  .cf-wide{flex:1 1 100%}
  .cf-wide textarea.st-th{width:100%;height:auto;padding:4px 6px;line-height:1.4;resize:vertical}
  .cf-phrow{display:flex;align-items:center;flex-wrap:wrap;gap:8px;margin:4px 0 6px}
  .cf-lb{font-size:12px;color:var(--muted);white-space:nowrap}
  .cf-phlist{display:flex;flex-wrap:wrap;gap:6px}
  .cf-ph{position:relative;display:inline-block;line-height:0}
  .cf-ph img{width:64px;height:48px;object-fit:cover;border:1px solid var(--line);border-radius:4px}
  .cf-ph-x{position:absolute;top:-6px;right:-6px;width:16px;height:16px;line-height:1;
    border:none;border-radius:50%;background:var(--bad);color:#fff;font-size:12px;
    cursor:pointer;padding:0}
  .cf-up{cursor:pointer}
  .cf-more{margin:2px 0 6px}
  .cf-more-bd{margin-top:6px;padding-left:8px;border-left:2px solid var(--line)}
  .cf-act{display:flex;align-items:center;gap:10px;margin-top:4px}
  .cf-act .btn-primary{height:28px;padding:0 14px;font-size:12px}
  .cf-tip{font-size:11px}
  .st-drill-body{font-size:13px}
  .drill-tbl{border-collapse:collapse;width:100%;max-width:720px}
  .drill-tbl th{font-size:12px;color:var(--muted);text-align:left;padding:4px 16px 4px 0;font-weight:500}
  .drill-tbl td{padding:4px 16px 4px 0;border-top:1px dashed var(--line);font-size:13px}
  .drill-tbl tr.in-avg td{background:var(--color-warning-bg)}
  .drill-note{margin-top:8px;font-size:12px}
  /* ── v60 行内「说明 ▾」（Donny 2026-09-17 拍板 C+A）────────────────────────
     把每格里那些「怎么算出来的」小字收成一条证据带，点开才出现。
     样式刻意**沿用货源下钻那一套**（`.st-drill-btn` 的字色 / `.st-drill td` 的米底），
     同一张表里两种展开长得一样 → 军规 #3 一致性。
     ⚠️ `.st-fold-btn` 故意**不叫** `.st-drill-btn`：回归里有 `:has-text('货源')` 这类
        按钮计数断言（verify_roles #242），换个类名才不会误伤。 */
  .fold-row{margin-top:4px}
  .st-fold-btn{border:none;background:none;color:var(--amber);font-size:12px;cursor:pointer;
    padding:0;font-weight:700}
  .st-fold-btn:hover{text-decoration:underline}
  .st-fold td{background:var(--paper-1);padding:8px 16px}
  .st-fold-body{font-size:13px}
  .fold-li{display:flex;gap:8px;align-items:baseline;padding:4px 0;
    border-top:1px dashed var(--line)}
  .fold-li:first-child{border-top:none}
  .fold-k{flex:0 0 92px;color:var(--muted);font-size:12px}
  .fold-v{flex:1;min-width:0}
  .fold-note{margin-top:8px;font-size:12px}
  /* ── v61 市场租价格内「各家 ▾」（Donny 2026-09-17「点小箭头展开那些市场上的租箱价」）──
     按钮沿用 `.st-drill-btn` / `.st-fold-btn` 的字色字号（军规 #3 一致性：同一张表里
     三种展开长得一样）；带子底色沿用 `.st-fold td` 的米色；表格沿用 `.drill-tbl` 的口径。
     ⚠️ 类名 `.mkt-btn` 故意不复用老类名 —— 回归里有按 `:has-text('货源')` 做的按钮计数断言。 */
  .mkt-btn{border:none;background:none;color:var(--amber);font-size:12px;cursor:pointer;
    padding:0 0 0 8px;font-weight:700}
  .mkt-btn:hover{text-decoration:underline}
  .mkt-list td{background:var(--paper-1);padding:8px 16px}
  .mkt-body{font-size:13px}
  .mkt-head{margin-bottom:8px}
  .mkt-link{border:none;background:none;color:var(--amber);font-size:12px;cursor:pointer;
    padding:0 4px;font-weight:700}
  .mkt-link:hover{text-decoration:underline}
  .fold-tbl{border-collapse:collapse;width:100%;max-width:760px}
  .fold-tbl th{font-size:12px;color:var(--muted);text-align:left;padding:4px 16px 4px 0;font-weight:500}
  .fold-tbl td{padding:4px 16px 4px 0;border-top:1px dashed var(--line);font-size:13px}
  .fold-tbl tr.mkt-min td{background:var(--color-warning-bg)}
  .fold-tbl td.mkt-p{font-weight:700;font-variant-numeric:tabular-nums}
  .fold-tbl td.mkt-d{font-variant-numeric:tabular-nums}
  /* ===== 定价策略·线路规则管理（v17：目的地×箱型×箱况 安全价 + 卖箱价取值 + 预估毛利）===== */
  .rule-custom{color:var(--amber);font-weight:700}
  .rule-none{color:var(--muted);font-weight:700}
  /* 行内改了数字但还没失焦落库 —— 明确告诉用户「还没保存」，别以为已经生效 */
  .unsaved-dot{color:var(--amber);font-weight:700;font-size:12px}
  /* 报价调节表：本来就挤。收紧「起点/目的地/箱型/箱况」四列的控件宽度，
     把省下来的宽度留给「可报租价」——它要放下「起点箱价 $2,365 − 买租差 $200」这行分解式。
     副标题一律不折行：折了就看不清这行分解式。 */
  /* 注意：上面 #sr_new_row input 有 min-width:90px，这里必须一起压，否则 width 被 min-width 顶回去 */
  #rules_card input.st-th,#rules_card select.st-th{width:78px;min-width:78px;padding:0 8px}
  #rules_card select.st-th{width:74px;min-width:74px}
  #sr_new_row td{padding:8px 8px}
  #sr_new_row button{padding:0 8px}
  #rules_card .cell-sub{white-space:nowrap}
  /* v8：规则表多了一列「预估堆存费」→ 数字框各收 6px，把宽度腾出来不换行；
     v32 又加了一列「净投入」（只读派生值，行宽见下面的 .sr-net-ro） */
  #rules_card input.st-th{width:72px;min-width:72px}
  /* ⚠️ v71：`.sr-net-ro` **已退休**（原本是 v32 那个「只读净投入」的浅底样式）。
     净投入现在和同行其它数字一样是**可编辑输入框**（Donny 2026-09-18：「这些要保留可以编辑的权利」）
     → 直接用同行的 `#rules_card input.st-th{width:72px}`，不再需要单独一套外观。
     删除时务必确认全项目已无 `class="sr-net-ro"` 的产出点（v71 已清）。 */
  /* 没设买租差的行：堆存费框不可改（规则行必须带买租差才存得下），灰掉提示先设买租差 */
  #rules_card input.st-th:disabled{background:var(--cream);color:var(--muted);cursor:not-allowed}
  #sr_new_row td{background:var(--paper-1);border-top:1px dashed var(--line);padding:8px 8px}
  #sr_new_row input,#sr_new_row select{height:32px;border:1px solid var(--border);border-radius:6px;padding:0 8px;font-size:13px}
  #sr_new_row input{width:100%;min-width:90px}
  #sr_new_row select{min-width:86px}
  #sr_new_row input:focus,#sr_new_row select:focus{outline:none;border-color:var(--amber)}
  #r_dest_hint{margin-top:4px;font-size:12px;font-weight:500}
  .sr-del{border:1px solid var(--color-danger-line);background:var(--color-surface);color:var(--bad);border-radius:6px;height:28px;padding:0 16px;
    font-size:12px;cursor:pointer;transition:.15s}
  .sr-del:hover{background:var(--color-danger-bg);border-color:var(--bad)}
  /* 暂停 / 恢复（v28，Donny 2026-09-12「操作那里除了删除，还可以做成暂停线路」）：
     同一个按钮来回切（能暂停必须能恢复）。暂停不是危险操作 → 中性描边；
     当前处于暂停态时按钮变成「恢复」并转 amber 强调，一眼看出这行该点哪个。 */
  .sr-hold{border:1px solid var(--border);background:var(--color-surface);color:var(--navy);border-radius:6px;height:28px;
    padding:0 16px;font-size:12px;cursor:pointer;transition:.15s}
  .sr-hold:hover{background:var(--tint-hover);border-color:var(--navy)}
  .sr-hold.on{border-color:var(--amber);background:var(--paper-warm);color:var(--gold-700)}
  .sr-hold.on:hover{background:var(--color-warning-bg);border-color:var(--amber)}
  .sr-hold:disabled{opacity:.55;cursor:not-allowed}
  /* 操作列按钮间距（v29 起并排三个：编辑 · 暂停/恢复 · 删除）。
     原来只写了 `.sr-hold + .sr-del`，多一个「编辑」两两就会粘在一起 → 改成对一组里所有相邻按钮生效 */
  .sr-ops button + button{margin-left:8px}
  /* 编辑（v29，Donny 2026-09-12「除了删除之外，可不可以编辑跟修改呢？」）：
     与「暂停」同一族的中性描边按钮（都是「改」不是「毁」），危险语义只留给「删除」 */
  .sr-edit{border:1px solid var(--border);background:var(--color-surface);color:var(--navy);border-radius:6px;height:28px;
    padding:0 16px;font-size:12px;cursor:pointer;transition:.15s}
  .sr-edit:hover{background:var(--tint-hover);border-color:var(--navy)}
  /* 编辑态那一行：底色铺一层淡 amber，一眼看出「这行正在改」；
     目的地输入框要放得下城市名（通用 .st-th 在规则表里只有 72px） */
  tr[data-editing="1"] td{background:var(--tint-edit)}
  tr[data-editing="1"] input#er_dest{width:112px;min-width:112px}
  /* 终点箱价列（v30，Donny 2026-09-12「把目的地的卖箱价也显示出来」）：
     主数是价格，小字标「档位 · 报价日期」——取值口径就写在页面公式区（采购方报价最新 > 实际成交均 > 市场报价均）。
     时效**只提醒、不改值**（政策页要长期可依）：超 7 天标黄、超 15 天或日期不详标红「已过期」，
     提醒该去催同事补价，而不是背地里拿老价算毛利。 */
  .sr-sell-sub.warn{color:var(--color-warning-text);font-weight:700}
  .sr-sell-sub.stale{color:var(--bad);font-weight:700}
  /* v95：终点价「越旧越淡」4 档 —— 用**颜色**替代黄标（Donny 2026-09-23）。
     只压颜色、不压字号：信息仍读得清，只是"不那么跳"。
     ⚠️ `stale`（已过期）那条线**照旧标红**，不在这一套里 —— 它说的是"这价不能用了"。
     ⚠️ 旧的 `.sr-sell-sub.warn`（黄标）**样式留着不动**：后端 `sell_warn` 仍在下发、
        回归脚本还在断它，只是前端**不再往元素上挂** `warn` 这个 class 了。 */
  .sr-age-0{color:var(--navy)}
  .sr-age-1{color:var(--ink-500)}
  .sr-age-2{color:var(--slate-500)}
  .sr-age-3{color:var(--slate-400)}
  /* 「待配买租差」折叠区（v29）：有行情、但还没配规则的目的地组合。默认收起（眼不见为净），
     能展开必须能收起 —— 同一个按钮来回切，箭头跟着转（交互对称铁律） */
  .sr-fold{margin-top:16px;border-top:1px dashed var(--line);padding-top:8px}
  .sr-fold-hd{display:block;width:100%;background:none;border:0;padding:8px 2px;text-align:left;
    font-family:inherit;font-size:13px;font-weight:600;color:var(--navy);cursor:pointer;line-height:1.6}
  .sr-fold-hd:hover{color:var(--amber-600)}
  .sr-fold-hd .muted{font-weight:400}
  .sr-fold-arw{display:inline-block;width:12px;margin-right:2px;color:var(--muted);transition:transform .15s}
  .sr-fold-hd[aria-expanded="true"] .sr-fold-arw{transform:rotate(90deg)}
  #sr_todo_body{margin-top:8px}
  /* 暂停行：整行压下视觉重量（数值仍照旧显示、仍可改），但操作列保持满对比 ——
     按钮还得看得见、点得到，否则「恢复」就成了死路 */
  tr.row-held td{background:var(--tint-hover)}
  tr.row-held input.st-th{opacity:.6}
  tr.row-held td:last-child{background:transparent}

  /* ===== 多图照片墙（买卖箱照片：实图/参考图）=====
     网格缩略图 + 悬浮×移除 + 「＋」续传；支持拖拽/粘贴；缩略图点开放大（与单图 viewer 一致） */
  .upm-zone{border:1px dashed var(--line);border-radius:var(--radius-sm);padding:8px;background:var(--paper-1);
    position:relative;min-width:200px}
  .upm-zone:hover{border-color:var(--amber)}
  .upm-zone.drag{border-color:var(--navy);background:var(--color-info-bg);box-shadow:0 0 0 2px rgba(11,31,58,.10)}
  .upm-zone input[type=file]{display:none}
  .upm-zone .paste-catcher{position:absolute;inset:0;width:100%;height:100%;opacity:0;border:0;resize:none;z-index:1}
  .upm-grid{display:flex;flex-wrap:wrap;gap:8px;align-items:center;position:relative;z-index:2}
  .upm-cell{display:flex;align-items:center}
  .upm-cell .thumb-wrap{position:relative;display:inline-flex}
  .upm-cell .thumb-x{position:absolute;top:-6px;right:-6px;width:16px;height:16px;border:none;border-radius:50%;
    background:var(--bad);color:var(--color-on-brand);font-size:12px;line-height:16px;cursor:pointer;padding:0;text-align:center}
  .upm-cell .thumb-x:hover{filter:brightness(.85)}
  .upm-thumb{width:56px;height:56px;object-fit:cover;border-radius:6px;border:1px solid var(--border);
    cursor:zoom-in;background:var(--color-surface);transition:.15s}
  .upm-thumb:hover{border-color:var(--amber);box-shadow:0 0 0 2px rgba(201,146,45,.18)}
  .upm-cell .spin{width:14px;height:14px;flex:none;border:2px solid var(--line);border-top-color:var(--amber);
    border-radius:50%;animation:spin .8s linear infinite}
  .upm-cell .upm-uping{font-size:12px;color:var(--muted);margin-left:8px}
  .upm-add{width:56px;height:56px;flex:none;border:1px dashed var(--border);border-radius:6px;background:var(--color-surface);
    color:var(--muted);font-size:20px;line-height:1;cursor:pointer;transition:border-color .15s,color .15s}
  .upm-add:hover{border-color:var(--amber);color:var(--amber-600)}
  /* 列表行内附件缩略图（点击放大看原图） */
  .att-thumb{width:32px;height:32px;object-fit:cover;border-radius:6px;border:1px solid var(--border);
    cursor:zoom-in;vertical-align:middle;display:inline-block;background:var(--color-surface);transition:.15s}
  .att-thumb:hover{border-color:var(--amber);box-shadow:0 0 0 2px rgba(201,146,45,.18)}
  /* 图片大图查看器（Lightbox）：z-index 压过 modal(50)/bulkbar(60)/toast(64) */
  .viewer-mask{position:fixed;inset:0;z-index:1000;background:rgba(11,31,58,.85);display:flex;align-items:center;
    justify-content:center;cursor:grab;user-select:none}
  .viewer-mask.hidden{display:none}
  .viewer-mask.grabbing{cursor:grabbing}
  .viewer-mask img{max-width:86vw;max-height:86vh;border-radius:6px;box-shadow:0 24px 64px rgba(0,0,0,.45);
    transform-origin:center center;-webkit-user-drag:none;cursor:zoom-out}
  .viewer-mask.grabbing img{cursor:grabbing}
  .viewer-tip{position:fixed;bottom:22px;left:50%;transform:translateX(-50%);color:rgba(255,255,255,.78);
    font-size:12px;background:rgba(0,0,0,.35);padding:8px 16px;border-radius:999px;pointer-events:none;white-space:nowrap}
  .viewer-close{position:fixed;top:16px;right:16px;width:34px;height:34px;border:none;border-radius:50%;
    background:rgba(255,255,255,.14);color:var(--color-on-brand);font-size:16px;cursor:pointer;line-height:1}
  .viewer-close:hover{background:rgba(255,255,255,.28)}
  /* 列表详情展开行：报价人/来源/联系方式/凭证附件（need-to-know 分层，点「详情」才显示，再点收起） */
  .detail-row > td{background:var(--color-bg);border-top:1px dashed var(--line);padding:8px 16px}
  .detail-grid{display:flex;gap:32px;flex-wrap:wrap;align-items:center;font-size:12px}
  .d-block{display:flex;align-items:center;gap:16px;flex-wrap:wrap}
  .d-t{font-weight:700;color:var(--navy);letter-spacing:.3px;flex:none}
  .d-item{color:var(--color-text-soft)}
  .d-block .att-thumb{width:28px;height:28px}
  .lk.detail.on{color:var(--amber-600);border-color:var(--amber)}
  .hidden{display:none}
  /* 骨架屏：加载列表时的占位微光条 */
  .skel{height:12px;border-radius:6px;width:70%;background:linear-gradient(90deg,var(--paper-3) 25%,var(--paper-2) 50%,var(--paper-3) 75%);
    background-size:200% 100%;animation:skel 1.2s infinite}
  @keyframes skel{0%{background-position:200% 0}100%{background-position:-200% 0}}
  /* 列表头行（标题 + 回收站入口） */
  .list-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px}
  /* 全局 toast（撤销 / 草稿恢复提示） */
  #toast{position:fixed;left:50%;bottom:34px;transform:translateX(-50%);background:var(--navy);color:var(--color-on-brand);
    border-radius:6px;padding:8px 16px;font-size:13px;display:none;align-items:center;gap:16px;z-index:60;box-shadow:var(--shadow)}
  #toast .undo-btn{background:var(--amber);color:var(--navy);border:none;border-radius:6px;height:28px;
    padding:0 16px;font-weight:700;cursor:pointer;font-size:12px}
  #toast .undo-btn:hover{background:var(--amber-400)}
  #toast .cd{opacity:.75;font-size:12px;font-variant-numeric:tabular-nums;min-width:24px;text-align:right}
  /* 回收站弹窗 */
  .modal-mask{position:fixed;inset:0;background:rgba(7,18,36,.45);display:flex;align-items:center;justify-content:center;z-index:50}
  .modal-mask.hidden{display:none}
  .modal{background:var(--color-surface);border-radius:var(--radius-lg);width:min(880px,94vw);max-height:80vh;display:flex;flex-direction:column;box-shadow:var(--shadow)}
  .modal-head{display:flex;align-items:center;gap:16px;padding:16px 24px;border-bottom:1px solid var(--line)}
  .modal-head h3{font-size:16px;font-weight:700}
  .modal-head .sub{font-size:12px;color:var(--muted)}
  .modal-head .sub b{color:var(--amber-600)}
  .modal-close{margin-left:auto;border:none;background:var(--paper-3);width:30px;height:30px;border-radius:6px;cursor:pointer;font-size:14px;color:var(--navy)}
  .modal-close:hover{background:var(--paper-4)}
  .modal-body{padding:16px 24px;overflow:auto}
  .modal-foot{padding:16px 24px;border-top:1px solid var(--line);display:flex;gap:8px;align-items:center}
  .modal-foot .tip{font-size:12px;color:var(--muted)}
  .btn-danger{background:var(--color-surface);border:1px solid var(--bad);color:var(--bad);border-radius:6px;height:34px;padding:0 16px;font-size:13px;cursor:pointer}
  .btn-danger:hover{background:var(--color-danger-bg)}
  /* 表单分组标签（字段分类排序） */
  .grp-t{flex-basis:100%;font-size:12px;color:var(--muted);font-weight:600;letter-spacing:2px;
    margin:16px 0 4px;padding-bottom:4px;border-bottom:1px dashed var(--line)}
  .entry .grp-t:first-child{margin-top:0}
  /* 凭证双段行：两个上传区并排各占一半，独占一整行（渠道来源字段之下） */
  .fld-duo{display:flex;gap:16px;flex:1 1 100%;min-width:100%;align-items:flex-end}
  .fld-duo .fld{flex:1;min-width:0}
  /* ===== 录入流程步骤（v15：① AI 清洗助手 → ② 批量录入；序号即流程顺序）===== */
  .flow-step{margin-bottom:16px}
  .step-head{display:flex;align-items:center;gap:8px;width:100%;background:var(--color-bg);
    border:1px solid var(--line);border-radius:var(--radius-sm);padding:8px 16px;margin-bottom:8px;
    font-family:var(--font);font-size:13px;color:var(--navy);text-align:left;cursor:pointer;transition:.15s}
  .step-head:hover{border-color:var(--amber);background:var(--paper-warm)}
  /* 静态步骤头（第 2 步批量录入）不加框，只用一条底线分组——避免与可折叠的第 1 步抢视觉 */
  .step-head.static{background:transparent;border:none;border-bottom:1px solid var(--line);
    border-radius:0;padding:0 0 8px;margin-bottom:16px;cursor:default}
  .step-head.static:hover{background:transparent;border-color:var(--line)}
  .step-no{flex:none;width:20px;height:20px;border-radius:50%;background:var(--amber);color:var(--color-brand);
    font-size:12px;font-weight:700;display:flex;align-items:center;justify-content:center}
  .step-t{font-weight:600;flex:none}
  .step-d{flex:1;min-width:0;font-size:12px;font-weight:400;color:var(--muted);
    overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .step-car{flex:none;font-size:12px;color:var(--muted);transition:transform .2s}
  .step-head[aria-expanded="true"] .step-car{transform:rotate(180deg)}
  /* ===== AI 清洗助手（提示词面板，可折叠）===== */
  .ai-panel{margin-top:8px;border:1px dashed var(--amber);
    border-radius:6px;background:var(--color-bg);padding:16px 16px}
  /* 两个按钮等宽等高：复制提示词 / 打开 DeepSeek —— a 标签要显式 inline-flex 才能跟 button 对齐 */
  .ai-actions{display:flex;gap:8px;margin-bottom:8px}
  .ai-actions .btn-ghost{height:32px;padding:0 16px;font-size:13px;
    display:inline-flex;align-items:center;text-decoration:none}
  .ai-steps{margin:0 0 8px;padding-left:16px;font-size:12px;color:var(--muted);line-height:1.8}
  .ai-prompt{margin:0;padding:8px 16px;background:var(--color-surface);border:1px solid var(--line);border-radius:6px;
    font-size:12px;line-height:1.7;color:var(--navy);white-space:pre-wrap;max-height:230px;overflow:auto;
    font-family:inherit}
  .grp-t::before{content:"";display:inline-block;width:8px;height:2px;background:var(--amber);
    margin-right:8px;vertical-align:middle;border-radius:6px}
  /* 列表批量操作条 */
  .bulkbar{display:flex;align-items:center;gap:8px;background:var(--paper-warm);border:1px solid var(--color-border-soft);
    border-radius:6px;padding:8px 16px;margin:8px 0 2px;font-size:13px}
  .bulkbar.hidden{display:none}
  .bulkbar b{color:var(--amber-600);font-size:16px}
  .bulkbar .btn-ghost{height:30px;padding:0 16px;font-size:12px}
  .rowck{width:15px;height:15px;cursor:pointer;accent-color:var(--amber)}
  th.ckh{width:34px}
  /* 行内操作按钮（编辑/备注/无效） */
  td.ops{white-space:nowrap}
  td.ops .lk{border:none;background:none;color:var(--blue);font-size:12px;cursor:pointer;
    padding:4px 8px;border-radius:6px}
  td.ops .lk:hover{background:var(--color-info-bg)}
  td.ops .lk.w{color:var(--amber-600)}
  td.ops .lk.w:hover{background:var(--color-warning-bg)}
  td.ops .lk.off{color:var(--muted)}
  td.ops .del{margin-left:4px}
  /* 无效记录：灰显 + 徽章 */
  tr.row-invalid td{opacity:.42}
  tr.row-invalid td.ops,tr.row-invalid td:first-child{opacity:1}
  .badge-off{display:inline-block;margin-left:8px;padding:1px 8px;border-radius:6px;font-size:12px;
    background:var(--color-danger-bg);color:var(--bad);font-weight:600;vertical-align:1px}
  @media(max-width:880px){.fld input,.fld select{min-width:110px}}

  /* ===== 行内校验：出错字段标红（替代原生 alert）===== */
  .fld-err input,.fld-err select{border-color:var(--bad)!important;background:var(--tint-danger-soft);
    box-shadow:0 0 0 2px rgba(178,58,49,.12)}
  /* ===== 错误 toast（红色变体，替代 alert）===== */
  #toast.err{background:var(--color-danger-deep)}
  /* ===== 两段式确认： armed = 按钮已变红待二次点击 ===== */
  .armed,.armed:hover{background:var(--bad)!important;border-color:var(--bad)!important;color:var(--color-on-brand)!important}
  /* ===== 顶栏退出按钮 ===== */
  .btn-exit{margin-left:16px;background:transparent;border:1px solid rgba(255,255,255,.35);color:var(--color-on-brand);
    border-radius:6px;padding:8px 16px;font-size:12px;cursor:pointer;flex:none}
  .btn-exit:hover{border-color:var(--amber);color:var(--amber-400)}
  /* ===== 顶栏免登录开关（v9）：关=透明描边（克制）；开=琥珀实心（一眼看出当前是免登录）===== */
  .btn-skip{margin-left:16px;background:transparent;border:1px solid rgba(255,255,255,.35);color:rgba(255,255,255,.88);
    border-radius:6px;padding:8px 16px;font-size:12px;cursor:pointer;flex:none;transition:background .15s,border-color .15s}
  .btn-skip:hover{border-color:var(--amber);color:var(--amber-400)}
  .btn-skip.on{background:var(--amber);border-color:var(--amber);color:var(--navy);font-weight:700}
  .btn-skip.on:hover{background:var(--amber-400);border-color:var(--amber-400);color:var(--navy)}
  .btn-skip:disabled{opacity:.6;cursor:wait}
  /* ===== 登录页 ===== */
  .login-wrap{min-height:100vh;display:flex;align-items:center;justify-content:center;
    background:linear-gradient(160deg,var(--navy) 0%,var(--navy-deep) 100%)}
  .login-card{background:var(--cream);border-radius:6px;padding:32px 32px;width:330px;
    box-shadow:0 20px 50px rgba(7,18,36,.35);display:flex;flex-direction:column;gap:8px}
  .login-card h1{margin:4px 0 0;font-size:20px;color:var(--navy);text-align:center;letter-spacing:1px}
  .login-sub{margin:0 0 8px;text-align:center;color:var(--muted);font-size:12px}
  .login-card label{font-size:13px;color:var(--navy);font-weight:600}
  .login-card input{border:1px solid var(--border);border-radius:6px;padding:8px 16px;font-size:14px;outline:none;
    font-family:inherit}
  .login-card input:focus{border-color:var(--amber);box-shadow:0 0 0 2px var(--ring-amber)}
  .login-err{color:var(--bad);font-size:12px}
  .login-btn{margin-top:8px;height:40px;border:none;border-radius:6px;background:var(--navy);color:var(--color-on-brand);
    font-size:14px;font-weight:600;letter-spacing:6px;cursor:pointer}
  .login-btn:hover{background:var(--navy-700)}
  .login-logo{text-align:center}

/* ===== 地名库（v16）=====
   三个新件：输入框旁的「+新增城市」小按钮、状态/待整理徽标、别名单元格。
   刻意用最小高度（28px）与最小改动：录入区版面是 v15 刚对称化过的，别把它撑变形。 */
.fld-inline{display:flex;gap:8px;align-items:center;width:100%}
.fld-inline input{flex:1;min-width:90px}
.btn-mini{height:28px;padding:0 8px;font-size:12px;white-space:nowrap;cursor:pointer;
  border:1px solid var(--border);border-radius:6px;background:var(--color-surface);color:var(--navy);
  font-family:inherit;flex:0 0 auto}
.btn-mini:hover{border-color:var(--amber);color:var(--amber)}

/* ===== 库外地名「行内两步新增」（v18，Donny 2026-09-11 定）=====
   标红后在输入框下方就地出现：①「这个名字准确吗？」→ ②「＋ 确认新增城市」两下完成，
   三语由地名词典自动生成。刻意做成「贴在字段里的小条」而不是弹窗 —— 录价时手不离键盘。
   交互对称性：① 态有 ✕（先不处理）、② 态有 ✕（返回上一步）；内容变回库内写法即自动收起。 */
.pl-tip{margin-top:8px;display:flex;flex-wrap:wrap;align-items:center;gap:8px;
  padding:8px 8px;border-radius:var(--radius-sm);font-size:12px;line-height:1.5;
  background:var(--tint-warn-ghost);border:1px solid var(--color-border-soft);color:var(--navy-700)}
.pl-tip.hidden{display:none}
.pl-tip.ok{background:var(--paper-1);border-color:var(--color-success-line)}
.pl-tip-ic{flex:none;font-size:12px;line-height:1}
.pl-tip-tx{flex:1;min-width:160px}
.pl-tip-tx b{font-weight:700;color:var(--amber-600)}
.pl-tip.ok .pl-tip-tx b{color:var(--ok)}
.pl-tip-btn{height:26px;padding:0 16px;font-size:12px;font-family:inherit;border-radius:6px;
  cursor:pointer;white-space:nowrap;flex:0 0 auto;
  border:1px solid var(--border);background:var(--color-surface);color:var(--navy-700)}
.pl-tip-btn:hover{border-color:var(--amber);color:var(--amber-600)}
.pl-tip-btn.primary{background:var(--navy);border-color:var(--navy);color:var(--color-on-brand);font-weight:600}
.pl-tip-btn.primary:hover{background:var(--navy-700);border-color:var(--navy-700);color:var(--color-on-brand)}
.pl-tip-btn:disabled{opacity:.6;cursor:default}
.pl-tip-x{flex:0 0 auto;width:22px;height:22px;padding:0;border:0;border-radius:6px;
  background:transparent;color:var(--muted);cursor:pointer;font-size:12px;line-height:1;
  font-family:inherit}
.pl-tip-x:hover{background:var(--paper-4);color:var(--navy)}
.pl-tip .muted{color:var(--muted)}
.pill{display:inline-block;padding:1px 8px;border-radius:6px;font-size:12px;font-weight:600;
  border:1px solid transparent}
.pill.on{background:var(--color-success-bg);color:var(--color-success-text);border-color:var(--color-success-line)}
.pill.off{background:var(--tint-hover);color:var(--color-text-muted);border-color:var(--color-border-cool)}
.pill-warn{display:inline-block;margin-left:8px;padding:1px 8px;border-radius:6px;font-size:12px;
  font-weight:700;background:var(--tint-warn);color:var(--color-warning-text);border:1px solid var(--color-warning-line)}
/* ── v72-B 终点角色标签（提箱地 / 还箱地）─────────────────────────────────
   用在「定价策略」的行情表组头行与数据行、终点名之后。配色克制、只占一行高，
   避免把表头挤乱（军规 #1 视觉层级 / #19 一致性：与 .pill 系列同尺寸同圆角）。 */
.role-pill{display:inline-block;margin-left:8px;padding:1px 8px;border-radius:6px;font-size:12px;
  font-weight:600;line-height:16px;vertical-align:middle;white-space:nowrap;border:1px solid transparent}
/* v106 视觉降噪：已配规则行的「还箱地」从彩色 pill 降为灰字（还箱地=常态，不配彩色边框）。
   「提箱地」「角色待定」仍是 pill——它们是「该被看见」的警告。 */
.role-txt{margin-left:8px;font-size:12px;color:var(--muted);font-weight:400;white-space:nowrap}
.role-pill.drop{background:var(--color-info-bg);color:var(--color-status-none);border-color:var(--color-border-cool)}          /* 还箱地＝正常，素色 */
.role-pill.pick{background:var(--tint-warn);color:var(--color-warning-text);border-color:var(--color-warning-line)}          /* 提箱地＝该被看见 */
.role-pill.unknown{background:var(--color-bg);color:var(--color-unknown-text);border-color:var(--color-unknown-line);border-style:dashed}
.pl-alias{color:var(--muted);font-size:12px;max-width:280px;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.pl-tools{display:flex;align-items:center;gap:8px;margin:2px 0 8px}
.pl-ck{font-size:13px;color:var(--navy);display:flex;align-items:center;gap:8px;height:36px}
.pl-ck input{width:16px;height:16px}
/* 地名库搜索框（v77b）—— 原来是无类名裸 input，19px 高、没边没框，
   与隔壁 .fld input 两套长相。这里对齐 .fld input 的视觉语言。 */
.pl-search{height:36px;border:1px solid var(--border);border-radius:6px;padding:0 16px;
  font-size:13px;font-family:inherit;color:var(--navy);background:var(--color-surface);outline:none}
.pl-search:focus{border-color:var(--amber);box-shadow:0 0 0 2px var(--ring-amber)}
.pl-search::placeholder{color:var(--muted)}
#mask_place .modal-body .fld textarea{height:auto;min-height:56px;padding:8px 8px;border:1px solid var(--border);
  border-radius:6px;font-family:inherit;font-size:13px;resize:vertical}

/* ══════════════════════════════════════════════════════════════════
   v39（2026-09-15/16）：箱价总览 · 竞争力记分牌 · 调价试算 · 价格历史 · 货源档案
   ══════════════════════════════════════════════════════════════════ */
  /* 看板新增两张卡片的配色：总览=蓝（汇总）· 档案=石板（资料）。
     前三个（navy/amber/green）是「明细流水」，这两个是另一类视图，所以另起一行、另给一组色。 */
  .type-btn.sum .ic{background:var(--blue)}
  /* ⚠️ v77d 修：`<div class="type-btn rsum">`（租赁汇总）漏了 `.ic` 背景规则
     → 白字压白卡片，**图标对比度 1.00（隐形）**。补成与 rent 同族的琥珀 + navy 字。 */
  .type-btn.rsum .ic{background:var(--amber);color:var(--color-brand)}
  .type-btn.sum.active{border-color:var(--blue);box-shadow:0 0 0 2px rgba(29,95,176,.15)}
  .type-btn.file .ic{background:var(--slate)}
  .type-btn.file.active{border-color:var(--slate);box-shadow:0 0 0 2px rgba(107,122,144,.18)}

  /* 缺口徽标条：一眼看到「系统缺什么」，整块可点 → 跳到询价待办对应那段 */
  .gapbar{display:flex;gap:8px;flex-wrap:wrap;margin:0 0 16px}
  .gap-chip{display:flex;align-items:baseline;gap:8px;border:1px solid var(--line);background:var(--cream);
    border-radius:6px;padding:8px 16px;font-size:13px;color:var(--navy);cursor:pointer;transition:.15s}
  .gap-chip:hover{border-color:var(--amber);background:var(--color-surface)}
  .gap-chip b{font-size:16px;font-weight:700;color:var(--amber-600);font-variant-numeric:tabular-nums}
  .gap-chip .gap-t{font-weight:600}
  .gap-chip .gap-d{font-size:12px;color:var(--muted)}
  .gap-chip.zero{cursor:default;opacity:.6}
  .gap-chip.zero b{color:var(--ok)}
  .gap-chip.zero:hover{border-color:var(--line);background:var(--cream)}
  /* ── v62 缺口分级（Donny 2026-09-18 拍板方案 A）─────────────────────────
     「要不要」比「属于哪一类」更重要，所以第一格改成「必须但空」并给红色；
     顺带缺**降权变灰、不可点**（他原话选的就是这条）。 */
  .gap-chip.must{border-color:var(--color-danger-line);background:var(--color-danger-bg)}
  .gap-chip.must b{color:var(--color-danger-text)}
  .gap-chip.must:hover{border-color:var(--color-danger);background:var(--color-danger-bg)}
  /* v63：这格现在**可点**了（点一下展开下方清单）→ 光标改回手，
     悬停也要有反馈（原来它是"顺带缺"的不可点灰格，`cursor:default` 是为那个做的）。 */
  .gap-chip.plain{border-style:dashed;cursor:pointer;opacity:.9}
  .gap-chip.plain b{color:var(--slate)}
  .gap-chip.plain:hover{border-color:var(--navy-600);background:var(--cream);opacity:1}
  /* 「必须但空」的矩阵格子 —— 红框 + 两行小字，可点开催办卡。
     ⚠️ 红色这一档是**从 `mc-miss` 手里接过来的**（见下面 mc-miss 的改动）——
        两种缺口抢同一个视觉，他就分不出哪个是"必须的"。 */
  td.mc-must{background:var(--color-danger-bg);color:var(--color-danger-text);font-weight:700;line-height:1.25;cursor:pointer;
    box-shadow:inset 0 0 0 1.5px var(--color-danger)}
  td.mc-must:hover{background:var(--color-danger-bg)}
  td.mc-must .mc-mt{display:block;font-size:12px}
  /* v70：第二行现在可能是「已过期 · 参考 $2250」——比原来的「已过期」长，
     放宽到自动换行（原来靠不换行保证一格两行，金额一进来会把格子撑横）。 */
  td.mc-must .mc-ms{display:block;font-weight:400;font-size:12px;color:var(--color-danger-text);
    white-space:normal;line-height:1.3;max-width:86px;margin:0 auto}
  /* ── v86（Donny 2026-09-22）：**「已过期」与「从没录过」拆成两种视觉** ────────────
     他原话「那个必录的表格里面的价格，哪些空了？哪些过期了？它都有显示啊。优化这个显示效果就可以了」。
     实测拆之前：租赁价必录卡 **126 个红格** 里 41 个是「已过期」（该催同事更新）、
     85 个是「从没录过」（该去要价）—— 两件**要人做的事不同**的事，却共用同一个红底，
     只靠一行 12px 小字分，一屏看下来根本分不出先催谁。
     ⇒ 过期格降成**琥珀**（比红轻、比"快过期"的米黄重），红底只留给"真缺"。
     色阶连起来读：绿(有效) → 米黄(快过期) → **琥珀(已过期)** → 红(从没录过)。
     ⚠️ 边框颜色也跟着降 —— 只换底色不换边框的话，1.5px 的红框还会把格子"喊"回红色档。 */
  td.mc-must-stale{background:var(--color-warning-bg);color:var(--color-warning-text);
    box-shadow:inset 0 0 0 1.5px var(--color-warning-line)}
  td.mc-must-stale:hover{background:var(--color-warning-bg)}
  td.mc-must-stale .mc-ms{color:var(--color-warning-text)}
  /* ⚠️⚠️ hover 兜底**不是装饰**：`table.mtx tbody tr:hover td` 特异性 (0,2,4) 压过
     `td.mc-must-stale` (0,1,1) → 不补这条，鼠标扫过整行时琥珀会被冲成 `--tint-hover`(灰蓝)，
     他会以为「颜色没生效」（v70 给 `mc-ok.bN` 补兜底踩过同一个坑）。 */
  table.mtx tbody tr:hover td.mc-must-stale{background:var(--color-warning-bg)}
  /* ── v62 催办卡内容（弹层外壳沿用 .modal-mask/.modal，见 mask_hist）────── */
  .must-kv{display:flex;gap:8px;padding:8px 0;border-bottom:1px dashed var(--line);
    font-size:13px;line-height:1.7;align-items:flex-start}
  .must-kv>i{font-style:normal;color:var(--muted);min-width:80px;flex:none;padding-top:1px}
  .must-rules{flex:1}
  .must-rules ul{margin:4px 0 0 16px}
  .must-rules li{margin:1px 0}
  .must-copybox{margin-top:16px;background:var(--soft);border:1px dashed var(--border);
    border-radius:6px;padding:8px 16px}
  .must-copyhd{font-size:12px;color:var(--muted);margin-bottom:8px}
  .must-copytxt{font-size:13px;line-height:1.75;color:var(--navy-700);white-space:pre-wrap}

  /* 竞争力记分牌：四个大数字（可做 / 让利可做 / 做不了 / 算不出） */
  .scorebar{display:flex;gap:16px;flex-wrap:wrap;margin-bottom:16px}
  .score-tile{flex:1;min-width:150px;border:1px solid var(--line);border-radius:6px;padding:16px 16px;background:var(--color-surface)}
  .score-tile .s-n{font-size:28px;font-weight:700;line-height:1.1;font-variant-numeric:tabular-nums}
  .score-tile .s-t{font-size:13px;font-weight:600;margin-top:2px}
  .score-tile .s-d{font-size:12px;color:var(--muted)}
  .score-tile.ok{border-color:var(--color-success-line);background:var(--paper-1)}   .score-tile.ok .s-n{color:var(--ok)}
  .score-tile.mid{border-color:var(--color-border-soft);background:var(--color-bg)}  .score-tile.mid .s-n{color:var(--amber-600)}
  .score-tile.no{border-color:var(--color-danger-line);background:var(--paper-1)}   .score-tile.no .s-n{color:var(--bad)}
  .score-tile.flat .s-n{color:var(--muted)}
  /* 「没优势」的目的地清单：一行一条，最多三条 */
  .score-worst{margin-top:8px;border-top:1px dashed var(--line);padding-top:8px;font-size:13px}
  .score-worst .sw-row{display:flex;align-items:baseline;gap:8px;padding:4px 0;flex-wrap:wrap}
  .score-worst .sw-dest{font-weight:600;min-width:120px}
  .score-worst .sw-btn{border:1px solid var(--border);background:var(--color-surface);border-radius:6px;height:26px;
    padding:0 8px;font-size:12px;cursor:pointer;color:var(--navy)}
  .score-worst .sw-btn:hover{border-color:var(--amber)}

  /* 调价试算：改动对比（报价 / 毛利 的变化，用箭头摆出来） */
  .simdiff{display:flex;gap:16px;flex-wrap:wrap;margin:16px 0 8px}
  .simdiff .sd-box{border:1px solid var(--line);border-radius:6px;padding:8px 16px;background:var(--cream);min-width:190px}
  .simdiff .sd-t{font-size:12px;color:var(--muted);font-weight:500}
  .simdiff .sd-v{font-size:16px;font-weight:600;font-variant-numeric:tabular-nums}
  .simdiff .sd-old{color:var(--muted);text-decoration:line-through;margin-right:8px;font-weight:400}
  .simdiff .sd-up{color:var(--ok);font-weight:700}
  .simdiff .sd-down{color:var(--bad);font-weight:700}
  .simdiff .sd-same{color:var(--muted)}

  /* 价格历史：统计行 + 简易走势柱（纯 CSS，不引图表库） */
  .statrow{display:flex;gap:16px;flex-wrap:wrap;margin-bottom:16px}
  .stat-box{border:1px solid var(--line);border-radius:6px;padding:8px 16px;background:var(--cream);min-width:120px}
  .stat-box .sb-t{font-size:12px;color:var(--muted)}
  .stat-box .sb-v{font-size:16px;font-weight:700;font-variant-numeric:tabular-nums}
  .hist-chart{display:flex;align-items:flex-end;gap:8px;height:92px;padding:8px 4px 0;border-bottom:1px solid var(--line);margin-bottom:16px}
  .hist-chart .hc-col{flex:1;min-width:26px;display:flex;flex-direction:column;justify-content:flex-end;align-items:center;height:100%}
  .hist-chart .hc-bar{width:70%;background:linear-gradient(180deg,var(--amber-400),var(--amber));border-radius:6px 6px 0 0;min-height:3px}
  .hist-chart .hc-bar.last{background:linear-gradient(180deg,var(--navy-700),var(--navy))}
  .hist-chart .hc-v{font-size:12px;color:var(--navy);font-weight:600;margin-bottom:4px;font-variant-numeric:tabular-nums}
  .hist-chart .hc-d{font-size:12px;color:var(--muted);margin-top:4px;white-space:nowrap}
  .hist-chart.empty{display:block;height:auto;color:var(--muted);text-align:center;padding:16px 0;border:0}

  /* ── v92：价格明细**三段分层**（有效 / 过期 / 历史）────────────────────
     Donny 2026-09-22：「可以分层的看」「这几天的同时的几家的报价哪一家最低？平均价是多少？
     过期的价格又是哪一些？历史的价格又是哪一些？还是以一个丰富查看价格的样式去设计」
     ⇒ 每段 = 段头(标题+条数) + 汇总行(最低/均价/几家) + 明细表。三段之间留白分开。 */
  .hs-sec{margin-bottom:22px}
  .hs-sec:last-child{margin-bottom:4px}
  .hs-hd{display:flex;align-items:baseline;gap:10px;margin-bottom:8px;
         padding-bottom:6px;border-bottom:1px solid var(--line)}
  .hs-hd h4{margin:0;font-size:14px;color:var(--navy-800);font-weight:700}
  .hs-hd h4::before{content:"";display:inline-block;width:3px;height:13px;border-radius:2px;
         background:var(--amber);margin-right:7px;vertical-align:-1px}
  .hs-hd .hs-sub{font-size:12px;color:var(--muted)}
  .hs-hd .hs-n{margin-left:auto;font-size:12px;color:var(--muted);font-variant-numeric:tabular-nums}
  /* 汇总行：最低（高亮）/ 均价 / 几家 / 几条 —— 他要的"哪一家最低、平均价多少"就在这一行 */
  .hs-sum{display:flex;align-items:baseline;gap:6px;flex-wrap:wrap;
          background:var(--cream);border:1px solid var(--line-warm);border-radius:6px;
          padding:7px 12px;margin-bottom:8px;font-size:13px}
  .hs-sum .hs-k{color:var(--muted);font-size:12px}
  .hs-sum .hs-v{font-variant-numeric:tabular-nums;color:var(--navy-800)}
  .hs-sum .hs-v.low{color:var(--green-700);font-size:15px}
  .hs-sum .hs-p{font-size:12px;color:var(--navy-700);font-weight:600}
  .hs-sum .hs-sep{color:var(--color-text-ghost-2);margin:0 4px}
  /* 明细表 + 可点行（点开看是谁报的、谁录的） */
  .hs-tb{margin-top:0}
  .hs-tb tbody tr.hs-row{cursor:pointer}
  .hs-tb tbody tr.hs-row:hover{background:#FAF7F0}
  .hs-tb tbody tr.hs-row.open{background:#FAF7F0}
  .hs-tb tbody tr.hs-row.open td:first-child::before{content:"▾ ";color:var(--amber)}
  .hs-tb tbody tr.hs-row td:first-child::before{content:"▸ ";color:var(--muted)}
  .hs-det td{background:var(--cream);padding:0}
  .hs-det-in{display:flex;gap:22px;flex-wrap:wrap;padding:10px 14px;
             border-left:3px solid var(--amber);font-size:13px}
  .hs-det-in .hs-df{display:flex;align-items:baseline;gap:7px}
  .hs-det-in .hs-df b{font-size:12px;color:var(--muted);font-weight:500}
  .hs-det-in .hs-df i{font-style:normal;color:var(--navy-800)}
  /* ── v101：三段**递进淡化**（Donny 2026-09-25「有效的应该更明显，无效的应该灰色或者
     颜色越来越淡或者半透明……里面的各种小字想办法收拾一下」）——
     有效段不动当主角；过期段整体降灰（ghost 系，同「缺价格灰字」一个语义级）；
     历史段更淡 + 整段半透明。交互不变（行仍可点开），只动观感。 */
  .hs-sec.s-stale .hs-hd h4{color:var(--color-text-dim)}
  .hs-sec.s-stale .hs-hd h4::before{background:var(--color-text-ghost)}
  .hs-sec.s-stale .hs-sum{background:transparent;border-color:transparent;padding:2px 0 6px}
  .hs-sec.s-stale .hs-sum .hs-v,.hs-sec.s-stale .hs-sum .hs-p{color:var(--color-text-ghost);font-weight:400}
  .hs-sec.s-stale .hs-sum .hs-v.low{color:var(--color-text-ghost);font-size:13px;font-weight:400}
  .hs-sec.s-stale .hs-tb td{color:var(--color-text-ghost)}
  .hs-sec.s-stale .hs-tb td b{color:var(--color-text-ghost);font-weight:600}
  .hs-sec.s-stale .hs-tb .amt{color:var(--color-text-ghost);font-weight:400}
  .hs-sec.s-stale .hs-tb thead th{background:transparent;color:var(--color-text-ghost)}
  .hs-sec.s-stale .hs-det-in{border-left-color:var(--color-text-ghost)}
  .hs-sec.s-stale .hs-det-in i{color:var(--color-text-ghost)}
  .hs-sec.s-old{opacity:.72}
  .hs-sec.s-old .hs-hd h4{color:var(--color-text-ghost)}
  .hs-sec.s-old .hs-hd h4::before{background:var(--color-text-ghost-2)}
  .hs-sec.s-old .hs-sum{background:transparent;border-color:transparent;padding:2px 0 6px}
  .hs-sec.s-old .hs-sum .hs-v,.hs-sec.s-old .hs-sum .hs-p,
  .hs-sec.s-old .hs-sum .hs-k{color:var(--color-text-ghost-2);font-weight:400}
  .hs-sec.s-old .hs-sum .hs-v.low{color:var(--color-text-ghost-2);font-size:13px;font-weight:400}
  .hs-sec.s-old .hs-tb td,.hs-sec.s-old .hs-tb td b{color:var(--color-text-ghost-2)}
  .hs-sec.s-old .hs-tb .amt{color:var(--color-text-ghost-2);font-weight:400}
  .hs-sec.s-old .hs-tb thead th{background:transparent;color:var(--color-text-ghost-2)}
  .hs-sec.s-old .hs-det-in{border-left-color:var(--color-text-ghost-2)}
  .hs-sec.s-old .hs-det-in i{color:var(--color-text-ghost-2)}
  /* 小字收拾：分隔点金色→暖灰（金色小噪点收掉）；底部帮助文案降为刻意淡 */
  #mask_hist .modal-foot .tip{color:var(--color-text-ghost)}
  #mask_hist .modal-foot .tip b{color:inherit;font-weight:600}

  /* 货源档案卡：展开行（详情 / 收起，对称） */
  .sc-detail{background:var(--cream)}
  .sc-detail .d-t{font-weight:600;color:var(--navy)}
  .sc-status{display:inline-block;padding:1px 8px;border-radius:6px;font-size:12px;font-weight:600;border:1px solid}
  .sc-status.s-0{background:var(--tint-hover);border-color:var(--color-border-cool);color:var(--color-text-muted)}
  .sc-status.s-1{background:var(--tint-warn-mid);border-color:var(--color-border-soft);color:var(--amber-600)}
  .sc-status.s-2{background:var(--color-info-bg);border-color:var(--color-info-line);color:var(--blue)}
  .sc-status.s-3{background:var(--color-success-bg);border-color:var(--color-success-line);color:var(--ok)}
  .sc-status.s-4{background:var(--tint-hover);border-color:var(--color-border-cool);color:var(--muted);text-decoration:line-through}

  /* 弹窗加宽（档案卡 18 个字段、试算与历史表都偏宽，880px 挤不下） */
  .modal.wide{width:min(1040px,96vw)}
  .modal-body .fld textarea{height:auto;min-height:56px;padding:8px 8px;border:1px solid var(--border);
    border-radius:6px;font-family:inherit;font-size:13px;resize:vertical;color:var(--navy);outline:none}
  .modal-body .fld textarea:focus{border-color:var(--amber);box-shadow:0 0 0 2px var(--ring-amber)}
  .sc-photos{display:flex;flex-wrap:wrap;gap:8px;margin-top:4px}
  /* 快过期（仍有效但超警示天数）的行：整行浅底提示，但不抢眼 —— 它还不是错，只是「该更新了」 */
  tr.row-warn{background:var(--tint-note)}

  /* ── v41 箱价总览**矩阵表**（竖＝地点／横＝箱型×箱况）────────────────────
     Donny 2026-09-16 亲定：国内一张表、国外一张表；缺的标红、过期的写「过期」。
     配色只有三档，别再往上加：有价（navy 黑字）／过期（琥珀）／缺（红）。 */
  .mtx-block{margin-top:16px}
  .mtx-head{display:flex;align-items:baseline;gap:16px;flex-wrap:wrap;margin:0 0 8px}
  .mtx-head h3{font-size:14px;margin:0;color:var(--navy)}
  .mtx-head h3:before{content:"";display:inline-block;width:6px;height:6px;border-radius:50%;
    background:var(--amber);margin-right:8px;vertical-align:middle}
  .mtx-meta{font-size:12px;color:var(--muted)}
  .mtx-meta b{color:var(--navy)}
  .mtx-meta b.bad{color:var(--bad)}
  .mtx-meta b.exp{color:var(--color-warning-text)}
  /* v59.2 总览矩阵「框内竖滚、表头吸框顶」（Donny 2026-09-17 拍板方案①）：
     ⚠️ 为什么吸不到**视口**顶：`overflow-x:auto` 会把 `overflow-y` 的计算值也变成 auto，
        这个框自成 scrollport，框里的 `thead th{top:0}` 只能吸在**框内**；框不定高就永不竖滚
        → 表头跟着页面一起滚走（v59.1 实测：21 行的「按国家」表就是这样）。定个 `max-height`
        让框自己竖滚，表头就钉在框顶了。**别把这行的 max-height 删了**，删了等于退回没吸顶。
     ⚠️ 矮表（如「按箱型」3 行 160px）不受影响：max-height 只在内容超出时才起作用。 */
  .mtx-wrap{overflow:auto;max-height:70vh}   /* 9 列放不下时横向滚，不挤压列宽（地点列已 sticky 吸左） */
  .mtx-loading{padding:24px 0;text-align:center;color:var(--muted);font-size:13px}
  .mtx-note{margin-top:8px;font-size:12px;color:var(--gold-700);background:var(--tint-note);border:1px solid var(--color-unknown-line);
    border-radius:6px;padding:8px 8px;line-height:1.6}
  .mtx-note b{color:var(--color-warning-text)}
  .mtx-note .dim{color:var(--muted)}
  .mtx-note .lk{margin-left:8px}
  table.mtx{width:100%;border-collapse:separate;border-spacing:0;font-size:13px}
  table.mtx th,table.mtx td{border-bottom:1px solid var(--border);padding:8px 8px;
    text-align:center;white-space:nowrap}
  table.mtx thead th{background:var(--tint-hover);font-weight:600;color:var(--navy);line-height:1.25}
  table.mtx thead th b{display:block;font-size:13px}
  table.mtx thead th span{display:block;font-size:12px;font-weight:600;color:var(--color-warning-text);letter-spacing:.4px}
  table.mtx th.pl{text-align:left;font-weight:700;background:var(--tint-hover);
    border-right:1px solid var(--border);position:sticky;left:0;z-index:2}
  /* v59.2 角格（表头左上那格「地点 / 目的地 · 规格」）要**同时**吸顶 + 吸左，且必须压在
     吸左的行头（z-index:2）**上面** —— 否则框内竖滚时，行头（DOM 在后）会盖住它。
     为什么单列一条：`table.mtx th.pl` 特异性比 `thead th` 高，上面那个 2 会把表头的 3 盖掉。 */
  table.mtx thead th.pl{top:0;z-index:4}
  table.mtx tbody tr:hover td{background:var(--tint-hover)}
  td.mc-ok{color:var(--navy);font-weight:700;line-height:1.28;cursor:pointer}
  td.mc-ok .mc-amt{display:block}
  td.mc-ok .mc-dt{display:block;font-weight:400;font-size:12px;color:var(--muted)}
  /* ⚠️ v70：把 `td.mc-ok.warn{background:var(--tint-edit)}` **撤掉**了 —— 底色现在只表「新鲜度」
     （下面 4 档），⚠ 只留角标。两个机制抢同一个底色，他就读不出"这个价到底多新"。
     ⚠️ 保留的一个既有事实：`td.mc-ok.warn` 这个 class 本身**还在挂**（悬停文案/角标靠它），
        只是不再改底色 —— 别顺手把 `warn` 从 DOM 里删掉。 */
  /* ── v70 有效格：越新越艳、越旧越淡（Donny 2026-09-18 拍板：绿色梯度）────
     4 档按「价龄 ÷ 该格有效期」切（见 `app.js` 的 `freshBand`）。
     ⚠️ 一下别改成写死天数：他把 15 天改成 10 天、或给某地点单设 9 天，颜色要自己跟着走。
     ⚠️⚠️ 下面 4 条 hover 兜底**不是装饰**：`table.mtx tbody tr:hover td` 特异性 (0,2,4)
         比 `td.mc-ok.b1` (0,2,1) **高** —— 不兜底的话鼠标扫过整行，色阶全被冲成灰蓝，
         他会以为"颜色没生效"。兜底后悬停是"同色系压深一档"，色阶不丢。 */
  td.mc-ok.b1{background:var(--band-1)}
  td.mc-ok.b2{background:var(--band-2)}
  td.mc-ok.b3{background:var(--band-3)}
  td.mc-ok.b4{background:var(--band-4)}
  td.mc-ok.b1 .mc-dt,td.mc-ok.b2 .mc-dt{color:var(--band-text)}
  table.mtx tbody tr:hover td.mc-ok.b1{background:var(--band-1-h)}
  table.mtx tbody tr:hover td.mc-ok.b2{background:var(--band-2-h)}
  table.mtx tbody tr:hover td.mc-ok.b3{background:var(--band-3-h)}
  table.mtx tbody tr:hover td.mc-ok.b4{background:var(--band-4-h)}
  td.mc-ok.warn .mc-amt:after{content:" ⚠";color:var(--color-warning-text);font-size:12px}
  td.mc-exp{color:var(--color-warning-text);font-weight:700;background:var(--tint-edit);cursor:pointer}
  /* v70：过期格**仍显金额**（用 20 天窗口内的参考均价，悬停明写"不是现价"）。
     金额字色沿用过期橙、日期行浅一档 —— 免得跟"有效"格的深蓝金额看混。
     ⚠️ `.mc-amt`/`.mc-dt` 的 `display:block` 原来只写在 `td.mc-ok` 下，
        过期格不补这两条的话，金额和「过期 · N 天前」会挤成一行。 */
  td.mc-exp .mc-amt{display:block}
  td.mc-exp .mc-dt{display:block;font-weight:400;font-size:12px;color:var(--color-warning-date)}
  /* v62：顺带缺**降权变灰、不给出口**（Donny 2026-09-18 拍板）。
     ⚠️ 原来它是**红的**（var(--color-danger-bg) + --bad）—— 红这一档现在让给 `td.mc-must`（必须但空）。
        不分档的话「你指定必须的缺」和「顺带缺」长得一模一样，他没法一眼看出该先催哪个。
     ⚠️ 变灰**不是**删除：格子照旧显示、照旧算进「缺 N 格」，只是不再跟必须的抢视觉。 */
  td.mc-miss{background:var(--paper-2);color:var(--color-text-ghost);font-weight:600}
  /* ── v63：非必录格 · **占位，不是缺** ───────────────────────────────
     ⚠️⚠️ 本页改「只显示必须要录的」之后，矩阵是**矩形**（必录的地点行 × 必录的规格列），
        但必录是**点集** —— 这个地点没有这个规格的必录时，这一格**不该显示成红的**。
        原来它会落到 `td.mc-miss`（红），那就是**假缺口**：看着像缺，其实你根本没要求过它。
        做成几乎看不见的"·"，标题写清「不是必须要录的」。 */
  td.mc-off{background:transparent;color:var(--color-text-ghost-2);font-weight:400;cursor:default;font-size:12px}

  /* ── v63 下半清单：矩阵里画不出的必录格（按规格分组，默认收起）────────
     用原生 `<details>` —— 默认收起、点标题开合，**交互天然对称**（军规 #5），
     不用自己写 JS 折叠（本项目为"只有进没有出"付过代价）。 */
  .must-rest{margin-top:16px}
  .must-rest .rest-box{border:1px dashed var(--border);border-radius:6px;
    background:var(--soft);padding:0}
  .must-rest summary{cursor:pointer;padding:8px 16px;font-size:13px;color:var(--navy-700);
    list-style:none;display:flex;align-items:center;gap:8px}
  .must-rest summary::-webkit-details-marker{display:none}
  .must-rest summary::before{content:"▸";color:var(--muted);font-size:12px;transition:transform .15s}
  .must-rest details[open] summary::before{transform:rotate(90deg)}
  .must-rest summary:hover{background:var(--cream);border-radius:6px}
  .must-rest .rest-body{padding:2px 16px 16px}
  .must-rest .rest-grp{display:flex;gap:16px;padding:8px 0;border-top:1px dashed var(--line);
    align-items:flex-start;font-size:13px;line-height:1.9}
  .must-rest .rest-spec{flex:none;min-width:120px;font-weight:700;color:var(--navy-700)}
  .must-rest .rest-objs{flex:1;display:flex;flex-wrap:wrap;gap:4px 8px}
  .must-rest .rest-obj{border:1px solid var(--border);background:var(--color-surface);border-radius:6px;
    padding:1px 8px;font-size:12px;cursor:pointer;font-family:inherit;color:var(--navy-700)}
  .must-rest .rest-obj.bad{border-color:var(--color-danger-line);color:var(--color-danger-text);background:var(--color-danger-bg)}
  .must-rest .rest-obj.ok{color:var(--muted)}
  .must-rest .rest-obj:hover{border-color:var(--navy-600);background:var(--cream)}

/* ── v42 价格历史：按报价方汇总（谁报过 / 报了几条 / 什么区间 / 最近一次）──
   一眼看全「这几家里最便宜的是谁」，不用在明细里逐行比。
   ⚠️ 明细表照旧全留着 —— 汇总是索引，明细才是底账。 */
.pvsum{margin:2px 0 8px}
.pvsum-h{font-size:13px;color:var(--navy);margin-bottom:8px;font-weight:600}
.pvsum-h .muted{font-weight:400;margin-left:8px}
.pvsum-row{display:flex;flex-wrap:wrap;gap:8px}
.pvsum .pv{display:inline-flex;align-items:baseline;gap:8px;padding:4px 8px;
  border:1px solid var(--line);border-radius:999px;background:var(--color-surface);font-size:13px;line-height:1.25;max-width:100%}
.pvsum .pv b{font-weight:600;color:var(--navy);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:220px}
.pvsum .pv i,.pvsum .pv u{font-style:normal;text-decoration:none;color:var(--muted);font-size:12px;white-space:nowrap}
.pvsum .pv em{font-style:normal;color:var(--amber-600);font-weight:600;white-space:nowrap}

/* ── v43 租价总览：行标签是「目的地 + 规格」两行，外加「策略」小标 ── */
table.mtx th.pl span{display:block;font-size:12px;color:var(--color-warning-text);font-weight:600}
table.mtx th.pl i.pv-plan{display:inline-block;font-style:normal;font-size:12px;font-weight:700;
  color:var(--amber-600);background:rgba(201,146,45,.12);border:1px solid rgba(201,146,45,.5);
  border-radius:999px;padding:0 8px;margin-left:8px;vertical-align:1px}
table.mtx td.vd{background:var(--color-surface)}

/* ── v45 买卖箱价对比：顶部计数条（数的是全量，不受筛选影响） ──
   胶囊样式与 .st-* 系同源，只是这里要一排平铺、不是单个徽章。 */
.bc-stat{display:flex;flex-wrap:wrap;gap:8px;margin:2px 0 16px}
.bc-chip{font-size:12px;font-weight:700;border-radius:999px;padding:4px 16px;
  background:var(--paper-3);color:var(--color-text-dim);white-space:nowrap}
.bc-chip.st-ok{background:var(--color-success-bg);color:var(--color-success-text)}
.bc-chip.st-risk{background:var(--color-warning-bg);color:var(--color-warning-text)}
.bc-chip.st-no{background:var(--paper-3);color:var(--color-text-dim)}
.bc-chip.st-flat{background:var(--paper-3);color:var(--color-text-dim)}
/* 买卖箱价对比的「地点 · 规格」两行标签 + 这一列不折行（窄列里中文会被压成一字一行） */
#bcmp_card td.rt-cell{white-space:nowrap}

/* ── v46：定价策略页第三个标签「定价规则」的图标色（前两个复用 .rent / .trade） ── */
.type-btn.rule .ic{background:var(--slate,var(--color-slate))}
.type-btn.rule.active{border-color:var(--slate,var(--color-slate));box-shadow:0 0 0 2px rgba(107,122,144,.18)}

/* ── v49：第四个标签「参数与有效期」的图标色 ──
   ⚠️ 别再新造色相 —— 取 navy 与 slate 之间的同族深色（和 rule 的 slate 摆一起能分辨，
      又不给整页加一个新色）。 */
.type-btn.param .ic{background:var(--color-text-soft)}
.type-btn.param.active{border-color:var(--color-text-soft);box-shadow:0 0 0 2px rgba(61,75,99,.18)}

/* ── v47：租赁箱价对比的**三层折叠组头**（目的地 → 箱型 → 箱况） ──
   层级感靠**三种递进的底色 + 递增缩进**表达，不靠加粗加色堆叠 —— 三级都长一样就没法扫视。
   组头整行可点（`tr.mk-grp` 上挂 onclick），所以 cursor:pointer + hover 反馈必须给，
   否则用户不知道这里能点（这是「只有进没有出」的反面：入口看不出来）。 */
tr.mk-grp>td{cursor:pointer;border-top:1px solid var(--line);user-select:none}
tr.mk-grp:hover>td{filter:brightness(.985)}
tr.mk-grp.lv1>td{background:var(--tint-fold);padding:8px 16px 8px 8px}
tr.mk-grp.lv2>td{background:var(--paper-2);padding:8px 16px 8px 32px}
tr.mk-grp.lv3>td{background:var(--paper-1);padding:8px 16px 8px 48px;border-top:1px dashed var(--line)}
/* 一级组头左侧一条琥珀竖条 —— 与「箱价必录」的档位分组同一套视觉语言 */
tr.mk-grp.lv1>td{box-shadow:inset 3px 0 0 var(--amber)}
.mk-tri{display:inline-block;width:14px;color:var(--amber-600);font-size:12px}
.mk-gname{color:var(--navy);font-size:14px}
tr.mk-grp.lv2 .mk-gname{font-size:13px}
tr.mk-grp.lv3 .mk-gname{font-size:13px;color:var(--navy-700)}
.mk-gcnt{margin-left:8px;font-size:12px;color:var(--muted)}
/* 组头里的状态分布胶囊（与 .bc-chip 同源，一排平铺） */
.mk-st{margin-left:8px;font-size:12px;font-weight:700;border-radius:999px;
  padding:2px 8px;background:var(--paper-3);color:var(--color-text-dim);white-space:nowrap}
.mk-st b{font-weight:800}
.mk-st.st-ok{background:var(--color-success-bg);color:var(--color-success-text)}
.mk-st.st-risk{background:var(--color-warning-bg);color:var(--color-warning-text)}
.mk-st.st-no{background:var(--paper-3);color:var(--color-text-dim)}
.mk-st.st-none{background:var(--color-info-bg);color:var(--color-status-none)}
.mk-st.st-flat{background:var(--paper-3);color:var(--color-text-dim)}


/* ── v50：导航「待办」上的红点数字（Donny：「导航「待办」挂红色数字」）──────
   数字 = 必须有的价缺几条。**不加载时带 .hidden** → 不显示「0」那种假红点；
   0 条时 JS 也加回 .hidden（「没事」不该顶个红点催人）。 */
.mn-btn{position:relative}
.mn-badge{display:inline-block;margin-left:8px;min-width:17px;padding:0 4px;
  border-radius:999px;background:var(--bad);color:var(--color-on-brand);font-size:12px;line-height:17px;
  font-weight:700;text-align:center;vertical-align:middle}
.mn-btn.active .mn-badge{background:var(--color-surface);color:var(--bad)}
/* 必录价格卡：盯/缺 那一格（数字给粗细，别让整列都在喊） */
.mq-watch{color:var(--navy);font-weight:700}
.mq-miss{color:var(--bad);font-weight:700}
.mq-miss-0{color:var(--color-success-text);font-weight:700}
/* ── v55：必询规格多选（复选框组）—— 新增区与表格行内**共用同一套** ──────────
   选中态 = 浅底 + 深边 + 加粗，**不反白**：
   反白后原生复选框的 accent 色会跟底色撞（变成看不见的勾），也违反"颜色克制"。
   ⚠️ 底色统一走 `var(--color-surface)`。
      （v77 前这里是 `var(--card-2,#fff)` —— `--card-2` **全项目从未定义**，一直靠兜底悄悄退化到白，已于 v77 清掉。）*/
.mq-checks{display:flex;flex-wrap:wrap;gap:4px;align-items:center}
.mq-chk{display:inline-flex;align-items:center;gap:4px;padding:4px 8px;
  border:1px solid var(--line);border-radius:999px;background:var(--color-surface);
  font-size:12px;font-weight:600;color:var(--navy);cursor:pointer;white-space:nowrap;
  line-height:1.45;transition:border-color .12s,background .12s}
/* ⚠️⚠️ **必须显式重置尺寸**：`.fld input` 那条通用样式（`height:36px` + `min-width:120px`，
   窄屏 `110px`）会**漏到复选框上**，把它撑成 110×36 的白色大方块
   → 一个 pill 变成 160~200px 宽 → 一行只放得下一个 → 整列竖着排（Donny 2026-09-17 截图反馈的排版 bug）。
   选择器带 `[type=checkbox]` 提特异度才压得住（`.fld input` 是 0,1,1，本条是 0,2,1）。**别再删。** */
.mq-checks input[type=checkbox]{width:14px;height:14px;min-width:0;min-height:0;
  padding:0;margin:0;flex:0 0 auto;border:0;background:transparent;
  accent-color:var(--navy);cursor:pointer}
.mq-chk:hover{border-color:var(--navy)}
.mq-chk.on{background:rgba(11,31,58,.07);border-color:var(--navy);font-weight:700}
.mq-checks input[type=checkbox]:disabled{cursor:default}
.mq-checks.ro{opacity:.55}                     /* 二级只读：整组压暗（`disabled` 只是点不动，看不出） */

/* v66：「每个箱型带自己的箱况」的二维规格控件（Donny 2026-09-18 定）。
   一行一个箱型：左边箱型 pill，右边紧跟**该箱型**的 4 个箱况 pill。
   ⚠️ 箱况必须**贴在本箱型那一行**（不是另起一横排）—— 这正是 v66 要表达的
      「40HQ 要 NEW+CW，但 20GP 只要 CW」。 */
.mq-spec-grid{display:flex;flex-direction:column;gap:8px}
.spec-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap;
  padding:4px 8px;border-radius:6px;transition:background .12s}
.spec-row.on{background:rgba(11,31,58,.035)}
.spec-bt{min-width:78px;justify-content:center}    /* 箱型这一列**对齐**，右边箱况才成一竖列 */
.spec-cds{display:flex;gap:8px;flex-wrap:wrap;align-items:center}
.spec-row .mq-chk.dis{opacity:.45}                /* 箱型没勾 → 它的箱况压暗（点不动，看得懂） */
/* ⚠️⚠️ 与 `.mq-checks` 同因：`.fld input`（height:36px + min-width:120px）会**漏进来**
   把复选框撑成 110×36 的大方块 → 一行放不下几个 → 整列竖着排。
   选择器带 `[type=checkbox]` 提特异度才压得住（`.fld input` 是 0,1,1，本条是 0,2,1）。**别再删。** */
.mq-spec-grid input[type=checkbox]{width:14px;height:14px;min-width:0;min-height:0;
  padding:0;margin:0;flex:0 0 auto;border:0;background:transparent;
  accent-color:var(--navy);cursor:pointer}
.mq-spec-grid input[type=checkbox]:disabled{cursor:default}
.mq-spec-grid.ro{opacity:.55}

/* v66：分对象覆盖的**行内展开行**（给表格里单个对象开小灶）。
   ⚠️ 用行内而不是弹层：表格里塞不下 5 箱型 × 4 箱况，弹层又要多一套遮罩/body 锁的对称性。 */
.mq-ov-row>td{padding:0;background:rgba(11,31,58,.03)}
.mq-ov-box{padding:8px 16px;border-left:3px solid var(--navy)}
.mq-ov-hd{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:8px}
.mq-ov-btn{margin-left:8px;padding:1px 8px;font-size:12px}
.mq-ov-tag{margin-left:8px;font-size:12px;font-weight:700;color:var(--navy);
  background:rgba(11,31,58,.08);border-radius:999px;padding:1px 8px}
/* v67.3「必须有的规格」列：一排**同款小标签**，不再是一长串「跟着上面（40HQ（…）、20GP（…））」
   （Donny：「必录里面跟着上面太难看了」「不要这种跟　是什么就是什么」「格式要对齐美观」）。
   ⚠️ 对齐三件事：① 箱型顺序后端按 BOX_TYPES 给 ② 箱型名固定宽度 ③ 「改规格」右对齐成一条线。 */
.mq-spec-td{min-width:260px}
.mq-spec-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.mq-spec-row .mq-ov-btn{margin-left:auto}       /* 右对齐 → 各行按钮竖直成线（覆盖 .mq-ov-btn 的 8px） */
.mq-sp{display:inline-flex;align-items:baseline;gap:8px;flex:0 0 auto;
  background:rgba(11,31,58,.05);border-radius:6px;padding:1px 8px;
  font-size:12px;line-height:1.55;white-space:nowrap}
.mq-sp>b{color:var(--navy);font-weight:700;min-width:38px}   /* 箱型名都 4 字符 → 固定宽度即对齐 */
.mq-sp>i{font-style:normal;color:var(--slate)}               /* 箱况是次要信息，用中性石板色 */
.mq-sp-unl{color:var(--muted)}
.mq-spec-none{font-size:12px;color:var(--muted)}
/* 数字列用等宽数字 —— 23 行的「3 格 · 缺 3」上下才对得齐 */
#pn_mq_card td{font-variant-numeric:tabular-nums}
.mq-spec-lbl.has-ov{font-weight:700}

/* v56：必询卡分**两块**（买卖箱价 / 租赁价），每块里 ① 必须有的规格 在上、② 按对象设置 在下。
   Donny 原话：「按买卖箱价和租赁价区分　然后分别设置哪些价格是必须有的
   　然后两种价格类型都分别有按对象设置　然后设置什么是必须有的价格后显示出来　里面就不用单独去选了」
   ⚠️ 两块之间**必须**有分隔：两块长得一模一样（都是「①②＋一张表」），
      不隔开他根本分不清自己在改哪一类 —— 而改错类的后果是静默的（数字看着还对）。 */
.mq-blk{margin-top:16px}
.mq-blk+.mq-blk{margin-top:24px;padding-top:16px;border-top:1px dashed var(--line)}
.mq-blk-t{font-size:14px}                       /* 块标题（买卖箱价 / 租赁价）比小节标题大一号 */

/* ══ v81（Donny 2026-09-21）：「必录买卖箱价格」里再分**两块** ══════════════════
   他原话：「必录入买卖箱价格分成 提箱地和目的地」＋二次确认「真拆成两套独立」。
   ⇒ 层级变成三层：**大类（买卖箱价 / 租赁价）→ 块（提箱地 / 目的地）→ 子块（①统一设置…）**。
   ⚠️⚠️ **三层必须一眼分得出层次**，否则他会分不清自己在改哪一块 ——
      而「改错块」的后果是**静默的**（数字看着还对，规则却挂到了另一类地方）。
      层次靠三件事拉出来（缺一不可）：
        ① 大类标题 `.mq-blk-t` 14px 最深色；块标题 `.mq-blk-sub-t` 13px 次深；
        ② 块有一圈**浅底 + 左粗边**（`.mq-blk-sub`），把「块」从视觉上框成一个整体；
        ③ 两块之间留 20px 实线与 16px 内距。
   ⚠️ 用 `box-shadow: inset` 画左粗边**不用 `border-left`** —— 后者占位，
      展开/收起时整块内容会横跳几像素（与 `.mq-dirty` 那条注释同一个原因）。 */
.mq-blk-sub{margin-top:20px;padding:12px 14px 4px;border-radius:10px;
  background:rgba(11,31,58,.022);
  box-shadow:inset 3px 0 0 rgba(201,146,45,.55)}
.mq-blk-sub+.mq-blk-sub{margin-top:20px}
.mq-blk-sub-hd{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;
  margin:0 0 2px;padding-bottom:8px;border-bottom:1px solid var(--line)}
.mq-blk-sub-t{font-size:13px;color:var(--navy);font-weight:700;flex:0 0 auto}
/* 块里第一个子块的 margin-top 收掉（否则块头下会多出 16px 空白，看着像没对齐） */
.mq-blk-sub>.mq-sub:first-of-type{margin-top:10px}
.mq-sub{margin-top:16px}
.mq-sub-hd{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap;margin-bottom:8px}
/* ①② 用浅底小标签，一眼看出「设规格」和「管对象」是两层 */
.mq-sub-hd>b{font-size:12px;color:var(--navy);flex:0 0 auto;
  background:rgba(11,31,58,.06);border-radius:6px;padding:2px 8px}
#pn_mq_def_trade .cell-sub,#pn_mq_def_rent .cell-sub{margin-top:4px}

/* v56.1「● 未保存」提示（勾了规格但没点保存）
   起因：保存**另一类**会触发全量重绘，把他刚勾好、还没保存的这块**悄悄刷回库里的值**
   → 他以为存上了（假成功）。现在那一块会**保留草稿**（见 app.js `renderMustDefBlock`），
   所以**必须让他看见「还没保存」**，否则草稿会一直挂在界面上。
   ⚠️ 颜色用深琥珀（`--amber-600`）**不用红**：没保存不是错误，但要比正文显眼。
   ⚠️ 整块那道竖线用 `inset box-shadow` 而不是 `border-left` —— 后者会**占位**，
      勾一下内容就右移几像素（布局跳动），看起来像"页面抖了一下"。 */
.mq-dirty{font-size:12px;font-weight:600;color:var(--amber-600);white-space:nowrap;margin-right:8px}
.mq-sub.is-dirty{box-shadow:inset 3px 0 0 var(--amber)}

/* v55.1 旧版式（保留：`mq-sec` 还被别处当通用小节用） */
.mq-sec{margin-top:16px}
.mq-sec+.mq-sec{margin-top:16px;padding-top:16px;border-top:1px dashed var(--line)}
.mq-sec-hd{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap;margin-bottom:8px}
.mq-sec-hd>b{font-size:13px;color:var(--navy);flex:0 0 auto}
.mq-sec-sub{font-size:12px;color:var(--muted);flex:0 1 auto;min-width:0}
.mq-sec-act{flex:0 0 auto;margin-left:auto}
#pn_mq_def .cell-sub{margin-top:4px}
/* 规格那一格：**等宽两半**、并排（`fld-br` 保证它俩单独占一行，不跟对象字段挤）。
   ⚠️ 等宽是硬要求 —— 一宽一窄就不"对称"了（Donny 的原话就是"排版不够紧凑对称"）。 */
.mq-f-spec{flex:1 1 460px;min-width:0}
/* 换行占位（flex 里没有 <br>，用 100% basis 的空 div 强制断行） */
.fld-br{flex-basis:100%;height:0;margin:0;padding:0}
/* 「+ 新增地点 / 线路」推到本行最右 —— 别再让它孤零零掉到下一行最左边 */
.mq-f-end{margin-left:auto}

/* 表格行内那份：紧凑（一列要塞下 3~5 个，窄了才换行） */
.mq-checks-row{gap:4px;max-width:260px}
.mq-checks-row .mq-chk{font-size:12px;padding:1px 8px;gap:4px}
.mq-checks-row input[type=checkbox]{width:12px;height:12px}
/* 待办页「必须有的价」块 —— 用一条琥珀左边线跟下面四块区分（这是「我指定的」，那四块是「数据反推的」） */
.todo-sec.todo-must{border-left:3px solid var(--amber);padding-left:16px;margin-left:-4px}
.todo-sec.todo-must h3 .todo-n{background:var(--color-warning-bg);color:var(--color-warning-text)}

/* ═══ v51：可调参数卡（注册表驱动，按 group 自动渲染）═══ */
.pn-p-rows{padding:0 4px}
.pn-grp{font-size:12px;font-weight:700;color:var(--navy);opacity:.75;letter-spacing:.4px;
  margin:16px 0 8px;padding-bottom:4px;border-bottom:1px dashed var(--line)}
.pn-p-rows .pn-grp:first-child{margin-top:4px}
.pn-unit{font-weight:400;color:var(--muted);font-size:12px}
/* v71：参数页新增控件类型「单选（下拉）」—— 租赁定价那三项（排序方式 / 「有优势」算到哪条线 / 准入）。
   与值类的数字框刻意长得不一样：选项是一句话，看一眼就知道现在按什么口径在跑（值型参数看不出来）。 */
.pn-choice{height:32px;min-width:300px;max-width:100%;border:1px solid var(--border);
           border-radius:6px;padding:0 8px;font-size:13px;background:var(--color-surface);color:var(--navy);
           box-sizing:border-box}
.pn-choice:disabled{background:var(--cream);color:var(--muted);cursor:not-allowed}
.pn-ord{margin-bottom:16px}
.pn-chips{display:flex;flex-wrap:wrap;gap:8px;align-items:center}
.pn-chip{display:inline-flex;align-items:center;gap:2px;padding:4px 4px 4px 8px;
  border:1px solid var(--line);border-radius:999px;background:var(--color-surface);
  font-size:12px;font-weight:600;color:var(--navy)}
.pn-mv{border:0;background:transparent;cursor:pointer;font-size:12px;line-height:1;
  padding:2px 4px;color:var(--navy);opacity:.55;border-radius:6px}
.pn-mv:hover:not(:disabled){background:rgba(11,31,58,.08);opacity:1}
.pn-mv:disabled{opacity:.15;cursor:default}

/* ── v52：价格改动留痕（「价格历史」弹窗里展开的那一块）────────────────
   按钮塞在价格格内（不加列）；展开是一整行 colspan=6 的方块。 */
.rev-b{margin-left:8px;border:1px solid var(--line);background:transparent;cursor:pointer;
  font-size:12px;line-height:1;padding:4px 8px;border-radius:999px;color:var(--navy);
  opacity:.7;vertical-align:middle}
.rev-b:hover{opacity:1;background:rgba(11,31,58,.06)}
.rev-sub td{background:rgba(11,31,58,.03);padding:0!important}
.rev-box{padding:8px 16px!important;border-left:3px solid var(--navy)}
.rev-t{font-size:12px;font-weight:700;color:var(--navy);opacity:.75;margin-bottom:8px}
.rev-item{padding:8px 0;border-top:1px dashed var(--line)}
.rev-item:first-of-type{border-top:0}
.rev-h{font-size:12px;display:flex;gap:8px;align-items:baseline;flex-wrap:wrap}
.rev-h b{color:var(--navy)}
.rev-chg{display:flex;flex-wrap:wrap;gap:8px;margin-top:4px}
.rev-f{display:inline-flex;align-items:baseline;gap:4px;padding:2px 8px;border-radius:999px;
  border:1px solid var(--line);background:var(--color-surface);font-size:12px}
.rev-f b{color:var(--navy);font-weight:600}
.rev-f i{font-style:normal;color:var(--muted);text-decoration:line-through}
.rev-f u{text-decoration:none;color:var(--muted)}
.rev-f em{font-style:normal;font-weight:700;color:var(--navy)}

/* ── v57：参数与有效期页「信息架构」改造（Donny 2026-09-17 选 B）───────────────
   依据《荣尚开发规范 DEV-SPEC v2.0 §3.5 页面信息结构》：
     · 族（`.pn-fam`）= 格式塔「共同区域」—— 同族的东西看出是一伙的。力度 框 ＞ 缩进 ＞ 分隔线。
     · 族头是 <button aria-expanded>，箭头转 90°，与待办页 `.todo-fold-hd` / 待配买租差 `.sr-fold-hd`
       同一套视觉语言（能进必须能出 = 交互对称）。
     · 族**默认全部展开**（族的本职不是折叠器）；只有子块「按对象单独设」默认折叠 ——
       这正是 §3.5 第③步原文「父块默认展开、子块默认折叠并显示『已设 N 条』摘要」。
     · 族头摘要 `.pn-fam-s` 靠 `margin-left:auto` 顶到右边，**收起时也看得见关键值**，不让人失去方位。 */
.pn-fam{margin-bottom:16px}
.pn-fam-hd{display:flex;align-items:center;gap:8px;width:100%;text-align:left;line-height:1.5;
  background:var(--paper-3);border:1px solid var(--line);border-radius:var(--radius-sm);
  padding:8px 16px;font-family:inherit;font-size:13px;font-weight:700;color:var(--navy);cursor:pointer}
.pn-fam-hd:hover{background:var(--paper-4);border-color:var(--amber)}
.pn-fam-arw{display:inline-block;width:12px;flex:none;font-size:12px;color:var(--muted);transition:transform .15s}
.pn-fam-hd[aria-expanded="true"] .pn-fam-arw{transform:rotate(90deg)}
.pn-fam-t{flex:none;letter-spacing:.2px}
.pn-fam-s{margin-left:auto;min-width:0;font-size:12px;font-weight:400;color:var(--muted);
  text-align:right;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pn-fam-s b{color:var(--navy-700);font-weight:600}
.pn-fam-s .pn-fam-warn{color:var(--bad);font-weight:700}
.pn-fam-bd{padding:16px 2px 0}
.pn-fam-bd > .card:last-child{margin-bottom:0}
/* 父 / 子 徽标 + 子块的「已设 N 条」摘要 */
.pn-bdg{font-size:12px;font-weight:700;padding:2px 8px;border-radius:999px;letter-spacing:.2px;white-space:nowrap}
.pn-bdg-def{background:rgba(11,31,58,.08);color:var(--navy-700)}
.pn-bdg-ovr{background:rgba(201,146,45,.20);color:var(--amber-600)}
.pn-bdg-n{font-size:12px;font-weight:400;color:var(--muted);white-space:nowrap}
/* 子块折叠头：虚线隔开，不跟卡片标题抢视觉 */
.pn-sub-hd{display:flex;align-items:center;gap:8px;width:100%;text-align:left;line-height:1.5;
  background:none;border:0;border-top:1px dashed var(--line);padding:8px 2px 2px;
  font-family:inherit;font-size:13px;color:var(--navy);cursor:pointer}
.pn-sub-hd:hover{color:var(--amber-600)}
.pn-sub-hd[aria-expanded="true"] .pn-fam-arw{transform:rotate(90deg)}
.pn-sub-t{flex:none;font-weight:600}
.pn-sub-s{font-size:12px;color:var(--muted)}

/* ══ v68.2 参数页减负（Donny 2026-09-18「参数与有效期 信息过载了」）══════════════════
   两处折叠：两张必录表（`.mq-tbl-fold`）+ 卡片说明段（`.hint-fold`）。
   ⚠️⚠️ **故意用「高度裁剪」而不是 `display:none`** —— 实测（`_tmp/probe_fold.py`）：
        · 高度裁剪：`inner_text()` 读得到全文 ✅ · Playwright `count()` 正常 ✅
        · display:none：`inner_text()` 也读得到 ✅ **但 `count()` 变 0** ❌
        而 `verify_roles` / `verify_freshness` 有一批断言正是靠 `#pn_mq_tbody_* tr` 的
        `count()` 数行数 / 数行内按钮 → 换成 display:none 会**一次改崩十几条断言**。
        （`is_visible()` 在裁剪下会谎报 true —— 但这两块**没有** is_visible 断言。）
   留痕族不用这里：它继续用 `.hidden`，因为 `verify_roles` 正是靠 `.pn-fam-bd.hidden`
   的 count 断言"收起态"。 */
/* ══ v76：必录买卖箱价格表按角色分两段 —— 段标题行 / 空段提示行 ══════════════════
   视觉语言**复用行情表的 `tr.mk-grp.lv1`**（米灰底 + 左侧琥珀竖条），
   两张表同一套分组长相，他不用重新学。
   ⚠️ 这两行是**静态标签**，不可点（不是折叠头）→ **不给 cursor:pointer、不给 hover**，
      否则又是一个「看着能点、点了没反应」的假按钮。 */
tr.mq-role-grp>td{background:var(--tint-fold);padding:8px 16px;border-top:1px solid var(--line);
  font-size:12px;font-weight:600;color:var(--navy);user-select:none}
tr.mq-role-grp:first-child>td{border-top:0}
tr.mq-role-grp[data-role="pick"]>td{box-shadow:inset 3px 0 0 var(--amber)}
tr.mq-role-grp[data-role="drop"]>td{box-shadow:inset 3px 0 0 var(--navy)}
tr.mq-role-empty>td{padding:8px 16px;font-size:12px;color:var(--muted);background:var(--color-surface)}
.mq-tbl-fold{max-height:0;overflow:hidden;transition:max-height .22s ease}
.mq-tbl-fold.open{max-height:6000px}       /* 40 行 ≈ 2900px，留足余量 */
/* v95（Donny 2026-09-24）：「必录价格里面这个展开明细不够突出，有时候甚至会被人忽略」
   —— 原来它是**没有背景的 flex 文字行**（`.pn-sub-hd` 只管 hover 变色），看着像纯文字、
   不像"能点开的东西"。给**按钮感**：浅底 + 细边 + 圆角 + 加粗 + 箭头染色。
   ⚠️ 只用中性色（`--paper-*` / `--line` / `--slate-400`），**不抢矩阵的色** ——
      他的硬原则是颜色克制、一屏不能有两个焦点；这块是「入口」不是「内容」。
   ⚠️ 只改外观：`id` / `class` / 文案（`mqTableToggle` 会动态换「展开/收起明细」）**一字未动**。 */
.mq-tbl-hd{margin-top:6px;border:1px solid var(--line);border-radius:6px;
  background:var(--paper-2);padding:6px 10px;cursor:pointer}
.mq-tbl-hd:hover{background:var(--paper-3);border-color:var(--slate-400)}
.mq-tbl-hd[aria-expanded="true"]{background:var(--paper-1);border-color:var(--slate-400)}
.mq-tbl-hd .mq-tbl-t{font-weight:700;color:var(--navy)}
.mq-tbl-hd .pn-fam-arw{color:var(--amber-600)}
.mq-tbl-hd .pn-sub-s b{margin-left:4px;color:var(--navy)}
/* v94（Donny 2026-09-23）：租赁折叠头那句「· 每行可改规格」——
   **收起状态也得看得见入口**（表默认收起，收起时看不见里面有什么 → 等于没做）。
   ⚠️ 比主数（`已纳入 42 个`）**更轻**：小一号、更浅，不抢主数、只是"指路"，符合他
      「颜色克制、留白合理」的要求；hover 才亮起来，平时不叫。
   ⚠️ 定语在后面（`margin-left`）而不是让主数跟它挤在一起 —— 主数是重点，先读到。 */
.mq-tbl-hd .mq-ov-hintwrap{margin-left:6px;font-size:11px;color:var(--muted);opacity:.75;
  transition:opacity .15s ease,color .15s ease}
.mq-tbl-hd:hover .mq-ov-hintwrap{opacity:1;color:var(--navy)}

/* ══ v69：「① 统一设置」折叠（Donny 2026-09-18「统一设置的箱型箱况这个功能都要能折叠」）═══════
   手法 = **高度裁剪**（max-height 0 ⇄ 60em），**不是** `display:none` / `.hidden`。
   两个理由，都在 app.js `mqDefSet` 上方写了长注释，这里只留结论：
     ① display:none 会让 Playwright 的 `.count()` 变 0 —— 套件里有一批断言靠它数复选框，
        会一次打崩好几条（实测见 `_tmp/probe_fold.py`）；
     ② 外层 `#pn_mq_def_sec_*` 自己就被 `renderMustDefBlock` 用 `.hidden` 表示
        「后端没登记这类参数」→ 共用同一个 class **必打架**。
   ⚠️ 已知特性：高度裁剪下 `is_visible()` 会**谎报 True**。所以折叠**不能靠 is_visible 判**，
      套件里单列了一条断言量 `fold_h` 与 `aria-expanded`。 */
.mq-def-hd{flex:1 1 auto;min-width:0;display:flex;align-items:center;gap:8px;
  background:none;border:0;padding:0;margin:0;cursor:pointer;
  font:inherit;color:inherit;text-align:left}
/* 标题沿用 `.mq-sub-hd>b` 那款浅底小标签 —— 折叠头把这个 `<b>` 收进了 button 里，
   不再是 `.mq-sub-hd` 的直接子元素，所以得单独补一份同样的样式。 */
.mq-def-hd>b{font-size:12px;color:var(--navy);flex:0 0 auto;
  background:rgba(11,31,58,.06);border-radius:6px;padding:2px 8px}
.mq-def-hd:hover>b{background:rgba(11,31,58,.1)}
.mq-def-hd .pn-fam-arw{flex:0 0 auto;transition:transform .18s ease}
.mq-def-hd[aria-expanded="true"] .pn-fam-arw{transform:rotate(90deg)}
/* 摘要：收起时它就是「这块现在盯什么」的唯一线索 → 单行省略，别换行把折叠头撑高 */
.mq-def-sum{flex:1 1 auto;min-width:0;color:var(--muted);font-size:12px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* ═══ v81c（Donny 2026-09-21）：「显示顺序」卡折叠（**高度裁剪**，不是 display:none）═══
   为什么必须高度裁剪：`verify_roles` 有一批 `#pn_order_rows .pn-ord` / `.pn-chip` 的
   **count 断言** —— display:none 会让 count() 变 0（v68.2 实测定的口径）。
   手法与 `.mq-tbl-fold` / `.mq-def-fold` 逐字相同：`max-height:0` → `.open` 撑开。 */
.pn-card-fold{max-height:0;overflow:hidden;transition:max-height .22s ease}
.pn-card-fold.open{max-height:60em}
/* 「显示顺序」的折叠头：借用 `.pn-sub-hd` 的虚线隔断语言，但要跟同一行右侧的
   「保存」按钮 + `count` 并排 —— 所以 flex:1 吃掉剩余宽度，虚线只留在下方。
   ⚠️ 它是个 <button>，所以 `text-align:left` + `font:inherit` 必给（不然浏览器默认居中 + 丑字体）。 */
.pn-card-fold-hd,.card .list-head .pn-card-hd{flex:1 1 auto;min-width:0;border-top:0;
  padding:0;margin:0;font:inherit;font-size:13px;font-weight:700;color:var(--navy);
  background:none;display:flex;align-items:center;gap:8px;text-align:left;cursor:pointer}
.card .list-head .pn-card-hd:hover .pn-sub-t{color:var(--amber-600)}
.pn-card-hd[aria-expanded="true"] .pn-fam-arw{transform:rotate(90deg)}
.mq-def-fold{max-height:0;overflow:hidden;transition:max-height .22s ease}
.mq-def-fold.open{max-height:60em}
.mq-def-note{margin:8px 0 8px}

/* ══ v69：「有效期」小卡（从撤掉的「价格有效期」族搬进各块）═══════════════════════════
   一道浅色左边条，跟「① 统一设置」「增加地点」「按地点/线路单独设」区分开：
   这一块填的是**数字**（天数），那几块是**勾选/对象表**。
   ⚠️ 颜色刻意与 `.mq-sub.is-dirty` 的琥珀色条区分（那条表示「有未保存草稿」）。 */
.mq-fresh{box-shadow:inset 3px 0 0 rgba(11,31,58,.12);padding-left:8px}
.hint-fold .hint-bd{max-height:1.6em;overflow:hidden;transition:max-height .22s ease}
.hint-fold.open .hint-bd{max-height:60em}
.hint-more{background:none;border:0;padding:0;margin:2px 0 0;font-family:inherit;
  font-size:12px;color:var(--amber-600);cursor:pointer}
.hint-more:hover{text-decoration:underline}

/* ══ v73：报价调节「规则行就地展开线路」（Donny 2026-09-19）═══════════════════════════
   一条规则（目的地 × 箱型 × 箱况）下面就地铺出它管到的每条线路（起点 → 目的地）。
   从属关系靠 ①浅底 ②左侧琥珀竖线 ③缩进 三样表达；子表本身弱化（无边框小字表头 + 极细虚线）。
   ⚠️ 只有 `.sr-lines-row`（挂着数据的子行）和 `.sr-line`（子表里的线路行）——
      政策行、组头行的样式一个都没碰。 */
.sr-lines-btn{display:inline-flex;align-items:center;gap:4px;padding:2px 8px;height:26px;
  border:1px solid var(--border);background:var(--color-surface);border-radius:999px;color:var(--navy);
  font:inherit;font-size:12px;font-weight:600;cursor:pointer;white-space:nowrap}
.sr-lines-btn:hover{border-color:var(--amber);background:var(--tint-warn-faint)}
.sr-lines-btn.on{border-color:var(--amber);background:var(--tint-warn-mid);color:var(--gold-700)}
.sr-lines-btn b{font-weight:800}
.sr-tri{font-size:12px;opacity:.75;line-height:1;display:inline-block}
/* 子行整块：`colspan=11` 一格装一张小表；td 自身不留内边距（内边距交给 .sr-lines） */
.sr-lines-row>td{padding:0;background:var(--paper-1);border-top:1px dashed var(--line)}
.sr-lines{margin-left:8px;padding:8px 16px 8px 16px;border-left:3px solid var(--amber)}
/* ⚠️ 子块里的 `.cell-sub` 要允许换行 —— 上面 `#rules_card .cell-sub{white-space:nowrap}`
   是为了窄列不折行，但子块的说明句整段 nowrap 会撑成一条长线。 */
.sr-lines .cell-sub{white-space:normal}
.sr-lines-hd{font-size:12px;color:var(--slate);line-height:1.55;margin-bottom:8px}
.sr-lines-hd b{color:var(--navy);font-weight:700}
.sr-lines-tb{width:100%;border-collapse:collapse}
.sr-lines-tb th{font-size:12px;font-weight:600;color:var(--muted);text-align:left;
  padding:4px 8px 4px;border-bottom:1px solid var(--line);white-space:nowrap}
.sr-lines-tb td{padding:4px 8px;border-bottom:1px solid var(--paper-3);vertical-align:top;
  font-size:13px;white-space:nowrap}
.sr-lines-tb tr:last-child td{border-bottom:0}
.sr-lines-tb td.rt-cell{white-space:nowrap}
/* 子表里的输入框比政策表宽一档（列多，太窄敲不进 4 位数）——
   ⚠️ 必须带 `#rules_card` 才盖得住 `#rules_card input.st-th{width:72px}`（见文件头注释）。 */
#rules_card .sr-lines-tb input.st-th.sr-in{width:88px;min-width:88px;padding:0 8px;height:28px}
/* ══════════════════════════════════════════════════════════════════════════════
   v78 · 「定价策略」页整页横向溢出收口（Donny 2026-09-21 选「收窄列，保住表头吸顶」）
   ─────────────────────────────────────────────────────────────────────────────
   现象：`#rules_card` 里的规则表 11 列合计 1413.6px，而卡片只有 1200px 宽
        （表格 x=145 / 卡片 x=120）→ 文档 scrollWidth 1559 vs clientWidth 1440 = **溢出 119px**，
        整页能往右拖出一条空白。
   为什么不用横滚：`overflow-x:auto` 会把 `overflow-y` 的计算值也变成 auto ⇒
        横滚容器里的表 `thead th{position:sticky;top:0}` **吸不动**（见文件头那段机制注释）。
        他明确选「保住表头吸顶」→ 只能收窄列。
   收窄只作用于 `#rules_card` —— **不动全局 `tbody td{padding:12px 16px}`**，
        那是全站 31 张表共用的，改它会连带所有页面一起变挤。
   压缩点（左右各算一次）：
     ① 表内单元格 16 → 10px（th/td 都收，含表头，否则表头与数据列对不齐）
     ② 三个操作按钮 0 16px → 0 10px
     ③ 操作按钮间距 8 → 6px
     ④ 行内数字/下拉框 72/74/78 → 66px，让「终点箱价/毛利/年化」这几种内容列自己收缩
   ⚠️ 内边距必须 th / td **同步收**，只收一边会让表头文字与数据错位（规范第 12 层「对齐」）。
   ══════════════════════════════════════════════════════════════════════════════ */
#rules_card thead th{padding:8px 10px}
#rules_card tbody td{padding:12px 10px}
/* 新建行原本是 8px 内边距 → 与新行对齐取同一值，避免"新建行更贴边"的视觉不一致 */
#rules_card #sr_new_row td{padding:8px 10px}
/* 操作列：三个按钮（编辑 · 暂停/恢复 · 删除）收内边距与间距。
   ⚠️ 收的是**左右**内边距，按钮高度仍由 `.sr-hold/.sr-del/.sr-edit{height:28px}` 定，
      再被 v77b 的 `min-height:36px` 兜底抬到 36px 高 —— 可点目标仍 ≥36×36（规范第 9 层）。 */
#rules_card .sr-ops button{padding:0 10px}
#rules_card .sr-ops button + button{margin-left:6px}
/* 数字框与下拉框收 6px：`.st-th` 基础 96px 在规则表里本就压到 78/74/72，
   再收 6px 让「买租差 / 存费 / 净投入 / 毛利 / 年化」五列各让一点，凑齐剩余缺口。 */
#rules_card input.st-th,#rules_card select.st-th{width:72px;min-width:72px}
#rules_card select.st-th{width:68px;min-width:68px}
#rules_card input.st-th{width:66px;min-width:66px}
/* 编辑态的目的地输入框跟着收（原 112px，它是 6 列里最宽的输入框） */
#rules_card tr[data-editing="1"] input#er_dest{width:104px;min-width:104px}
/* 「覆盖线路」那枚 `N 条线路` 按钮（.sr-lines-btn）收内边距，它是 119.6px 列的撑宽者之一 */
#rules_card .sr-lines-btn{padding:0 8px}
/* 目的地列：`+新增城市` 小按钮（.btn-mini）收内边距 */
#rules_card .btn-mini{padding:0 8px}
/* ══════════════════════════════════════════════════════════════════════════════
   v79 · 可折叠说明块（.note-fold）—— 「说明小字别挡着干活」
   ─────────────────────────────────────────────────────────────────────────────
   Donny 2026-09-21：「这些说明的小字已经严重影响到我工作了　折叠起来　在我需要了解
   某个功能的时候我点击再弹出来」。⇒ **默认收起**，点标题展开，记住他的选择。
   用在哪（本轮 2 处，都是"每次都占着屏幕、但一天只读一次"的说明）：
     · 定价策略 · 公式与规则（10 段 1161 字 → 746px）
     · 报价调节 · 怎么用（851 字 → 192px）
   ⚠️ **一个字都没删**：全部原文搬进 `.note-fold-bd`，点开就是原样。
   ⚠️ 用 `.hidden`（display:none）折叠 —— 这两处**没有** `count()` 断言，
      不是必录表（必录表才必须用高度裁剪，见文件头那条注释）。
   ⚠️ 按钮热区 ≥36px 高（规范第 9 层）；箭头 / 标题 / 副标题三件套一次成型。
   ══════════════════════════════════════════════════════════════════════════════ */
.note-fold{margin:16px 0 4px}
/* v115 筛选折叠壳：贴在卡片内容顶部，间距比文案折叠更紧；徽标弱化不抢眼 */
.flt-fold{margin:2px 0 10px}
.flt-fold .note-fold-bd{padding-top:6px}
.flt-badge{color:var(--amber,#C9922D);font-weight:600}
.note-fold-hd{display:flex;align-items:center;gap:8px;width:100%;min-height:36px;
  padding:6px 12px;border:1px solid var(--color-border-soft);border-radius:6px;
  background:var(--paper-warm);color:var(--navy);font-family:inherit;font-size:13px;
  font-weight:600;text-align:left;cursor:pointer;transition:.15s}
.note-fold-hd:hover{background:var(--color-warning-bg);border-color:var(--amber)}
.note-fold-hd:focus-visible{outline:none;border-color:var(--amber);
  box-shadow:0 0 0 2px var(--ring-amber)}
.note-fold-arw{flex:none;width:12px;color:var(--gold-700);font-size:11px;
  transition:transform .15s;display:inline-block}
.note-fold[data-open="1"] .note-fold-arw{transform:rotate(90deg)}
.note-fold-ttl{flex:none;color:var(--gold-700)}
.note-fold-sub{flex:1;min-width:0;font-weight:400;font-size:12px;color:var(--color-text-muted);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.note-fold-hint{flex:none;font-size:12px;font-weight:400;color:var(--gold-700)}
/* 展开后的内容区：把原说明块的内层样式继续用（.st-spec 自带上边距，这里抹平） */
.note-fold-bd{padding-top:8px}
.note-fold-bd>.st-spec{margin-top:0}

/* ═══ v80（Donny 2026-09-21）：「参数与有效期」说明小字默认收起，点 ? 就地弹出 ═══
   实测依据：面板 3672px = 4.08 屏，说明小字 38 块 919px 占 25%，其中 .cell-sub 17 块是最大头。
   ⚠️ 作用域严格锁在 `#pn_pane_param` —— `.fld` / `.cell-sub` 都是**全站通用**类，
      改它们会连锁到录入页、批量表、行情页（那边的小字是**数据状态**不是说明，绝不能收）。
   ⚠️ `.pn-help-bd[hidden]` 用 `display:none` 收 —— 这里**没有 count 断言**
      （verify_roles 只数 `.pn-fam-bd`），所以安全；`.hidden` 类那种手法留给留痕族。 */
#pn_pane_param .pn-help-box{position:relative;display:flex;justify-content:flex-end;min-height:22px;margin-top:2px}
#pn_pane_param .pn-help-q{flex:none;width:22px;height:22px;padding:0;border:1px solid var(--border);
  border-radius:50%;background:var(--paper);color:var(--muted);font-family:inherit;font-size:12px;
  font-weight:600;line-height:1;cursor:pointer;transition:.15s}
#pn_pane_param .pn-help-q:hover{background:var(--color-warning-bg);border-color:var(--amber);color:var(--gold-700)}
#pn_pane_param .pn-help-q:focus-visible{outline:none;border-color:var(--amber);box-shadow:0 0 0 2px var(--ring-amber)}
#pn_pane_param .pn-help-q[aria-expanded="true"]{background:var(--color-warning-bg);border-color:var(--amber);
  color:var(--gold-700);border-radius:50%}
#pn_pane_param .pn-help-bd{margin-top:6px;padding:8px 10px;border-left:2px solid var(--amber);
  border-radius:0 6px 6px 0;background:var(--paper-warm);font-size:12px;line-height:1.7;
  color:var(--color-text-muted);text-align:left}
#pn_pane_param .pn-help-bd b{color:var(--navy);font-weight:600}
/* ⚠️ v81b（2026-09-21）：下面这条工具条**已撤销**（模板里的节点已删）——
   族级 `?` 取代了它。样式暂时留着不删：万一要回滚，模板改回来即可生效。 */
#pn_pane_param .pn-help-bar{display:flex;align-items:center;gap:12px;margin:0 0 12px;
  padding:8px 12px;border:1px solid var(--color-border-soft);border-radius:6px;background:var(--paper-warm)}
#pn_pane_param .pn-help-bar-t{flex:1;min-width:0;font-size:12px;color:var(--color-text-muted)}
#pn_pane_param .pn-help-bar-t b{color:var(--gold-700)}
/* 块头的「展开全部说明」按钮：文字按钮，跟 `.hint-more` 同一套视觉语言 */
#pn_pane_param .pn-help-all{flex:none;padding:4px 10px;border:1px solid var(--border);
  border-radius:6px;background:var(--paper);color:var(--gold-700);font-family:inherit;
  font-size:12px;font-weight:600;cursor:pointer;transition:.15s}
#pn_pane_param .pn-help-all:hover{background:var(--color-warning-bg);border-color:var(--amber)}
#pn_pane_param .pn-help-all:focus-visible{outline:none;border-color:var(--amber);box-shadow:0 0 0 2px var(--ring-amber)}

/* ═══ v81b（Donny 2026-09-21）：族头一枚 `?`，统一开合本族说明 ══════════════════
   他原话：「不要在每个按钮旁边放问号 在板块那里放一个问号就行了 统一打开关闭」+「族头」。
   ⇒ 13 枚字段级 `?` 已撤（模板），换成每个族头一枚。

   ⚠️ `.pn-fam-s` 已被 `margin-left:auto` 顶到右边 —— `?` 排在它**之后**，自然贴最右端；
      两块之间靠 gap 留 10px，不会黏在一起。
   ⚠️ `?` 是 `span[role=button]` 而**不是 `button`** —— 族头本身就是 `<button>`，
      里面再放 `<button>` 是**非法 HTML**（浏览器会把它拆出去、DOM 结构错乱）。
      键盘可达靠 `tabindex` + `onkeydown` 自己接（`pnFamHelpKey`）。
   ⚠️ 折叠手法：`.pn-fam-help[hidden]` 用 `display:none` —— 这里**没有 count 断言**
      （族人说明不是必录表），安全。 */
.pn-fam-q{flex:none;width:20px;height:20px;margin-right:-4px;display:inline-flex;
  align-items:center;justify-content:center;border:1px solid var(--border);border-radius:50%;
  background:var(--paper);color:var(--muted);font-size:11px;font-weight:700;line-height:1;
  cursor:pointer;transition:.15s;user-select:none}
.pn-fam-q:hover{background:var(--color-warning-bg);border-color:var(--amber);color:var(--gold-700)}
.pn-fam-q:focus-visible{outline:none;border-color:var(--amber);box-shadow:0 0 0 2px var(--ring-amber)}
.pn-fam-q[aria-expanded="true"]{background:var(--color-warning-bg);border-color:var(--amber);color:var(--gold-700)}
/* 族级说明清单：术语 + 一句话，横向两列（术语列固定宽 → 各行说明对齐） */
.pn-fam-help{margin:0 0 12px;padding:10px 14px;border-left:2px solid var(--amber);
  border-radius:0 6px 6px 0;background:var(--paper-warm);font-size:12px;line-height:1.7;
  color:var(--color-text-muted)}
.pn-fam-help-t{font-size:12px;font-weight:700;color:var(--navy);margin-bottom:6px;
  padding-bottom:6px;border-bottom:1px solid var(--color-border-soft)}
.pn-fam-help-dl{display:grid;grid-template-columns:minmax(96px,auto) 1fr;gap:6px 14px;margin:0}
.pn-fam-help-dl dt{font-weight:600;color:var(--navy-700);white-space:nowrap}
.pn-fam-help-dl dd{margin:0;min-width:0}
.pn-fam-help-dl dd b{color:var(--navy);font-weight:600}
.pn-fam-help-dl dd br{display:none}   /* 说明里若带换行 → 折成同段（清单式不要散行） */

/* v81b：参数字段旁的说明体（**无 `?` 按钮**）—— 由族头 `?` 统一开合。
   ⚠️ 它取代了 v80 的 `.pn-help-box`（那个带一枚散 `?`）—— 他要「不要在每个按钮旁边放问号」。
   ⚠️ `[hidden]` → `display:none`，不占位；展开时按 `.pn-help-bd` 同一套视觉（左侧琥珀竖线）。
   ⚠️ 这里**没有 count 断言**，用 display:none 安全。 */
.pn-help-inline{margin:4px 0 0;padding:7px 10px;border-left:2px solid var(--amber);
  border-radius:0 6px 6px 0;background:var(--paper-warm);font-size:12px;line-height:1.7;
  color:var(--color-text-muted)}
.pn-help-inline b{color:var(--navy);font-weight:600}   /* 说明里若带换行 → 折成同段（清单式不要散行） */



/* ══════════════════════════════════════════════════════════════════════════
   v81d（Donny 2026-09-21）：「板块内统一设置（本板块默认）+ 行内单独设置」
   两个东西两处样式：
     · `.mq-fresh-blk` —— 板块「① 统一设置」里那一行"本板块默认有效期"
     · `.mq-days-*`    —— 明细表「有效期」列那个可点小按钮 + 点开后的行内输入
   ⚠️ 别用 `display:none` 藏任何可数元素 —— 本项目断言大量用 `count()`。
   ══════════════════════════════════════════════════════════════════════════ */
.mq-fresh-blk{border-top:1px dashed var(--line,#e6e8ee);margin-top:8px;padding-top:8px}
.mq-fresh-blk .fld label{color:var(--ink-2,#5a6472)}

/* ══════════════════════════════════════════════════════════════════════════
   v83（Donny 2026-09-21）：「业务参数里面所有小字都需要折叠　所有」
   ──────────────────────────────────────────────────────────────────────────
   板块「① 统一设置」里那一行说明（`这一块里没单独设过的…出厂 N 天`）**跟着容器一起收**：
     · 容器 `.mq-def-fold` 收着（没有 `.open`）→ 说明藏起来
     · 容器撑开（`.open`）→ 说明跟着出来
   ⇒ **不额外给一枚按钮**：那个容器本来就有折叠头（`mqDefToggle`），一个容器一个开关，
      再挂一枚就成了"两枚开关管同一件事"（他会问"到底点哪个"）。
   ⚠️ 用 `display:none` 藏 —— 这三段**没有 `count()` 断言**（已扫全部套件确认），安全。
   ⚠️ 作用域只在 `.mq-fresh-blk` 内、且只打 `.blk-sub` 这个新加的类 ——
      `.cell-sub` 是全站通用（录入页/行情页/明细表都用），**绝不能**碰它本身：
      别的页面那些小字是**数据状态**（"先录该目的地箱价"），不是说明书，收了就把信息藏没了。 */
.mq-fresh-blk .cell-sub.blk-sub{display:none}
.mq-def-fold.open .mq-fresh-blk .cell-sub.blk-sub{display:block}

td.mq-days,th.mq-th-days{white-space:nowrap;width:1%}
.mq-days-btn{display:inline-flex;align-items:center;gap:6px;cursor:pointer;
  border:1px solid var(--line,#e6e8ee);background:#fff;border-radius:8px;
  padding:3px 9px;font:inherit;color:var(--ink-2,#5a6472);line-height:1.5}
.mq-days-btn:hover{border-color:var(--brand,#C9922D);color:var(--brand-ink,#8a6316)}
.mq-days-btn .mq-days-n{font-weight:700;color:var(--ink,#22303f)}
/* 「自设」标记 —— 与"跟板块默认"必须一眼可分（前者是例外，要能被打眼找到） */
.mq-days-btn.is-own{border-color:var(--brand,#C9922D);background:#fffdf5}
.mq-days-tag{font-size:11px;padding:0 5px;border-radius:6px;
  background:var(--brand,#C9922D);color:#fff}
/* 点开后的行内编辑：输入框 + 保存 + 清除 + ×
   ⚠️⚠️ 这层容器 `.mq-days-in-w` 与**按钮同级**（都是 `td.mq-days` 的孩子）——
      绝不能把输入框塞进 `<button>` 里（非法嵌套，浏览器会提前闭合父按钮，
      实测症状：清除后输入框不收起、class 停在 `is-own is-open`）。见 app.js `daysCell`。
   ⚠️ `.mq-days-btn.is-open` 保留只为兼容旧样式引用；v81d 起开态不再用类名表达，
      而是"按钮整块被输入框区替换掉" → 那个类实际不会再出现（留着无害、别依赖它）。 */
.mq-days-in-w{display:inline-flex;align-items:center;gap:5px;
  border:1px solid var(--brand,#C9922D);background:#fffdf5;border-radius:8px;padding:2px 6px}
.mq-days-in{width:64px;padding:3px 6px;border:1px solid var(--line,#e6e8ee);
  border-radius:6px;font:inherit;text-align:right}
.mq-days-ok,.mq-days-clr,.mq-days-x{padding:2px 8px;font-size:12px;border-radius:6px}
.mq-days-x{padding:2px 7px;font-weight:700;line-height:1}


/* ═══ v81f（Donny 2026-09-21）：下方「新增目的地」＝ 下拉选组合 → 选中才出参数 → 保存生效 ═══
   原先是 20 行 11 列的大表（他说「不要点开的时候全部显示出来是提供地点给我选」）→ 整块换成
   一个下拉 + 选中后才长出的一行参数。类名一律 `sr-pick-*` / `sr-pk-*`，**不与主表共用**，
   避免动到已配规则那张表（它有 count 断言）。
   ⚠️ 折叠用 v79 的 `.note-fold`（`display:none` 收），这里没有 count 断言，安全。 */
.sr-pick-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin:2px 0 4px}
.sr-pick-lb{flex:none;font-size:13px;color:var(--color-text-muted)}
#sr_pick_sel{min-width:340px;max-width:520px}
#sr_pick_cnt{font-size:12px}
/* 选中后的参数行：**一行铺开**（他要求"选了之后才有设置"，不是另开一块大表） */
.sr-new-tb{margin-top:6px}
.sr-new-tb td{vertical-align:top}
.sr-new-tb th,.sr-new-tb td{padding-top:6px;padding-bottom:6px}
.sr-pk-key{font-weight:600;color:var(--brand,#C9922D)}
.sr-new-tb input.st-th{width:100%;min-width:72px;box-sizing:border-box}
.sr-new-tb .cell-sub{margin-top:2px}
.sr-new-act{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-top:10px}
.sr-new-act .btn-primary{height:32px;padding:0 16px}
.sr-new-act .muted{font-size:12px}

/* ══════════════════════════════════════════════════════════════════════════
   v85（Donny 2026-09-21）：待办页取消，缺价信息**辅助性并入**市场行情两张卡。
   他原话「显示的不要那么为主，辅助性的显示，视觉冲击力不要那么强，占用的版面不要那么大」。
   ⇒ 三件套：① 头部换成**细弱一行条**（不是主按钮）② 卡内清单**默认收起**、
      不再用琥珀左边线那种"强调"视觉 ③ 与卡片既有元素同色阶，不新增色。
   ⚠️ 只**追加**规则，不动上面 `.todo-*` 家族 —— 那套还要被这两处槽位复用。
   ══════════════════════════════════════════════════════════════════════════ */

/* ① 缺口细弱条：与 `.count` 同一行，视觉级别介于「小字」与「按钮」之间。
     刻意**不用** `.btn-primary`/`.btn-mini` —— 它是提示不是动作入口，别抢主按钮的注意力。 */
.mkt-gap-mini{
  flex:none; display:inline-flex; align-items:baseline; gap:4px;
  background:none; border:0; border-bottom:1px dashed var(--color-danger-line);
  padding:0 0 1px; margin:0; cursor:pointer;
  font-family:inherit; font-size:12px; color:var(--color-danger-text);
  transition:.15s;
}
.mkt-gap-mini b{font-size:13px;font-weight:700;font-variant-numeric:tabular-nums}
.mkt-gap-mini:hover{color:var(--color-danger);border-bottom-color:var(--color-danger)}
.mkt-gap-mini.hidden{display:none}

/* ② 卡内清单槽位 —— v87：已从「表格上方」搬到**表格下方**，
     所以气口从 `margin-top` 改成 `margin-bottom`（与上方表格拉开、与下方下半清单贴住）。 */
#ov_todo_slot,#rn_todo_slot{margin-bottom:4px}

/* ③ 卡内版「必须有的价」：去掉待办页那条**琥珀左边线**（那是"强调"手法，
     现在是辅助信息，不该有）；标题 h3 也不再出现，只留折叠头。 */
.todo-sec.todo-must-inline{
  border-left:0; padding-left:0; margin-left:0; margin-top:10px;
}
.todo-sec.todo-must-inline .todo-tools{
  margin:0 0 4px; padding-top:8px; border-top:1px dashed var(--line);
}
/* 工具行里那段说明文字很长（会换行）→ 限制它在右侧，别把三个按钮挤走 */
.todo-sec.todo-must-inline .todo-tools .cell-sub{
  flex:1 1 320px; min-width:0; margin-top:0; line-height:1.6;
}

/* ══════════════════════════════════════════════════════════════════════════
   v87（Donny 2026-09-22）：缺价明细**下移到表格下方 + 缩成一行**。
   他原话「我是跟你说，这个代办折叠起来放在举证表格的下面吗？为什么还是在上面？还是展开的？」
   ⇒ 复用 v79 的 `.note-fold`（样式全在，一个字没改），这里只补三处**尺寸差量**：
     ① 它默认的 `margin:16px 0 4px` 在卡里太空 → 收紧；
     ② 副标题要能坐住「118 项（41 已过期 · 77 从没录过）· 20 个地点」→ 单行省略；
     ③ 展开后的内容区不再补 padding（内层 `.todo-sec` 自己带上边距）。
   ⚠️ 折叠用 `.hidden`（display:none）—— 这块**没有 count 断言**，
     矩阵那批 `tr` 计数是另一处、走高度裁剪（见文件头那条），别混。
   ══════════════════════════════════════════════════════════════════════════ */
.mq-listfold{margin:10px 0 0}
.mq-listfold .note-fold-ttl{font-weight:700}
.mq-listfold .note-fold-sub b{font-weight:700;font-variant-numeric:tabular-nums}
.mq-listfold .note-fold-bd{padding-top:2px}
/* 展开后承接 v85 那条「这条是辅助信息」的分隔线（原来挂在常显的工具行上） */
.mq-listfold .note-fold-bd>.todo-sec{margin-top:2px}

/* ═══ v89（Donny 2026-09-22）：明细行勾选 + 统一设置批量应用 ══════════════════
   「每个单独的明细可以用勾选　选中后在统一设置里面批量设置」。
   ⚠️ 勾选列的宽度要**写死**（`2.2em`）—— 不写死的话表头勾选框与行内勾选框会因为
      不同行的内容宽度差而左右错位（他会立刻看出来）。 */
.mq-th-sel,.mq-sel-td{width:2.2em;min-width:2.2em;text-align:center;padding-left:8px!important;padding-right:0!important}
.mq-th-sel input,.mq-sel-td input{cursor:pointer;width:14px;height:14px;vertical-align:middle;margin:0}
/* 选中行高亮：用左侧一道色条 + 极浅底 —— 不抢色阶（矩阵那边一屏四档色已经够花） */
table.mtx tr.is-sel>td, table.mq-tbl tr.is-sel>td{background:#f3f7fd!important}
table.mtx tr.is-sel>td:first-child, table.mq-tbl tr.is-sel>td:first-child,
table.mtx tr.is-sel>td.mq-sel-td, table.mq-tbl tr.is-sel>td.mq-sel-td{box-shadow:inset 3px 0 0 var(--accent,#0B1F3A)}
/* ⚠️ hover 兜底（本项目铁律：`tr:hover td` 特异性 (0,2,4) 会压过单 class 选择器）
   → 不补这条，鼠标扫过时选中底色被冲成通用的 hover 色，他会以为"勾了没反应"。 */
table.mtx tbody tr:hover td.is-sel, table.mq-tbl tbody tr:hover td.is-sel{background:#eef5fd!important}

/* 「已选 N 行 · 应用到这里」状态栏 —— 0 行时整条 hidden（不占版面） */
.mq-selbar{display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  margin:0 0 10px;padding:8px 12px;border-radius:6px;
  background:#f3f7fd;border:1px solid #d3e2f5}
.mq-selbar.hidden{display:none}
.mq-selbar-t{font-weight:600;color:#0B1F3A}
.mq-selbar-t b{font-variant-numeric:tabular-nums;color:var(--accent,#0B1F3A)}
.mq-selbar-sub{color:#5b6b7f;font-size:12px}
.mq-selbar-sub b{color:#0B1F3A}
.mq-selbar-go{margin-left:auto}

/* ═══ v102 荣尚报价（销售版）═════════════════════════════════════════════
   Donny 2026-09-25：销售看荣尚价 + 箱子照片/年份/细节，供应商不体现。
   视觉：价格卡大字醒目（这是页面的主角）；现询行整体降淡；特价行金边。 */
#sell_copy{font-family:inherit;font-size:13px;line-height:1.8;padding:10px 12px;border:1px solid var(--color-border);
  border-radius:8px;background:var(--color-surface);color:var(--color-text);resize:vertical;min-height:220px}
.sell-group{margin-bottom:16px}
.sell-group .grp-t{margin-bottom:4px}
.sell-line{border:1px solid var(--color-border);border-radius:10px;padding:10px 14px;margin:8px 0;background:var(--color-surface)}
.sell-line-main{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}
.sell-org{font-weight:700;color:var(--color-text);font-size:14px}
.sell-spec{color:var(--color-text-muted);font-size:13px}
.sell-price{margin-left:auto;display:flex;align-items:baseline;gap:2px}
.sell-price .amt{font-size:20px;font-weight:800}
.sell-photos{display:flex;gap:8px;margin-top:8px;flex-wrap:wrap}
.sell-thumb{width:64px;height:64px;object-fit:cover;border-radius:8px;border:1px solid var(--color-border);
  cursor:pointer;background:var(--color-surface-alt)}
.sell-detail{margin-top:8px;font-size:13px;color:var(--color-text-soft);white-space:pre-wrap}
.sell-inq{opacity:.66}
.sell-special{border-color:var(--color-warning-line)}
/* v103 页内两标签（租赁报价/卖箱报价）：选中=深色主操作，未选中=白边，胶囊对齐 */
.sell-tabs{display:flex;gap:8px;margin-bottom:12px}
.sell-tab{padding:9px 26px;border:1px solid var(--color-border);border-radius:8px;background:var(--color-surface);
  cursor:pointer;font-size:14px;font-weight:600;color:var(--color-text-soft);transition:background .15s,color .15s}
.sell-tab:hover{border-color:var(--color-brand)}
.sell-tab.on{background:var(--navy);border-color:var(--navy);color:#fff}

/* ═══ v110 对手方 ═══ */
.cp-link{color:var(--navy);font-weight:600;cursor:pointer;border-bottom:1px dotted var(--color-border-cool)}
.cp-link:hover{color:var(--amber);border-bottom-color:var(--amber)}
.cp-star{color:var(--amber);font-size:12px;letter-spacing:1px}
.cp-role{display:inline-block;padding:0 6px;margin-right:4px;border:1px solid var(--color-border-soft);
  border-radius:5px;font-size:12px;color:var(--muted);white-space:nowrap}
.cp-coop{color:#1a7f37;font-size:12px;font-weight:600}
/* ═══ v104 细节收口到货源 ═══════════════════════════════════════════════
   货源下钻清单：选中=金边突出；过期=沉底灰显（看得见但选不了）；计均=淡黄底（沿用）。 */
.drill-tbl tr.picked td{background:var(--color-warning-bg);border-top:1px solid var(--color-warning-line)}
.drill-tbl tr.picked td:first-child{box-shadow:inset 3px 0 0 var(--color-warning-line)}
.drill-tbl tr.expired td{opacity:.45}
.drill-tbl tr.expired td .amt,.drill-tbl tr.expired td b{text-decoration:line-through}
.drill-tbl tr.expired+.expired td{border-top:1px dashed var(--color-warning-line)}
/* 覆盖线路子行：选定货源的详情卡摘要（小字、克制，不加重行高） */
.pick-sum{margin-top:2px}
.pick-sum .cf-sum{font-size:12px;color:var(--color-text-soft)}
/* 特价按钮：开=琥珀描边（与「特价」标签同族色），不抢主操作的风头 */
.st-drill-btn.sp-on{border-color:var(--color-warning-line);color:var(--color-warning-text);font-weight:700}
/* v102 细节弹窗：特价勾选框（浏览器默认大蓝框不合 UI 硬原则，压成小方框） */
#mask_lsi label.lsi-spec-row{display:flex!important;align-items:center;gap:8px;font-weight:500;cursor:pointer;justify-content:flex-start;text-align:left;width:100%}
#lsi_special{width:15px;height:15px;min-width:0;accent-color:var(--color-brand);flex:none;margin:0;cursor:pointer}
/* ══ v112 询价指路 ══ */
/* 下钻头部：家数进度 + 基准选择 */
.drill-head{display:flex;align-items:center;gap:10px;margin:0 0 6px}
.cover-pill{display:inline-block;font-size:12px;font-weight:600;padding:2px 10px;border-radius:10px;white-space:nowrap}
.cover-pill.ok{background:rgba(46,125,50,.12);color:#2e7d32}
.cover-pill.short{background:rgba(191,54,12,.12);color:#bf360c}
.bl-sel{font-size:12px;padding:2px 6px;border:1px solid var(--line);border-radius:6px;background:var(--color-surface);color:var(--navy);max-width:220px}
/* v112b：先问标（合作过的对手方——询价优先） */
.ask-first{display:inline-block;font-size:11px;font-weight:700;padding:1px 7px;border-radius:9px;background:rgba(46,125,50,.14);color:#2e7d32;white-space:nowrap;vertical-align:middle}
/* ══ v113 必录对手方 + 待办「找谁问」+ 线路目标 ══ */
/* 对手方列表名称旁「必录」小标（深色底=固定名单，跟主按钮同色系） */
.must-chip{display:inline-block;font-size:11px;font-weight:700;padding:1px 7px;border-radius:9px;background:var(--navy,#0B1F3A);color:#fff;white-space:nowrap;vertical-align:middle}
/* v113.4：必录改为列表行一键开关（button）——on=实心深色带 ✕，off=灰描边 + 必录 */
button.must-chip{cursor:pointer;border:none;font-family:inherit;line-height:1.6}
button.must-chip.on{background:var(--navy,#0B1F3A);color:#fff}
button.must-chip.off{background:transparent;color:var(--muted,#8a93a3);border:1px dashed var(--line,#d5dbe3);padding:0 6px}
/* v114 批量操作栏（军规 #30）：勾选≥1 浮出，贴在列表卡头部下方 */
.bulk-bar{display:flex;gap:8px;align-items:center;padding:8px 12px;margin:8px 0;border:1px solid var(--navy,#0B1F3A);border-radius:8px;background:rgba(11,31,58,.05)}
.bulk-bar.hidden{display:none}
.bulk-bar .bulk-n{font-size:13px;color:var(--navy,#0B1F3A);min-width:64px}
.btn-danger-ghost{border:1px solid #c0392b;color:#c0392b;background:transparent;border-radius:6px;padding:5px 12px;font-size:13px;cursor:pointer}
.btn-danger-ghost:hover{background:rgba(192,57,43,.08)}
/* 目标下拉与基准下拉同款，略窄（0-4 数字项） */
select.bl-sel.tgt-sel{max-width:190px}
/* 待办缺价行「找谁问 ▾」的就地展开行：贴在当前行下面，弱化边框不抢视线 */
.mq-ask-row>td{padding:0 8px 8px 26px;background:transparent}
.mq-ask-row .st-drill-body{border:1px solid var(--line);border-radius:8px;padding:8px 10px;margin-top:2px}
.mq-ask-row .drill-tbl{margin:0}

/* v116：顶栏登录身份 + 改密入口 */
.userbox{font-size:13px;font-weight:500;color:var(--navy,#0B1F3A);white-space:nowrap;vertical-align:middle}
.btn-pw{font-size:12px;padding:2px 10px;white-space:nowrap;vertical-align:middle}
