/* ★ 2026-09-30：本台此前**几乎不用共享排版尺度**（`design/tokens.css` 的 --fs-*，全文件只用 2 处），
   字号一律写裸 px —— 而 15 / 16 / 20 **三档根本不在尺子上**（尺子是 10/11/12/13/14/18/22/28/34）。
   两台后台同为一类东西，尺子不能一台一台各写一套。
   改法：① 与尺子同值的（11/12/13）换成令牌，**视觉零变化**；② 尺子上没有的三档按语义归到最近一档：
     品牌名 16→18（**与管理台的品牌同尺寸**）、模型卡名 15→14（"正文强调：小标题"）、概览 KPI 数 20→22（"大区块标题"）。
   —— ②的三处是**可见变化**（±2px），改完已看屏。 */

.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}

  /* 本台的历史变量名 → token 的<b>别名</b>。这是唯一允许的映射层：
     页面其余部分照旧用旧名，但<b>值只有一个来源</b>（design/tokens.css）。
     两个管理台是同一类东西 ⇒ 同一个主题（theme-console）。 */

  *{box-sizing:border-box}
  body{margin:0;font:14px/1.6 -apple-system,"PingFang SC",system-ui,sans-serif;background:var(--bg);color:var(--fg)}
  .wrap{max-width:1120px;margin:0 auto;padding:20px}
  /* ── 左导航 + 右内容（#43 · 2026-09-26）─────────────────────────────
     **与创作台同一套骨架**：导航固定在左，内容占满剩余。业主定盘：
     「运营后台、管理后台的信息架构都参考创作台的信息架构，左侧导航，右侧内容」。
     做法是**纯 CSS**：`#app` 变两列 grid，`.nav` 跨满所有行 ⇒ 不必挪任何 DOM
     （`#app` 的直接子元素是 `.nav` + 各 tab 面板，用 grid 列定位即可，不用包一层容器）。
     ⚠️ 只改**布局**，不改导航的**切法**（4 项的判据仍然是"改变的是我们的条件 vs 客户的东西"）。 */
  #app.shell{display:grid;grid-template-columns:var(--rail-w) minmax(0,1fr);gap:0;align-items:start}
  #app.shell > .nav{grid-column:1;grid-row:1/-1;position:sticky;top:20px;flex-direction:column;
    gap:2px;margin-bottom:0;padding:6px;background:var(--panel);border:1px solid var(--line);border-radius:12px}
  #app.shell > :not(.nav){grid-column:2;min-width:0}
  #app.shell .nav button{text-align:left;justify-content:flex-start;width:100%;border-radius:var(--r-md);padding:0 var(--sp-3)}

  .brand{display:flex;align-items:center;gap:10px;margin-bottom:14px}
  .brand b{font-size:var(--fs-title);letter-spacing:.5px}.brand .brand-ic{width:22px;height:22px;display:block;flex:none}
  /* ★ 2026-09-30：尺寸向另两台看齐（创作台与管理台的 `.chip` 都是 `1px 8px` + `--fs-micro`）——
     本台原来是 `2px sp-2` / `1px sp-2` + `--fs-micro`。字体本就一致，只对齐内边距。
     ⚠️ 本台的徽章**带 1px 描边**（用描边承载状态色），所以同样 `1px 8px` 会比另两台高 2px，
        这是有意保留的样式差异（描边 = 状态），不动。 */
  .tag{font-size:var(--fs-micro);padding:1px 8px;border:1px solid var(--line);border-radius:var(--r-pill);color:var(--dim)}
  .tag.ops{color:var(--warn);border-color:var(--warn-line);background:var(--warn-bg)}
  .card{background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:var(--sp-4);margin-bottom:14px}
  h3{margin:0 0 10px;font-size:var(--fs-body);color:var(--dim);font-weight:600;letter-spacing:.4px}
  /* ★ 2026-09-30：与另两台对齐 —— 内边距原是 `var(--sp-2) 10px`（右内边距写死），
     改成 `--sp-2 --sp-3`（全令牌，密度档位才生效）；描边 `--line` → `--line-strong`
     （令牌表写明"控件边界：输入框/按钮，≥3:1"，`--line` 达不到这条对比度下限）。 */
  input,button,select{font:inherit;background:var(--card);color:var(--fg);border:1px solid var(--line-strong);border-radius:var(--r-md);padding:var(--sp-2) var(--sp-3)}
  input{width:100%}
  button{cursor:pointer;background:var(--card)}
  button:hover, button:focus-visible{border-color:var(--acc)}
  button.primary{background:var(--accent);border-color:var(--accent);color:var(--accent-ink)}
  button.mini{padding:var(--sp-1) 10px;font-size:var(--fs-small);border-radius:7px}
  table{width:100%;border-collapse:collapse;font-size:var(--fs-body)}
  th,td{text-align:left;padding:var(--sp-2) var(--sp-2);border-bottom:1px solid var(--line)}
  th{color:var(--dim);font-weight:600;font-size:var(--fs-small)}
  tbody tr:last-child td{border-bottom:none}
  .muted{color:var(--dim)}
  .err{color:var(--bad);font-size:var(--fs-body);min-height:16px}
  .pill{font-size:var(--fs-micro);padding:1px 8px;border-radius:var(--r-pill);border:1px solid var(--line)}
  .pill.on{color:var(--ok);border-color:var(--ok-line);background:var(--ok-bg)}
  .pill.off{color:var(--bad);border-color:var(--danger-line);background:var(--danger-bg)}
  .nav{display:flex;gap:var(--sp-2);flex-wrap:wrap;margin-bottom:14px}
  .nav button{font-size:var(--fs-small);padding:var(--sp-1) var(--sp-3);border-radius:var(--r-pill);color:var(--dim)}
  /* ★ 2026-10-04：导航**分组**（11 个页签分三簇：经营 / 供给 / 平台）。
     本台的导航是**顶部横排**（见文件末「后写覆盖」那段：`.nav` 是 flex-direction:row、
     下划线式页签），所以分组也必须是**横排**——`flex-direction:row` + 组间一条**竖**分隔线。
     ⚠️ 第一版我写成了 `flex-direction:column`（照左栏时代的印象）⇒ 把横排顶栏竖成了一列，
        整页塌掉（1440 下实测：导航占满整宽、按钮居中、内容被挤到下方）。
     分组只是**结构标签**：不动切法、不动页内容、不动页签的下划线选中态。 */
  .nav-group{display:flex;flex-direction:row;align-items:center;gap:2px}
  .nav-group + .nav-group{margin-left:var(--sp-3);padding-left:var(--sp-3);border-left:1px solid var(--line)}
  .nav-group-title{font-size:var(--fs-micro);color:var(--muted);letter-spacing:1.2px;padding:0 var(--sp-2);user-select:none;cursor:default;white-space:nowrap}
  /* 时间段选择的**选中态**（2026-09-19 由 C10 查出）。
     `.cur` 此前**只在 .nav 里定义**，而「近 7/30/90 天」这组按钮不在 .nav 里
     ⇒ 选中的那个和没选的长得一模一样，用户看不出自己选的是哪个。 */
  .mini.range.cur{border-color:var(--accent);color:var(--accent);background:var(--accent-bg)}

  /* `.row` 此前没有定义，样式全靠各处的内联 style —— 内联只能管一处，
     同一个语义散在多个标签里就会各自漂移。收成一条公共规则。 */
  .row{display:flex;gap:10px;align-items:center}
  /* ★ 2026-09-29：`.row` 里的 input 是 `width:100%`（全局规则），会把同排的按钮挤成竖排
     （实测：「发送验证码」被压成「发送验 / 证码」两行）。⇒ 按钮不参与拉伸、不折行。 */
  .row button, .row select{flex:none;white-space:nowrap}
  /* ★ 2026-10-10（业主截图：「停用 / 启用」卡里那个选择器，下拉跑到**页面最底部**被截掉）：
     根因 —— `position:relative` 本来只写在 `.row .pick` 上；那张卡用的是**内联 flex**（不是 `.row`），
     于是选择器**没有定位上下文**，`.pick-list`（`position:absolute`）就相对**初始包含块**定位。
     定位上下文是**组件自身**的性质，不该由「爹是谁」决定 ⇒ 提到 `.pick` 上。
     同理 `flex:1` 留在 `.row` 里（那是"在整排里怎么占宽"，确实取决于排布）。 */
  .pick{position:relative}
  .row .pick{flex:1;min-width:220px}
  .row .pick .pick-trigger{display:flex;align-items:center;justify-content:space-between;gap:8px;width:100%;text-align:left;white-space:nowrap}
  .pick-trigger > span:first-child{overflow:hidden;text-overflow:ellipsis}
  .pick-caret{color:var(--dim);flex:none}
  .pick-list{position:absolute;z-index:30;left:0;right:0;top:calc(100% + 4px);background:var(--panel);border:1px solid var(--line-strong);border-radius:var(--r-md);overflow:hidden}
  .pick-q{padding:var(--sp-2);border-bottom:1px solid var(--line)}
  .pick-opts{max-height:220px;overflow:auto}
  .pick-item{display:block;width:100%;text-align:left;border:0;border-radius:0;background:transparent;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .pick-item:hover, .pick-item.cur{background:var(--accent-bg);border-color:transparent}
  .pick-empty{padding:var(--sp-2) var(--sp-3)}

  .nav button.cur{color:var(--accent);border-color:var(--accent-line);background:var(--accent-bg)}
  .nav span{font-size:var(--fs-small);color:var(--dim);border:1px dashed var(--line);border-radius:var(--r-pill);padding:var(--sp-1) var(--sp-3)}
  /* ★ 2026-09-29 修两处，**两条规则都要留**：
     ① 通用 `.hide` —— 退出按钮 / 登录卡 / 五个 tab 面板都靠它。
     ② `#app.hide` —— `.shell` 的规则是 `#app.shell`（一个 id + 一个类 = 1-1-0），
        通用 `.hide`（0-1-0）**特异性永远输给它** ⇒ 未登录时整个应用骨架照常显示在登录卡下面
        （实测：appClass="hide shell" · appDisplay="grid"）。同特异性 + 靠后覆盖，不用 `!important`。
     ⚠️ 我第一次只写了 ②、把 ① 换了 —— 结果「退出」按钮和五个 tab 的隐藏全失灵
        （**修一处不能拿走别处还在用的东西**；这条是**看了页面**才发现的）。 */
  .hide{display:none}
  #app.hide{display:none}
  .grid2{display:grid;grid-template-columns:1fr 1fr;gap:10px}
  @media(max-width:760px){.grid2{grid-template-columns:1fr}}
  /* 模型卡 */
  .mcard{background:var(--panel);border:1px solid var(--line);border-radius:12px;margin-bottom:var(--sp-3);overflow:hidden}
  .mhead{display:flex;align-items:baseline;gap:10px;padding:var(--sp-3) var(--sp-4);background:var(--panel2);border-bottom:1px solid var(--line);flex-wrap:wrap}
  .mhead .nm{font-size:var(--fs-md);font-weight:600}
  .mhead .meta{font-size:var(--fs-small);color:var(--dim)}
  .mhead .raw{font-size:var(--fs-micro);color:var(--muted);margin-left:auto}
  .num{font-variant-numeric:tabular-nums}
  /* ★ 2026-09-30：**表格里的数字必须等宽**（理由同管理台：字体栈首位 -apple-system/SF Pro
     的默认数字是比例数字，同列位数会左右晃）。本台此前只在 2 处写了 tabular-nums，
     而这一台恰恰是**数字最密的一台**（价目 / 积分 / 余额 / 毛利率 / 计数）。
     落在 `table` 上只影响数字宽度，不动中文与行距，一次覆盖所有表。 */
  table{font-variant-numeric:tabular-nums}
  .cost{color:var(--fg)}
  .sell{color:var(--gold)}
  .pay{color:var(--dim);font-size:var(--fs-small)}
  .ov{display:flex;gap:var(--sp-5);flex-wrap:wrap;align-items:center}
  .ov .k{font-size:var(--fs-micro);color:var(--dim);letter-spacing:.4px}
  .ov .v{font-size:var(--fs-xl);font-variant-numeric:tabular-nums}
  .ov .v small{font-size:var(--fs-small);color:var(--dim);font-weight:400}
  .toolbar{display:flex;gap:10px;align-items:center;margin-bottom:var(--sp-3)}
  .toolbar input{max-width:280px}
  .toolbar select{max-width:170px}
  .editor{display:flex;gap:6px;align-items:center}
  .editor input{width:110px;padding:var(--sp-1) var(--sp-2)}
  .hint{font-size:var(--fs-small);color:var(--dim)}

  /* 定价表：一张表看完，不再一个模型一张卡（见 render() 的注释） */
  .ptablewrap { overflow-x: auto; }
  .ptable { width: 100%; border-collapse: collapse; table-layout: auto; }
  /* ★ 2026-10-11（业主：「分档的收起和展开按钮要**一直显示**」）——
     根因不在这里，而在下面那条**通配**规则：
       `.ptable tbody tr .mini { opacity: 0 }` + `tr:hover .mini { opacity: 1 }`
     它把**任何**表格行里的 `.mini` 都藏到 hover 才显形。`mtable` 早有豁免
     （见下面 `.ptable.mtable tbody tr .mini { opacity: 1 }`），**价目这张表漏了** ⇒ 分档开关看不见。
     按同一个套路补豁免：**只豁免分档开关这一个**（同一行里别的 mini 按钮维持原样 ——
     不因为这一处需求，把整张表的交互行为改掉）。 */
  .ptable tbody tr .pmod .mini { opacity: 1; }
  .ptable.pt7 { table-layout: fixed; }
  /* 列宽：让整表在 ~1000px 内排完，不必横滚（此前 7 列没定宽 ⇒ 最后一列被切） */
  .ptable.pt7 th:nth-child(1), .ptable.pt7 td:nth-child(1) { width: 210px; }
  .ptable.pt7 th:nth-child(2), .ptable.pt7 td:nth-child(2) { width: 150px; }
  .ptable.pt7 th:nth-child(3), .ptable.pt7 td:nth-child(3) { width: 175px; }
  .ptable.pt7 th:nth-child(4), .ptable.pt7 td:nth-child(4) { width: 115px; }
  .ptable.pt7 th:nth-child(5), .ptable.pt7 td:nth-child(5) { width: 105px; }
  .ptable.pt7 th:nth-child(6), .ptable.pt7 td:nth-child(6) { width: 80px; }
  .ptable.pt7 th:nth-child(7), .ptable.pt7 td:nth-child(7) { width: 92px; }
  /* 动宾式按钮不该被压成竖排（"改厂商价" 曾竖成 "改/厂"） */
  .ptable .mini { white-space: nowrap; }

  /* 37 行 ⇒ 37 个同样的按钮排成一列 = 纯噪音（一眼看过去像表格的纹理）。
     默认不显示，**指到那一行才出现** —— 供给页要读的是"价比"，不是"能点什么"。
     ⚠️ 必须同时保 `:focus-within`：只做 hover 等于**把键盘用户挡在门外**
        （Tab 到按钮时那一行也算"里面"，按钮随即显形）。 */
  .ptable tbody tr .mini { opacity: 0; transition: opacity .12s; }
  .ptable tbody tr:hover .mini,
  .ptable tbody tr:focus-within .mini { opacity: 1; }
  .ptable th { text-align: left; }
  .ptable .pmod { vertical-align: top; }
  .ptable .pmod .nm { display: inline; font-weight: var(--fw-medium); }
  /* ★ 2026-10-04：厂商显示名 —— **同一行**的次要小字（列头「模型 / 厂商」要求两个都在）。
     2026-10-02 曾把厂商整行 `display:none` 掉（为消撑高），字段随之从屏幕上消失；这里补回，
     但**不**恢复成第二行（一行一个模型，表不长）。 */
  .ptable .pmod .prov {
    display: inline; margin-left: 8px;
    font-size: var(--fs-micro); font-weight: normal; color: var(--muted);
    white-space: nowrap;
  }
  .ptable .pmod .raw {
    display: block; margin-top: 2px;
    font-family: var(--font-mono); font-size:var(--fs-micro);
    color: var(--muted);
    max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  /* 同一模型的行组之间：一条更粗的线分隔，比重复模型名更省视线 */
  .ptable tr.pgroup > td { border-top: 2px solid var(--line-strong); }
  /* ★ 2026-10-04（业主：「修改利润率的时候，利润率编辑字段被掩盖了」）：
     上面 `.editor` 是 **nowrap** 的 flex ⇒ 内容一宽就溢出单元格；而表格的绘制次序是
     **后面的单元格画在先前单元格的上层** ⇒ 探出去的那截被邻列的文字盖住（看上去像叠印）。
     本表是 `table-layout: fixed`（每列宽度钉死）⇒ 编辑器的第一条纪律是**待在自己列里**：
     装不下就换行，绝不横着探出去。 */
  .ptable .editor { flex-wrap: wrap; }
  .ptable .editor input { max-width: 100%; }
  .ptable .editor.stack { flex-direction: column; align-items: flex-start; gap: 2px; }
  /* 利润率那一列只有 80px（th,td 左右各 8px 内边距 ⇒ 内容 64px）：
     这颗输入框按列宽反推宽度 + 收窄内边距，才既塞得下三位数、又不探出列外。 */
  .ptable .editor input.compact { width: 48px; padding: var(--sp-1) 6px; }

  /* 模型表（.ptable.mtable）：它的操作按钮（对外 / 设为默认 / 改）是主动作，不走价目表那套「悬停才现」；
     列宽按模型表自己的字段定（「走哪家」吃剩余宽度，避免被价目表的 80px 压扁）。 */
  .ptable.mtable tbody tr .mini { opacity: 1; }
  .ptable.mtable th:nth-child(1), .ptable.mtable td:nth-child(1) { width: 200px; }
  .ptable.mtable th:nth-child(2), .ptable.mtable td:nth-child(2) { width: 110px; }
  .ptable.mtable th:nth-child(3), .ptable.mtable td:nth-child(3) { width: 90px; }
  .ptable.mtable th:nth-child(4), .ptable.mtable td:nth-child(4) { width: 130px; }
  .ptable.mtable th:nth-child(5), .ptable.mtable td:nth-child(5) { width: 110px; }
  .ptable.mtable th:nth-child(6), .ptable.mtable td:nth-child(6) { width: auto; }
  .ptable.mtable th:nth-child(7), .ptable.mtable td:nth-child(7) { width: 150px; }
  .ptable.mtable th:nth-child(8), .ptable.mtable td:nth-child(8) { width: 180px; }
  .secEdit { display: inline-flex; gap: 6px; align-items: center; }
  .secEdit input { width: 260px; }
  /* 供应商页的两张表（pvt 供应商 / sect 密钥）：列宽按各自内容定，不套用价目表的 7 列通用列宽；
     表内操作按钮常显（通用的 hover 显隐只属于价目表）；数字列右对齐；密钥编辑成栅格。 */
  .ptable .num { text-align: right; }
  .ptable.pvt th:nth-child(1), .ptable.pvt td:nth-child(1) { width: 200px; }
  .ptable.pvt th:nth-child(2), .ptable.pvt td:nth-child(2) { width: auto; }
  .ptable.pvt th:nth-child(3), .ptable.pvt td:nth-child(3) { width: 80px; }
  .ptable.pvt th:nth-child(4), .ptable.pvt td:nth-child(4) { width: 200px; }
  .ptable.pvt th:nth-child(5), .ptable.pvt td:nth-child(5) { width: 110px; }
  .ptable.pvt th:nth-child(6), .ptable.pvt td:nth-child(6) { width: 170px; }
  .ptable.sect th:nth-child(1), .ptable.sect td:nth-child(1) { width: 200px; }
  .ptable.sect th:nth-child(2), .ptable.sect td:nth-child(2) { width: 90px; }
  .ptable.sect th:nth-child(3), .ptable.sect td:nth-child(3) { width: 80px; }
  .ptable.sect th:nth-child(4), .ptable.sect td:nth-child(4) { width: 170px; }
  .ptable.sect th:nth-child(5), .ptable.sect td:nth-child(5) { width: 170px; }
  .ptable.sect th:nth-child(6), .ptable.sect td:nth-child(6) { width: 300px; }
  .ptable.pvt tbody tr .mini, .ptable.sect tbody tr .mini { opacity: 1; }
  .ptable .secEdit { display: grid; grid-template-columns: minmax(0, 1fr) auto auto; gap: 6px; align-items: center; }
  .ptable .secEdit input { width: 100%; min-width: 0; }
  .mini.danger { border-color: var(--danger); color: var(--danger); }
  /* ⚠️ 别名映射**必须放在 .theme-console 上**，不能放 :root。
     CSS 自定义属性在**声明它的元素**上完成替换 ⇒ 放在 :root 会把 --card 的值
     定格在 :root（亮色那一版），下游 .theme-console 的覆写传不进来，于是卡片永远是白的。
     （2026-09-19 运营后台实测：:root 上的 --panel 解析成了亮色那一版的 --card，
       而 body 上的 --card 已经是暗色版 ⇒ 卡片永远白） */

  .theme-console{--panel:var(--card); --panel2:var(--chip);
    --fg:var(--ink); --dim:var(--muted);
    --acc:var(--accent); --bad:var(--danger); --gold:var(--warn); --ok:var(--ok);}

/* 外观三档（与创作台的「我」菜单同一套词与形：浅色 / 深色 / 跟随系统）。
   在两个 tag 与「退出」之间，是"这个页面自己的属性"，不抢内容的视线。 */
.scheme-seg{display:inline-flex;align-items:center;border:1px solid var(--line);border-radius:var(--r-pill);overflow:hidden}
.scheme-seg button{font:inherit;font-size:var(--fs-micro);line-height:1;padding:var(--sp-1) 10px;background:transparent;border:0;color:var(--dim);cursor:pointer;min-height:24px}
/* ↑ min-height:24px —— 度量框架 D5 要求可点元素触达区 ≥24×24。
   ★ 2026-09-30：探针实测这组按钮「触达区 42×21 / 43×21 / 65×21 < 24×24」——
     21 = 11px 字 + padding 上下各 5。宽度都够，只差高度 3px。
   用 min-height 而不是加大 padding：不依赖字号与 line-height 的算法，
     换字号也不会再跌破门槛。观感不变（只补 3px 高的命中区）。 */
.scheme-seg button:hover{color:var(--fg)}
.scheme-seg button.on{background:var(--panel2);color:var(--fg)}
.scheme-seg button+button{border-left:1px solid var(--line)}

/* ══════════════════════════════════════════════════════════════════════
 * 2026-09-30 视觉修正（与另两台对齐；逐条都有实测出处）
 * ══════════════════════════════════════════════════════════════════════ */

/* ① 左导航此前是一个**浮在空处的圆角小盒**（宽 200、高 208，下面 700px 全黑）——
     读起来像"一块没归位的组件"，而不是"这台导航"。
     另两台（创作台 / 管理后台）的导航都是**通高的栏**：改成一个栏，
     三台的第一眼结构才一样。 */
#app.shell > .nav {
  background: transparent;
  border: 0;
  border-right: 1px solid var(--line);
  border-radius: 0;
  padding: 0 14px 0 0;
  align-content: start;
  min-height: calc(100vh - 40px);
}
#app.shell .nav button { border-radius: 8px; padding: var(--sp-2) var(--sp-3); }
@media (max-width:820px){
  #app.shell > .nav { border-right: 0; border-bottom: 1px solid var(--line);
                      padding: 0 0 var(--sp-3); min-height: 0; }
}

/* ② 标题层级：本台此前 **没有任何 h1/h2 规则** ⇒ 用的是浏览器默认字号
     （h1 2em=28px、h2 1.5em=21px），而 h3 是 13px 灰。
     于是"卡标题"(h2) 比"小节标题"(h3) 大三倍，页面没有一套自己的层级。
     现在与另两台同一把尺子：区块标题 = --fs-md(14px) 加粗；
     小节标题 = 12px 次要色；数据本身（.ov .v 20px）才是最大的东西。 */
h2 { margin: 0 0 var(--sp-3); font-size: var(--fs-md); font-weight: var(--fw-strong); }
h3 { margin: 0 0 10px; font-size: var(--fs-small); color: var(--dim); font-weight: var(--fw-medium); letter-spacing: .2px; }

/* ③ 表格：行高由内边距定死 → 与另两台同一档；表头加一条底线，扫读时头与身分得开。 */
th, td { padding: var(--sp-2) var(--sp-3); }
thead th { border-bottom: 1px solid var(--line); }
tbody tr:hover { background: var(--raise-1); }

/* ④ 卡片内边距与卡间距统一到 16px（此前 16/14 混用）。 */
.card { padding: var(--sp-4); margin-bottom: var(--sp-4); }

/* ⑤ 导航项：此前继承了 `input,button,select` 的 1px 描边 ⇒ 五个**带框按钮**堆成一列，
     读起来像"一排按钮"，而不是"这台分成哪几块"。另两台的导航项都没有描边（只有当前项有底）。
     三台的第一眼结构应当一样 —— 这是"看起来是同一个产品"最便宜的一步。 */
#app.shell .nav button { border-color: transparent; background: transparent; color: var(--dim); }
#app.shell .nav button:hover { background: var(--raise-2); color: var(--fg); }
#app.shell .nav button.cur { background: var(--accent-bg); color: var(--accent); border-color: transparent; }

/* ⑥ **与另两台同一套骨架：通栏**。
     此前 `.wrap{max-width:1120px;margin:0 auto}` 把**整台**（含左导航）缩在中间，
     于是最左最右各空出一条；而创作台与管理后台都是**导航贴左边、内容占满剩余**。
     三台的第一眼结构不一样，是"看起来像三个产品"最直接的来源。
     改成通栏：导航贴左，内容自己限宽（--page-w）。 */
/* ★ 2026-09-30：**左栏贴左缘**（另两台如此）。做法：页面级左右内边距交给**非 `#app` 的那几行**
   （品牌行 / 账号行），`#app` 从 x=0 起 —— 否则左栏会比另两台多缩进 20px。 */
.wrap { max-width: none; margin: 0; padding: 20px 0; }
.wrap > :not(#app) { padding-inline: var(--sp-5); }
#app.shell { grid-template-columns: var(--rail-w) minmax(0, 1fr); }
/* 内容列与另两台的**同一条内容栏**：**rail + 24（贴栏，不居中）**。
   ★ 2026-09-30 改：此前是 `max(24px, (100% - --page-w)/2)`（居中 ⇒ x=316）。
   查清这条错值是怎么来的：本台的注释自己写着"此前内容从 x=240 起；**管理台从 x=316 起**"
   —— 也就是说本台是**照着管理台**改的；而管理台的注释写着"与另两台的同一条内容栏"
   —— 也就是说管理台**以为**创作台也在 316。**两台的意图本来都是对齐创作台**，
   只是在"照谁"的传递里错了一环：创作台实际是 **264**（内容贴栏，rail+24）。
   ⇒ 回到 264。判据不止"创作台是参照"，更硬的一条是：创作台的**工作区**内容也在 rail+24
     （三栏布局要求内容贴栏），所以"统一到居中"会在创作台内部造出矛盾（项目页 316 / 项目内 264），
     而"统一到 rail+24"在**任何一台内部都不产生矛盾**。`--page-w` 仍管最大宽度。 */
#app.shell > :not(.nav) { padding-inline: var(--sp-5);
  /* ⚠️ 必补：原先的 `max(24px, (100% - 1120px)/2)` **同时管了两件事** ——
     贴栏的内边距与"内容最大宽 1120"。只把 padding 改成 24 会把**上限一起丢掉**
     （管理台那边实测卡片随即从 1120 涨到 1224）。这里把上限显式补回来。 */
  max-width: calc(var(--page-w) + 2 * var(--sp-5)); }

/* ⑦ 控件高度落到三档（`--ctl-sm/md/lg`，设计令牌里唯一定义）。
     此前高度是 `font-size + padding` 推出来的 —— 实测本台有 [24,40,37,48,87,29] 六种。 */
#app.shell .nav button { min-height: var(--ctl-md); }
button.primary { min-height: var(--ctl-md); }
button.mini { min-height: var(--ctl-sm); }
.scheme-seg button { min-height: var(--ctl-sm); }

/* ═══════════════════════════════════════════════════════════════════════════
 * ★ 2026-10-02（业主：「团队管理和运营后台的信息架构都改成顶部导航」
 *              + 「核心信息要保持在页面的中心区域，尊重用户的视觉注意力机制」）
 *
 * 本台此前与管理台同一个形状：`#app.shell` 是 [`--rail-w` | 内容] 两列，
 * 导航竖排在左、`position:sticky; top:20px` 吸左栏的顶。
 * 改成与管理台**同一形状**（三台第一眼结构一致是"看起来是同一个产品"最便宜的一步）：
 *   ① 一列网格 ⇒ 导航通栏在第 1 行、内容在第 2 行；
 *   ② 导航**吸顶**（滚动时不动，与台头一起当固定顶栏用）；
 *   ③ 当前项改**下划线**（与管理台同一条读法）；
 *   ④ 内容块 **width:100% + max-width + margin-inline:auto** ⇒ 撑满**且**居中。
 *
 * ⚠️ 为什么用 `margin-inline:auto` 而不是 `justify-self:center`：
 *    `justify-self:center` 会让网格项**缩到内容那么大**再居中（不再 stretch），
 *    管理台那边实测 main 从撑满缩成 438px —— 业主当场看出"很奇怪"。
 *    auto 外边距配 `width:100%` 才是"宽度照满、重心居中"。
 *
 * ⚠️ 后写覆盖：本文件上游已有多条 `.nav` / `#app.shell` 规则（左栏时代），
 *    这里全部**显式**盖掉，不靠"去掉旧的那几条"（那样会同时弄丢它们的注释与来历）。
 *    注：`#app.shell > :not(.nav)` 的 `padding-inline` 与 `max-width`（⑥那条）
 *    **故意不覆盖** —— 它们仍然是对的，只补网格位置与居中。
 */
#app.shell { grid-template-columns: minmax(0, 1fr); }
#app.shell > .nav {
  grid-column: 1 / -1; grid-row: 1;
  flex-direction: row; flex-wrap: wrap; align-content: center;
  position: sticky; top: 0; z-index: 30;
  border-right: 0; border-bottom: 1px solid var(--line);
  padding: 0 var(--sp-5); min-height: 0;
  background: var(--card);
}
#app.shell .nav button {
  width: auto; justify-content: center; text-align: center;
  border-bottom: 2px solid transparent; border-radius: 0;
}
#app.shell .nav button.cur {
  background: transparent; color: var(--accent);
  border-color: transparent; border-bottom-color: var(--accent);
}
#app.shell > :not(.nav) {
  grid-column: 1 / -1; grid-row: 2;
  width: 100%; margin-inline: auto;
}

/* ⑧ **动作列 = 余量的去处**（与管理台同一条，2026-09-30）。
     此前动作列写死 `width:110`，其余列 `auto` ⇒ 浏览器按各列 **max-content 的比例**分余量，
     装着最长文本的那一列吃得最多。实测「运营账号」的账号列被撑到 ~309px（装的是一个手机号），
     姓名、状态跟着被推开，一行里全是空档。
     修法：动作列 `width:100%` 吸收余量并贴右 —— 空白留在表格最右端（那才像一张表）；
     其余列不折行，用内容宽。 */
.actcol { width: 100%; text-align: right; white-space: nowrap; }
table:has(> thead > tr > th.actcol) th:not(.actcol),
table:has(> thead > tr > th.actcol) td:not(.actcol) { white-space: nowrap; }

/* ⑨ 表单里的输入框**不该拉满**。
     `.grid2` 是 `1fr 1fr`，于是「开一个新运营账号」那两个输入框各被拉到 ~530px ——
     装的是一个手机号和一个姓名。输入框的宽度应当**暗示它要装什么**：
     手机号给 220、姓名给 220，右边留白，视线自然落在「开户」上。 */
#tab-operators .grid2 { grid-template-columns: repeat(2, minmax(0, 220px)); justify-content: start; }

/* ★ 2026-10-09 平台面统一版式（运营账号）：
   `.ptable` 的列宽是为供给页 7 列定死的（210/150/175…），套在 5 列的账号表上会把「状态」「创建」撑歪。
   这里改回按内容排（auto），动作列 `.actcol` 吸收余量并贴右 —— 与上面 ⑧ 的设计一致。
   「停用」按钮沿用 `.ptable` 的悬停才显形，但这张表的动作是要一眼可见的 ⇒ 常显。 */
#tab-operators .ptable { table-layout: auto; }
#tab-operators .ptable th,
#tab-operators .ptable td { width: auto; white-space: nowrap; }
#tab-operators .ptable th.actcol { width: 100%; }
#tab-operators .ptable tbody tr .mini { opacity: 1; }

/* ★ 2026-09-30 窄屏：试过一次兜底，**失败，已撤回**（留档免重犯）。
   820px 实测：内容被挤进左侧约 215px 一列、右侧大片空白；品牌名断成「运营后/台」、
   「退出」竖排、KPI 一行一个、近7天/近30天/近90天 变竖排文字。
   同宽度下另两台都是好的（创作台左栏收成汉堡、管理台导航转竖列）——**只有这一台不响应**。
   第一次修法：@media (max-width:1023px){html,body{min-width:1024px}} —— **实测无效**：
   内容仍被挤成窄列，还多出一条横向滚动条 ⇒ 净损失，撤回。
   已查到的线索：下面第 28 行 **本来就有** @media (max-width:820px){#app.shell{grid-template-columns:1fr}…}，
   意图是存在的，但它没有产出可用布局。⇒ 下一步从这里查：
   为什么 .shell 收到一列后，内容列仍只有 ~195px。 */

/* ** 2026-09-30 窄屏修好。**
   这条媒体查询原本在文件**第 28 行**，而 `#app.shell` 的两列模板（240px 1fr）定义在它**后面**，
   同特异性⇒后写的赢 ⇒ 它在任何宽度都没生效过。
   实测证据（CDP 直接问页面，vw=800）：matchMedia('(max-width:820px)') === true，
   但 #app 的 computed grid-template-columns 仍是「240px 560px」两列 ⇒ 内容被挤成一列。
   修法：把它**移到文件末尾**（同特异性靠顺序取胜）。 */
@media (max-width:820px){#app.shell{grid-template-columns:1fr}
    #app.shell > .nav{grid-column:1;grid-row:auto;position:static;flex-direction:row;flex-wrap:wrap}
    #app.shell > :not(.nav){grid-column:1}}

/* ** 2026-09-30 窄屏顶栏。实测 820px：品牌名被拆成「运营后/台」、
   「退出」被挤成竖排一个字一行。原因：顶栏是一条 flex 行且**不换行**，
   窄下去只能压缩单个元素（压到一个字宽）。
   修法：允许**整行换行**（标签/账号/主题切换/退出 落到第二行），并不许品牌名拆字。 */
@media (max-width: 1023px){
  .brand { flex-wrap: wrap; row-gap: var(--sp-2); }
  .brand b { white-space: nowrap; }
}

/* ═══════════════════════════════════════════════════════════════════════
 * ⑧ **把三档真正落到高度上**（2026-09-30 实测）
 *
 * ⑦ 里写了 `min-height: var(--ctl-md/sm)` —— 但那是**下限**，而真实高度是
 * `padding-block + 行高 + 边框` **算出来的**：
 *   左导航项实测 **37**（要 32）· 表格行内动作（开户/记账/停用）**29**（要 26）·
 *   「退出」**40**（无档）。
 * 这正是当初立「控件尺寸要声明、不要算」这条纪律要治的病，只是当时只写了下限。
 * ⇒ 高度归**档位声明**，纵向 padding 归零、文字垂直居中。
 *   （与另一台管理后台同一条做法：`button.act` 也补了同样的两行。）
 * ═══════════════════════════════════════════════════════════════════════ */
#app.shell .nav button,
button.primary,
button.mini {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding-block: 0;
}
#app.shell .nav button { min-height: var(--ctl-md); }
button.primary { min-height: var(--ctl-md); }
button.mini { min-height: var(--ctl-sm); }

/* 「退出」= 这两台顶栏里**同一个动作**。
   实测：管理后台是**无框小字 24px**、这里是**带框按钮 40px** —— 同一个东西两台差 16px，
   而它既不是主操作、也不该抢视线（它是出口，不是动作）。
   ⇒ 取**同一档同一形**：sm(26) · 无框 · 次要色。（管理后台那一处同步改成 26。） */
#logout {
  background: transparent;
  border: 0;
  color: var(--dim);
  min-height: var(--ctl-sm);
  padding: 0 var(--sp-2);
  font-size: var(--fs-small);
  cursor: pointer;
}
#logout:hover { color: var(--fg); }



/* ── 页内二级导航（内容区左栏）· 2026-10-05 ──────────────────────────────
   业主：「每个页面在内容区引入左侧二级导航 TAB，简化操作旅程」。
   `<main>` 变两列 grid（[左栏 rail-w | 内容 page-w]），左栏列本页章节、sticky 吸住。
   ⚠️ 与 10-02「核心信息居中」的取舍：内容列仍 = --page-w（不缩），整块随左栏略右移
      rail-w/2 ≈ 120px；换来"从进入到达成少滚一半"。窄屏（无左侧空间）收起左栏回单列。 */
#app.shell > main.pagemain{ display:grid; grid-template-columns: var(--rail-w) minmax(0,1fr);
  gap: var(--sp-3); align-items:start;
  max-width: calc(var(--page-w) + var(--rail-w) + var(--sp-3) + 2 * var(--sp-5)); }
#app.shell > main.pagemain > .pagenav{ grid-column:1; grid-row:1; align-self:start;
  position:sticky; top:76px; z-index:20; display:flex; flex-direction:column; gap:0;
  padding:0; border:0; border-left:2px solid var(--line); border-radius:0; background:transparent; }
#app.shell > main.pagemain > :not(.pagenav){ grid-column:2; min-width:0; }
#app.shell .pagenav button{ text-align:left; width:100%; justify-content:flex-start; font-size: var(--fs-small);
  color: var(--dim); padding: var(--sp-2) var(--sp-3); border-radius:0; background: transparent;
  border:0; border-left:2px solid transparent; margin-left:-2px; min-height: var(--ctl-md); }
#app.shell .pagenav button:hover{ color: var(--fg); }
#app.shell .pagenav button.cur{ color: var(--accent); border-left-color: var(--accent); background: var(--accent-bg); }
#app.shell main.pagemain [data-sec], #app.shell main.pagemain h3{ scroll-margin-top: 76px; }
@media (max-width: 1440px){
  #app.shell > main.pagemain{ grid-template-columns: minmax(0,1fr); }
  #app.shell > main.pagemain > .pagenav{ display:none; }
}

/* 流水页（2026-10-09 真机实测）：表格里的"值按钮"与短词**不许折行**——
   客户 id / 成员·容器 / 划入·划出 都被挤成了两行，看着像坏了。
   展开行的附注（colspan 那一格）反过来：长句要能折，不给 nowrap。 */
#app.shell main.pagemain #tab-ledger td, #app.shell main.pagemain #tab-ledger th{ white-space: nowrap; }
#app.shell main.pagemain #tab-ledger td[colspan]{ white-space: normal; }
#app.shell main.pagemain #tab-ledger table table{ width: auto; min-width: 460px; }


/* ══════════════════════════════════════════════════════════════════════════
   ★ 2026-10-09 **三栏**：对象面 │ 对象列表 │ 对象页
   依据：`design/preview-ops-drilldown.html`（业主认可的原型）。
   一层是"面"（生意/客户/模型/供应商/平台），二层是"该面的对象"，
   三层是"这个对象/这段时间的页"。**只加列，不动既有两列的规则**。
   ══════════════════════════════════════════════════════════════════════════ */
#app.shell { grid-template-columns: var(--rail-w) 232px minmax(0, 1fr); }
#app.shell > .nav { grid-column: 1; grid-row: 1 / -1; }
#app.shell > .objlist {
  grid-column: 2; grid-row: 1 / -1; align-content: start;
  border-right: 1px solid var(--line); padding: 0 14px 0 0;
}
/* ⚠️ 必须同时钉行：`.objlist` 是 `grid-row: 1 / -1`（撑满所有行），
   主区若只给列不给行，auto 摆放会把它挤到**第二行**（实测 top=994、视口外）。 */
#app.shell > :not(.nav):not(.objlist) { grid-column: 3; grid-row: 1; }
.objlist .ol-item {
  display: block; width: 100%; text-align: left; border: 1px solid transparent;
  background: transparent; color: var(--fg); border-radius: 8px; padding: var(--sp-2) var(--sp-3);
  cursor: pointer; font: inherit;
}
.objlist .ol-item:hover { background: var(--raise-2); }
.objlist .ol-item.cur { border-color: var(--accent); color: var(--accent); background: var(--accent-bg); }
@media (max-width: 1080px) {
  #app.shell { grid-template-columns: var(--rail-w) minmax(0, 1fr); }
  #app.shell > .objlist { display: none; }
}

/* 选中对象时，旧的那些页让位给对象页（一处规则，不逐个改 12 个 pane） */
#app.shell .pagemain.picking > div[id^="tab-"] { display: none; }
#app.shell .pagemain.picking > .pagenav { display: none; }
#app.shell .objpage { display: grid; gap: 14px; }

/* ══════════════════════════════════════════════════════════════════════════
   ★ 2026-10-09（业主真机截图）两处**结构级**修正 —— 放在文件末尾，确保不被断点或
   先前的规则压回去：

   ① **一级导航永远是「栏」**。此前 `flex-direction:column` 与三栏网格都被关在媒体查询里，
      窄一点的窗口（Retina 截图 1920 实为约 960 CSS px）会让一级导航退化成
      **横排 + 换行**（真机量到：nav direction=row、wrap=wrap），看着像坏了。
      导航是"栏"这件事**不属于断点行为**：窄了让内容滚、让栏变窄，不许把栏变成横条。
   ② **藏掉 `main.pagemain > .pagenav`（「本页章节」栏）**。三栏成型后，一级管"面"、
      二级管"该面的对象/账期/视图"，页面里再立一栏章节导航就是**第三栏导航**。
      原型（design/preview-ops-drilldown.html 的 renderBiz）里没有它：
      生意面就是**一页读数**（指标 + 账），章节跟着页面往下滚即可。
   ══════════════════════════════════════════════════════════════════════════ */
#app.shell > .nav {
  display: flex !important;
  flex-direction: column !important;
  flex-wrap: nowrap !important;
  align-items: stretch;
}
#app.shell { grid-template-columns: var(--rail-w) 232px minmax(0, 1fr); }
#app.shell > main.pagemain { grid-template-columns: minmax(0, 1fr) !important; }
#app.shell > main.pagemain > .pagenav { display: none !important; }

/* ══════════════════════════════════════════════════════════════════════════
   ★ 2026-10-09（业主：三栏的宽度比例 / 分割线 / 边距也要对齐）
   基准 = 原型 `design/preview-ops-drilldown.html` 的：
     .app{grid-template-columns:196px 300px 1fr}
     .rail{border-right:1px solid var(--line);padding:16px 10px;gap:2px}
     .rail a{padding:8px 10px}
     .list{border-right:1px solid var(--line)}  .list h2{padding:18px 18px 10px}
     .rows{padding:0 8px 16px}  .ritem{padding:9px 10px}
     .head{padding:20px 26px 14px;border-bottom:1px solid var(--line)}
     .wrap{padding:18px 26px 40px}
   三栏是**通栏 + 1px 分割线**，不是三张卡片 —— 此前我这一台把导航做成了带边框/圆角/底色的卡片，
   与原型（以及另两台的骨架）不是同一个形状。
   ══════════════════════════════════════════════════════════════════════════ */
#app.shell { grid-template-columns: 196px 300px minmax(0, 1fr); }

/* 一级：通栏，只有一条右边线 */
#app.shell > .nav {
  grid-column: 1; grid-row: 1 / -1;
  background: var(--bg); border: 0; border-right: 1px solid var(--line); border-radius: 0;
  padding: 16px 10px; gap: 2px; align-content: start;
}
#app.shell .nav button { padding: 8px 10px; border-radius: 8px; }

/* 二级：同样通栏 + 右边线；标题与行距照原型 */
#app.shell > .objlist {
  grid-column: 2; grid-row: 1 / -1;
  border-right: 1px solid var(--line); border-left: 0;
  padding: 0 8px 16px; display: flex; flex-direction: column; align-content: start;
}
.objlist .ol-item { padding: 9px 10px; border-radius: 8px; }

/* 内容：顶部一条下边线，正文 26px 左右边距 */
#app.shell > main.pagemain { padding: 0; }
#app.shell .objhead { padding: 20px 26px 14px; margin: 0; border-bottom: 1px solid var(--line); }
#app.shell .objpage { padding: 0 26px 40px; }

/* ══════════════════════════════════════════════════════════════════════════
   ★ 2026-10-09 **窄窗口下收窄两条栏**（业主：三栏比例要对齐；但原型是 100vh 定宽应用，
   吃满屏幕，1920 下两条栏只占 26%。本台要在笔记本窗口（约 960–1280 CSS px）里也能用，
   所以**原型那组是宽屏基准值，窄了按比例让位给正文**）。

   只改**尺寸**，不动结构、不加交互（原型没画折叠/抽屉）。正文列是 minmax(0,1fr)，
   两条栏收窄多少，正文就多出多少。
   ══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 1440px) {
  #app.shell { grid-template-columns: 180px 268px minmax(0, 1fr); }
}
@media (max-width: 1180px) {
  #app.shell { grid-template-columns: 168px 240px minmax(0, 1fr); }
  #app.shell .objhead { padding: 18px 20px 12px; }
  #app.shell .objpage { padding: 0 20px 32px; }
}
@media (max-width: 960px) {
  #app.shell { grid-template-columns: 152px 216px minmax(0, 1fr); }
}

/* ══════════════════════════════════════════════════════════════════════════
   ★ 2026-10-09（业主两条）：
   ① **第二栏再收窄**（原型 300px 是 1920 宽屏的值；本台在笔记本窗口里 300 太占）。
   ② **第二栏要固定，不跟第三栏滚**。—— 这条是我漏的：原型是**每列各自滚**
      （`.app{height:100vh;overflow:hidden}` + `.rows{overflow:auto}` + `.main{overflow:auto}`），
      而我只给一级栏加了 sticky，二级栏是普通流 ⇒ 正文一滚，二级栏跟着滚没了。
      现在一级、二级都 sticky 在视口顶，各自内部滚；正文仍随页面滚。
   ⚠️ 顺序要紧：基准写在媒体查询**之前**，否则基准会把媒体查询压回去。
   ══════════════════════════════════════════════════════════════════════════ */
#app.shell > .nav,
#app.shell > .objlist {
  position: sticky; top: 0; align-self: start;
  max-height: calc(100vh - var(--shell-main-top, 87px)); overflow-y: auto; overscroll-behavior: contain;
}
#app.shell { grid-template-columns: 196px 240px minmax(0, 1fr); }
@media (max-width: 1440px) { #app.shell { grid-template-columns: 180px 224px minmax(0, 1fr); } }
@media (max-width: 1180px) { #app.shell { grid-template-columns: 168px 208px minmax(0, 1fr); } }
@media (max-width: 960px)  { #app.shell { grid-template-columns: 152px 192px minmax(0, 1fr); } }

/* ══════════════════════════════════════════════════════════════════════════
   ★ 2026-10-09（业主验收：这不对，很多问题）—— 真机量出来的两处硬伤：

   ① **一级导航文字是居中的**（computed: text-align:center / justify-content:center）。
      原型 `.rail a` 是左对齐的栏目项。center 不来自本文件（来自共享样式表），
      所以这里用 !important 钉死 —— 导航是"栏"，项必须左对齐。
   ② **主区内容被推到右边、左边一大片空白**（computed: main 仍是 display:grid，
      网格 `62px 382px`）。根因：`--rail-w` 这个变量在本仓**根本没定义**，
      于是 `grid-template-columns: var(--rail-w) minmax(0,1fr)` 成了"失效变量"的残迹，
      而「本页章节」那一列（.pagenav）已经废掉、不再需要占位。
      ⇒ **主区不该再是 grid**，改普通块，子元素自然通栏堆叠。
   ══════════════════════════════════════════════════════════════════════════ */
#app.shell .nav button {
  text-align: left !important;
  justify-content: flex-start !important;
}
#app.shell > main.pagemain {
  display: block !important;
  grid-template-columns: none !important;
  padding: 0;
}

/* ══════════════════════════════════════════════════════════════════════════
   ★ 2026-10-09（业主验收截图 · 第二轮）

   ① **一级导航的选中态是"整栏下划线"** —— 看着像页签，不像"栏里的项"。
      原型 `.rail a` 的选中态是**圆角底色块**（accent 底 + accent 字），不是下划线。
      下划线来自本台早期的顶部页签样式（共享样式表），这里按"栏内项"改回来。
   ② **顶栏窄窗口下「退出」掉到第二行、甩到最左**：
      原因是一行里东西太多（品牌 + 两个标签 + 账号 + 三个外观段 + 退出），
      `#who` 又带 `margin-left:auto` ⇒ 一换行，最后那个就孤零零落在左边。
      改法：顶栏**不换行**，把中间的账号串**截断**（个人信息可省，操作按钮不能掉行）。
   ══════════════════════════════════════════════════════════════════════════ */
#app.shell .nav button.cur {
  background: var(--accent-bg) !important;
  color: var(--accent) !important;
  border: 1px solid var(--accent-line) !important;
  border-radius: 8px !important;
}

.brand { flex-wrap: nowrap !important; }
.brand > #who {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ══════════════════════════════════════════════════════════════════════════
   ★ 2026-10-09（逐页验收第 3 棒 · 修）
   ① 列表页的标题此前是 `div.objtitle` ⇒ **不是标题元素**（该页没有标题层级，
      屏幕阅读器读不到页标题，视觉层级也与对象页不一致 —— 对象页是 h2）。
      改成 h2 并显式给字号/字重/边距（本台没有 .objtitle 的既有样式）。
   ② 「功能开关」页那组统计（开关 8 项 / 开 3 / 关 5）此前散在一行两端，
      三个数之间没有关系感。收成**左对齐的一簇**，只作用于该页（不碰别处的读数）。
   ══════════════════════════════════════════════════════════════════════════ */
#app.shell .objtitle {
  margin: 0;
  font-size: var(--fs-title);
  font-weight: 600;
  letter-spacing: .3px;
}
#tab-flags .ov {
  display: flex;
  gap: 28px;
  align-items: baseline;
  justify-content: flex-start;
}

/* ★ 2026-10-09：「视图」组吸底常显（业主：回弹会导致看不到「客户管理」）
   —— 当时视图组排在 30 行对象**之后**，被压到栏底只露半行 ⇒ `sticky` 钉底 + `margin-top:auto` 顶下去。
   ★ 2026-10-10（业主：「占用的空间没干掉」）：二级栏**上半截已删**（对象清单 / 时间范围都移走），
   视图组成栏里**唯一**的内容 ⇒ 那两条只留下一大块空白（`margin-top:auto` 把唯一子项顶到栏底，上面全空）。
   ⇒ 去掉 `position/bottom/margin-top`：让它从栏顶正常流下来，栏有多高就用多高。
   `border-top` 也去掉：它原本是与上方**对象区**的分界；现在上方是带 `border-bottom` 的栏目标题条，会成双线。 */
.objlist .ol-views {
  background: var(--bg);
  padding: 6px 0 2px;
}


/* ★ 2026-10-09（业主：数据量超过 10 条就应该有筛选功能）—— 账（LedgerCut）的筛选框 */
.lc-filter {
  width: 150px;
  background: var(--panel);
  border: 1px solid var(--line);
  color: var(--fg);
  border-radius: 8px;
  padding: 4px 8px;
  font: inherit;
  font-size: var(--fs-small);
  outline: none;
}
.lc-filter::placeholder { color: var(--muted); }
.lc-filter:focus { border-color: var(--accent-line); }

/* ★ 2026-10-09（业主：顶栏要固定，不要跟着回弹或者滚动）
   把「面包屑 + 品牌行」合成一条**固定顶栏**：页面滚它不动、也不会被橡皮筋回弹带走。
   两条栏（一级/二级）则钉在它下面：top: var(--shell-top)（运行时量出的顶栏下沿）。 */
.wrap > .topbar {
  position: sticky;
  top: 0;
  z-index: 30;
  background: var(--bg);
}
#app.shell > .nav,
#app.shell > .objlist { top: var(--shell-top, 132px); }

/* ── 左侧两栏收起（业主：两栏要能收起）──────────────────────────
   外壳 `#app.shell` 是三列网格（面 196 · 对象 240 · 内容 1fr）；
   收起 = 两列归零 + 两个栏隐藏，内容拿回整宽。类由顶栏的 RailToggle 切换并记在 localStorage。 */
/* 两个左栏**各自**能收（业主：「两个左栏都能够自行收起」）—— 三条组合态都要写。
   面导航 = .nav（第 1 列）· 对象/账期 = .objlist（第 2 列）。 */
/* 收起 = **缩成窄条**（不是整栏消失）—— 按钮就住在栏里，缩没了就没法再展开。
   窄条里只留 `.rail-head`（那一枚按钮），其余内容 hide。 */
#app.shell.rail1hide { grid-template-columns: 34px 240px minmax(0, 1fr); }
#app.shell.rail2hide { grid-template-columns: 196px 34px minmax(0, 1fr); }
#app.shell.rail1hide.rail2hide { grid-template-columns: 34px 34px minmax(0, 1fr); }
#app.shell.rail1hide > .nav { padding: 8px 4px; overflow: hidden; }
#app.shell.rail2hide > .objlist { padding: 8px 4px; overflow: hidden; }
#app.shell.rail1hide > .nav > *:not(.rail-head) { display: none; }
#app.shell.rail2hide > .objlist > *:not(.rail-head) { display: none; }
.rail-head { display: flex; justify-content: flex-end; }
.rail-head .rail-toggle { margin: 0 0 6px; }
.rail-toggle {
  margin-left: 6px; display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; padding: 0; cursor: pointer;
  color: var(--dim); background: transparent;
  border: 1px solid var(--line); border-radius: var(--r-md);
}
.rail-toggle:hover { color: var(--fg); background: var(--raise-2); }

/* ── 内容顶部 TAB（业主：用 TAB 组织，别让人纵向翻滚）────────────── */
.vtabs { display: flex; gap: 4px; border-bottom: 1px solid var(--line); margin: 6px 0 12px; }
.vtabs button {
  background: transparent; border: 0; border-bottom: 2px solid transparent;
  color: var(--dim); padding: 6px 12px; cursor: pointer; font-size: var(--fs-body);
}
.vtabs button:hover { color: var(--fg); }
.vtabs button.cur { color: var(--accent); border-bottom-color: var(--accent); }

/* 页内章节 TAB：只对「标题是内容区直接子元素」的扁平页生效（见 PageNav 的护栏）。 */
.pgtabs { position: sticky; top: var(--shell-top, 132px); z-index: 12; background: var(--bg); flex-wrap: wrap; }
.pgtabs button { font-size: var(--fs-micro); padding: 4px 10px; }

/* ★ 2026-10-09 像素级复核（截图实证）：第二栏那枚按钮出来了、**第一栏那枚没有**。
   原因：`.nav` 内部有一整套按钮级规则（ `.nav button { border-color:transparent; background:transparent; … }`
   以及 `padding` 等），把 `.rail-toggle` 的外观抹平/挤掉。这里给 `rail-head` 与其按钮一条**显式高优先级**规则，
   保证两栏的按钮都以同一副样子出现在**各自栏内的第一行、右对齐**。 */
#app.shell > .nav > .rail-head,
#app.shell > .objlist > .rail-head {
  display: flex !important;
  justify-content: flex-end;
  align-items: center;
  min-height: 28px;
  margin: 0 0 8px;
  flex: 0 0 auto;
}
#app.shell > .nav > .rail-head > .rail-toggle,
#app.shell > .objlist > .rail-head > .rail-toggle {
  width: 28px !important; height: 28px !important; padding: 0 !important;
  display: inline-flex !important; align-items: center; justify-content: center;
  border: 1px solid var(--line) !important;
  background: transparent !important;
  color: var(--dim) !important;
  border-radius: var(--r-md) !important;
}
#app.shell > .nav > .rail-head > .rail-toggle:hover,
#app.shell > .objlist > .rail-head > .rail-toggle:hover {
  color: var(--fg) !important; background: var(--raise-2) !important;
}

/* ══════════════════════════════════════════════════════════════════════════
   ★ 2026-10-09 运营台整理（经营数据 · 列表页 · 账）
   ① 一个时间窗管整页：读数头 = 标题 + 当前窗 + 筛选；KPI 做成一排卡片。
   ② 列表页：每个属性一列、可按列排序；0 一律 `—`。
   ③ 成本列的细条：只表示占比，读数仍是右边的数。
   ══════════════════════════════════════════════════════════════════════════ */
.ov-head { display: flex; align-items: center; gap: 12px; margin: 0 0 14px; flex-wrap: wrap; }
.ov-head h2 { margin: 0; font-size: var(--fs-title); font-weight: 600; letter-spacing: .3px; }
.ov-win { font-size: var(--fs-small); color: var(--accent); background: var(--accent-bg); border: 1px solid var(--accent-line);
  border-radius: var(--r-pill); padding: 1px 10px; white-space: nowrap; }
.ov-win small { color: var(--dim); margin-left: 6px; font-size: var(--fs-micro); }
.ov-q, .ol-q { margin-left: auto; width: 220px; max-width: 40%; font-size: var(--fs-small); padding: 4px 10px; border-radius: 8px; }
.ov-alert { display: flex; align-items: center; gap: 10px; margin: 0 0 14px; padding: 8px 14px;
  border: 1px solid var(--warn-line); background: var(--warn-bg); border-radius: 10px; font-size: var(--fs-body); }
.ov-alert b { color: var(--warn); font-weight: 600; white-space: nowrap; }
.ov-alert span { flex: 1; min-width: 0; }

.kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(148px, 1fr)); gap: 10px; margin: 0 0 14px; }
.kpi { background: var(--panel); border: 1px solid var(--line); border-radius: 12px; padding: 12px 14px; min-width: 0; }
.kpi .k { font-size: var(--fs-micro); color: var(--dim); letter-spacing: .4px; }
.kpi .v { font-size: var(--fs-xl); font-variant-numeric: tabular-nums; line-height: 1.35; margin-top: 2px; overflow-wrap: anywhere; }
.kpi .s { font-size: var(--fs-micro); color: var(--muted); margin-top: 2px; font-variant-numeric: tabular-nums; }
.kpi.wide { grid-column: 1 / -1; }
/* ★ 2026-10-12（「一眼看懂」）：一屏同权重的东西太多，就没有主次。
   经营数据页 —— 主行三个数（收入/成本/毛利）是判断，其余经营事实**降一档**。 */
.kpis.sec .kpi { padding: 9px 12px; }
.kpis.sec .kpi .v { font-size: var(--fs-md); }
.kpi .v.u { display: flex; flex-wrap: wrap; gap: 4px 18px; font-size: var(--fs-md); }
.kpi .v.u b { font-weight: 600; font-size: var(--fs-xl); }
.kpi .v.u span { color: var(--dim); font-size: var(--fs-small); }
.ov-pair { align-items: start; margin-bottom: 14px; }
.ov-pair > .card { margin-bottom: 0; }
.ov-params { margin: 6px 2px 0; font-size: var(--fs-micro); color: var(--muted); }

/* 账：能点的行才有手形与悬停；吸顶表头 */
#app.shell tr.lc-drill { cursor: pointer; }
.lc-unattr { font-size: var(--fs-micro); color: var(--muted); margin: 8px 0 0; }

/* 列表页 */
.winseg { display: inline-flex; gap: 4px; margin-left: 8px; }
/* 列表页（ObjListPage）：版式走 .ov-head + .ptable，这里只补它没有的交互态（表头排序钮、整行可点）。 */
.listpage .ptable th .thsort { all: unset; box-sizing: border-box; display: block; width: 100%;
  cursor: pointer; color: var(--dim); font-weight: 600; }
.listpage .ptable th .thsort:hover, .listpage .ptable th .thsort:focus-visible { color: var(--fg); }
.listpage .ptable th .thsort .ar { display: inline-block; width: 10px; margin: 0 2px; color: var(--accent); text-align: center; }
.listpage .ptable .sub { font-size: var(--fs-micro); color: var(--muted); font-weight: 400; }
.listpage .ptable tr.rowlink { cursor: pointer; }
.listpage .ptable tr.rowlink:focus-visible { outline: 1px solid var(--accent); outline-offset: -1px; }
.listpage .ptable tr.rowlink:hover td { background: var(--raise-2); }
.listpage .ptable td.t-dim { color: var(--muted); }
.listpage .ptable td.t-bad:not(:has(.pill)) { color: var(--bad); }

/* 对象页头：事实一行排开（名-值成对），不再是一段话 */
.facts { display: flex; flex-wrap: wrap; gap: 6px 28px; margin: 10px 0 0; }
.facts > div { min-width: 0; }
.facts dt { font-size: var(--fs-micro); color: var(--muted); letter-spacing: .4px; }
.facts dd { margin: 0; font-size: var(--fs-body); font-variant-numeric: tabular-nums; }
.facts > div.wide { flex-basis: 100%; }

/* ══════════════════════════════════════════════════════════════════════════
   ★ 2026-10-09 像素级整理
   ① 正文留白：各 tab 页此前顶着分栏线、顶着窗口右缘，没有天头与边距 ⇒ 统一 20/26。
   ② 工具条：所有控件同高 28；分段控件 = 一个圆角框 + 内部竖线，不再是一排各自带框的按钮。
   ③ 占比条：有轨道（满额参照）、与数字同一内边距，从左长起。
   ④ 排序箭头：右对齐的列把箭头放标签左边，标签右缘与数字右缘对齐。
   ⑤ 列表页头：与表格左缘对齐（此前被 objpage + objhead 两层 26px 推到 52px）。
   ══════════════════════════════════════════════════════════════════════════ */
#app.shell > main.pagemain > div[id^="tab-"] { padding: 20px 26px 48px; }
@media (max-width: 1180px) { #app.shell > main.pagemain > div[id^="tab-"] { padding: 16px 20px 40px; } }

#app.shell .lc-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin: 0 0 12px; }
#app.shell .lc-head h3 { margin: 0; }
#app.shell .lc-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 0 0 10px; }
#app.shell .lc-bar > .lc-filter,
#app.shell .lc-bar > select { height: 28px; min-height: 28px; box-sizing: border-box; border-radius: 8px;
  font-size: var(--fs-small); padding-block: 0; }
#app.shell .lc-bar > .lc-filter { padding-inline: 10px; }
#app.shell .lc-bar > select { padding-inline: 10px 6px; }
#app.shell .lc-busy { font-size: var(--fs-micro); color: var(--muted); }

#app.shell .lc-seg { display: inline-flex; align-items: stretch; height: 28px; box-sizing: border-box;
  border: 1px solid var(--line); border-radius: 8px; overflow: hidden; background: var(--panel); }
#app.shell .lc-seg > button.mini { min-height: 0; height: 100%; border: 0; border-radius: 0; background: transparent;
  color: var(--dim); padding: 0 11px; font-size: var(--fs-small); box-shadow: none; }
#app.shell .lc-seg > button.mini + button.mini { border-left: 1px solid var(--line); }
#app.shell .lc-seg > button.mini:hover { color: var(--fg); }
#app.shell .lc-seg > button.mini.cur { background: var(--accent-bg); color: var(--accent); }
#app.shell .listpage .ol-q { height: 28px; box-sizing: border-box; padding: 0 10px; }

#app.shell .lc-crumb { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; min-height: 22px; margin: 0 0 10px;
  font-size: var(--fs-small); }
#app.shell .lc-crumb .sep { color: var(--dim); }
#app.shell .lc-crumb .cur { color: var(--muted); }
#app.shell .lc-step { display: inline-flex; align-items: center; gap: 6px; }
#app.shell .lc-crumb .pill { display: inline-flex; align-items: center; height: 22px; padding: 0 9px;
  font-size: var(--fs-small); background: transparent; color: var(--fg); cursor: pointer; }
#app.shell .lc-crumb .pill:hover { border-color: var(--accent-line); color: var(--accent); }

td.barcell { position: relative; }
td.barcell::after { content: ''; position: absolute; right: 12px; bottom: 4px; width: 72px; height: 2px;
  border-radius: 1px; background: var(--line); opacity: .7; }
td.barcell .bar { position: absolute; z-index: 1; right: calc(12px + 72px - 72px * var(--w, 0) / 100); bottom: 4px;
  height: 2px; border-radius: 1px; width: calc(72px * var(--w, 0) / 100); background: var(--accent); opacity: .85; }
td.barcell > span { position: relative; }

#app.shell .ov-pair { align-items: stretch; }
#app.shell table { font-variant-numeric: tabular-nums; }
.kpi .v.u b { color: var(--fg); }
#app.shell > .nav, #app.shell > .objlist { min-height: calc(100vh - var(--shell-main-top, 87px)); }
#app.shell > .objlist { padding-bottom: 0; }
.objlist .ol-views { padding: 6px 0 14px; }
#app.shell .objpage { padding-top: 20px; }
@media (max-width: 1180px) { #app.shell .objpage { padding-top: 16px; } }

/* 两栏收起钮：同一行、同一右缘 —— 两栏上内边距、右内边距取同一值（此前 16/10 对 0/8，差 16px 高、2px 宽） */
#app.shell > .nav,
#app.shell > .objlist { padding: 12px 10px 0; }
#app.shell > .nav > .rail-head,
#app.shell > .objlist > .rail-head { margin-bottom: 8px; }
#app.shell > .nav > .rail-head > .rail-toggle,
#app.shell > .objlist > .rail-head > .rail-toggle { min-height: 0 !important; width: 28px !important; height: 28px !important; box-sizing: border-box; }
.brand > *, .scheme-seg button, #logout { white-space: nowrap; flex-shrink: 0; }
.brand > #who { flex-shrink: 1; }
.ov-head h2, .ov-win { white-space: nowrap; }

/* ★ 2026-10-09 栏目标题条（业主：收起钮「不整齐」）：两左栏顶部统一为一条 34px 的标题条——
   左侧栏名（板块 / 账期 / 客户 (n) …），右侧收起钮；与主区天头同高、同一基线。 */
#app.shell > .nav > .rail-head,
#app.shell > .objlist > .rail-head {
  justify-content: space-between;
  height: 34px; min-height: 34px; margin: 0 0 8px;
  padding: 0 2px 0 4px;
  border-bottom: 1px solid var(--line);
}
#app.shell .rail-title {
  font-size: var(--fs-small); font-weight: 600; letter-spacing: .4px;
  color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  min-width: 0;
}
#app.shell > .nav > .rail-head > .rail-toggle,
#app.shell > .objlist > .rail-head > .rail-toggle { margin: 0 !important; }
#app.shell.rail1hide > .nav > .rail-head,
#app.shell.rail2hide > .objlist > .rail-head { justify-content: center; padding: 0; border-bottom: 0; }
#app.shell.rail1hide > .nav > .rail-head > .rail-title,
#app.shell.rail2hide > .objlist > .rail-head > .rail-title { display: none; }

/* 主区标题统一（各面 pane 的 h2 同一字号、同一节奏；ov-head 内的 h2 归零边距由其自己对齐） */
#app.shell main.pagemain h2 { font-size: var(--fs-title); font-weight: 600; letter-spacing: .3px; margin: 0 0 12px; }
#app.shell main.pagemain .ov-head h2 { margin: 0; }

/* 占比条（对账页 · 四栏） */
.sharebar { height: 6px; border-radius: 3px; background: var(--raise-2); overflow: hidden; min-width: 80px; }
.sharebar > i { display: block; height: 100%; background: var(--accent); }

/* ★ 2026-10-09 并行合流后的像素修正（截图实证）：
   - 「板块」栏名被 `.nav span` 的虚线胶囊样式套住 ⇒ 栏名去掉边框与底色；
   - 「全部展开」「N / M 个模型」在窄列里被压成竖排 ⇒ 按钮与计数不换行；
   - 非价目表的 `.ptable` 改回自动列宽，不再套 7 列的钉死宽度。 */
#app.shell .rail-title { border: 0; padding: 0; border-radius: 0; background: none; }
button.mini { white-space: nowrap; flex-shrink: 0; }
#hits, #msHits { white-space: nowrap; }
/* 表头不逐字换行（自动列宽下，中文表头会被挤成竖排） */
.ptable th { white-space: nowrap; }

/* ★ 2026-10-09 ledgercut */
/* 账的页头标题用 h3 时，与其它页头 h2 同字号、同字重，且去掉 h3 全局的下边距（否则与按钮不齐） */
.ov-head > h3 { margin: 0; font-size: var(--fs-title); font-weight: 600; letter-spacing: .3px; color: var(--fg); }
/* 待补价表：是「要动手补」的清单，补价按钮常显（不走 ptable 的悬停才现） */
.ptable.pend tbody tr .mini { opacity: 1; }

/* 窄窗口：表格宽度不足时整表在卡片内横向滚动，不再把列挤成竖排（供应商的模型/密钥列曾逐字换行） */
.ptable { min-width: 640px; }

/* ══════════════════════════════════════════════════════════════════
   费用面 · 汇总带与页面骨架（2026-10-13 业主：「全面优化，用户极其苛刻」）

   三条原则：
   ① **结论在上、过程在下** —— 汇总带只放"判断"用的数，过程量降为一小行
   ② **一个数一个位置、同类一律同形** —— 金额统一 ¥x,xxx.00，整数统一千分位
   ③ **能自己解释的地方不要人猜** —— 空值明确写「—」

   ★ 2026-10-14：原先用它的两页（`CostBoard` 收支 · `Consumption` 消费）已废 ——
     四页（收支/账单/消费/日报）收成一张「收支」（`IncomeExpense.tsx`）。
     汇总带（`cb-sum*`）与下面那套页面骨架（`dr-*`）继续由**新收支页与价目页**共用。
   ══════════════════════════════════════════════════════════════════ */

/* 汇总带（「总」那一格）：三格等宽、左对齐成列；格与格之间用竖线分隔（比堆间距更"整"） */
#app.shell .cb-sum{display:flex;flex-wrap:wrap;gap:0;margin:0 0 8px;
  background:var(--panel);border:1px solid var(--line);border-radius:12px;overflow:hidden}
#app.shell .cb-sumitem{flex:1 1 130px;min-width:110px;padding:var(--sp-3) var(--sp-4);
  border-right:1px solid var(--line)}
#app.shell .cb-sumitem:last-child{border-right:0}
#app.shell .cb-sumitem-key{background:color-mix(in srgb, var(--accent) 5%, transparent)}
/* 标签行：主名与注解**各自不折断**（中文被从中间拆开＝看着像坏了），
   放不下时**整块换行**（注解掉到下一行），不把「积分消耗」拆成「积分消/耗」。 */
#app.shell .cb-sumlab{font-size:var(--fs-small);display:flex;align-items:baseline;gap:2px 6px;
  flex-wrap:wrap;white-space:nowrap}
#app.shell .cb-sumq{font-size:var(--fs-micro);opacity:.62}
#app.shell .cb-sumnum{font-size:22px;font-weight:600;margin-top:2px;
  font-variant-numeric:tabular-nums;white-space:nowrap}
/* 汇总带的附加小字（「N/M 项未出账」）——
   主数值保持 22px 不折行；这一截独立成行、降字号、允许折行，
   避免长串把整格顶出卡片边界（2026-10-17 业主截图的溢出）。
   信息不删：业主明确要求「已知与未知分开说」，这里只是换个排布。 */
#app.shell .cb-sumnum .cb-sumaux{display:block;font-size:var(--fs-micro);font-weight:400;
  opacity:.66;white-space:normal;line-height:1.3;margin-top:1px}
#app.shell .cb-sumnum.cb-neg{color:var(--danger)}
/* 过程量：一行小字，紧贴汇总带下方 —— 看得见但不抢位置 */
#app.shell .cb-meta{font-size:var(--fs-small);margin:0 0 12px 2px}

/* 收支页：客户行的展开箭头；展开出来的团队行（比父行退一格、淡一档） */
#app.shell .ie-chev{display:inline-block;width:14px;margin-right:2px;color:var(--muted);font-size:11px}
/* 团队子行要比父行的**文字**再深一格（父行文字前有 16px 的展开箭头，30px 只够打平） */
#app.shell .ie-sub td{padding-left:44px;color:var(--muted);
  border-bottom:1px solid color-mix(in srgb,var(--line) 55%,transparent)}
/* ★ 2026-10-18：表格里的**副值**（积分 ≈ 元 · 已剔除额）—— 与主数值同一格、
   小一号、淡一档。它给的是换算与拆分，不是又一个独立指标，所以不进表头、不占列。 */
#app.shell .ie-yen{display:block;font-size:var(--fs-micro);color:var(--muted);
  font-weight:400;line-height:1.35;white-space:nowrap}
/* ★ 2026-10-17（业主）：维度表改成「父行 + 供应商子行 + 合计行」三段。
   父行加粗（一眼看到谁），子行缩进淡一档（谁在上面花钱），
   合计行加顶线 + 略深底（分段结束，不是又一个数据行）。 */
#app.shell .ie-parent td{font-weight:600}
#app.shell tr.ie-chase-cur td{background:color-mix(in srgb, var(--accent) 8%, transparent)}
#app.shell .ie-total td{border-top:2px solid var(--line);font-variant-numeric:tabular-nums;
  background:color-mix(in srgb,var(--fg) 3%,transparent)}

/* ★ 2026-10-19（业主）：**一张表只有一个主语** —— 分类不再做子行，改成 chips。
   一个 chip = 一个分类值 + 它自己的数；点它 = 把下面那张表收窄到它。
   合计跟着选中项走（口径写在上方那行小字里），表里只有一层，仍按积分降序。 */
#app.shell .ie-scope{font-size:var(--fs-small);margin:2px 0 8px 2px}
#app.shell .ie-sum{margin:0 0 12px}
#app.shell .ie-chips{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin:0 0 12px}
#app.shell .ie-chip{display:inline-flex;align-items:baseline;gap:7px;padding:5px 13px;
  border:1px solid var(--line);border-radius:999px;background:transparent;color:var(--fg);
  font:inherit;font-size:var(--fs-small);cursor:pointer;white-space:nowrap}
#app.shell .ie-chip:hover{border-color:color-mix(in srgb,var(--accent) 45%,var(--line))}
#app.shell .ie-chip .n{color:var(--muted);font-size:var(--fs-micro);font-variant-numeric:tabular-nums}
#app.shell .ie-chip.on{border-color:var(--accent);
  background:color-mix(in srgb,var(--accent) 12%,transparent);color:var(--accent);font-weight:600}
#app.shell .ie-chip.on .n{color:var(--accent);opacity:.75}
/* 「未归类」不是一种业务，是主数据没挂上的缺口 —— 虚线淡色，与业务类型区分开 */
#app.shell .ie-chip.dirty{border-style:dashed;color:var(--muted)}
#app.shell .ie-chip.more{color:var(--muted)}

/* ── 费用面页面骨架（`PriceSheet` 价目 / `IncomeExpense` 收支 共用）──────────
   日期条 + 卡片（标题 + 截断前的总数 + 表格 + 点行展开"详情"）。
   颜色全部走既有变量（--fg / --line / --muted…），跟随主题，不写死色值。 */
#app.shell .dr-wrap{display:flex;flex-direction:column;gap:14px;padding:4px 0 24px}
#app.shell .dr-bar{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
#app.shell .dr-bar label{display:flex;align-items:center;gap:6px;font-size:13px;color:var(--muted);white-space:nowrap}
/* 页头右侧的时间/导出控件：**每个控件内部不折字**（「日期/月份」被拆开像坏了），
   但**控件之间可以换行** —— 内容区窄时整行往下挪，绝不能把「导出」挤出屏外。
   实测（800px 视口 + 两条侧栏展开）：不许换行 ⇒ 「今天」「导出」直接看不见。 */
#app.shell .ie-ctl{flex-wrap:wrap;margin-left:auto}
#app.shell .ie-when.ie-ctl{margin-left:0}
#app.shell .dr-table th[rowspan]{vertical-align:bottom}
#app.shell .cb-sumitem.ie-accrual{flex:1 1 200px}
#app.shell .cb-sumitem.ie-bill{flex:2 1 320px}
#app.shell .ie-bill-parts{display:flex;gap:28px;margin-top:6px}
#app.shell .ie-bill-parts .cb-sumnum{font-size:18px}
#app.shell .dr-bar input[type=date]{padding:5px 8px;border:1px solid var(--line);border-radius:6px;background:transparent;color:var(--fg);font:inherit}
#app.shell .dr-note{font-size:12px;color:var(--muted);line-height:1.6}
#app.shell .dr-hint{padding:18px;color:var(--muted);font-size:13px}
#app.shell .dr-card{border:1px solid var(--line);border-radius:10px;overflow:hidden}
#app.shell .dr-card>header{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;padding:9px 12px;border-bottom:1px solid var(--line)}
#app.shell .dr-card>header b{font-size:14px}
#app.shell .dr-sub{font-size:12px;color:var(--muted)}
#app.shell .dr-total{margin-left:auto;font-size:12px;color:var(--muted);font-variant-numeric:tabular-nums}
/* 卡片级导出：按钮长在它导出的那张表上 —— 位置本身就是「导什么」的说明 */
#app.shell .dr-card-export{margin-left:auto}
#app.shell .dr-table{width:100%;border-collapse:collapse;font-size:13px;font-variant-numeric:tabular-nums}
#app.shell .dr-table th{padding:7px 12px;font-weight:500;font-size:12px;color:var(--muted);border-bottom:1px solid var(--line)}
#app.shell .dr-table td{padding:7px 12px;border-bottom:1px solid color-mix(in srgb,var(--line) 55%,transparent)}
#app.shell .dr-table tr:last-child td{border-bottom:0}
#app.shell .dr-row{cursor:pointer;transition:background .12s ease}
#app.shell .dr-row:hover{background:color-mix(in srgb,var(--fg) 4%,transparent)}
#app.shell .dr-idx{display:inline-block;min-width:18px;margin-right:6px;color:var(--muted);font-size:11px}
#app.shell .dr-raw{display:inline-block;margin-left:8px;font-size:11px;color:var(--muted);font-family:ui-monospace,monospace}
#app.shell .dr-detail{padding:10px 12px 12px 36px;background:color-mix(in srgb,var(--fg) 3%,transparent);font-size:12.5px;line-height:1.9}
#app.shell .dr-d1{font-weight:600;margin-bottom:2px}
#app.shell .dr-d2{color:var(--muted);font-size:12px;line-height:1.7}
#app.shell .dr-detail code{font-size:11.5px;background:color-mix(in srgb,var(--fg) 6%,transparent);padding:1px 5px;border-radius:4px}
#app.shell .dr-empty{padding:16px 12px;color:var(--muted);font-size:13px}
#app.shell .dr-foot{border-top:1px dashed var(--line);padding-top:10px;display:flex;flex-direction:column;gap:6px}
/* ⚠️ 新栈挂载点样式 —— **唯一一条被复制到各面的 CSS**。
 *
 * 旧页面是「手写静态 HTML」：HTML 里直接就是 <body><div class="wrap">…。
 * 新栈（React）需要一个挂载点 ⇒ HTML 里多一层 <div id="root">。
 * `display: contents` 让这层**不参与布局**（盒子被"拆掉"，子元素直接落在 body 的布局里）——
 * 于是 body 的 flex 与 .wrap 的定位与升级前**逐像素一致**。
 *
 * 不用它会发生什么：多出来的那层成为 body 布局的子项 ⇒ 整页位置偏移。
 * （这个坑在创作台与运营台**都**踩过：多一层 #root 让整页竖着堆成一列。）
 *
 * ★ 2026-09-27（施工项 #19）：本文件是**权威副本**，正本在 `frontend/shared/root.css`，
 *   各面下的副本由 `scripts/sync_shared.sh` 派生。**不要在各面下直接改**——改了会被 --check 判漂移。
 *   （此前两个副本的注释已经各说各的 ⇒ 那正是"下一次漂移就在规则本身"的前兆。）
 */
#root { display: contents }
