
:root{
  /* 鸿蒙 HarmonyOS UI · 浅灰紫底 · 蓝紫主色 · 大圆角卡片 · 柔和投影 */
  --page:#ECEEFB;            /* 工作区底，淡蓝紫 */
  --bg:#ffffff;              /* 卡片/面板底 */
  --panel-2:#F0F2FC;         /* 内嵌：表头/输入框/浅底块 */
  --border:rgba(23,28,82,.08); /* 发丝线（蓝灰） */
  --ink-1:#1A1C38;           /* 标题、大数字（蓝黑） */
  --ink-2:#3B3F59;           /* 正文、表格单元 */
  --ink-3:#8A8EAA;           /* 标签、caption、弱信息 */
  /* 品牌：双业务身份色（主操作鸿蒙蓝紫 · 淘宝陶土保留区分） */
  --accent:#3D5AFE;          /* 主操作 · 鸿蒙蓝紫 */
  --accent2:#C4643F;         /* 淘宝业务 / 次操作 */
  --accent-soft:rgba(61,90,254,.09);
  --accent2-soft:rgba(196,99,63,.13);
  --accent-mid:#5B7CFF;      /* 蓝紫浅档(图表) */
  --accent2-mid:#E09B74;     /* 淘宝色浅档(图表) */
  --on-accent:#fff;
  --glow:rgba(61,90,254,.26);
  --shadow-sm:0 1px 2px rgba(20,24,80,.05),0 3px 10px rgba(20,24,80,.06);
  --shadow:0 2px 6px rgba(20,24,80,.05),0 10px 28px rgba(20,24,80,.08);
  /* 语义色 */
  --ok:#2E8A5B;  --ok-ink:#1E6B44;  --ok-soft:rgba(46,138,91,.12);
  --warn:#C07A16; --warn-ink:#7d510c; --warn-soft:rgba(192,122,22,.14);
  --bad:#C0453C; --bad-ink:#8f2f27;  --bad-soft:rgba(192,69,60,.12);
  /* 圆角角色：鸿蒙大圆角卡片 */
  --r:20px; --r-sm:12px;
  --bg-soft:#EEF2FC;          /* 客户端主题底（client.html 会覆盖） */
  --side:236px; --row:46px;
  /* 布局匀边距（2026-10-03 第八轮）：屏幕四周统一留 14px。
     · `--gut`   = 侧栏到屏幕边、侧栏↔内容、内容到屏幕边的**共同**间距
     · `--sbw`   = 竖向滚动条占位宽（与 `::-webkit-scrollbar{width}` 必须一致）
     关键：滚动条的占位是**加在 padding 之外**的（实测 10 + 14 = 24px），
     所以内容区右侧只留 `--gut − --sbw` = 4px，滚动条再占 10px，
     两者相加正好 14px —— 右侧边距才会与侧栏左边距相等。 */
  --gut:14px; --sbw:10px;
  /* ★全站字号系数（2026-10-03 第十四件）★ —— 桌面恒为 1，手机端在**文件末尾**的
     「移动端字号」段里改成 1.16，于是全站字号（含 index.html 的内联 font-size）一起联动。

     用法：所有 ≤21px 的字号都写成 `font-size:calc(13px * var(--fz,1))`
     （由 `_icons/migrate_font_scale.py` 批量改写，带计数断言；二次转换 0 处即幂等）。
     · 桌面：`calc(13px * 1)` 计算值就是 13px → **渲染与改造前逐像素相同**；
     · 手机：390px 实测原有 400+ 个元素挤在 12~13px（桌面密集尺度），×1.16 后
       正文 12→13.9px、表格 13→15.1px、底部 tab 10.5→12.2px。

     ⚠ **≥22px 的字号刻意没改写**：那是 KPI 大数 / 图表标签这类展示级尺寸，
       本来就够大，再放大 15% 会在窄屏挤破卡片。
     ⚠ 改这个数之前先想清楚：它会同时影响 **client.html**（客户门户共用 style.css）
       与**全部弹窗**。改完必须重跑 `_icons/probe_fonts.js` + `check_mobile.js --views all --modals`。 */
  --fz:1;
}
*{box-sizing:border-box;margin:0;padding:0}
html,body{height:100%}
body{background:var(--page);color:var(--ink-2);
  font-family:system-ui,-apple-system,"PingFang SC","Microsoft YaHei",sans-serif;
  font-size:calc(14px * var(--fz,1));line-height:1.55;-webkit-font-smoothing:antialiased}
.num{font-variant-numeric:tabular-nums}
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer;min-height:28px}
a{color:inherit;text-decoration:none}
table{border-collapse:collapse;width:100%}
svg{display:block}

/* ⚠⚠ 外壳三件套（.app / .side / .main / .body）一律写成**成对选择器**
   `.app,.c-app` —— 客户门户（client.html）用 `.c-*` 这套类名，
   与管理端共享同一份声明。改这里两边一起变，不会再各自 evolve 成长两个模样。
   2026-10-06 之前两边是两套值，实测 1440 下差得离谱：侧栏贴边 vs 离页边 14px、
   224 vs 236 宽、实白方块 vs 玻璃卡片、内容区居中定宽 1000px（右侧空 108px）。
   详见本文件第 1206 行「客户门户 · 外壳与管理端严格对齐」段。 */
.app,.c-app{display:grid;grid-template-columns:var(--side) 1fr;min-height:100vh}
@media (max-width:1180px){ .app,.c-app{grid-template-columns:66px 1fr}
  .side .lb,.c-nav .lb{display:none} }

/* ── 侧栏 ─────────────────────────────── */
.side,.c-side{background:var(--bg);border-right:1px solid var(--border);
  display:flex;flex-direction:column;gap:2px;padding:14px 10px 12px;
  /* 2026-10-03：侧栏入口 14 → 16（财务组补「税务申报」「收付款」）后内容高 994px，
     而 .app 用的是 min-height:100vh —— 侧栏把整页撑出 94px 空白滚动，
     900px 高的主流屏上底部的品牌卡（.foot）被挤出视口 82px。
     按标准后台布局改为「自身 100vh + 内部滚动」：内容不超时不出现滚动条，
     超出时只在侧栏内部滚，主区高度与整页滚动都不受影响。 */
  height:100vh;overflow-y:auto;overflow-x:hidden}
/* ⚠ 这里不要写 scrollbar-width / scrollbar-color —— Chrome 121+ 一旦见到这两个标准属性
   就会用它接管，并**忽略 ::-webkit-scrollbar 的全部自定义样式**（症状："样式写了不生效"）。
   侧栏滚动条样式统一在文件末尾「全局滚动条」段定义。 */
.brand{display:flex;align-items:center;gap:10px;padding:2px 10px 18px}
.brand .mk{width:30px;height:30px;border-radius:8px;flex:none;position:relative;
  background:linear-gradient(140deg,var(--accent),var(--accent2));box-shadow:0 4px 10px rgba(61,90,254,.25)}
.brand .mk::after{content:"";position:absolute;left:8px;top:8px;width:14px;height:14px;
  border:2px solid rgba(255,255,255,.85);border-radius:3px}
.brand b{font-size:calc(15px * var(--fz,1));color:var(--ink-1);font-weight:700;letter-spacing:.01em;display:block}
.brand span{font-size:calc(11px * var(--fz,1));color:var(--ink-3);display:block;margin-top:1px}
.grp{font-size:calc(11px * var(--fz,1));color:var(--ink-3);padding:16px 10px 5px;letter-spacing:.06em;font-weight:500}
.side a,.c-nav a{display:flex;align-items:center;gap:10px;padding:9px 10px;border-radius:var(--r-sm);
  color:var(--ink-3);font-size:calc(13.5px * var(--fz,1));position:relative}
.side a:hover,.c-nav a:hover{background:var(--panel-2);color:var(--ink-2)}
.side a.on,.c-nav a.on{background:var(--accent-soft);color:var(--accent);font-weight:600}
.side a.on svg{color:var(--accent)}
.side svg{width:17px;height:17px;flex:none;color:currentColor}
.side .bdg,.c-nav .bdg{margin-left:auto;font-size:calc(11px * var(--fz,1));background:var(--bad);color:#fff;border-radius:999px;
  min-width:18px;height:18px;display:grid;place-items:center;padding:0 5px;font-weight:600}
/* 2026-10-03：侧栏底部署名卡（.side .foot + .av）已按要求整块移除，
   其基础样式与 ≤1180px 收起态样式一并删除，详见 index.html 侧栏末尾注释。 */

/* ── 主区 ─────────────────────────────── */
.main,.c-main{display:flex;flex-direction:column;min-width:0;height:100vh;overflow:hidden}
/* 2026-10-03：右侧头部（.top 页面标题条 + .subtabs 二级导航条）整块移除。
   历史沿革：这里先后删过 .top .crumb（面包屑「经营台 /」）、.top .sp（撑开占位）、
   .top .statbtn（CSS 在、HTML 早已无人用）、.gsearch 系列（全局搜索框）、
   .top .btn（顶栏「新增客户」）—— 最后用户要求连「页面标题条 + 二级导航条」一起去掉，
   右侧面板现在直接从 .body 开始，切页全靠左侧导航。
   ⚠ 不要加回来，理由见 index.html 顶部注释。
   附注：.body 的 padding-top 保持 22px 未动 —— 原来顶栏在时内容也顶到 22px，
   删掉后只是把这两条横条的高度还给首屏：1440×900 实测，有二级条的页内容顶端
   124px → 22px（多出 102px，即 .top 53 + .subtabs 49），经营概览页 75px → 22px。 */
.btn{border:1px solid var(--border);border-radius:var(--r-sm);padding:7px 14px;font-size:calc(13px * var(--fz,1));
  display:inline-flex;align-items:center;gap:7px;color:var(--ink-2);background:var(--bg);font-weight:500}
.btn:hover{border-color:var(--ink-3)}
.btn svg{width:15px;height:15px}
.btn.primary{background:var(--accent);border-color:var(--accent);color:var(--on-accent);font-weight:600}
.btn.acc2{background:var(--accent2);border-color:var(--accent2);color:#fff;font-weight:600}
.btn.acc2:hover{filter:brightness(.96)}
.btn.ghost{background:transparent}

.body,.c-shell{padding:22px 24px 34px;display:flex;flex-direction:column;gap:22px;
  min-width:0;overflow:auto;flex:1}

/* 视图切换 */
[data-view]{display:none}
[data-view].on{display:flex;flex-direction:column;gap:18px}

/* 指标条：一律等宽（2026-10-03 第八轮 · 应用户要求）
   原为 `1.5fr 1fr 1fr 1fr`（首卡"主指标"一档大），用户要求「同一横排的多个卡片
   彼此等宽」—— 四张卡都是同级指标，首卡独占 1.5 倍只会让整行看着歪。
   ⚠ 用 `minmax(0,1fr)` 而非 `1fr`：`1fr` = `minmax(auto,1fr)`，
     内容不换行时会把列撑破容器（铁律 15）。
   ⚠ 只有 3 张卡的行（淘宝销售）用 `.k3` 收成 3 列。
     **绝不能用内联 `style="grid-template-columns:…"`** —— 内联样式优先级高于样式表，
     断点里的 `.kpis{grid-template-columns:1fr}` 覆盖不了它，手机端会被锁死成 3 列，
     「¥2,619成功+在途」直接顶破卡片（本轮手机端体检抓出来的，铁律 15 原文就写着这条）。 */
.kpis{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:16px}
@media (max-width:1280px){ .kpis{grid-template-columns:repeat(2,minmax(0,1fr))} }
/* 3 张卡的行（淘宝销售）：列数与 4 卡行不同，但仍走类、随时能被断点覆盖 */
.kpis.k3{grid-template-columns:repeat(3,minmax(0,1fr))}
.kpi{background:var(--bg);border:1px solid var(--border);border-radius:var(--r);padding:15px 17px 16px}
.kpi .k{color:var(--ink-3);font-size:calc(12.5px * var(--fz,1));display:flex;gap:8px;align-items:center}
.kpi .k .dot{width:7px;height:7px;border-radius:2px;flex:none}
.kpi .v{font-size:26px;font-weight:700;color:var(--ink-1);line-height:1.25;margin-top:5px;
  display:flex;align-items:baseline;gap:7px;font-variant-numeric:tabular-nums}
.kpi .v em{font-size:calc(12.5px * var(--fz,1));font-weight:500;color:var(--ink-3);font-style:normal}
.kpi.hero .v{font-size:32px}
.delta{font-size:calc(12px * var(--fz,1));font-weight:600}
.delta.up{color:var(--ok-ink)} .delta.down{color:var(--bad-ink)}
.kpi .foot{display:flex;gap:14px;color:var(--ink-3);font-size:calc(12px * var(--fz,1));margin-top:9px;flex-wrap:wrap}
.kpi .foot b{color:var(--ink-2);font-weight:600}
.mini{height:5px;border-radius:3px;background:#E3E6F8;margin-top:11px;overflow:hidden}
.mini i{display:block;height:100%;border-radius:3px}

/* 面板 */
/* 2026-10-03 第八轮：左右两栏也改等宽（原 1.7fr 1fr）。
   用户要求「同一横排的多个卡片彼此等宽」，`.duo` 是页面上另一种"两卡同行"的形态。 */
.duo{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px;align-items:start}
@media (max-width:1180px){ .duo{grid-template-columns:1fr} }

/* ★两栏等高（2026-10-04 · 应用户要求）★
   用户：「【本年收入构成】模块的高度要始终和【近 6 个月经营收入】模块高度保持一致」。
   `.duo` 上面写的是 `align-items:start`（两张卡各按自己的内容高），所以环形图那卡
   比柱状图那卡**矮 88px**（实测：柱图卡 322px、环形卡 234px）。
   做法两步：
     ① `.duo-eq` 把这一排恢复成栅格默认的 stretch → 两张卡同高（高度由高者决定）；
     ② 环形图那卡改成纵向 flex，让多出来的高度**居中**用掉，而不是顶在上边留白。
   ⚠ 注意 `.duo` 默认仍是 `start`（各按内容高），想等高的那一排必须挂 `.duo-eq`。
   2026-10-04 第八件后半：用户看了总览的效果后要求「PC 端其余同类部位也照做」，
   于是客户档案 ×2、设置页那三排补挂 `.duo-eq`（实测差 5.1 / 0 / 78.7px）。
   全站共 4 处 `.duo`，4 处全部挂类（注释前说的「不动另外三处」已作废）。
   ⚠ 内容一律**顶对齐**、多出来的高度在底部留白 —— 只有环形图那卡特判成居中
     （它整块是 grid，`align-content` 才管得住；其余卡片是普通块流，文档更自然）。 */
.duo-eq{align-items:stretch}
.panel:has(> .donut-box){display:flex;flex-direction:column}
.panel:has(> .donut-box) > .donut-box{flex:1 1 auto;align-content:center}
.panel{background:var(--bg);border:1px solid var(--border);border-radius:var(--r);overflow:hidden}
.panel > header{display:flex;align-items:center;gap:10px;padding:13px 16px;font-weight:650;
  color:var(--ink-1);font-size:calc(14.5px * var(--fz,1));border-bottom:1px solid var(--border)}
.panel > header .sp{margin-left:auto}
.panel > header .meta{color:var(--ink-3);font-size:calc(12px * var(--fz,1));font-weight:400}
.panel .pad{padding:18px}

/* 收款渠道构成 · 2026-10-03 新增（收付款页「收款流水」）
   一行展示每个收款渠道的实收金额与笔数。本期没有发生的渠道（支付宝 / 现金）
   加 .mute 弱化但**仍然列出来** —— 否则用户会以为系统只管微信，
   看不到「这些渠道都在统计范围内」。 */
.chans{display:flex;flex-wrap:wrap;gap:8px;padding:14px 16px 2px}
.chans .ch{display:inline-flex;align-items:baseline;gap:7px;
  border:1px solid var(--border);border-radius:var(--r-sm);
  padding:7px 12px;font-size:calc(12.5px * var(--fz,1));color:var(--ink-3);background:var(--bg)}
.chans .ch b{color:var(--ink-1);font-weight:600;font-size:calc(13px * var(--fz,1))}
.chans .ch em{font-style:normal;font-weight:650;color:var(--accent);
  font-variant-numeric:tabular-nums}
.chans .ch i{font-style:normal;font-size:calc(11.5px * var(--fz,1))}
.chans .ch.mute{background:var(--panel-2);border-style:dashed}
.chans .ch.mute b{color:var(--ink-3)}
.chans .ch.mute em{color:var(--ink-3);font-weight:600}

/* 面板内的说明块：与弹窗 .note 同一视觉，用于「怎么统计」这类口径交代 */
.panel > .note{background:var(--accent2-soft);border-radius:10px;
  padding:11px 13px;margin:14px 16px 16px;font-size:calc(12.5px * var(--fz,1));
  line-height:1.75;color:var(--ink-2)}
.panel > .note b{font-weight:650;color:var(--ink-1)}

/* 筛选条 */
.filters{display:flex;flex-wrap:wrap;gap:10px;align-items:center;
  background:var(--bg);border:1px solid var(--border);border-radius:var(--r);padding:12px 14px}
.filters .fl{color:var(--ink-3);font-size:calc(12.5px * var(--fz,1))}
/* 筛选行的横滑容器：桌面端 display:contents —— 自身不生成盒子，标签与胶囊
   直接参与 .filters 的 flex 布局，外观与改造前完全一致（零风险）。
   只有 ≤760px 才成为可横滑的一行，见文件末尾「移动端触控优化」段第 14 项。 */
.fx-rail{display:contents}
.chip{border:1px solid var(--border);border-radius:999px;padding:4px 12px;color:var(--ink-3);
  font-size:calc(12.5px * var(--fz,1));cursor:pointer;background:var(--bg)}
.chip.on{border-color:var(--accent);color:var(--accent);background:var(--accent-soft);font-weight:600}
.field{border:1px solid var(--border);border-radius:var(--r-sm);padding:6px 11px;min-width:170px;
  background:var(--bg);color:var(--ink-2);font-size:calc(13px * var(--fz,1));display:flex;align-items:center;gap:7px}
.field svg{width:14px;height:14px;color:var(--ink-3)}
.field input{border:0;outline:0;background:transparent;font:inherit;color:inherit;width:100%}
.field input::placeholder{color:var(--ink-3)}

/* 表格 */
th,td{text-align:left;padding:0 16px;height:var(--row);border-bottom:1px solid var(--border);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-size:calc(13px * var(--fz,1))}
th{color:var(--ink-3);font-weight:500;font-size:calc(12px * var(--fz,1));letter-spacing:.02em;background:var(--panel-2)}
tbody tr:last-child td{border-bottom:0}
tbody tr:hover{background:#F5F7FD}
td.n{text-align:right;font-variant-numeric:tabular-nums}
th.n{text-align:right;font-variant-numeric:tabular-nums}
td .link{color:var(--accent);font-weight:500;cursor:pointer}
.tag{display:inline-block;padding:2px 9px;border-radius:999px;font-size:calc(12px * var(--fz,1));font-weight:500}
.tag.ok{background:var(--ok-soft);color:var(--ok-ink)}
.tag.warn{background:var(--warn-soft);color:var(--warn-ink)}
.tag.bad{background:var(--bad-soft);color:var(--bad-ink)}
.tag.neu{background:var(--panel-2);color:var(--ink-3)}
.tag.soft{background:var(--accent-soft);color:var(--accent)}
.tag.s2{background:var(--accent2-soft);color:var(--accent2)}
.op{color:var(--accent);font-size:calc(12.5px * var(--fz,1));font-weight:500;cursor:pointer;padding:2px 6px;border-radius:6px}
.op:hover{background:var(--accent-soft)}
.op.s2{color:var(--accent2)} .op.s2:hover{background:var(--accent2-soft)}

/* 图例 */
.legend{display:flex;flex-wrap:wrap;gap:8px 18px;font-size:calc(12.5px * var(--fz,1));color:var(--ink-3)}
.legend span{display:inline-flex;align-items:center;gap:6px}
.legend i{width:9px;height:9px;border-radius:2px;display:block}

/* 「本年收入构成」环形图那一格（.pad 里左侧环形 + 右侧图例）
   —— 2026-10-03 从**内联 style** 收成语义类。两个理由：
   ① 内联优先级最高，窄屏断点覆盖不了（铁律 31）；
   ② 手机端字号 ×1.16 后，150px 环形 + 12px 间距 只剩约 166px 给图例，
      「软件项目款」被拆成「软件项目 / 款」（`_icons/diff_lines.py` 抓到的破损折行）。
      收成类之后，窄屏改成**上下堆叠**：环形居中放大到 200px
      （= viewBox 1:1，环形里的 12px 文字不再被 0.75 缩放压成 9px），
      图例独占整行宽度，不再折行。 */
.donut-box{display:grid;grid-template-columns:150px 1fr;gap:12px;align-items:center}
.donut{width:150px;height:150px}

/* 提醒列表 */
.remind{display:flex;flex-direction:column}
.remind .row{display:grid;grid-template-columns:14px 1fr auto;gap:12px;align-items:center;
  padding:11px 16px;border-bottom:1px solid var(--border)}
.remind .row:last-child{border-bottom:0}
.remind .row:hover{background:#F5F7FD}
.remind .sig{width:9px;height:9px;border-radius:50%;flex:none}
.remind .t{color:var(--ink-1);font-weight:600;font-size:calc(13.5px * var(--fz,1))}
.remind .d{color:var(--ink-3);font-size:calc(12px * var(--fz,1));margin-top:1px;display:flex;gap:8px;flex-wrap:wrap}
.remind .d b{color:var(--ink-2);font-weight:600}

/* 紧急度条 */
.urg{display:flex;height:10px;border-radius:5px;overflow:hidden;gap:2px}
.urg i{flex:1;border-radius:3px}
.urg-lab{display:flex;gap:18px;margin-top:10px;font-size:calc(12px * var(--fz,1));color:var(--ink-3);flex-wrap:wrap}
.urg-lab span{display:inline-flex;align-items:center;gap:6px}
.urg-lab i{width:8px;height:8px;border-radius:2px;display:block}

/* 四种状态 */
[data-state]{display:none}
[data-state].on{display:flex;flex-direction:column;gap:18px}
.empty,.loading,.error{background:var(--bg);border:1px solid var(--border);border-radius:var(--r);
  display:grid;place-items:center;gap:10px;padding:60px 24px;text-align:center;color:var(--ink-3)}
.empty b,.error b{color:var(--ink-1);font-size:calc(15px * var(--fz,1))}
.skel{background:linear-gradient(90deg,#E5E8FA,transparent,#E5E8FA);
  height:var(--row);border-radius:var(--r-sm);margin:6px 16px;opacity:.75}

/* 弹窗 */
.scrim{position:fixed;inset:0;background:rgba(20,24,80,.44);opacity:0;
  pointer-events:none;transition:opacity .18s;z-index:30}
.scrim.on{opacity:1;pointer-events:auto}
.modal{position:fixed;left:50%;top:50%;transform:translate(-50%,-44%);z-index:31;
  width:min(520px,92vw);background:var(--bg);border-radius:12px;padding:20px 22px;
  opacity:0;pointer-events:none;transition:.18s;box-shadow:0 30px 70px rgba(20,24,80,.28)}
.modal.on{opacity:1;pointer-events:auto;transform:translate(-50%,-50%)}
.modal h3{font-size:calc(16px * var(--fz,1));color:var(--ink-1);display:flex;align-items:center;gap:9px}
.modal .sub{color:var(--ink-3);font-size:calc(12.5px * var(--fz,1));margin:4px 0 14px}
.modal .fld{display:grid;grid-template-columns:88px 1fr;gap:11px 14px;margin-top:12px;font-size:calc(13px * var(--fz,1))}
.modal .fld dt{color:var(--ink-3);padding-top:6px}
/* 必填星号：dt 列固定 88px（约 6.7 个中文字），「冲销应收（必选）」8 字会折行，
   故必填标记改用一颗星号 —— 四个字 + 星号放得下。 */
.modal .fld dt .req{color:var(--bad);font-weight:600;margin-left:2px}
.modal .fld dd input,.modal .fld dd select{width:100%;border:1px solid var(--border);
  border-radius:var(--r-sm);padding:7px 10px;font:inherit;background:var(--bg);color:var(--ink-2)}
.modal .acts{display:flex;gap:9px;justify-content:flex-end;margin-top:20px}
.modal .note{background:var(--accent2-soft);border-radius:8px;padding:10px 12px;font-size:calc(12.5px * var(--fz,1));
  color:var(--accent2);line-height:1.6;margin-top:12px}
.modal .note b{font-weight:650}
.dropzone{border:1.5px dashed var(--border);border-radius:10px;padding:22px 18px;
  text-align:center;color:var(--ink-3);font-size:calc(13px * var(--fz,1));margin-top:14px;background:var(--panel-2)}
.dropzone .up{width:34px;height:34px;border-radius:9px;background:var(--accent-soft);color:var(--accent);
  display:grid;place-items:center;margin:0 auto 10px}
.dropzone b{color:var(--accent);font-weight:600}

/* 合同上传区 */
.upload{border:1.5px dashed var(--border);border-radius:var(--r);padding:16px 18px;background:var(--panel-2);
  display:flex;flex-direction:column;gap:8px;align-items:flex-start;min-width:0}
.upload:hover{border-color:var(--accent-mid)}

/* 合同预览文档 */
.doc{border:1px solid var(--border);border-radius:var(--r);background:#fff;padding:18px 20px;
  max-height:58vh;overflow:auto;display:flex;flex-direction:column;gap:14px}
.doc-head{font-size:calc(16px * var(--fz,1));font-weight:700;text-align:center;color:var(--ink-1);border-bottom:1px solid var(--border);padding-bottom:10px}
.doc-meta{display:grid;grid-template-columns:1fr 1fr;gap:8px 18px;font-size:calc(13px * var(--fz,1));background:var(--panel-2);border-radius:var(--r-sm);padding:12px 14px}
.doc-meta div{display:flex;justify-content:space-between;gap:12px}
.doc-meta span{color:var(--ink-3)}
.doc-meta b{font-weight:600;color:var(--ink-2)}
.doc-body{display:flex;flex-direction:column;gap:12px}
.doc-body .sec{border-left:3px solid var(--accent);padding-left:12px}
.doc-body .t{font-weight:600;color:var(--ink-1);font-size:calc(13.5px * var(--fz,1))}
.doc-body p{font-size:calc(13px * var(--fz,1));color:var(--ink-2);margin-top:4px;line-height:1.6}
.doc-sign{display:grid;grid-template-columns:1fr 1fr 1fr;gap:18px;border-top:1px dashed var(--border);padding-top:14px;font-size:calc(13px * var(--fz,1))}
.doc-sign span{color:var(--ink-3);display:block}
.doc-sign b{font-weight:600}

/* ══ 客户门户 · 客户端 ══
   2026-10-03：原「客户门户（演示）」侧栏入口已按要求移除，
   随之一并删掉 `.side a.cl` 那 6 条规则 —— 它是那条入口专用的
   （陶土橙配色 + 演示徽标），入口没了就再没有元素带 .cl。
   ⚠ 不要因为「看着像淘宝业务的橙」就把它们加回来：淘宝业务走的是
   `data-group="ecom"`，与这里无关。 */

/* 客户端区块：各模块统一纵向间距（与其他视图对齐） */
#cHome{display:flex;flex-direction:column}
#cHome > *{margin-bottom:22px}
#cHome > *:last-child{margin-bottom:0}
#cAuth{display:flex;flex-direction:column;gap:22px}

/* 客户端顶部条 */
.c-top{display:flex;align-items:center;gap:12px;padding:12px 16px;
  border:1px solid var(--border);border-radius:var(--r);background:var(--bg);flex-wrap:wrap}
.c-brand{display:flex;align-items:center;gap:10px}
.c-brand .mk{width:30px;height:30px;border-radius:8px;background:linear-gradient(140deg,var(--accent),var(--accent2));
  display:grid;place-items:center;color:#fff;flex:none}
.c-brand b{font-size:calc(15px * var(--fz,1));color:var(--ink-1);display:block}
.c-brand span{font-size:calc(11px * var(--fz,1));color:var(--ink-3);display:block}
.c-user{display:flex;align-items:center;gap:9px;font-size:calc(13px * var(--fz,1));color:var(--ink-2)}
.c-user .av{width:28px;height:28px;border-radius:50%;background:var(--accent-soft);color:var(--accent);
  display:grid;place-items:center;font-weight:600;font-size:calc(12px * var(--fz,1))}

/* 登录/注册卡片 */
.c-auth{max-width:430px;margin:4vh auto 0;background:var(--bg);border:1px solid var(--border);
  border-radius:12px;padding:28px 30px;display:flex;flex-direction:column;gap:14px}
.c-auth .logo{width:44px;height:44px;border-radius:12px;background:linear-gradient(140deg,var(--accent),var(--accent2));
  display:grid;place-items:center;color:#fff}
.c-auth h2{font-size:calc(18px * var(--fz,1));color:var(--ink-1)}
.c-auth .sub{color:var(--ink-3);font-size:calc(12.5px * var(--fz,1))}
.c-auth .in{border:1px solid var(--border);border-radius:var(--r-sm);padding:10px 12px;font:inherit;
  color:var(--ink-2);width:100%;background:var(--bg)}
.c-auth .in:focus{outline:1.5px solid var(--accent-mid);border-color:var(--accent-mid)}
.c-auth .row{display:flex;align-items:center;justify-content:space-between;font-size:calc(12px * var(--fz,1));color:var(--ink-3)}
.c-auth .row a{color:var(--accent);font-weight:500;cursor:pointer}
.c-auth .row a:hover{text-decoration:underline}
.c-auth .hint{font-size:calc(12px * var(--fz,1));color:var(--accent2);background:var(--accent2-soft);border-radius:8px;
  padding:9px 12px;line-height:1.6}

/* 商品/服务卡片 */
.svc{display:grid;grid-template-columns:repeat(3,1fr);gap:16px}
/* ⚠ 2026-10-10：服务卡从 3 张加到 4 项（+1 张虚线 CTA 卡 = 5 张）。
   5 张在 3 列网格里会排成「3 + 1 + 1」，第二行那张孤零零占一格、
   右边留一大片空白，看起来像漏了东西。
   这里把**最后一张 CTA 卡**拉通整行 —— 它本来也不是一张「服务」，
   是「还有想做的事？」的行动召唤，视觉上就该独占一行、居中呈现。
   ⚠ 只作用于 :last-child，不要改 grid 列数：列数一改，
     另外四张真服务卡的宽度就跟着变了，那是更大的视觉变动。 */
.svc > .card:last-child{grid-column:1 / -1}
@media (max-width:1180px){.svc{grid-template-columns:1fr 1fr}}
@media (max-width:760px){.svc{grid-template-columns:1fr}}
.svc .card{background:var(--bg);border:1px solid var(--border);border-radius:var(--r);
  padding:18px 20px;display:flex;flex-direction:column;gap:12px}
.svc .card .tt{font-weight:650;color:var(--ink-1);font-size:calc(14px * var(--fz,1));display:flex;align-items:center;gap:8px}
.svc .card .tt svg{width:17px;height:17px;color:var(--accent);flex:none}
.svc .card .dt{color:var(--ink-3);font-size:calc(12px * var(--fz,1))}
.svc .card .amt{font-size:calc(17px * var(--fz,1));font-weight:700;color:var(--ink-1);margin-top:auto;font-variant-numeric:tabular-nums}
.svc .card .foot{display:flex;align-items:center;gap:8px;color:var(--ink-3);font-size:calc(12px * var(--fz,1));flex-wrap:wrap}

/* 电子签署 · 流转步骤 */
.esign-flow{display:flex;align-items:center;flex-wrap:wrap;gap:0}
.esign-step{display:flex;align-items:center;gap:8px;font-size:calc(12.5px * var(--fz,1));color:var(--ink-3)}
.esign-step .n{width:20px;height:20px;border-radius:50%;background:var(--panel-2);color:var(--ink-3);
  display:grid;place-items:center;font-size:calc(11px * var(--fz,1));font-weight:600;flex:none}
.esign-step.done .n{background:var(--ok);color:#fff}
.esign-step.cur .n{background:var(--accent);color:#fff}
.esign-step.done{color:var(--ok-ink)}
.esign-step.cur{color:var(--ink-1);font-weight:600}
.esign-line{width:26px;height:2px;background:var(--border);margin:0 8px}
.esign-line.done{background:var(--ok)}

/* 签署条款勾选 */
.agree{display:flex;align-items:flex-start;gap:9px;border:1px solid var(--border);border-radius:var(--r-sm);
  padding:11px 12px;font-size:calc(12.5px * var(--fz,1));color:var(--ink-3);margin-top:12px;cursor:pointer;line-height:1.55}
.agree input{width:15px;height:15px;flex:none;margin-top:2px;accent-color:var(--accent)}
.agree b{color:var(--accent);font-weight:500}
.agree.done{border-color:var(--ok);background:var(--ok-soft);color:var(--ok-ink)}

/* 顶部提示条 */
.c-banner{display:flex;align-items:flex-start;gap:11px;background:var(--accent-soft);
  border:1px solid var(--accent-soft);border-radius:var(--r);padding:13px 15px;font-size:calc(13px * var(--fz,1));color:var(--ink-2);line-height:1.6}
.c-banner svg{width:18px;height:18px;color:var(--accent);flex:none;margin-top:1px}
.c-banner b{color:var(--accent)}

/* toast —— 顶部居中显示（铁律：与底部 .mtab 解耦，避免被遮挡且更直观） */
.toast{position:fixed;left:50%;top:18px;transform:translateX(-50%) translateY(-16px);
  background:#1A1C38;color:#fff;padding:11px 18px;border-radius:9px;font-size:calc(13px * var(--fz,1));
  box-shadow:0 12px 30px rgba(20,24,80,.25);opacity:0;pointer-events:none;transition:.22s;z-index:40;
  display:flex;align-items:center;gap:9px;max-width:88vw}
.toast.on{opacity:1;transform:translateX(-50%) translateY(0)}
.toast svg{width:16px;height:16px;flex:none}

/* ═══ 项目协作看板（软件业务）═══ */
/* 阶段横向时间轴 */
.pro-phases{display:flex;align-items:center;flex-wrap:wrap;gap:0;padding:2px 0 8px}
.ph{display:flex;align-items:center;gap:8px;font-size:calc(12.5px * var(--fz,1));color:var(--ink-3)}
.ph .n{width:22px;height:22px;border-radius:50%;background:var(--panel-2);color:var(--ink-3);
  display:grid;place-items:center;font-size:calc(11.5px * var(--fz,1));font-weight:600;flex:none}
.ph.done .n{background:var(--ok);color:#fff}
.ph.cur .n{background:var(--accent);color:#fff}
.ph.done{color:var(--ok-ink)}
.ph.cur{color:var(--ink-1);font-weight:600}
.ph.cur .nm{color:var(--accent);font-weight:600}
.ph-line{width:34px;height:2px;background:var(--border);margin:0 9px}
.ph-line.done{background:var(--ok)}

/* 协作任务卡（客户待办 / 工作项） */
.pro-tasks{display:flex;flex-direction:column;gap:12px}
.pro-task{display:grid;grid-template-columns:12px 1fr auto;gap:10px;align-items:center;
  padding:12px;border:1px solid var(--border);border-radius:var(--r-sm);font-size:calc(13px * var(--fz,1))}
.pro-task .sig{width:9px;height:9px;border-radius:50%;flex:none;background:var(--border)}
.pro-task.need .sig{background:var(--warn)}
.pro-task.done .sig{background:var(--ok)}
.pro-task b{color:var(--ink-1);font-weight:600;font-size:calc(13px * var(--fz,1))}
.pro-task .d{color:var(--ink-3);font-size:calc(12px * var(--fz,1));margin-top:2px;display:flex;gap:8px;flex-wrap:wrap}
.pro-task .d b{color:var(--ink-2)}
.pro-task.done{opacity:.72}
/* 需客户配合：强调高亮 */
.pro-task.need{border-color:var(--accent2);background:var(--accent2-soft)}

/* ═══ 移动端底部 Tab（≤760px）═══ */
.mtab{display:none}
@media (max-width:760px){
  .app,.c-app{grid-template-columns:1fr}
  .side,.c-side{display:none}
  .main,.c-main{height:auto;min-height:100vh;overflow:visible}
  /* 2026-10-03 紧凑化（应用户要求）：边距 16→10、卡片间距 18→12。
     ⚠ padding-bottom 76 不能再小：底部固定 Tab 实测 58px 高 + 呼吸余量，
       88→76 已到临界，再小最后一屏内容会被 Tab 压住。
     2026-10-06：`.c-shell` 并入本条（原先 client.html 自己写 74px，两套取值）。 */
  .body,.c-shell{padding:10px 10px 76px;gap:12px;overflow:visible}
  /* 原 .top{padding:12px 14px} 随头部整块移除 · 2026-10-03 */
  /* 底部固定 Tab */
  .mtab{display:flex;position:fixed;left:0;right:0;bottom:0;z-index:25;
    background:var(--bg);border-top:1px solid var(--border);
    box-shadow:0 -6px 18px rgba(20,24,80,.07);padding-bottom:env(safe-area-inset-bottom)}
  .mtab a{flex:1;display:flex;flex-direction:column;align-items:center;gap:2px;
    padding:8px 0 6px;color:var(--ink-3);font-size:calc(10.5px * var(--fz,1));min-height:0}
  .mtab a.on{color:var(--accent);font-weight:600}
  .mtab svg{width:20px;height:20px}
  /* 弹窗在移动端贴近底部 */
  .modal{top:auto;bottom:0;transform:none;width:100vw;max-width:100vw;
    border-radius:14px 14px 0 0;padding:13px 12px 18px;max-height:88vh;overflow:auto}
  .modal.on{transform:none}
  .c-auth{max-width:none;margin:2vh 14px 0}
  .kpis{grid-template-columns:1fr 1fr}
  /* 3 卡行跟着收：特异性与基础段 `.kpis.k3` 相同、位置更靠后，故能覆盖 */
  .kpis.k3{grid-template-columns:1fr 1fr}
  .svc{grid-template-columns:1fr}
}

/* ═══ 鸿蒙 UI 风格化（卡片化 · 柔和投影 · 大圆角）═══ */
.side,.c-side{border-right:1px solid var(--border);box-shadow:1px 0 0 rgba(20,24,80,.04)}
/* .top 的投影随头部整块移除而删除 · 2026-10-03 */
.panel,.kpi,.svc .card,.c-auth,.filters,.c-banner,.empty,.loading,.error,.dropzone,.upload,.doc{
  border-color:rgba(23,28,82,.07);box-shadow:var(--shadow-sm)}
.panel,.kpi,.svc .card,.c-auth,.c-banner,.empty,.loading,.error,.upload,.doc{border-radius:var(--r)}
.modal{border-radius:16px;box-shadow:0 24px 64px rgba(20,24,80,.22)}
.btn,.field,.fld dd input,.fld dd select{border-radius:var(--r-sm)}
.btn.primary{box-shadow:0 6px 16px var(--glow)}
.side a,.c-nav a,.pro-task,.pro-task.need{border-radius:12px}
.panel > header{border-bottom-color:rgba(23,28,82,.06)}
th{background:var(--panel-2)}
tbody tr:hover,.remind .row:hover{background:#f3f5fc}
.c-auth .logo,.brand .mk{box-shadow:0 4px 12px rgba(61,90,254,.25)}
.mtab{background:rgba(255,255,255,.9);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);box-shadow:0 -6px 20px rgba(20,24,80,.06)}
.esign-step .n,.ph .n{box-shadow:0 2px 6px rgba(20,24,80,.10)}

/* ═══ 鸿蒙 · 层次感细化（专业 UI 打磨）═══ */
/* 1) 侧栏 / 客户端导航选中项：左侧蓝色竖线指示条 → 2026-10-03 应用户要求【整块移除】。
      选中态只保留 .side a.on / .c-nav a.on 的浅主色胶囊底（见上方基础段），
      不再叠加竖线。client.html 里那行 `content:none` 的补救覆盖也一并删除。
      ⚠ 不要加回来。原先此处为：
        .side a.on,.c-nav a.on{position:relative}
        .side a.on::before,.c-nav a.on::before{content:"";position:absolute;left:3px;top:50%;
          transform:translateY(-50%);width:3px;height:15px;border-radius:2px;background:var(--accent)} */
/* 2) KPI 主指标卡 → 2026-10-03 应用户要求【移除卡片渐变底】，与普通卡同底（var(--bg)）。
      层级感改由「主色数字 + 浅主色描边」承担，不再靠渐变面。
      ⚠ 不要加回 background 渐变。原先此处为：
        .kpi.hero{background:linear-gradient(150deg,rgba(61,90,254,.13),#fff 55%);
                  border-color:rgba(61,90,254,.18)} */
.kpi.hero{border-color:rgba(61,90,254,.18)}
.kpi.hero .k{color:var(--accent);font-weight:600}
.kpi.hero .v{color:var(--accent)}
/* 3) 卡片 hover 轻微上浮：交互反馈 */
/* 4) 标题 / 表头字重层级拉开 */
.panel > header{font-weight:650}
th{font-weight:600;color:var(--ink-3)}
.kpi .v{font-weight:750}
.svc .card .amt{font-weight:750}
/* 5) 面板标题左强调条 → 2026-10-02 应用户要求【整体移除】。
      模块标题前不再有任何竖线/强调条，标题直接左对齐到面板内边距。
      原先此处为：.panel > header::before{width:4px;height:16px;border-radius:2px;
                  background:linear-gradient(180deg,var(--accent),var(--accent-mid))}
      全站受影响 59 处模块标题（index.html 52 + client.html 7）。
      ⚠ 不要再加回来；标题的层级感由字号/字重（font-weight:650）承担。 */

/* ═══ 移动端弹窗适配（鸿蒙底部弹窗：全宽 · 底部滑出 · 内容滚动）═══ */
@media(max-width:760px){
  .modal{left:0;right:0;top:auto;bottom:0;
    width:100%;max-width:100%;max-height:86vh;overflow-y:auto;
    transform:translateY(100%);border-radius:18px 18px 0 0;
    /* 2026-10-03 紧凑化：18/18/22 → 13/13/18。弹窗是贴在屏幕底部的半屏卡片，
       内边距缩掉 5px 等于左右各多出 10px 给内容，窄屏上很值。 */
    padding:13px 13px calc(18px + env(safe-area-inset-bottom))}
  .modal.on{transform:translateY(0);opacity:1}
  .modal .fld{grid-template-columns:1fr;gap:6px 0}
  .modal .fld dt{font-size:calc(12px * var(--fz,1));color:var(--ink-3)}
  .modal .acts{flex-wrap:wrap}
}

/* ═══════════════════════════════════════════════════════
   v2 优化 · 信息架构重排 + 新增模块
   ═══════════════════════════════════════════════════════ */

/* 1) 二级子导航条（.subtabs）：整段已删除 · 2026-10-03
   它原本承载「组内切换」（业务组的四个子项、财务组的四个子项…），
   但左侧导航早就把这些入口平铺了一遍，是同一份清单的第二次出现。
   上一轮把「税务申报 / 收付款」补进侧栏后，二级条彻底冗余，按用户要求整块移除。
   这里同时删掉过前缀分组名 .st-lab（2026-10-03 早些时候）。
   ⚠ 别把 .st 这一族规则加回来 —— 表格里的 <th> 用的是 .sticky 等其他类，与此无关。 */

/* 2) 顶栏全局搜索：整段已按用户要求移除（2026-10-03）
   原 .gsearch / .gsearch-pop / .gs-row / .gs-empty 规则一并删除（见 index.html 顶栏注释）。
   ⚠ 别误删 .gs-row2 —— 那是「年度目标进度」面板用的，与 .gs-row 不是一回事。 */

/* 3) 表格面板的导出 / 打印 */
.tbl-acts{display:flex;gap:2px;margin-left:8px}

/* 4) 日历 */
/* 7 列日历：列必须用 minmax(0,1fr)。写 1fr 时列的最小尺寸是 auto，
   而 .ce 事件标签是 nowrap + 省略号，会把列撑到内容宽度 —— 窄屏直接顶破容器
   （实测 360px +78px / 430px +8px）。改成 minmax(0,1fr) 后省略号才会生效。 */
.cal-head,.cal-grid{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:6px}
.cal-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch}

/* 指标条目组（项目成本 / 电商盈亏 / 税务申报）
   原先写在各页内联 style 里（repeat(4,1fr) 与 repeat(3,1fr)），窄屏放不下会顶破
   容器（实测 360px +71px）。收成语义类，列数与间距交给断点控制。 */
.stat4{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:14px}
.stat3{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:14px}
.cal-head span{font-size:calc(11.5px * var(--fz,1));color:var(--ink-3);text-align:center;padding-bottom:4px}
.cal-d{min-height:76px;border:1px solid var(--border);border-radius:10px;padding:6px 8px;background:var(--bg)}
.cal-d.mute{background:transparent;border-color:transparent}
.cal-d b{font-size:calc(12.5px * var(--fz,1));color:var(--ink-2);font-weight:600;font-variant-numeric:tabular-nums}
.cal-d.today{border-color:var(--accent);background:var(--accent-soft)}
.cal-d.today b{color:var(--accent)}
.cal-d .ce{display:block;margin-top:5px;font-size:calc(11px * var(--fz,1));line-height:1.35;padding:2px 6px;
  border-radius:5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ev-biz{background:var(--accent-soft);color:var(--accent)}
.ev-renew{background:var(--bad-soft);color:var(--bad-ink)}
.ev-tax{background:var(--ok-soft);color:var(--ok-ink)}
.ev-ecom{background:var(--accent2-soft);color:var(--accent2)}

/* 5) 权限勾选区 */
.perm{display:flex;flex-wrap:wrap;gap:8px;margin-top:14px;padding:12px;
  border:1px solid var(--border);border-radius:var(--r-sm);background:var(--panel-2)}

/* 6) 敏感信息：默认不动，点击才露出完整内容 */
.secret{cursor:pointer;border-bottom:1px dashed var(--border)}
.secret:hover{border-bottom-color:var(--accent)}
.secret.revealed{color:var(--accent);font-weight:600;border-bottom-style:solid}

/* 7) 侧栏底部「单人信息」三条规则已随署名卡移除而删除 · 2026-10-03 */

/* 8) 响应式
   2026-10-03：原「窄屏收窄搜索框」「移动端搜索独占一行 + .top 换行」两条
   随顶栏搜索框移除而删除；同日稍后连标题条与二级导航条也整块移除，
   故这一段现在只剩日历单元格的窄屏尺寸。 */
@media (max-width:760px){
  /* .subtabs 的窄屏内边距随头部移除而删除 · 2026-10-03 */
  .cal-d{min-height:60px;padding:4px 5px}
  .cal-d .ce{font-size:calc(10px * var(--fz,1));padding:1px 4px}
}

/* ══════════════ 品牌标 · 统一形态 ══════════════
   工作台侧栏与客户门户（侧栏 + 登录页）统一为「渐变块 + 白色圆角方框」，
   不再各自放一个人像图标。图标体系见 style-icons.css。 */
.c-brand .mk{
  width:30px;height:30px;border-radius:8px;flex:none;position:relative;
  background:linear-gradient(140deg,var(--accent),var(--accent2));
  display:block;color:#fff;
}
.c-brand .mk::after{
  content:"";position:absolute;left:8px;top:8px;
  width:14px;height:14px;border:2px solid rgba(255,255,255,.85);border-radius:3px;
}
/* 登录页 logo 是 44px 的渐变块（display:grid 居中），方框直接用伪元素占位 */
.c-auth .logo::after{
  content:"";width:20px;height:20px;
  border:3px solid rgba(255,255,255,.9);border-radius:5px;
}

/* ══════════════ 侧栏收起态 · 图标轨道（≤1180px）══════════════
   收起后侧栏只有 66px，`.side` 内边 10px×2 + 右发丝线 1px → 实际内容宽仅 45px。
   原先只隐藏了导航文字（`.side .lb`），剩下三处文字仍按原字号排版，被压成窄条后逐字竖排：

     元素         实测内容盒   症状
     ──────────  ─────────  ─────────────────────────────
     .brand 文字    15px      「集中科技」竖排 12 行，整块溢出 20px
     .foot 文字      4px      「集中科技 / 郑州市惠济区·经营台」竖排 14 行，溢出 8px
     .side a 内容   25px      图标 17 + 间距 10 + 徽标 18 = 45，溢出 20px

   → 2026-10-03：`.foot` 署名卡已整块移除，上表第 2 行随之消失（此处保留原表，
     因为它记录的正是当年做这段收起态规则的**依据**，删掉就无法理解 `.brand` 那条为何存在）。

   处理原则：收起态只保留「图形」，文字一律不参与排版；徽标脱离文档流挂右上角。

   ★ 本段必须位于文件末尾 ★ —— 前面存在同选择器的规则
     （如第 55 行 `.grp`），同特异性下靠「后出现者胜」，放到前面会被覆盖。
   注：编号与明细见 `_icons/measure_rwd.py`（响应式探针，可随时复测）。 */
@media (max-width:1180px){
  /* 品牌：只留渐变标，居中 */
  .brand{justify-content:center;padding:2px 0 16px}
  .brand>div{display:none}

  /* 分组小标题：居中并收紧字距，避免 45px 内挤 */
  .grp{text-align:center;padding:16px 0 5px;letter-spacing:.02em}

  /* 导航项：去掉横向内边让内容盒回到 45px，图标居中；徽标改绝对定位 */
  .side a,.c-nav a{gap:0;justify-content:center;padding-left:0;padding-right:0}

  /* 数量徽标：右上角小胶囊。白圈（2px）把与图标的重叠切开，读作「角标」而非压字。
     尺寸取 13px：图标居中占 14~31，徽标 right:1px 占 31~44，两者刚好相切不互相压。 */
  .side .bdg,.c-nav .bdg{margin-left:0;position:absolute;top:3px;right:1px;
    min-width:13px;height:13px;padding:0 3px;font-size:calc(9.5px * var(--fz,1));line-height:1;
    display:grid;place-items:center;border-radius:999px;
    box-shadow:0 0 0 2px var(--bg)}
  /* 「客户门户 · 演示」入口已移除，其徽标收成圆点的规则一并删除（2026-10-03） */

  /* 底部：署名卡（.side .foot）已整块移除，此处原有三条收起态规则一并删除 · 2026-10-03 */
}

/* ═══════════════════════════════════════════════════════════════════
   表格滚动容器 .tbl-wrap（全断点共用）
   ───────────────────────────────────────────────────────────────────
   _icons/wrap_tables.py 给 index.html 的 30 个 / client.html 的 2 个
   <table> 各包了这一层。

   为什么不只在手机端生效：
     弹窗里的「数据口径说明」表（#glossary，3 列）min-content 宽 682px，
     而 .modal 内容宽只有 434px —— 在桌面端同样放不下，
     改造前它一直在溢出 248px（旧扫描器把问题算在 .modal 头上，
     而 .modal 是「隐藏但仍在布局中」的，因此长期没被发现）。
     有滚动容器才是根治。

   正常表格 width:100% 不会触发滚动，只有内容确实比容器宽时才出现滚动条。
   ═══════════════════════════════════════════════════════════════════ */
.tbl-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch}

/* 图表横滑容器 .chart-wrap（2026-10-03 第十四件）
   ───────────────────────────────────────────────────────────────────
   与 .tbl-wrap 同一个机制、同一套边缘渐隐（app.js 的 sync 已把它一起收进去），
   只是用来装图表而不是 <table>。
   2026-10-04 起柱状图改成流式布局（见下面的 .bars），本身不再横向溢出，
   保留它是当兜底：`.bars` 有 `min-width:260px`，极窄屏仍可横滑。
   ⚠ 必须直接挂在 .panel 下面一层：`.panel:has(> .chart-wrap)` 与 app.js 的
     `w.parentElement` 判断都要求它是 .panel 的**直接子元素**，包在 .pad 里就不生效。 */
.chart-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch}

/* ═══════════════════════════════════════════════════════════════════
   ★双轴柱状图 .bars（2026-10-04 · 应用户要求）★
   ═══════════════════════════════════════════════════════════════════
   用户要求：「柱状图区域要随着其所在的模块宽度，自动调整相互间距」。

   改造前是一张固定 viewBox 的 SVG：`viewBox="0 0 600 258"` + `width:100%` +
   固定 `height:238px`。`preserveAspectRatio` 默认 `xMidYMid meet`，缩放比取
   `min(容器宽/600, 238/258)` —— 容器一旦宽过 600×(238/258) = **553.5px**，
   就改由**高度**定标，整张图缩在中间、两侧各留一大片空白。
   实测（2560×1440 显示器、窗口最大化）：模块内宽约 1095px，图只占中间 553px，
   左右各空约 271px —— 柱子看着又细又挤，且**完全不理模块宽度**。

   所以不再用 SVG 画柱状图，改成 CSS 栅格 + flex：
     · 横轴 6 个月各占一格（`.bcol{flex:1 1 0}`）→ **组间距随模块宽度自动收放**；
     · 两根柱宽度取格宽的 26%（clamp 12~48px）→ 柱宽也随宽度增长；
     · 双轴刻度 / 月份 / 轴标题都是**普通 DOM 文字**，固定 11px（×`--fz`），
       不再跟着 viewBox 缩放 —— 原方案在 390px 下缩放比只有 0.533，
       轴标签被压到约 5.9px，当时不得不把整张图钉成 600px 宽让容器横滑。
       现在没有这个问题，窄屏也是 11×1.16 ≈ 12.8px。
   纵向与改前一致：12px（轴标题行）+ 208px（绘图区）+ 18px（月份行）= **238px**，
   柱高按 208px 折算成百分比，数值与改前逐条相等（52.04% = 原 108.25/208）。
   ⚠ 网格线用背景渐变画（`repeat-y` 25% 一格 + 底线单独一层），不占布局。 */
.bars{display:grid;min-width:260px;height:238px;
  grid-template-columns:auto minmax(0,1fr) auto;
  grid-template-rows:12px 208px 18px;column-gap:6px}
/* 绘图区标题：软件靠左、淘宝靠右，压在绘图区上方（对位改前的 x=50 / x=596） */
.bars-t{grid-row:1;font-size:calc(11px * var(--fz,1));line-height:12px}
.bars-t.sw{grid-column:2;justify-self:start;color:var(--accent)}
.bars-t.tb{grid-column:2;justify-self:end;color:var(--accent2)}
/* 双轴刻度：5 个刻度用 space-between 排，而每个 span **高度为 0** ——
   于是文字的垂直中线正好落在它所在的位置上，即 5 条网格线（0/25/50/75/100%）上。
   这是 DOM 里复刻 SVG 文字基线的唯一稳法（用 grid 均分 5 行会落在 10/30/50/70/90%）。 */
.bars-y{grid-row:2;display:flex;flex-direction:column;justify-content:space-between;
  font-size:calc(11px * var(--fz,1));line-height:1;color:var(--ink-3)}
.bars-y.sw{grid-column:1;padding-right:2px}
.bars-y.tb{grid-column:3;padding-left:2px;color:var(--accent2)}
.bars-y > span{height:0;display:flex;align-items:center;white-space:nowrap}
.bars-y.sw > span{justify-content:flex-end}
/* 绘图区：flex 行 = 每月一格，柱底与底线齐平 */
.bars-plot{grid-column:2;grid-row:2;display:flex;
  background:
    linear-gradient(rgba(20,24,80,.06) 0 1px,transparent 1px) 0 0/100% 25% repeat-y,
    linear-gradient(rgba(20,24,80,.06) 0 1px,transparent 1px) 0 100%/100% 1px no-repeat}
.bcol{flex:1 1 0;min-width:0;display:flex;align-items:flex-end;justify-content:center;gap:6px}
.b{display:block;width:clamp(12px,26%,48px);height:var(--h);background:var(--c);border-radius:3px}
/* 月份行：6 等分，格子边界与上面的 .bcol 一一对应 */
.bars-x{grid-column:2;grid-row:3;display:flex;
  font-size:calc(11px * var(--fz,1));line-height:18px;color:var(--ink-3)}
.bars-x > span{flex:1 1 0;min-width:0;text-align:center;white-space:nowrap}

/* ═══════════════════════════════════════════════════════════════════
   ★年度申报时间线 .tl（2026-10-04 · 与 .bars 同一次改造）★
   ═══════════════════════════════════════════════════════════════════
   改前：`viewBox="0 0 900 90"` + `width:100%` + 固定 `height:86px`。
   与上面 `.bars` **完全同一个病**（详见那里的推导）：缩放比 = `min(容器宽/900, 86/90)`，
   一旦容器宽过 900×(86/90) = **860px** 就改由高度定标，缩放比被钉死在 0.9556，
   整条时间线缩在正中间不再变宽。实测左右纯空白：
     1440 → 各 132px    1920 → 各 372px    2560 → 各 692px
   （凭证见 index.html 里那段替换说明，`getScreenCTM().a` 恒为 0.96）

   改后：节点一律按 `left:var(--x)` 百分比定位，`--x` = 原 `cx/900`，
   轴向两端各留 40/900 = 4.44%（= 原 `x1=40` / `x2=860`）。
   容器多宽、节点就铺多宽 —— 不需要 JS，也不需要反复重算。
   ⚠ 标签是 `position:absolute` 独居一层（不参与节点的盒子计算），
     所以即使相邻两个标签宽度差很多，也不会把节点挤歪。
   ⚠ 圆点加了 3px 白描边（`box-shadow`）把轴线在点位上"断开"，改前是靠
     circle 后画盖住 line；现在 DOM 里 `.tl-line` 是先写的兄弟节点，
     叠放顺序天然在圆点之下，靠白边做出同样的视觉。
   ⚠ ≤760px 降级成竖排列表（见文件末尾的媒体查询）—— 原方案在 390px 下
     缩放比只有 0.43，11px 的字被压到 4.7px，根本读不了。 */
.tl{position:relative;height:86px;min-width:520px}
.tl-line{position:absolute;left:4.444%;right:4.444%;top:50%;height:2px;
  margin-top:-1px;background:rgba(20,24,80,.12)}
.tl-node{position:absolute;left:var(--x);top:50%;width:0;height:0}
.tl-node .dot{position:absolute;left:0;top:0;width:var(--d);height:var(--d);
  margin:calc(var(--d) / -2) 0 0 calc(var(--d) / -2);
  border-radius:50%;background:var(--c);box-shadow:0 0 0 3px var(--bg)}
.tl-node .lab{position:absolute;left:50%;top:12px;transform:translateX(-50%);
  white-space:nowrap;font-size:calc(11px * var(--fz,1));font-weight:400;
  line-height:1.35;color:var(--ink-3)}
/* 第一个节点是「当前期」，原图标签在轴上方且用红字加粗 —— 保留这个差别 */
.tl-node.up .lab{top:auto;bottom:14px;color:#8f2f27;font-weight:600}

/* ═══════════════════════════════════════════════════════════════════
   业务深化组件 · 2026-10-02
   ───────────────────────────────────────────────────────────────────
   配套新增/深化的模块：获客线索、产品与授权、经营核算、
   年度目标进度、客户分层、工时投入。

   设计原则（与全站一致）：
     · 颜色只走已有的语义变量（accent / ok / warn / bad），不新增色值；
     · 层级靠「字号 + 字重 + 浅底」表达，不靠竖线（竖线已按要求全站移除）；
     · 这些组件都不带边框，嵌在 .panel 内，由面板提供卡片边界。
   ═══════════════════════════════════════════════════════════════════ */

/* 1) 客户分层徽章：A / B / C 三档 —— 颜色即优先级，字母即分档 */
.tier{display:inline-grid;place-items:center;width:22px;height:22px;
  border-radius:7px;font-size:calc(11.5px * var(--fz,1));font-weight:700;line-height:1}
.tier.a{background:var(--accent);color:#fff}
.tier.b{background:var(--accent-soft);color:var(--accent)}
.tier.c{background:var(--panel-2);color:var(--ink-3)}

/* 2) 线索阶段分布条
   注意：这是「分布」不是「累计漏斗」—— 每条线索只落在唯一阶段，
   所以各段之和 = 本月线索总数，不做逐级递减以免误导。            */
.fn-row{display:grid;grid-template-columns:78px 1fr 40px;align-items:center;gap:12px}
.fn-row + .fn-row{margin-top:10px}
.fn-l{font-size:calc(12.5px * var(--fz,1));color:var(--ink-3)}
.fn-n{font-size:calc(13px * var(--fz,1));font-weight:650;color:var(--ink-1);text-align:right}
.fn-bar{height:10px;border-radius:5px;background:var(--panel-2);overflow:hidden}
.fn-bar i{display:block;height:100%;border-radius:5px;
  background:linear-gradient(90deg,var(--accent-mid),var(--accent))}
.fn-bar.ii-bad i{background:linear-gradient(90deg,#E8776A,var(--bad))}

/* 3) 年度目标进度：左侧主目标大条 + 右侧三个小目标 */
.goal{display:grid;grid-template-columns:1.35fr 1fr;gap:20px;align-items:center}
.goal-k{font-size:calc(12.5px * var(--fz,1));color:var(--ink-3)}
.goal-v{display:flex;align-items:baseline;gap:7px;font-size:30px;font-weight:750;
  color:var(--accent);line-height:1.25;margin-top:3px;font-variant-numeric:tabular-nums}
.goal-v em{font-size:calc(12.5px * var(--fz,1));font-weight:500;color:var(--ink-3);font-style:normal}
.goal-v b{font-size:calc(14px * var(--fz,1));font-weight:600;color:var(--ink-3)}
.goal-sep{font-size:calc(15px * var(--fz,1));color:var(--ink-3);font-weight:400}
/* 进度条：实色 = 已完成，斜纹 = 剩余（斜纹不抢眼，一眼分得清） */
.gbar{display:flex;height:12px;border-radius:6px;overflow:hidden;
  background:var(--panel-2);margin-top:10px}
.gbar i{display:block;height:100%;background:linear-gradient(90deg,var(--accent-mid),var(--accent))}
.gbar i.ghost{background:repeating-linear-gradient(135deg,#E3E6F8,#E3E6F8 4px,#F0F2FC 4px,#F0F2FC 8px)}
.goal-f{font-size:calc(12px * var(--fz,1));color:var(--ink-3);margin-top:8px}
.goal-f b{color:var(--ink-2);font-weight:600}
.goal-side{display:flex;flex-direction:column;gap:11px}
.gs-row2{display:grid;grid-template-columns:72px 1fr 52px;align-items:baseline;gap:10px;font-size:calc(12.5px * var(--fz,1))}
/* 「真实净利润」5 个字：手机端原先把标签列定成 60px，放不下 5×14.5≈73px，
   被拆成「真实净 / 润」。修法 = 标签不给断 + 窄屏把标签列从定宽改成 auto（= 内容宽），
   让中间的值列让出十几个像素。桌面 72px 列本来就装得下（5×12.5 = 62.5px），
   加了 nowrap 也仍是逐像素不变（已用 1440px 截图 SHA256 对比确认）。 */
.gs-row2>span{color:var(--ink-3);white-space:nowrap}
.gs-row2>b{color:var(--ink-1);font-weight:600;font-variant-numeric:tabular-nums}
.gs-row2>em{font-style:normal;font-weight:650;color:var(--accent);text-align:right}

/* ═══════════════════════════════════════════════════════════════════
   移动端触控优化（≤760px）· 2026-10-02
   ───────────────────────────────────────────────────────────────────
   【为什么要专门做这一段】
   Chrome 在 Windows 上把窗口宽度强制到最小 512px，
   `--headless=new --window-size=390,844` 量到的 documentElement.clientWidth
   仍是 512 —— 媒体查询虽然触发，但一切按 512px 排版，**手机端量测全是假数据**
   （旧脚本 check_overflow.py 因此在手机上「零溢出」，实为假通过）。
   本次改用 CDP 设备模拟（`_icons/cdp.js` + Emulation.setDeviceMetricsOverride）
   才拿到真实 390×844 / DPR3 / 触屏 的渲染。

   【改造前实测（390×844）】
     可点元素 208 个 → 163 个高度 <32px、37 个 32~44px。
     最差的几类：
       <a class="op">（表格内「编辑/修改」）… 20~23px 高
       <span class="chip">（筛选胶囊）    … 29px
       .st（二级导航）                    … 30px
       .btn（含顶栏「新增客户」）          … 36px
       <button class="op">（列表行操作）   … 28px
     另有两处结构性问题：
       · 宽表被硬挤 —— 390px 下「客户管理」表第 4~6 列完全不可见且无法滑动
       · 面板标题、说明、操作挤在一行 —— 标题折两行、meta 折两行、头像被压扁

   【触控基线】（Apple HIG 44pt / Material 48dp 的通行底线）
     主操作按钮 ........ ≥44×44
     列表行内操作 ...... ≥44 高，且独立成行（不与文字争横向空间）
     紧凑筛选胶囊 ...... ≥40 高（紧凑控件的行业惯例区间），行间 ≥10px
     表格内操作 ........ ≥44 高；表格整体横滑，不再压缩列宽

   ★ 本段必须留在 style.css 最末尾 ★
     第 416 行的 ≤760px 弹窗段、第 532 行的 ≤1180px 收起态段都在前面，
     同特异性下靠「后出现者胜」，移到前面会被覆盖。
     （本项目已有前车之鉴：侧栏收起态段落必须留在末尾，同类问题。）
   ═══════════════════════════════════════════════════════════════════ */

@media (max-width:760px){

  /* ── 1) 顶栏：整块已移除（面包屑 / 搜索框 / 新增客户 2026-10-03 早些时候移除，
     页面标题条与二级导航条于同日整块移除）。原 .top / .top h1 的窄屏规则一并删除。 ── */
  /* 筛选区里的搜索框：外层 .field 给 44 高，内层 input 同时撑满，
     这样「点输入框周围一圈」也能聚焦 —— 否则只有 20px 高的文字行可点。 */
  .field{min-height:44px;padding:0 11px}
  .field input{height:100%;min-height:44px}

  /* ── 2) 通用按钮 ─────────────────────────────────────────────── */
  /* 2026-10-03 紧凑化：左右内边距 16→11（原来一颗「导出 Excel」光内边距就吃掉 32px）。
     ⚠ 只缩左右 —— 上下是 0，高度全靠 min-height:44 撑，这是触控底线（铁律 11），
       动它会让 1242 个按钮重新掉出 44×44。 */
  .btn{min-height:44px;padding:0 11px;font-size:calc(14px * var(--fz,1));gap:8px}
  .btn svg,.btn .icn{width:17px;height:17px}

  /* ── 3) 行内操作 .op（改造前 165 处不达标，最大头）────────────
     桌面端 .op 是「蓝色小文字 + 2px/6px 内边」≈ 28px 高，
     在触摸屏上既是小目标、又没有按钮的可点暗示。
     移动端一律做成 44px 高的独立目标，底色浅淡以明确「按这里」。 */
  .op{
    display:inline-flex;align-items:center;justify-content:center;
    min-height:44px;padding:0 11px;border-radius:10px;
    font-size:calc(13.5px * var(--fz,1));font-weight:600;white-space:nowrap;
    background:var(--accent-soft);
  }
  .op.s2{background:var(--accent2-soft)}
  /* 同行两个操作之间留足 8px，避免「想点左边点到右边」 */
  .op + .op{margin-left:8px}
  .tbl-acts{gap:8px}

  /* 表格里的操作去掉淡底：整列发蓝太花，靠 44px 盒高保证可点性 */
  .tbl-wrap .op{background:transparent;padding:0 9px}

  /* ── 4) 筛选条 ───────────────────────────────────────────────── */
  .filters{gap:10px;padding:11px}
  .filters .fl{font-size:calc(12.5px * var(--fz,1))}
  .filters .field{flex:1 1 100%;min-width:0}      /* 搜索框独占一行 */
  .filters .btn{flex:1 1 100%}                     /* 主按钮整行、拇指好按 */
  .filters > .btn + .btn{margin-left:0}
  .chip{min-height:44px;padding:0 11px;display:inline-flex;
    align-items:center;font-size:calc(13px * var(--fz,1));border-radius:999px}

  /* ── 5) 二级导航（.subtabs）的移动端触控规则：随头部整块移除而删除 · 2026-10-03
     这里原有一条 44px 触控 + 右缘渐隐的规则（当时 390px 下「工单售后」会被裁掉）。
     头部移除后，移动端的组内切换只剩底部 .mtab 与内容区里的下钻入口，
     故这族规则已无对象，一并清理。 */

  /* ── 6) 面板 header：标题与操作一行，说明文字另起一行 ──────────
     改造前：「软件客户与项目」折成两行，「导出 Excel / 打印」各折两行，
     meta 折两行 —— 三者抢同一行。                                              */
  /* 紧凑化的同时把 header 与 .pad 的左右内边距**对齐到同一个数（13px）**：
     改造前 header 15 / pad 18，标题与表格首列差 3px 不同轴；现在都一样，
     视觉上标题正好压在内容左边界上（铁律 5 的分寸）。 */
  .panel > header{flex-wrap:wrap;align-items:center;gap:7px 10px;padding:10px 13px}
  .panel > header .sp{display:none}
  .panel > header > .meta,
  .panel > header > .legend{flex:1 1 100%;order:3;white-space:normal;
    line-height:1.5;font-size:calc(12px * var(--fz,1))}
  /* 说明文字里夹的导航链接（如「进入提醒中心 →」）要够高才点得准 */
  .panel > header > a.meta{display:inline-flex;align-items:center;
    min-height:44px;color:var(--accent);font-weight:600;font-size:calc(13px * var(--fz,1))}
  .panel > header > .op:first-of-type,
  .panel > header > .tbl-acts{margin-left:auto}

  /* ── 7) 表格：改为可横滑，不再压列 ───────────────────────────
     配 _icons/wrap_tables.py 给每个 <table> 包的 .tbl-wrap 容器。
     width:max-content 让表格按内容宽度排布（列不再被挤成一条），
     超出容器即横滑；min-width:100% 保证窄表仍撑满。                   */
  .tbl-wrap table{width:max-content;min-width:100%}
  /* 容器本身的可滚性见文件前面「表格滚动容器 .tbl-wrap（全断点共用）」段 */
  /* 能滑必须让人看出来 —— 否则用户以为「就这几列」。
     做法：表格区左右边缘压一层「白→透明」渐隐（覆盖在内容之上）。
     两个关键点：
       ① 渐隐必须挂在【不滚动】的祖先上，否则会跟着表格一起滚走。
          故基准取 .panel（position:relative），而不是 .tbl-wrap 自己。
       ② top 用 --tbl-h（面板标题的实际高度，由 app.js 写入），
          让遮罩只盖住表格区，不碰标题 —— 这样也不必给 header 补背景色，
          在客户门户那种「渐变底面板」上才不会露出色块。
     类名由 app.js / client.html 的 sync 按实际滚动位置切换：
     能往右滑才显右渐隐，滑到头即消失（纯 CSS 判断不了滚动位置）。  */
  .panel:has(> .tbl-wrap),
  .panel:has(> .chart-wrap){position:relative}
  .panel.tbl-ovf-r::after,
  .panel.tbl-ovf-l::before{
    content:"";position:absolute;left:auto;right:auto;
    top:var(--tbl-h,0);bottom:0;width:36px;
    z-index:2;pointer-events:none}
  .panel.tbl-ovf-r::after{right:0;
    background:linear-gradient(90deg,rgba(255,255,255,0),#fff 82%)}
  .panel.tbl-ovf-l::before{left:0;
    background:linear-gradient(270deg,rgba(255,255,255,0),#fff 82%)}
  /* td 原为固定 height:var(--row) 且上下无 padding，
     放不下 44px 的操作按钮，改为内容撑高。 */
  th,td{height:auto;padding-top:13px;padding-bottom:13px}

  /* ── 8) 提醒列表：操作按钮移到下一行右对齐 ───────────────────
     原 grid 为 `14px 1fr auto`，操作列挤得正文只剩不到 300px。
     现在让 .op 跨到第 2 行右端，正文独占第一行。                        */
  .remind .row{row-gap:11px;padding:14px 16px;align-items:center}
  .remind .row > .op{grid-column:2 / 4;grid-row:2;justify-self:end}
  .remind .t,.remind .d{white-space:normal}

  /* ── 9) 底部 Tab 与弹窗 ──────────────────────────────────────── */
  .mtab a{padding:9px 0 7px;gap:3px}
  .mtab .icn{width:22px;height:22px}
  /* 未读徽标：绝对定位贴在图标右上角。
     ⚠ .mtab a 是纵向 flex（图标 / 文字），数字徽标若当普通子元素会被挤成第三行，
       故走绝对定位 —— 与侧栏收起态（.side .bdg 的窄屏规则）同一手法。 */
  .mtab a{position:relative}
  .mtab a .bdg{position:absolute;top:3px;left:50%;margin-left:3px;
    min-width:16px;height:16px;padding:0 4px;border-radius:999px;
    background:var(--bad);color:#fff;font-size:calc(10px * var(--fz,1));line-height:1;
    display:grid;place-items:center;font-weight:600;box-shadow:0 0 0 2px var(--bg)}
  .modal .acts{gap:8px}
  .modal .acts .btn{flex:1 1 0;min-height:48px;justify-content:center}
  .fld dd input,.fld dd select{min-height:44px}

  /* ── 10) 其余小控件 ─────────────────────────────────────────── */
  .perm label,.agree{min-height:44px}
  .legend{line-height:1.9}
  /* 客户门户登录页：原生复选框只有 13px 见方，是最典型的「小目标」。
     做法：触控交给外层 label（点文字也能勾选），方框本身放大到 19px 便于看清。 */
  .c-auth label:has(input[type=checkbox]),
  .c-auth label:has(input[type=radio]){
    min-height:44px;display:flex;align-items:center;gap:8px}
  .c-auth input[type=checkbox],.c-auth input[type=radio],
  .agree input[type=checkbox],.agree input[type=radio]{width:19px;height:19px}
  /* 登录页的文字链接（如「免费注册 →」）原为 19px 高 */
  .c-auth a{min-height:44px;display:inline-flex;align-items:center}

  /* ── 11) 业务深化组件：窄屏纵向堆叠 ──────────────────────────
     目标块在 390px 下左右并排会把数字挤成两行，改上下堆叠；
     阶段分布条与渠道行同步收窄首列，给中间的数字让出宽度。   */
  .goal{grid-template-columns:1fr;gap:16px}
  .goal-v{font-size:26px}
  .gs-row2{grid-template-columns:auto 1fr auto;gap:8px}
  .fn-row{grid-template-columns:66px 1fr 34px;gap:9px}

  /* ── 12) 指标条窄屏防溢出 ────────────────────────────────────
     .kpi .v 是 baseline 对齐的 flex，默认不换行。360–390px 下两列各只剩
     约 130–140px 净宽，hero 卡的「¥38.6万 + ▲12.4%」放不下会顶破容器
     （实测 360px +19px / 390px +5px，连锁把 section、body 一起撑宽）。
     做法：允许换行 + 收紧卡片内边距；字号与单列兜底见文件末尾两段。   */
  .kpi{padding:10px 11px 11px}
  .kpi .v{flex-wrap:wrap;row-gap:3px}

  /* ── 13) 日历横滑 + 指标条目组降列 ───────────────────────────
     日历给容器设最小宽度后交由 .cal-wrap 横滑：每格约 67px，
     「发货对账」这类 4 字标签能完整显示，不再被省略号截断。
     指标条目组由 4 / 3 列降为 2 列，360px 下每列仍有约 158px 净宽。 */
  .cal-wrap .cal-head,.cal-wrap .cal-grid{min-width:472px}
  .stat4,.stat3{grid-template-columns:1fr 1fr;gap:10px}

  /* ── 14) 筛选区：折叠成「一行横滑胶囊 + 一行搜索/主按钮」──────
     改前最多 5 行（3 组「标签+胶囊」各占一行、搜索一行、按钮一行），
     光筛选区就吃掉约 288px。改后 2 行、约 130px：
       行 1  .fx-rail        标签与胶囊横滑，不再换行
       行 2  .field + .btn   搜索框与主按钮同行常驻
     关键取舍：搜索与「新增 XX」是高频动作，绝不能跟着胶囊一起滑走，
     所以它们留在 rail 外面。桌面端 .fx-rail 是 display:contents，不受影响。 */
  /* overflow:hidden 有两个作用：① 让下面的渐隐伪元素被卡片圆角裁掉，
     否则矩形白块会从圆角处露到浅紫灰页面底上；② 不影响 rail 自己的横滑。 */
  .filters{position:relative;gap:10px;overflow:hidden}
  .fx-rail{display:flex;flex-wrap:nowrap;align-items:center;gap:8px;
    width:100%;overflow-x:auto;overflow-y:hidden;
    -webkit-overflow-scrolling:touch;scrollbar-width:none;padding:2px 0}
  .fx-rail::-webkit-scrollbar{display:none}
  .fx-rail > *{flex:none}                        /* 标签与胶囊不被压扁 */
  .filters .field{flex:1 1 auto;min-width:0}     /* 与主按钮同行，让出空间给按钮 */
  .filters .btn{flex:0 0 auto}                   /* 按钮按内容宽，不再独占一行 */
  /* 能滑要看得出来：与表格同一套做法（类由 app.js 按实际滚动位置切换）。
     渐隐只盖横滑那一行，位置与高度由 JS 实测写入 --fx-top / --fx-h ——
     不写死 padding，桌面与移动的 padding 不同。
     宽度取 40px 而非表格的 36px：卡片有 14px 内边距 + 1px 边框，
     30px 里只有 15px 压在内容上，白雾太薄看不出「还能滑」。
     （注：2026-10-03 紧凑化后卡片内边距已 14→11，白雾只会更厚，无需调整。） */
  .filters.fx-ovf-r::after,
  .filters.fx-ovf-l::before{content:"";position:absolute;
    top:var(--fx-top,0);height:var(--fx-h,44px);width:40px;
    z-index:2;pointer-events:none}
  .filters.fx-ovf-r::after{right:0;
    background:linear-gradient(90deg,rgba(255,255,255,0),var(--bg) 80%)}
  .filters.fx-ovf-l::before{left:0;
    background:linear-gradient(270deg,rgba(255,255,255,0),var(--bg) 80%)}

  /* ── 16) 申报时间线 .tl：百分比定位 → 竖排列表 ─────────────────
     桌面的横向时间线到了手机上会变成两难：① 保持横向 → 11px 的标签
     被压到 4.7px（改前 SVG 就是这个下场）；② 强行放大 → 相邻标签互相重叠。
     所以这里直接取消绝对定位，降级成「圆点 + 文字」的竖排列表。
     ⚠ 别忘了把 .tl 的 min-width 也清掉 —— 它一旦留着，390px 下整块会
       横向溢出 130px（含卡片一起被 check_mobile.js 判爆）。 */
  .tl{position:static;height:auto;min-width:0;
    display:flex;flex-direction:column;gap:12px}
  .tl-line{display:none}
  .tl-node{position:static;left:auto;top:auto;width:auto;height:auto;
    display:flex;align-items:center;gap:10px}
  .tl-node .dot{position:static;left:auto;top:auto;margin:0;flex:0 0 auto}
  .tl-node .lab,
  .tl-node.up .lab{position:static;left:auto;top:auto;bottom:auto;
    transform:none;white-space:normal;
    font-size:calc(12.5px * var(--fz,1));text-align:left}
}

/* ── 窄屏兜底一档（≤430px）· 2026-10-02 ────────────────────────
   401–430px 仍维持两列，靠降字号 + 换行挤下；420 左右是最紧的一档。
   放在 ≤760px 移动段之后，保证优先级覆盖上面的字号。            */
@media (max-width:430px){
  .kpi .v{font-size:23px}
  .kpi.hero .v{font-size:27px}
  .kpi .foot{gap:10px}
  .goal-v{font-size:25px;flex-wrap:wrap}
}

/* ── 窄屏兜底二档（≤400px）· 2026-10-02 ────────────────────────
   360 / 375px 下两列已无余量（即使 23px 也会把「¥38.6万」和徽章挤到贴边），
   直接改单列：KPI 每张独占一行，数字反而更舒展、更好读。
   单列后宽度富裕，字号回调一档，避免整页显小。                   */
@media (max-width:400px){
  .kpis{grid-template-columns:1fr}
  .kpis.k3{grid-template-columns:1fr}
  .kpi .v{font-size:25px}
  .kpi.hero .v{font-size:29px}
  .gs-row2{grid-template-columns:auto 1fr auto;gap:7px}
  .fn-row{grid-template-columns:58px 1fr 30px;gap:8px}
}

/* ═══════════════════════════════════════════════════════════════════
   悬浮玻璃侧栏 · 科技感（≥761px）· 2026-10-03 第四轮
   ───────────────────────────────────────────────────────────────────
   诉求：「将左侧整体做成圆角卡片背景、半透明悬浮效果，更富有科技感」。

   三层叠加实现：
     ① **页面底 → 多色径向光斑**。把 `.app` 从纯色 `--page` 换成
        蓝紫主色（左上）+ 陶土辅色（右上）+ 底部回光（下中）三团柔和光斑。
        侧栏是半透明的，光斑会从它背后透上来 —— 这是「玻璃」能成立的前提，
        纯色底上做半透明等于没做（看不出通透）。
     ② **侧栏 → 独立卡片**。给 `.app` 加 14px 内边距 + 14px 列间距，
        侧栏从「贴边通栏」变成一张离页边 14px 的圆角卡片。
     ③ **玻璃质感**。半透明白底 + `backdrop-filter` 模糊背后的光斑，
        再补两道描边（外圈白色亮边 + `inset` 顶部高光）与一层大而柔的投影，
        把卡片从页面「托」起来。

   ⚠ 四个必须守住的点：
     · **只在 ≥761px 生效**。≤760px 侧栏本就隐藏（改用底部 `.mtab`），
       而 `.app` 加内边距会把移动端主区压窄 28px —— 上一轮刚调平的
       「21 视图 × 4 设备零溢出」会当场破功。故整段包在 `@media (min-width:761px)`，
       与已有的 `@media (max-width:760px)` 正好互补、无重叠区间。
     · **`calc(100vh - 28px)` 的 28 = 14×2**。内边距一改，`.side` 与 `.main` 两处都要同步改，
       否则 100vh + 上下各 14px 会凭空多出 28px 页面滚动条。
     · **必须写 `-webkit-backdrop-filter`**。部分 WebView（小程序内嵌页）只认前缀版，
       漏了会退化成一块不透明的白板 —— 比不加还难看。
     · **悬停/选中也要改成半透明**。`.side a:hover` 原用实色 `--panel-2`，
       在玻璃上会糊出一块不透明白斑，把质感盖掉。
   ═══════════════════════════════════════════════════════════════════ */
@media (min-width:761px){
  /* 2026-10-03 第八轮 · 边距统一为 14px（用户要求「侧栏顶边与右侧顶边齐平、
     侧栏左边距与右侧边距一致」）。
     改造前：侧栏外侧 14px，但 `.body` 自带 `22px 24px` 内边距 ——
     于是侧栏卡顶边在 14px、右侧第一张卡（筛选条 / 口径条）顶边在 36px，
     两者差 22px 斜着看很明显；内容右边缘在 1402（离屏边 38px）也与左侧的 14px 不齐。
     现在：
       · `.app` 右内边距收到 **0**、`.body` 自己带 `padding-right:14px` ——
         内容区右边缘 = 1440 − 14 = **1426**，离屏边正好 14px = 侧栏左边距 ✓；
         滚动条（10px）落在 `.body` 内边距里，不再额外吃掉内容宽度。
       · `.body` 的 `padding-top` 归 0 —— 第一张卡顶边 = 14px = 侧栏卡顶边 ✓。
     ⚠ 于是全屏四面都是 14px：屏左 14 | 侧栏 236 | 14 | 内容 | 14 | 屏右。
     ⚠ `.body` 的 padding-right 是 `calc(--gut − --sbw)` = 4px，不是 14px ——
       **滚动条占位是加在 padding 之外的**（实测：右内边距 14 + 滚动条 10 → 内容右边缘
       退到 1416，离屏边 24px，比左侧多出 10px）。所以要让「padding + 滚动条」合计 = 14px。
       另加 `scrollbar-gutter:stable` 常驻预留，页面长短不同也不会让右边距忽大忽小。
     ⚠ 改 `--sbw` 时 `::-webkit-scrollbar{width}` 与本节都要一起变（已用变量绑定）。 */
  .app,.c-app{
    padding:var(--gut) 0 var(--gut) var(--gut);
    gap:var(--gut);
    min-height:100vh;
    background:
      radial-gradient(1180px 640px at 6% -12%, rgba(61,90,254,.20), transparent 62%),
      radial-gradient(880px 540px at 104% 2%, rgba(196,99,63,.12), transparent 60%),
      radial-gradient(760px 720px at 46% 124%, rgba(91,124,255,.18), transparent 62%),
      var(--page);
  }
  .main,.c-main{height:calc(100vh - 28px)}
  /* 顶边与侧栏齐平（padding-top:0）＋ 右边距（padding + 滚动条）= 侧栏左边距 14px */
  .body,.c-shell{padding:0 calc(var(--gut) - var(--sbw)) 24px 0;scrollbar-gutter:stable}

  .side,.c-side{
    height:calc(100vh - 28px);
    border:1px solid rgba(255,255,255,.66);
    border-radius:20px;
    background:linear-gradient(160deg,rgba(255,255,255,.80),rgba(255,255,255,.56));
    backdrop-filter:blur(20px) saturate(1.6);
    -webkit-backdrop-filter:blur(20px) saturate(1.6);
    box-shadow:
      0 18px 46px rgba(31,42,120,.15),
      0 2px 6px rgba(31,42,120,.06),
      inset 0 1px 0 rgba(255,255,255,.92);
  }

  /* 玻璃底上的交互态：改半透明，别用实色块盖掉质感 */
  .side a:hover,.c-nav a:hover{background:rgba(255,255,255,.62)}
  .side a.on,.c-nav a.on{background:linear-gradient(100deg,rgba(61,90,254,.17),rgba(61,90,254,.07))}
}
/* 66px 图标轨道下 20px 圆角偏夸张，收一档更像精修的圆角胶囊 */
@media (min-width:761px) and (max-width:1180px){
  .side,.c-side{border-radius:16px}
}

/* ═══════════════════════════════════════════════════════════════════
   客户门户 · 外壳与管理端严格对齐（2026-10-06 · 应用户要求）
   ───────────────────────────────────────────────────────────────────
   client.html 的骨架类名是 .c-app / .c-side / .c-main / .c-shell
   （历史原因：它不引 app.js，早期连布局都自己写了一份）。
   改造前两套值并存，实测 1440×900 下的差距：

     | 口径             | 管理端             | 客户门户（旧）        |
     | 页面背景         | 3 团径向光斑       | 纯色 --bg-soft       |
     | 侧栏 x / y       | 14 / 14           | 0 / 0（贴边）        |
     | 侧栏 宽 / 高     | 236 / 872         | 224 / 900（通栏满高）|
     | 侧栏质感         | 圆角 20 + 毛玻璃   | 直角 + 实白 + 右边框 |
     | 侧栏内部滚动     | overflow-y:auto   | visible             |
     | 侧栏↔内容间距    | 14                | 108                 |
     | 内容右边缘离屏   | 14                | 108（居中定宽 1000） |
     | 首张卡片顶边     | 14（与侧栏齐平）   | 24                  |
     | 视图内卡片间距   | 18px              | 22px                |
     | KPI 列宽         | 278.5（4 列铺满）  | 228（挤在 960 里）   |

   本轮的做法不是「抄一遍值」，而是**把三处外壳声明改成成对选择器**
   （第 63 行基础段 / 第 478 行 ≤760 段 / 第 1158 行 ≥761 玻璃段），
   于是两边共用同一份 `${--gut}` 驱动的声明 —— 将来改 14px 匀边距，
   客户门户自动跟随，不会再分叉。

   ⚠ 本段只放客户门户**独有**的两件事，其他一概不放。
   ═══════════════════════════════════════════════════════════════════ */
@media (min-width:761px){
  /* ① 未登录态没有侧栏（.c-side 带 .hidden → display:none），门户点不出来第二列。
        ⚠ 这里必须写成**单列**，不能写成 `grid-template-columns:0 1fr` ——
          grid 的显式轨道不会因为 item 消失而塌陷，但**自动排布会把剩下的 item
          顺延到第一个可用格子**：侧栏被 display:none 后，唯一剩下的 .c-main
          会被塞进第 1 列；第 1 列宽若是 0，主区当场收缩成 0px（实测 h=872, w=0，
          整页只剩一条边）。正确做法是此刻只有一列 —— 单列 1fr 占满全宽。
        ⚠ 也不用 `:has(> .c-side.hidden)`：老安卓 WebView 不认 :has，
          一旦不支持就永久留白，比 JS 挂类脆弱得多。登录成功由 JS 给 .c-app
          挂 .authed 才恢复两列（见 client.html 的 #cLoginBtn.onclick）。 */
  .c-app{grid-template-columns:1fr;gap:0}
  .c-app.authed{grid-template-columns:var(--side) 1fr;gap:var(--gut)}
  /* ② 登录卡垂直留白：管理端没有这一步，是门户独有的首屏居中 */
  #cAuth{padding:8vh 0}
}
@media (min-width:761px) and (max-width:1180px){
  .c-app.authed{grid-template-columns:66px 1fr}
}

/* 2026-10-07：PC 端整体放大到「相当于浏览器 110%」的观感（胡先生反馈 100% 偏小、110% 刚好）。
   用 CSS `zoom` 等价于浏览器缩放，且 zoom 不会像 `transform: scale` 那样建立 fixed 定位包含块，
   故弹窗 / Toast / 滚动指示条（均 position:fixed，见下方 .scrim/.modal/.toast/.sbmin）不受影响。
   ① 仅 PC 端（>760px）生效，手机端保持原样（触达 44px 触控底线、窄屏紧凑化不被破坏）；
   ② 断点用 CSS 视口宽度判定，zoom 不改变媒体查询响应的视口宽度，故 1440 宽屏仍走完整侧栏布局；
   ③ 与浏览器 110% 一致：内容会比视口宽约 10%，出现整页横向滚动——这是用户已接受的「刚好」状态。
   若要更克制，把 1.1 调到 1.05~1.08 即可（横向溢出随之减小）。 */
@media (min-width:761px){ html{ zoom:1.1 } }

@media (max-width:760px){
  /* 移动端登录卡：≤760 段已把 .c-app 收成单列，这里只调垂直留白 */
  #cAuth{padding:4vh 0}
}

/* ── 宽弹窗变体（2026-10-03 第七轮 · 合作伙伴）───────────────────────
   伙伴详情弹窗里是 6 列表格（推荐日 / 推荐客户 / 成交额 / 佣金比例 /
   应付佣金 / 结算状态），内容宽实测 521px；而 `.modal` 基础段是
   `width:min(520px,92vw)` —— **只写内联 `max-width:720px` 不会变宽**
   （520 < 720，max-width 条件根本不成立），结果表格被压在 434px 里
   横向溢出 87px（交付自查量出来的）。故加一个显式 width 的变体类。
   ⚠ 窄屏必须把宽度让回去：`.modal` 在 ≤760px 是 100vw 的底部抽屉，
     而 `.modal.modal-wide` 特异性更高，不写这条会窄成 92vw、左右露缝。 */
.modal.modal-wide{width:min(720px,92vw)}
@media (max-width:760px){ .modal.modal-wide{width:100vw;max-width:100vw} }

/* ═══════════════════════════════════════════════════════════════════
   全局滚动条 · 细圆角「内缩胶囊」（2026-10-03 第五轮 · 应用户要求）
   ───────────────────────────────────────────────────────────────────
   改造前只有 `.side` / `.tbl-wrap` 有自定义滚动条，而**主内容区（`.body`）**
   用的还是系统默认样式 —— Windows 下约 17px 宽、两端还带上下箭头按钮，
   与鸿蒙浅色 UI 完全不相称。客户门户 client.html 更是整页走浏览器默认滚动条。

   做法（既细、又好点中）：
     · 轨道透明 —— 不画那条灰底，滑块"浮"在内容边缘；
     · 滑块加**同色透明边框** + `background-clip:padding-box` 裁掉，
       视觉宽度 = 轨道宽 − 2×边框宽，而**整个轨道宽仍是可点区域**；
     · 悬停 / 按下逐级加深，给出"可以拖"的反馈。

   ⚠ 本段必须留在文件末尾：`.side` / `.tbl-wrap` 等变体的特异性更高、
     与顺序无关，但**全局 `::-webkit-scrollbar` 会命中所有滚动容器**，
     放在前面会被后面同特异性的旧规则盖掉（重蹈"改了半天没生效"的覆辙）。

   ⚠⚠ 绝对不要在**任何**滚动容器上写 `scrollbar-width` / `scrollbar-color`：
     Chrome 121+ 一旦见到这两个标准属性就改用它们渲染，
     并**完全忽略 `::-webkit-scrollbar` 的自定义样式** ——
     症状是"CSS 明明写了，滚动条却还是系统默认那副样子"。
     故标准属性只写在下面的 `@supports not selector(::-webkit-scrollbar)` 里，
     专供 Firefox 兜底（它不支持 webkit 伪元素）。
   ═══════════════════════════════════════════════════════════════════ */
::-webkit-scrollbar{width:var(--sbw);height:var(--sbw)}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-corner{background:transparent}
/* 关掉 Windows 经典滚动条两端的箭头按钮 */
::-webkit-scrollbar-button{display:none;width:0;height:0}
/* ★滑块设为完全透明（2026-10-03 第十六件 · 应用户要求）★
   用户要「长度只有现在 1/10 + 透明度减半 + 只在滚动时出现」—— 这三条
   **原生滚动条一条都做不到**：
     · `::-webkit-scrollbar-thumb` 没有 height/width 可写，长度只能靠
       track 的 margin 间接改，而那会把滑块挤到中间、位置指示失真；
     · CSS 检测不到「正在滚动」，只有 :hover / :active 两个状态。
   故改为：原生条**保留占位与拖动能力**（透明但仍可点可拖，鼠标用户不失去
   操作方式），视觉呈现交给 JS 画的 `.sbmin` 指示条（见文件末尾那段）。
   ⚠ 不要改回有色：一旦原生条与自绘条同时可见，右边会出现两条。 */
::-webkit-scrollbar-thumb{background:transparent;border-radius:99px;
  border:3.5px solid transparent;background-clip:padding-box}
::-webkit-scrollbar-thumb:hover{background:transparent;background-clip:padding-box}
::-webkit-scrollbar-thumb:active{background:transparent;background-clip:padding-box}

/* 侧栏是窄列（236px 完整 / 66px 图标轨道），滚动条再细一档，少挤占导航项 */
.side::-webkit-scrollbar,.c-side::-webkit-scrollbar{width:8px}
.side::-webkit-scrollbar-thumb,.c-side::-webkit-scrollbar-thumb{border-width:2.5px}  /* 视觉 3px */

/* 表格 / 日历是"内容中间的横向滑条"，太厚会在面板里显笨重，同样收细 */
.tbl-wrap::-webkit-scrollbar,.cal-wrap::-webkit-scrollbar{height:10px}
.tbl-wrap::-webkit-scrollbar-thumb,.cal-wrap::-webkit-scrollbar-thumb{border-width:3px}

/* ── 「短一些」的历史做法已废弃（2026-10-03 第十六件）────────────────
   第八轮曾用 `::-webkit-scrollbar-track{margin:36px 0}` 把轨道两端让出一截，
   靠「轨道短了滑块自然跟着短」来缩短滑块（实测 .body 滑块 668→?、.side 594→?）。
   ⚠ 本轮已删除：原生条改成透明后，margin 只会让**两端各 36/44px 拖不动**，
     而长度这件事已交给 JS 指示条处理，没有再留的理由。
     若哪天又要回退到原生条，这段可以从 `_backup/` 里找回来。 */

/* 弹窗正文（.modal .body）与列表滚动区沿用全局样式即可，无需单独定义 */

/* Firefox 兜底：仅在不支持 ::-webkit-scrollbar 的浏览器里生效。
   同样设为透明 —— JS 的 `.sbmin` 指示条在 Firefox 下一样工作，
   两条并存会重影。原生条仍占位、仍可拖。 */
@supports not selector(::-webkit-scrollbar){
  *{scrollbar-width:thin;scrollbar-color:transparent transparent}
}

/* ═══════════════════════════════════════════════════════════════════
   ★移动端字号（2026-10-03 第十四件 · 应用户要求）★
   ═══════════════════════════════════════════════════════════════════
   用户反馈：「移动端文字太小了」。

   CDP 真机视口实测（390×844，`_icons/probe_fonts.js`）：改造前 **400+ 个元素
   挤在 12~13px**（表头 12、表格正文 13、次要说明 12.5、底部 tab 10.5）——
   这是**桌面密集尺度**，在 1440px 屏、60cm 视距下正常，搬到手机上就偏小
   （iOS 正文基准 17px、Android 16px，我们连表头都只有 12px）。

   修法：全站字号统一乘一个系数 `--fz`（定义见文件顶部 `:root` 的说明）。
   桌面 `--fz:1` → `calc(12px * 1)` 计算值仍是 12px，**与改造前逐像素相同**；
   这里只把它改成 1.16，全站（含 index.html 的 46 处内联 font-size、
   client.html 的 `<style>`）一起联动。

   效果对照（×1.16）：
     表头/次要 11~12 → 12.8~13.9px    表格正文 13 → 15.1px
     行内操作 13.5 → 15.7px           底部 tab 10.5 → 12.2px
     KPI 大数 23~32px **刻意不动** —— 本来就够大，再放大 15% 会在窄屏挤破卡片

   ⚠ 必须留在**文件末尾**：这里 `:root` 与顶部基础段的 `:root` 特异性相同，
     同特异性下后出现者胜，放到前面会被盖掉（同铁律 7 的道理）。
   ⚠ 只改 `--fz` 这一个数就能整体增减，但改完必须重跑两个检查器：
     `_icons/probe_fonts.js`（看新分布）+
     `check_mobile.js --views all --modals`（确认没把哪张卡挤破）。
   ═══════════════════════════════════════════════════════════════════ */
@media (max-width:760px){
  :root{ --fz:1.16 }

  /* 表单控件单独顶到 16px（不走系数）：iOS Safari 在字号 <16px 时
     **一聚焦就自动放大整个页面**，且不会自己缩回去，非常烦人。
     选择器必须写到 `input` 之外 —— 基础段里 `.modal .fld dd input{font:inherit}`
     特异性更高，只写裸 `input` 会被它盖掉、白写。 */
  input,select,textarea,.field,
  .modal .fld dd input,.modal .fld dd select{font-size:16px}

  /* ── 柱状图不再需要「钉尺寸 + 横滑」了（2026-10-04 改）──────────────
     旧方案：SVG 的 font-size 是 **viewBox 用户单位**，`viewBox="0 0 600 258"` +
     `width:100%` 在 390px 下缩放比被压到 0.533 → 轴标签从约 9.8px 掉到约 5.9px，
     且 `getComputedStyle` 读出来仍是 11、看不出这个问题
     （要用 `_icons/probe_svgtext.js` 量「渲染盒高 ÷ 计算字号」才看得见）。
     当时只能把图钉回 600×258（缩放比 1.0）交给 .chart-wrap 横滑。

     现在柱状图已改成 HTML/CSS 流式布局（见文件前部 `.bars`），
     轴刻度与月份都是普通 DOM 文字、固定 11px×`--fz` ≈ 12.8px，
     **没有 viewBox 缩放这回事**，也就不必钉宽、不必横滑。
     唯一要收的是横向空间：手机端把柱间距与轴刻度间距压一压。 */
  .bars{column-gap:4px}
  .bcol{gap:4px}
  .b{width:clamp(10px,26%,40px)}

  /* ── 折行修复：字号放大后「定宽容器把短标签挤破」的 4 处 ─────────────
     这几处**横向溢出为 0**，`check_mobile.js` 全绿也照不出来 ——
     它们是纵向的：文字在定宽列里多折了一行，把标签拆成
     「软件项目 / 款」这种形态。靠 `_icons/probe_lines.js` 量「同一段文字
     渲染成几行」+ `_icons/diff_lines.py` 与改造前比对才发现
     （全量 22 视图 + 27 弹窗 / 2994 个文本节点，改造后新增 4 处）。

     判据（写进 diff_lines.py）：父容器是 flex/grid + 自身文本 ≤24 字
     + 该文本无空格且 ≤8 字 —— 同时满足才算「被挤破」；
     `.scope` 说明条里那种「一个 flex 项装 90 个字」的长句折行属正常回流，不算。 */

  /* ① 本年收入构成：环形图与图例上下堆叠（详见 .donut-box 处的注释）。
        环形放大到 200px = viewBox 1:1，里面的「本年」从 9px 回到 12px。 */
  .donut-box{grid-template-columns:1fr;gap:14px}
  .donut{width:200px;height:200px;justify-self:center}

  /* ② 合同预览的 .doc-meta：桌面两列，每列里「标签 …… 值」两端对齐。
        390px 下每列只剩约 148px，长值（2025-08-02 至 2025-11-08）把标签
        挤到 **28px**（4 个字竖成 4 行）。改单列后标签有 60px、值有 242px，
        两者都回到一行。 */
  .doc-meta{grid-template-columns:1fr}
  .doc-meta span{flex:0 0 auto;white-space:nowrap}

  /* ③ 弹窗底部三个按钮（如「关闭 / 报备新客户 / 结算待付款」）：
        `.modal .acts .btn{flex:1 1 0}` 让每个按钮只分到约 103px，
        扣掉左右各 16px 内边距后放不下 5 个字（81px）→「结算待付款」折成两行。
        加 nowrap 后按钮的 min-content = 整段文字宽度，flex 不会再把它压到
        文字以下；一行放不下时由 `.modal .acts{flex-wrap:wrap}` 整颗按钮换行，
        比拆字好看，也不会误触。 */
  .modal .acts .btn{white-space:nowrap}

  /* ══ 紧凑化三件套 · 2026-10-03（应用户要求）══════════════════════
     用户三条点名：① 按钮内边距 ② 卡片与卡片间距 ③ 模块与屏幕边缘间距。
     上面已经改完 ①（.btn/.op/.chip 的 padding-x 16→11）和 ③（.body 边距 16→10）。
     这里是 ② 与剩下的卡片内边距 —— 它们的基础值写在样式表**前部**
     （.kpis 133 行 / .duo 154 行 / .panel .pad 161 行 / [data-view] 122 行），
     按铁律 7「同特异性下后出现者胜」，覆盖规则必须写在**文件末尾**这一段。

     实测（390px，22 视图全量）：
       [data-view].on gap 18→12   .kpis gap 16→10   .duo gap 16→10
       .panel .pad    18→13   ← 与 .panel > header 的左右 13px 对齐（同轴）
     ⚠ 只动**间距**，一个字号都不动：字号是上一轮刚调过并逐像素验证过的。 */
  [data-view].on{gap:12px}
  .kpis{gap:10px}
  .duo{gap:10px}
  .panel .pad{padding:13px}
}

/* ═══════════════════════════════════════════════════════════════════
   ★滚动指示条 `.sbmin`（2026-10-03 第十六件 · 应用户要求）★
   ═══════════════════════════════════════════════════════════════════
   用户三条点名：① 长度改为现在的 1/10  ② 透明度改为现在的 50%  ③ 默认不显示，
   滚动时才出现。

   实测基线（1440×900 总览页，`_icons/probe_scrollbar.js`）：
     .body 滑块 668px → 目标 67px      .side 滑块 594px → 目标 59px
   透明度：原 `rgba(23,28,82,.22)` → 取一半 **.11**。
   ⚠ 2026-10-04：用户反馈「还是太长」，长度**再压一次**（RATIO 0.10 → 0.01）：
     实测 .body 7.3px / .side 6.6px。改的是 `scrollbar.js` 里的 RATIO / MINLEN / MAXLEN，
     本节只是颜色与显隐，不受影响。

   ⚠ 为什么必须 JS 自绘：这三条**原生滚动条一条都做不到** ——
     · `::-webkit-scrollbar-thumb` 没有 height/width 可写，长度只能靠
       `::-webkit-scrollbar-track` 的 margin 间接改，而 margin 是**两端对称**
       让出的，要让滑块只剩 1/10 就得让掉 90%，滑块会被挤到中间、几乎不动，
       位置指示彻底失真；
     · CSS 没有「正在滚动」这个状态，只有 :hover / :active。
   故：原生条改透明（仍占位、仍可点可拖，鼠标操作不丢），视觉交给 `.sbmin`。

   `.sbmin` 三条设计要点：
   ① **挂 document.body + position:fixed** —— 不能挂滚动容器内部：
      absolute 子元素会**跟着内容一起滚走**；fixed 又会被祖先的 transform
      变成「相对该祖先定位」（弹窗 .modal 就有 translateY）。挂到 body 下、
      坐标全部用 `getBoundingClientRect()` 的视口坐标算，两种情况都躲开。
   ② **长度按 1/10 但两头 clamp**：内容越长原生滑块越短，再 ÷10 会短到看不见，
      故 `clamp(18, 原生长/10, 72)`。
   ③ `pointer-events:auto` + JS 拖动 —— 原生条透明后用户不知道往哪拖，
      指示条自己就得能拖。

   ⚠ 这是**唯一**能改动滚动条观感的地方：改前先读上面那段注释。
   ⚠ 滚动条在 Chrome 截图里**一律不绘制**（铁律 27），只能靠探针读数值验证。
   ═══════════════════════════════════════════════════════════════════ */
.sbmin{position:fixed;z-index:9000;left:0;top:0;width:0;height:0;
  border-radius:99px;pointer-events:auto;
  /* .11 = 改造前 .22 的 50%（用户要求「透明度设置为当前的 50%」） */
  background:rgba(23,28,82,.11);
  opacity:0;transition:opacity .18s linear,background-color .18s linear}
.sbmin.on{opacity:1}
.sbmin:hover,.sbmin.drag{background:rgba(23,28,82,.26)}

/* ═══════════════════════════════════════════════════════════════════
   ★背景固定（2026-10-03 第十六件 · 应用户要求）★
   ═══════════════════════════════════════════════════════════════════
   用户：「背景图片固定，如果滚动页面内容时，保持背景图片固定」。

   用 `body::before` 做一层真正的**固定背景层**（position:fixed + inset:0）：
   ⚠ 不用 `background-attachment:fixed` —— iOS Safari / WKWebView 对它支持很差
     （实测常退化成 scroll，甚至整块背景不绘制），而这个站要跑小程序 WebView。
     fixed 伪元素层在各端表现一致。

   ⚠ 底色**不由这一层负责**（只画 `--page-img`）：
     底色继续由 body / client.html 各自的 `background` 决定
     （工作台是 --page #ECEEFB，客户门户是 --bg-soft #EEF2FC）。
     若这层也铺底色，会用一个色盖掉另一个色，客户门户的底色就变了。
     当前 `--page-img` 默认为 `none` → 这层完全透明 → **视觉零变化**；
     将来要放背景图，只需 `--page-img:url(...)`，它自动就是固定的。

   `z-index:-1` 让它落在内容之下、body 自身背景之上；`pointer-events:none`
   保证不挡点击。

   ★★ `display` 用 `var(--page-before,none)` 是个**刻意的开关**★★
   ⚠ 第一版没有这个开关（伪元素常驻），结果**即使整层完全透明**，客户门户
     整页截图也**不再逐像素一致**：`position:fixed` 伪元素会让 body 走独立
     栅格化，其上方文字从亚像素抗锯齿（LCD）退化成灰度抗锯齿 —— 逐像素比才
     看得出，肉眼分不出，但一致性基线就这么破了（实测 418876ea → 85de3ae4）。
   ⚠ 用 `display:none` 关掉：完全不渲染、不生成盒子 → 零副作用。
     （试过 `content:var(--page-before,none)` 更彻底，但**实测无效**：
       把 `--page-before` 设成 `''` 后 Chrome 仍算 content:none，
       伪元素照样不生成 —— 于是「打开开关」这条路就走不通了。故改 display。）
   所以要背景图时，三行一起给（少一行就是不显示）：
       :root{ --page-before:block;      ← 开：让这一层参与渲染
              --page-img:url("bg.jpg"); ← 图
              --page-img-bg:#ECEEFB }   ← 可选：图没盖满时的兜底色

   ⚠⚠ **CSS 注释不能嵌套**（2026-10-03 踩过，而且踩了两次）：
     上面这段示例原先写成 `--page-before:block;` 后面跟一个**斜杠星号式**
     的行内注释，结果那个「星号斜杠」**提前闭合了本段外层注释**，
     后面的示例文字变成非法 CSS。改完第一次我又在「警告不要嵌套」这句里
     照抄了一遍那个写法，于是第二遍照样中招 —— 所以：
     整条 `body::before` 规则被浏览器**静默丢弃** —— 不报错、不警告，
     只表现为「样式写了不生效」，排查花了很久。
     故注释里一律用 `←` 或 `#`，**绝不让「斜杠 + 星号」这两个字符连写**。
     已固化检查：`_icons/check_css_comments.py`（扫全站 CSS 的注释嵌套）。
   ═══════════════════════════════════════════════════════════════════ */
body::before{content:'';display:var(--page-before,none);
  position:fixed;inset:0;z-index:-1;pointer-events:none;
  background-image:var(--page-img,none);
  background-color:var(--page-img-bg,transparent);
  background-size:cover;background-repeat:no-repeat;background-position:center top}
/* ⚠ 不要再给 body 加 `background-attachment:fixed`（2026-10-03 实测）：
     ① 纯色背景下它**没有任何可见效果**，真正干活的是上面的 ::before 层；
     ② 但它会令 body 进入独立的合成/栅格化路径，文字的亚像素抗锯齿随之变化 ——
        客户门户整页截图因此**不再逐像素一致**（差异落在内容区文字上，单看
        采样点颜色一样，是抗锯齿级的差别）。
     ③ 若真要写，必须写成 `html body`（特异性 0,0,2）—— client.html 自带的
        `body{background:var(--bg-soft)}` 简写会把 attachment 重置回 scroll，
        且它在后面加载，写 `body{...}` 必被盖掉。
   综合：收益为零、代价是破坏一致性 → 不加。 */

/* ═══════════════════════════════════════════════════════════════════
   ≤760px 补修：.fn-row 三列在窄屏顶破容器
   ───────────────────────────────────────────────────────────────────
   2026-10-07（产品评审 P1-4 应收账龄）真机体检抓到：`check_mobile.js
   --views all` 在 360/390/414/430 四档下报 payments 视图顶破 5 处 ——
   .fn-row 顶破 +17~30px、.fn-n（¥19,200）顶破 +26~30px、.fn-l（"未到期"）
   顶破 +30px。根因：`.fn-row` 的三列是写死的 `58px 1fr 30px`（≤760），
   而「逾期 0–30 天」「¥19,200」这两个内容在 58px / 30px 列里放不下 ——
   数字列只有 30px，而「¥19,200」需要约 52px。桌面 78px/40px 之所以没事，
   是因为线索阶段分布那一处的内容更短（「已联系」+「3」）。
   ⚠ 两处内容长度不同，所以**不能靠加宽首列解决**（会把进度条挤到没有），
     也不能靠缩小字号（铁律 34：字号统一走 --fz，不要一处一处改 px）。
   正解：窄屏把「标签 + 数字」并到一行（数字右对齐、标签可换行），
     进度条单独占满第二行 —— 列数从 3 降到 2，且两列都用 auto/minmax，
     数字列不再被写死的 30px 卡住。
   ⚠ 按本项目铁律，移动端新增规则一律追加到文件末尾这一段，不许上移。
   ═══════════════════════════════════════════════════════════════════ */
@media (max-width:760px){
  /* 窄屏两行布局：上排「标签 … 金额」，下排进度条 */
  .fn-row{grid-template-columns:1fr auto;gap:6px 10px}
  .fn-l{grid-column:1;min-width:0}
  .fn-n{grid-column:2;white-space:nowrap;text-align:right}
  .fn-bar{grid-column:1 / -1}
  .fn-row + .fn-row{margin-top:12px}
}

/* ═══════════════════════════════════════════════════════════════════
   移动端「全部功能」抽屉（2026-10-07 · 底 Tab 高价值页无入口）
   ───────────────────────────────────────────────────────────────────
   背景：底 Tab 只有 6 格，全站 21 个视图 → 客户管理 / 项目列表 /
   合同与签署 / 发票 / 收付款 / 工单售后这些每天要翻的页在手机上进不去。
   做法：第 6 格固定为「全部」，点开一个按分组罗列全量视图的抽屉。
   内容由 app.js 的 buildMNav() **现读侧栏 DOM** 生成，不另建一份列表。

   为什么这个形态：
     · 底栏宽度宝贵 —— 8 格以后每格只剩 45px，「合同与签署」四个字必然折行；
     · 手写第二份导航 = 新增视图要改两处，迟早漏一处，那正是
       「加页面时纠结要不要挤进底栏」的根因；现读侧栏则只改一行。
   ⚠ 按本项目铁律，移动端新增规则一律追加到文件末尾这一段，不许上移。
   ═══════════════════════════════════════════════════════════════════ */
.modal.mnav{width:min(560px,94vw);padding:18px 20px 16px;max-height:86vh;
  display:flex;flex-direction:column}
/* 桌面端也允许打开（调试 / 深链），无需为移动端单独造一套结构 */
.mnav-body{flex:1;overflow:auto;margin:2px -4px 0;padding:0 4px;
  -webkit-overflow-scrolling:touch}
/* 分组标题：与侧栏 .grp 同一套字重与颜色，视觉上认得出是同一份导航 */
.mnav-grp{font-size:calc(12px * var(--fz,1));color:var(--ink-3);font-weight:500;
  margin:12px 0 6px;letter-spacing:.04em}
.mnav-grp:first-child{margin-top:0}
/* 条目：触控目标 ≥44px（铁律 11），图标复用侧栏的 .icn（跟随 currentColor） */
.mnav-a{display:flex;align-items:center;gap:10px;width:100%;
  min-height:44px;padding:8px 10px;margin-bottom:2px;
  background:transparent;border:0;border-radius:10px;
  color:var(--ink-1);font:inherit;font-size:calc(14px * var(--fz,1));
  text-align:left;cursor:pointer}
.mnav-a .icn{width:18px;height:18px;color:var(--ink-3)}
.mnav-a .t{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.mnav-a .bdg{background:var(--accent);color:#fff;border-radius:9px;
  padding:1px 7px;font-size:calc(11px * var(--fz,1));font-weight:500}
.mnav-a:hover{background:var(--panel-2)}
.mnav-a.on{background:var(--accent-soft);color:var(--accent-ink);font-weight:600}
.mnav-a.on .icn{color:var(--accent)}

/* ≤760px：抽屉贴底成「半屏 sheet」，与既有弹窗的贴底行为一致 */
@media (max-width:760px){
  .modal.mnav{top:auto;bottom:0;left:0;transform:none;width:100vw;max-width:100vw;
    border-radius:16px 16px 0 0;max-height:80vh;padding:14px 14px 16px}
  .modal.mnav.on{transform:none}
  .mnav-a{min-height:46px}
}
/* 底部 Tab 的「全部」格：当前视图不在底栏 5 项里时标成"部分选中"，
   提示用户"你在这个抽屉的分组里"—— 不能落回概览高亮，那会误导。 */
.mtab a.part{color:var(--accent-2)}
.mtab a.part .icn{opacity:.9}

/* ═══════════════════════════════════════════════════════════════════
   概览页「常用九宫格」· 只在 ≤760px 显示（2026-10-07）
   ───────────────────────────────────────────────────────────────────
   底 Tab 改「5 高频 + 全部抽屉」后，全量可达解决了，但抽屉里 19 项是平级列表，
   分不出轻重。实际一天点开最多的是这 8 页 —— 在概览顶部给一排直达。
   桌面端 display:none（桌面有侧栏，不需要这一排）。
   ⚠ 4 列 × 2 行：390px 下每格 88px，远超 44px 触控底线（铁律 11）。
   ⚠ 与 .mtab 的关系：九宫格是**页面内**元素、随页面滚动消失；
     抽屉是**全局**元素、任何页面都能唤起。两者互补，不重复。
   ⚠ 按本项目铁律，移动端新增规则一律追加到文件末尾这一段，不许上移。
   ═══════════════════════════════════════════════════════════════════ */
.quick{display:none}
@media (max-width:760px){
  .quick{display:grid;grid-template-columns:repeat(4,1fr);gap:8px}
  .quick a{display:flex;flex-direction:column;align-items:center;justify-content:center;
    gap:5px;min-height:62px;padding:8px 4px;border-radius:12px;
    background:var(--bg);border:1px solid rgba(23,28,82,.07);
    box-shadow:var(--shadow-sm);text-decoration:none}
  .quick a:active{background:var(--panel-2)}
  .quick .icn{width:21px;height:21px;color:var(--accent)}
  .quick span{font-size:calc(12px * var(--fz,1));color:var(--ink-2);
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}
}

/* ═══════════════════════════════════════════════════════════════════
   销售漏斗 .fnl（2026-10-07 P2）
   ───────────────────────────────────────────────────────────────────
   ⚠ 为什么用 CSS 栅格 + DOM 文字，**不用固定 viewBox 的 SVG**（铁律 40）：
     漏斗每层的条宽是百分比，若画成 SVG，容器宽过某个阈值后定标权会转到高度，
     条就不再变宽、两侧留白跟着长 —— 桌面宽屏下漏斗会缩成中间一小撮。
     纯 CSS 的 width:% 跟着内容盒走，容器怎么变都成立。
   ⚠ 每层是「左标签 / 中间条 / 右转化率」三列，最右一列固定 132px 收：
     转化率文案（"70.4% · 流失 8"）在 390px 下必须单行不折，
     折行会把整层高度顶高一截，漏斗就不成漏斗了。
   ⚠ 条内的数字用绝对定位压在条上（.fnl-t b），不占布局宽度 ——
     否则「34」会把 79.4% 那层的条挤短，宽度就不再等于数量比例了。
   ═══════════════════════════════════════════════════════════════════ */
.fnl{display:flex;flex-direction:column;gap:8px}
.fnl-r{display:grid;grid-template-columns:76px minmax(0,1fr) 132px;
  align-items:center;gap:12px}
.fnl-k{font-size:calc(12.5px * var(--fz,1));color:var(--ink-2);white-space:nowrap}
.fnl-t{position:relative;height:26px;border-radius:8px;background:var(--panel-2);
  display:flex;align-items:center;overflow:visible}
.fnl-t > i{position:absolute;left:0;top:0;bottom:0;border-radius:8px;
  background:linear-gradient(90deg,#8FA6FF,var(--accent));display:block}
.fnl-t > b{position:relative;z-index:1;padding-left:10px;
  font-size:calc(13px * var(--fz,1));font-weight:700;color:var(--ink-1)}
/* 末层（成交）换成成功色，视觉上把「签下来的」标出来 */
.fnl-r.last .fnl-t > i{background:linear-gradient(90deg,#7FC8A4,var(--ok))}
.fnl-d{font-size:calc(12px * var(--fz,1));color:var(--ink-3);text-align:right;
  white-space:nowrap}
/* 「各来源的漏斗完成度」那节渠道名较长（老客户转介绍 6 字），78px 会折行 */
.fn-lw{width:96px}

/* ≤760px：三列改两行 —— 标签与转化率同一行、条独占一行。
   理由：390px 减去内边距约 358px，76+132+两处 gap(24) 已经占掉 232px，
   条只剩 126px，短到看不出比例。宁可让条占满整行。 */
@media (max-width:760px){
  .fnl-r{grid-template-columns:auto 1fr;gap:4px 10px;row-gap:4px}
  .fnl-k{grid-column:1;grid-row:1}
  .fnl-d{grid-column:2;grid-row:1}
  .fnl-t{grid-column:1 / -1;grid-row:2;height:24px}
}


/* ══ 权限模型（P2-3 · 2026-10-07）══════════════════════════════════════
   为什么要有这一段：原型里 m-staff 弹窗的 7 个 chip 是**死的** ——
   app.js 里搜不到任何 chip/perm 的事件绑定，点一下没反应。
   而「不同员工看到不同菜单」是这类后台最常被追问的一条，
   口头说「有权限」不算数，得让人看得见矩阵、点得动、能筛掉侧栏。

   这一段只做三件事：
     ① 权限矩阵表（哪一档能看哪些入口）
     ② 员工列表里的权限徽标
     ③ 被收回权限的入口在侧栏隐藏后的占位处理
   全部用既有 token，不引新色（铁律 5：鸿蒙浅色 + 大圆角 + 柔和投影）。 */

/* ① 权限矩阵 */
.pmx {
  margin-top: 14px;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  overflow: auto;                    /* 21 行 × 6 列，窄屏要能横滑 */
  background: var(--panel);
}
.pmx table { width: 100%; border-collapse: collapse; }
.pmx th, .pmx td {
  padding: 7px 10px;
  font-size: calc(12.5px * var(--fz));
  text-align: center;
  border-bottom: 1px solid var(--border-2);
  white-space: nowrap;
}
.pmx th {
  background: var(--panel-2);
  color: var(--ink-3);
  font-weight: 600;
  position: sticky; top: 0; z-index: 1;
}
.pmx th:first-child, .pmx td:first-child {
  text-align: left;
  position: sticky; left: 0;                     /* 入口名列横滑时固定 */
  background: var(--panel);
  font-weight: 600;
  color: var(--ink);
  box-shadow: 1px 0 0 var(--border-2);
}
.pmx th:first-child { background: var(--panel-2); z-index: 2; }
.pmx tr:last-child td { border-bottom: 0; }

/* 权限格：● 全权 / ◐ 只读 / — 无权。三态而不是两态 ——
   「能看不能改」在财务页极常见（财务协助要看毛利，但不能改报价）。 */
.pmx .y { color: var(--ok-ink); font-size: 1.05em; line-height: 1; }
.pmx .h { color: var(--warn-ink); font-size: 1.05em; line-height: 1; }
.pmx .n { color: var(--ink-4); opacity: .5; }
.pmx td.g0, .pmx td.g1 { color: var(--ink-2); font-weight: 600; }

/* 分组行：把 21 个入口按 NAV 的 6 个组隔开，否则一长串看不出体系 */
.pmx tr.grp td {
  background: var(--panel-2);
  color: var(--ink-3);
  font-size: calc(11.5px * var(--fz));
  font-weight: 650;
  letter-spacing: .04em;
  text-align: left;
  position: sticky; left: 0;
}

/* ② 员工列表里的权限徽标 */
.pbadge {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 1px 8px; border-radius: 999px;
  font-size: calc(11.5px * var(--fz)); font-weight: 600;
  background: var(--accent-soft); color: var(--accent);
  border: 1px solid var(--accent-line, var(--border));
}
.pbadge.lim { background: var(--warn-soft, #FFF4E5); color: var(--warn-ink); }
.pbadge.min { background: var(--panel-2); color: var(--ink-3); }

/* ③ 侧栏按权限隐藏时的平滑收起 —— 直接 display:none 会让整组下方的
   「今天 / 销售 / …」分组标题孤零零留着，视觉上像坏了。
   故分组标题在无可见项时一并隐藏（app.js 的 applyPerms 会加 .empty）。 */
.side .grp.empty { display: none; }

/* 弹窗里的角色卡：选中态要比普通 chip 更明确，否则「这套权限给谁」看不出来 */
.prole {
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: 11px 13px;
  cursor: pointer;
  transition: border-color .15s, background .15s;
}
.prole:hover { border-color: var(--ink-4); }
.prole.on { border-color: var(--accent); background: var(--accent-soft); }
.prole b { display: block; font-size: calc(13.5px * var(--fz)); margin-bottom: 3px; }
.prole span { font-size: calc(12px * var(--fz)); color: var(--ink-3); line-height: 1.55; display: block; }
.pgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(168px, 1fr)); gap: 9px; margin-top: 12px; }

/* ── ≤760px：矩阵改成「按角色分块」更好读，横滑表格在手机上不直观 ── */
@media (max-width: 760px) {
  .pmx th, .pmx td { padding: 8px 9px; font-size: calc(12px * var(--fz)); }
  .pmx th:first-child, .pmx td:first-child { position: static; box-shadow: none; }
  .pgrid { grid-template-columns: 1fr; }
  /* 手机上仍要能横滑（21 行 6 列压不进 390px），但提示必须看得见 */
  .pmx { -webkit-overflow-scrolling: touch; }
  .prole { min-height: 44px; }
}

/* 权限预览退出条（.pbar）—— 挂在 body 上，fixed 顶部居中。
   为什么要它：预览态下侧栏少了一多半入口，演示时若忘了退出会以为页面坏了。
   它同时是「当前正在以谁的身份看」的唯一提示，不加就得靠记忆。 */
.pbar {
  position: fixed; left: 50%; top: 14px; transform: translateX(-50%);
  z-index: 90;                       /* 低于弹窗(120)，别盖住 m-staff */
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px 8px 14px;
  border-radius: 999px;
  background: var(--ink); color: #fff;
  box-shadow: 0 8px 24px rgba(20, 24, 60, .22);
  font-size: calc(12.5px * var(--fz));
  max-width: min(92vw, 720px);
}
.pbar b { font-weight: 650; }
.pbar span { color: rgba(255, 255, 255, .78); }
.pbar .op { color: #fff; background: rgba(255, 255, 255, .16); padding: 3px 10px; border-radius: 999px; }
.pbar .op:hover { background: rgba(255, 255, 255, .26); }
@media (max-width: 760px) {
  .pbar { top: 8px; padding: 6px 8px 6px 12px; gap: 8px; border-radius: 14px; }
  .pbar span { display: none; }      /* 手机上只留「以谁预览」+ 退出，退出按钮仍是 44px 高 */
  .pbar .op { min-height: 44px; display: inline-flex; align-items: center; }
}

/* ── P2-5 门户：待办行的双按钮 + 项目进度条（2026-10-07）──────────────
   .pro-task 原是 12px 1fr auto 三列，第三格放一个按钮刚好。
   P2 给待办加了「标记完成」后变成两个按钮，塞进同一个 auto 格会被压扁 ——
   所以把第三格换成一个 .pacts 容器，桌面横排、移动端独立成行右对齐（铁律 11）。 */
.pacts { display: flex; gap: 8px; justify-content: flex-end; }
.pacts .op { white-space: nowrap; }

/* 项目进度条：四个阶段，CSS 栅格 + DOM 文字。
   铁律 40：不用固定 viewBox 的 SVG 画自适应图形 —— 容器宽过阈值后定标权会转到高度，
   图不再变宽、两侧留白跟着长。栅格 + flex 是这里唯一稳的画法。 */
.psteps { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; }
.pstep {
  position: relative; padding: 12px 12px 12px 34px;
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--panel-2);
}
.pstep .n {
  position: absolute; left: 11px; top: 12px;
  width: 17px; height: 17px; border-radius: 50%;
  display: grid; place-items: center;
  font-size: calc(10.5px * var(--fz)); font-weight: 700;
  background: var(--border); color: var(--ink-3);
}
.pstep b { display: block; font-size: calc(13px * var(--fz)); color: var(--ink-1); font-weight: 600; }
.pstep i { font-style: normal; font-size: calc(11.5px * var(--fz)); color: var(--ink-3); }
.pstep.done { background: var(--ok-soft, #EAF7F0); border-color: transparent; }
.pstep.done .n { background: var(--ok); color: #fff; }
.pstep.done b { color: var(--ink-1); }

@media (max-width: 760px) {
  /* 窄屏：四列进度条压进 390px 会每格不到 90px、字全折行 → 改两列 */
  .psteps { grid-template-columns: repeat(2, 1fr); }
  /* 两个按钮独立成行右对齐，且保证 ≥44px 触控。
     ⚠ 这条规则原本只写 `.pacts .op`，结果管理端「数据与安全」面板里
       6 个**裸** `button.op`（导出 / 立即备份 / 查看 / 打开 / 方法）没被包进 .pacts，
       落在改后的两列网格里被压成 22px 宽 —— 高度够 44、宽度不够 44，仍不合格。
       故改为：`.pro-task` 下的按钮**无论有没有 .pacts 包裹**，
       都独立成第 2 列并给 min-width/min-height 44。 */
  .pro-task { grid-template-columns: 12px 1fr; row-gap: 8px; }
  .pro-task .pacts { grid-column: 2; justify-content: flex-end; flex-wrap: wrap; }
  .pro-task > .op,
  .pro-task .pacts .op {
    grid-column: 2;
    min-height: 44px; min-width: 44px;
    display: inline-flex; align-items: center; justify-content: center;
    margin-left: auto;
  }
  /* 第三列的**状态标签**（.tag，如「已开启」）同样要落到第 2 列：
     两列栅格下它会被自动排到第 1 行第 2 格（只有 12px 宽的信号列），
     实测横向溢出 +5px。它不需要 44px 触控（不可点），只需不被挤破。 */
  .pro-task > .tag { grid-column: 2; justify-self: start; }
}

/* ══ 修复：两处「中文被逐字压成竖排」（2026-10-09）══════════════════════
   共同根因：flex / grid 子项的**自动最小尺寸 = min-content**，而中文的
   min-content 就是「一个字宽」—— 容器稍一收窄，浏览器就把文字压成一列竖排；
   它不报错、不溢出，只在截图里看得见。

   ① 客户端待办行的双按钮（原型遗留缺陷）——
      `.pro-task` 是 `12px 1fr auto` 三列网格，但待办行有 **4 个**子元素
      （信号点 / 正文 / 去注册 / 标记完成）：第 4 个按钮没有列可站，被自动
      排到第 2 行第 1 格 —— 那格只有 12px 宽，于是「标记完成」逐字竖排。
      ⚠ 线上原版就是坏的（已比对确认），不是本次引入。
      第 1769 行早已为该场景预留 `.pacts` 容器（基础样式在第 1773 行），
      只是 HTML 一直没包上。现已让待办行改用 `.pacts`，这里补一条：
      容器内的状态标签（核对确认后就地替换按钮）同样不能被压。            */
.pacts .tag { white-space: nowrap; flex: none; }

/* ② 提醒规则弹窗的「接收人」岗位勾选（2026-10-09 新增，本次引入）——
      两个坑叠加：`.modal .fld dd input{width:100%}`（第 304 行，本为文本
      输入框而写）把 checkbox 也撑成整行宽 —— label 是 flex 行，checkbox
      占满后文字只剩 0 宽，于是逐字竖排；且 label 默认 `flex-shrink:1`，
      一行放不下 5 项时 5 个 label 一起被压缩。
      修法：checkbox 恢复自身尺寸（连带清掉为输入框加的边框/内边/底色），
      label 关掉收缩（一行放不下就整颗换行）。                            */
.modal .fld dd input[type=checkbox] {
  width: auto; min-width: 0; flex: none;
  padding: 0; border: 0; background: none;
}
.modal .fld .recv { display: flex; flex-wrap: wrap; gap: 10px 16px; align-items: center; }
.modal .fld .recv label {
  display: flex; gap: 6px; align-items: center;
  flex: none; white-space: nowrap; cursor: pointer;
}
/* 窄屏：最后一项「客户（同时推客户门户与客户 APP）」在 390px 下整行也放不下，
   改纵向排列、每项独占一行，长项允许内部换行。 */
@media (max-width: 760px) {
  .modal .fld .recv { flex-direction: column; align-items: flex-start; gap: 12px; }
  .modal .fld .recv label { white-space: normal; }
}
