/* 设计 token。
 *
 * 取值由脚本从 `SII Platform v14.dc.html` 按出现频次统计推出,再逐个回原型
 * 核对用途 —— **不靠眼睛认色**。这是一套新的视觉系统,与上一版(v5/v8)
 * 不通用:主色 #0F6E7A → #0B7285,顶栏 #14181D → #0D1220,页底也换了。
 * 两套 token 分文件放,不混用 —— 混用的表现是同一个青色在两页上差一点点,
 * 而没有人说得清哪个是对的。
 *
 * 三条沿用前几版的硬规矩(原型同样遵守):
 *   1. **不加阴影。** 层次只靠边框与背景色。
 *   2. **ID、路径、数值、时长用等宽。**
 *   3. 无图片、无图标字体、无 SVG —— 视觉元素全是 CSS 色块与文字符号。
 *
 * 字体走系统栈,不引 Google Fonts:线上 CSP 会挡掉外部字体并**静默回退**,
 * 那时字重与字距全错而界面看起来「差不多对」。
 */

:root {
  /* ── 字号:六级 ─────────────────────────────────
   *
   * 2026-08-15 之前全站有 **14 种字号**(9 到 19,还带一堆半像素台阶)。
   * 那不是排版,是每处各写各的:导航项 12.5、卡片标题 13、副标题 12、
   * 表头 9.5……单看每一处都说得通,合在一起眼睛读不出任何系统。
   *
   * 业主的判断很准:「Tab 栏字号比较小,但主体页面字体比较大,看着奇怪。」
   * 根因是两头拉开而中间没有台阶 —— 导航 12.5 直接跳到页标题 19(1.52 倍),
   * 而**统计读数也是 19**,于是页标题和数字一样大,谁也不比谁重要。
   *
   * 现在六级,相邻比 1.13–1.24,导航与正文落在同一级:
   *
   *   micro  10    全大写微标签:表头、分组标题 —— 必带字距,否则糊成一团
   *   aux    11.5  辅助:说明、次要文字、表格副字段
   *   base   13    **基准**:正文、导航项、表格主字段、按钮
   *   lead   15    区块标题:卡片标题、层名
   *   page   17    页标题
   *   metric 21    统计读数 —— 页面上唯一比标题大的东西,因为它才是要读的
   *
   * 新写界面**一律用这些变量**,不写 px —— 守卫钉着这一条。
   */
  --t-micro:   10px;
  --t-aux:     11.5px;
  --t-base:    13px;
  --t-lead:    15px;
  --t-page:    17px;
  --t-metric:  21px;

  /* 行高三级。数据密的地方用 lh-2,成段说明用 lh-3。 */
  --lh-1: 1.35;   /* 标题 */
  --lh-2: 1.55;   /* 表格、导航、单行 */
  --lh-3: 1.7;    /* 成段说明 */

  /* ── 主色 ─────────────────────────────────────── */
  --c-primary:      #0B7285;   /* 主色 */
  --c-primary-deep: #075463;   /* 深:hover / 主色底上的字 */
  --c-primary-mid:  #4E9FB0;   /* 中:第二色、条形 */
  --c-primary-soft: #9FCBD6;   /* 浅:边框 */
  --c-primary-tint: #D7EDF1;   /* 浅底:徽标 */
  --c-primary-wash: #E9F4F7;   /* 更浅:选中行、强调块 */

  /* ── 强调(琥珀):待办 / 人工 / 成本警示 ────────── */
  --c-amber:      #B45309;
  --c-amber-wash: #FDF8F1;
  --c-amber-line: #E8DCC9;
  --c-amber-tag:  #F7EEE0;

  /* ── 错误 / 超期 ──────────────────────────────── */
  --c-danger:      #A33A3A;
  --c-danger-wash: #FDF1F1;

  /* ── 深色顶栏 ─────────────────────────────────── */
  --c-nav:       #0D1220;   /* 顶栏底 */
  --c-nav-block: #182134;   /* 顶栏内块 */
  --c-nav-line:  #2A3550;   /* 顶栏边框 */
  --c-nav-dim:   #6B7791;   /* 顶栏占位字 */
  --c-nav-text:  #D5DCE6;   /* 顶栏正文 */
  --c-nav-mute:  #A8B2C2;   /* 顶栏弱字 */

  /* ── 文字梯度 ─────────────────────────────────── */
  --c-ink:     #0D1220;   /* 标题 / 主字段 */
  --c-text:    #2F3949;   /* 正文 */
  --c-text-2:  #4C5666;   /* 次级 */
  --c-text-3:  #78849A;   /* 三级:标签、ID、说明 */
  --c-text-4:  #8E9BAE;   /* 极弱 */
  --c-text-off:#BAC3D1;   /* 禁用 */
  --c-on-dark: #FFFFFF;   /* 压在深色/主色上的字 */

  /* ── 面 ───────────────────────────────────────── */
  --c-page:    #EFF2F7;   /* 页底 */
  --c-shell:   #EEF0F2;   /* 外壳底(body) */
  --c-card:    #FFFFFF;
  --c-surface: #F6F8FC;   /* 次级面 / 表头 */
  --c-surface-2:#ECF0F5;  /* 更深一档:徽标底、合计行 */

  /* ── 边框 ─────────────────────────────────────── */
  --c-line:      #E3E9F1;   /* 主 */
  --c-line-weak: #ECF0F5;   /* 弱 */
  --c-line-mid:  #BAC3D1;   /* 中:虚线按钮 */

  /* ── 三层的层色(数据 / 分析 / 实验)────────────── */
  --c-layer-data:  #4E9FB0;
  --c-layer-analy: #0B7285;
  --c-layer-exp:   #B45309;
  --c-neutral-bar: #A8B4BA;   /* 条形中性色 */

  --f-sans: 'IBM Plex Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI',
            'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;
  --f-mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, 'SF Mono',
            Menlo, Consolas, monospace;

  --r-3: 3px; --r-4: 4px; --r-5: 5px; --r-6: 6px; --r-7: 7px; --r-8: 8px; --r-9: 9px;
}

* { box-sizing: border-box; font-variant-numeric: tabular-nums;
    -webkit-font-smoothing: antialiased; }
::selection { background: var(--c-primary-tint); color: var(--c-primary-deep); }

html, body {
  margin: 0; padding: 0; background: var(--c-shell);
  font-family: var(--f-sans); color: var(--c-text);
}
a { color: var(--c-primary); text-decoration: none; }
a:hover { color: var(--c-primary-deep); }

/* 原型是 1440px 固定宽内部后台;实现为最小 1280px、内容区自适应。 */
.app {
  min-width: 1280px; max-width: 1720px; margin: 0 auto;
  background: var(--c-page); min-height: 100vh;
  display: flex; flex-direction: column;
}

/* ── 顶栏 ─────────────────────────────────────────── */
.top {
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 20px; height: 52px; flex: 0 0 52px; background: var(--c-nav);
}
.top .l, .top .r { display: flex; align-items: center; }
.top .l { gap: 16px; }
.top .r { gap: 14px; }
/* 品牌锁定组:标记 + 字标 + 细分隔线 + 产品说明。
 * 机构感来自排版(全大写、字距 .14em),不来自装饰 —— 这个控制台
 * 一天要看八小时,顶栏的本分是安静。 */
.brand {
  display: flex; align-items: center; gap: 9px;
  background: none; border: 0; cursor: pointer; padding: 0;
}
.brand .mark { display: flex; line-height: 0; }
.brand .wm {
  font: 600 var(--t-base)/1 var(--f-sans); letter-spacing: .14em;
  color: var(--c-on-dark);
}
/* 产品说明在窄屏收起 —— 顶栏放不下时先让说明走,标记与字标留住。 */
.brand .sep {
  width: 1px; height: 13px; background: var(--c-on-dark); opacity: .26;
}
.brand .pd {
  font: 400 var(--t-aux)/1 var(--f-sans); color: var(--c-text-3); white-space: nowrap;
}
@media (max-width: 1100px) { .brand .sep, .brand .pd { display: none; } }
.brand:focus-visible { outline: 2px solid var(--c-on-dark); outline-offset: 3px; }
.chip-scope {
  display: flex; align-items: center; gap: 8px;
  padding: 5px 11px; background: var(--c-nav-block); border-radius: var(--r-5);
}
.chip-scope .k { font: 400 var(--t-aux)/1.4 var(--f-mono); color: var(--c-text-3); }
.chip-scope .v { font: 500 var(--t-aux)/1.4 var(--f-sans); color: var(--c-on-dark); }
.chip-state {
  padding: 3px 8px; border: 1px solid var(--c-nav-line); border-radius: var(--r-4);
  font: 500 var(--t-micro)/1.6 var(--f-mono); letter-spacing: .08em; color: var(--c-nav-mute);
}
.searchbtn {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  width: 250px; padding: 6px 10px; background: var(--c-nav-block);
  border: 0; border-radius: var(--r-5); cursor: pointer;
  font: 400 var(--t-aux)/1.4 var(--f-sans); color: var(--c-nav-dim);
}
.searchbtn kbd {
  padding: 1px 5px; border: 1px solid var(--c-nav-line); border-radius: var(--r-3);
  font: 500 var(--t-micro)/1.5 var(--f-mono); color: var(--c-text-3);
}
.navbtn {
  position: relative; padding: 5px 9px; background: none;
  border: 1px solid var(--c-nav-line); border-radius: var(--r-5); cursor: pointer;
  font: 400 var(--t-aux)/1.4 var(--f-sans); color: var(--c-nav-text);
}
.navbtn .dot {
  position: absolute; top: -5px; right: -5px; min-width: 15px; height: 15px;
  padding: 0 3px; border-radius: 8px; background: var(--c-amber);
  font: 600 var(--t-micro)/15px var(--f-mono); color: var(--c-on-dark); text-align: center;
}
.runbtn {
  background: none; border: 0; cursor: pointer; padding: 0;
  font: 400 var(--t-aux)/1.4 var(--f-mono); color: var(--c-text-3);
}
.me { display: flex; align-items: center; gap: 8px; }
.me .n { font: 400 var(--t-aux)/1.4 var(--f-sans); color: var(--c-nav-text); }
.ava {
  width: 26px; height: 26px; border-radius: 50%; background: var(--c-primary);
  font: 600 var(--t-aux)/26px var(--f-sans); color: var(--c-on-dark); text-align: center; flex: none;
}

/* ── 主体 / 左菜单 ────────────────────────────────── */
.body { display: flex; flex: 1; align-items: stretch; }
.side {
  /* `min-width: 0` 是必须的:flex 项默认 `min-width: auto`,内容比
     flex-basis 宽时会把它顶开 —— 长管线名一进来,侧栏就从 214 变成 260,
     而 `.nm` 的省略号也因此永远不触发。实测过才看得出(2026-08-15)。 */
  flex: 0 0 214px; min-width: 0; background: var(--c-card);
  border-right: 1px solid var(--c-line);
  display: flex; flex-direction: column; padding: 12px 0;
}
.grp { margin-bottom: 14px; }
.grp > .t {
  display: flex; align-items: baseline; gap: 6px; padding: 0 14px 6px;
  font: 600 var(--t-micro)/1 var(--f-mono); letter-spacing: .13em; color: var(--c-text-4);
}
.grp > .t .en { font-weight: 400; letter-spacing: .06em; color: var(--c-text-off); }
.item {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  width: 100%; text-align: left; cursor: pointer; padding: 8px 14px;
  background: transparent; border: 0; border-left: 3px solid transparent;
  font: 500 var(--t-base)/1.5 var(--f-sans); color: var(--c-text);
}
.item:hover { background: var(--c-surface); }
.item[aria-current="page"] {
  background: var(--c-primary-wash); color: var(--c-primary-deep);
  border-left-color: var(--c-primary);
}
.item:focus-visible { outline: 2px solid var(--c-primary); outline-offset: -2px; }
.item .n { font: 400 var(--t-aux)/1.5 var(--f-mono); color: var(--c-text-4); }
.item .n[data-todo="1"] {
  padding: 1px 6px; border-radius: 7px;
  background: var(--c-amber-wash); color: var(--c-amber); font-weight: 600;
}
/* 管线项:圆点 = **数据源接没接**(实心=在跑,空心=待接入);
   角标 = 七步走了几步。两样东西分开表达,不合成一个「状态」——
   合成的话,有数据在跑但没走完治理流程的管线怎么画都在骗人。 */
.pipe { padding-left: 14px; }
.pipe .d {
  width: 6px; height: 6px; border-radius: 50%; flex: none;
  background: transparent; box-shadow: inset 0 0 0 1.5px var(--c-text-off);
}
.pipe .d[data-on="1"] { background: var(--c-text-off); box-shadow: none; }
.pipe[aria-current="page"] .d, .pipe[data-active="1"] .d {
  box-shadow: inset 0 0 0 1.5px var(--c-primary);
}
.pipe[aria-current="page"] .d[data-on="1"],
.pipe[data-active="1"] .d[data-on="1"] {
  background: var(--c-primary); box-shadow: none;
}
.kid { padding-left: 30px; }
/* 侧栏里「读取中 / 读不到 / 一条都没有」这三种说明。
   **要和可点的管线明显不同** —— 此前它们挂着一个 CSS 里根本不存在的
   `.muted`,于是与真管线同字重同颜色,一句「注册表里还没有管线」
   看起来就像一条叫这个名字的管线。 */
.item.muted {
  font-weight: 400; color: var(--c-text-3); cursor: default;
  font-size: var(--t-aux);
}
.item.muted:hover { background: transparent; }

/* ── 内容区 ───────────────────────────────────────── */
.main { flex: 1; padding: 20px 26px 28px; min-width: 0; }
.h1 { margin: 0 0 3px; font: 600 var(--t-page)/var(--lh-1) var(--f-sans); color: var(--c-ink); }
.sub { margin: 0; font: 400 var(--t-aux)/1.7 var(--f-sans); color: var(--c-text-2); }
.phead {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 20px; margin-bottom: 14px;
}

/* ── 卡片 / 表格 ──────────────────────────────────── */
.card {
  background: var(--c-card); border: 1px solid var(--c-line);
  border-radius: var(--r-8); padding: 16px 18px;
}
.card > .h {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin: 0 0 10px; font: 600 var(--t-base)/1.4 var(--f-sans); color: var(--c-ink);
}
.tbl { background: var(--c-card); border: 1px solid var(--c-line);
       border-radius: var(--r-8); overflow: hidden; }
.tbl .th {
  display: grid; background: var(--c-surface);
  border-bottom: 1px solid var(--c-line); padding: 9px 14px;
}
.tbl .th > * {
  font: 600 var(--t-micro)/1.5 var(--f-mono); letter-spacing: .1em; color: var(--c-text-3);
}
.tbl .tr {
  display: grid; padding: 11px 14px; border-bottom: 1px solid var(--c-line-weak);
  align-items: center; width: 100%; text-align: left;
  background: var(--c-card); border-left: 0; border-right: 0; border-top: 0;
}
.tbl .tr:last-child { border-bottom: 0; }
button.tr { cursor: pointer; font: inherit; }
button.tr:hover { background: var(--c-surface); }
.tr.total { background: var(--c-surface); font-weight: 600; }

/* ── 主字段 / 副字段 ──────────────────────────────
 *
 * `.m`(main)与 `.s`(sub)是全站用得最多的两个类 —— 19 个文件、142 处。
 * 而 2026-08-15 之前它们**只在 `.tr` 里有定义**:
 *
 *     .tr .m { … }    .tr .s { … }
 *
 * 于是表格外的每一处都没有任何字体声明,落回浏览器默认 **16px/400**:
 * 比页标题(17px)只小 1px,比正文(13px)大了三级。业主说的
 * 「Tab 栏字号小、但主体页面字体大,看着奇怪」就是这个 ——
 * 主体上那些「大字」不是设计出来的,是**没写样式**。
 * CSS 不会为用了没定义的类报错,它只是什么都不做。
 *
 * 两个类在表内表外**必须长同一个样**,否则同一段话搬进表格就变形。
 *
 * 等宽按**内容**给(见文件头第 2 条):ID、路径、数值、时长加 `mono`。
 * 早先 `.tr .s` 默认等宽 —— 那是按**位置**给的,于是「文献全文库」
 * 「开放获取子集 · 2000 年至今」这些散文也排成了等宽。
 */
.m { font: 500 var(--t-base)/var(--lh-2) var(--f-sans); color: var(--c-ink); }
.s { font: 400 var(--t-aux)/var(--lh-2) var(--f-sans); color: var(--c-text-3); }
/* 成段说明用 `.s.p`:行高松一档。密排的副字段与整段的说明不是一回事。 */
.s.p { line-height: var(--lh-3); color: var(--c-text-2); }

/* ── 徽标 / 按钮 ──────────────────────────────────── */
.tag {
  display: inline-block; padding: 2px 7px; border-radius: var(--r-4);
  font: 500 var(--t-micro)/1.5 var(--f-mono); white-space: nowrap;
  background: var(--c-surface-2); color: var(--c-text-2);
}
.tag[data-t="ok"]   { background: var(--c-primary-tint); color: var(--c-primary-deep); }
.tag[data-t="todo"] { background: var(--c-amber-wash);   color: var(--c-amber); }
.tag[data-t="warn"] { background: var(--c-amber-tag);    color: var(--c-amber); }
.tag[data-t="stop"] { background: var(--c-danger-wash);  color: var(--c-danger); }

.btn {
  padding: 7px 14px; border-radius: var(--r-6); border: 1px solid transparent;
  background: var(--c-primary); color: var(--c-on-dark);
  font: 500 var(--t-aux)/1.4 var(--f-sans); cursor: pointer; white-space: nowrap;
}
.btn:hover { background: var(--c-primary-deep); }
.btn.ghost { background: var(--c-card); border-color: var(--c-line); color: var(--c-text); }
.btn.ghost:hover { background: var(--c-surface); }
.btn.sm { padding: 5px 10px; font-size: 11.5px; border-radius: var(--r-5); }
.btn[disabled] {
  background: var(--c-surface); border-color: var(--c-line);
  color: var(--c-text-off); cursor: not-allowed;
}
.why { font: 400 var(--t-aux)/1.6 var(--f-sans); color: var(--c-amber); margin-top: 5px; }
/* 虚线按钮:＋ check */
.btn.dash {
  background: none; border: 1px dashed var(--c-line-mid); color: var(--c-text-3);
}
.btn.dash:hover { border-color: var(--c-primary); color: var(--c-primary); }

/* chip 组:筛选 / 方案 / check 库 */
.chip {
  padding: 5px 11px; border-radius: var(--r-5); border: 1px solid var(--c-line);
  background: var(--c-card); cursor: pointer;
  font: 500 var(--t-aux)/1.4 var(--f-sans); color: var(--c-text-2);
}
.chip[aria-pressed="true"] {
  background: var(--c-primary-wash); border-color: var(--c-primary);
  color: var(--c-primary-deep);
}

/* ── 三层的层卡 ───────────────────────────────────── */
.layers { display: flex; gap: 12px; }
.layer {
  flex: 1; padding: 16px 18px; border: 1.5px solid var(--c-line);
  border-radius: var(--r-9); background: var(--c-card);
  cursor: pointer; text-align: left;
}
.layer[aria-pressed="true"] { border-color: var(--c-primary); }
.layer:focus-visible { outline: 2px solid var(--c-primary); outline-offset: 1px; }
.layer .hd { display: flex; align-items: center; gap: 9px; margin-bottom: 10px; }
.layer .no {
  width: 22px; height: 22px; border-radius: 50%; flex: none;
  background: var(--c-surface-2); color: var(--c-text-3);
  font: 600 var(--t-aux)/22px var(--f-mono); text-align: center;
}
.layer[aria-pressed="true"] .no { background: var(--c-primary); color: var(--c-on-dark); }
.layer .nm { font: 600 var(--t-lead)/1.3 var(--f-sans); color: var(--c-ink); }
.layer .mets { display: flex; gap: 18px; margin-bottom: 10px; }
.layer .met .v { font: 600 var(--t-metric)/1.2 var(--f-sans); color: var(--c-ink); }
.layer .met .k { font: 400 var(--t-micro)/1.5 var(--f-mono); color: var(--c-text-3); }
.layer .res {
  display: flex; gap: 14px; padding-top: 9px; border-top: 1px solid var(--c-line-weak);
  font: 400 var(--t-aux)/1.5 var(--f-mono); color: var(--c-text-3);
}

/* ── 布局助手 ─────────────────────────────────────── */
.stack { display: flex; flex-direction: column; gap: 13px; }
.grid  { display: grid; gap: 13px; }
.rowb  { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.mono  { font-family: var(--f-mono); }
.note {
  background: var(--c-primary-wash); border-left: 3px solid var(--c-primary);
  border-radius: var(--r-4); padding: 9px 12px;
  font: 400 var(--t-aux)/1.7 var(--f-sans); color: var(--c-text);
}
.note[data-t="todo"] { background: var(--c-amber-wash); border-left-color: var(--c-amber); }
.note[data-t="stop"] { background: var(--c-danger-wash); border-left-color: var(--c-danger); }

/* 水平条 */
.barrow { display: flex; align-items: center; gap: 10px; }
.bartrack { flex: 1; height: 7px; background: var(--c-surface-2); border-radius: var(--r-2, 2px); overflow: hidden; }
.barfill { height: 100%; border-radius: 2px; }

/* ── 数据来源标记 ─────────────────────────────────
 * 上一轮的教训:7 块标了「实数」而前端一次 fetch 都没有。
 * 管线页的数据多数还来自设计稿 —— 一律标「演示」,
 * 只有真的调了后端接口的块才允许标「实数」。 */
.src {
  display: inline-block; margin-left: 6px; padding: 1px 6px;
  border: 1px solid var(--c-line); border-radius: var(--r-3);
  font: 500 var(--t-micro)/1.6 var(--f-mono); letter-spacing: .05em;
  color: var(--c-text-3); vertical-align: middle; cursor: help;
}
.src[data-w="live"] { border-color: var(--c-primary-soft); color: var(--c-primary); }
.src[data-w="demo"] { border-color: var(--c-amber-line);   color: var(--c-amber); }
.src[data-w="absent"]{ border-color: var(--c-line-mid);    color: var(--c-text-3); }

/* 命令面板 */
.scrim {
  position: fixed; inset: 0; background: rgba(13,18,32,.42);
  display: flex; align-items: flex-start; justify-content: center; padding-top: 12vh; z-index: 50;
}
.palette {
  width: 560px; background: var(--c-card); border: 1px solid var(--c-line);
  border-radius: var(--r-9); overflow: hidden;
}
.palette input {
  width: 100%; padding: 13px 16px; border: 0; border-bottom: 1px solid var(--c-line);
  font: 400 var(--t-base)/1.5 var(--f-sans); color: var(--c-ink); outline: none;
}
.palette .row {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  width: 100%; padding: 9px 16px; background: none; border: 0; cursor: pointer;
  text-align: left; font: 500 var(--t-base)/1.5 var(--f-sans); color: var(--c-text);
}
.palette .row:hover { background: var(--c-primary-wash); }
.palette .row .k { font: 400 var(--t-aux)/1.5 var(--f-mono); color: var(--c-text-4); }

@media (prefers-reduced-motion: reduce) { * { transition: none !important; } }

/* ══ 管线作业区 ══════════════════════════════════════════════════════════
 *
 * 业主 2026-08-15:「点到某一个管线进去之后,就是进到这个管线里的作业
 * 页面,然后左边的侧边栏就可以隐藏掉,然后再有一个回退的按钮就行了。
 * 你现在这种跳来跳去的这种情况,看起来非常非常难受。」
 *
 * 所以进了管线是**另一屏**,不是同一屏里嵌一块:侧栏收起,整宽给内容,
 * 导航全部收在这一横条上 —— 回退在最左,标签在下面一行。
 *
 * 这一条要跟平台模式明显不同,否则人分不清自己在哪一屏。做法是给它
 * 白底 + 一条下边框,与页底的灰形成一个「头」。 */
.main.wide { padding: 0 0 28px; }
.phead-bar {
  background: var(--c-card); border-bottom: 1px solid var(--c-line);
  padding: 13px 26px 0; margin-bottom: 20px;
}
.phead-bar .row {
  display: flex; align-items: center; gap: 12px; margin-bottom: 11px;
}
/* 回退:**整屏唯一的出口**,所以给足点击区并带箭头。
   藏起来的话人会按浏览器后退,而那会退到上一个作用域 —— 更乱。 */
.phead-bar .back {
  display: flex; align-items: center; gap: 6px; flex: none;
  padding: 4px 9px 4px 6px; margin-left: -6px;
  background: none; border: 0; border-radius: var(--r-5); cursor: pointer;
  font: 500 var(--t-base)/var(--lh-2) var(--f-sans); color: var(--c-primary);
}
.phead-bar .back:hover { background: var(--c-primary-wash); }
.phead-bar .back:focus-visible { outline: 2px solid var(--c-primary); outline-offset: 1px; }
.phead-bar .back .a { font-size: var(--t-lead); line-height: 1; }
.phead-bar .sep { width: 1px; height: 16px; background: var(--c-line); flex: none; }
.phead-bar .nm {
  font: 600 var(--t-page)/var(--lh-1) var(--f-sans); color: var(--c-ink);
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.phead-bar .chips { display: flex; gap: 6px; margin-left: auto; flex: none; }
.phead-bar .chips .c {
  padding: 2px 8px; border: 1px solid var(--c-line); border-radius: var(--r-4);
  font: 500 var(--t-micro)/1.7 var(--f-mono); color: var(--c-text-3);
  background: var(--c-surface); white-space: nowrap;
}
.phead-bar .chips .c[data-on="1"] {
  color: var(--c-primary-deep); background: var(--c-primary-wash);
  border-color: var(--c-primary-soft);
}
.phead-bar .chips .c[data-todo="1"] {
  color: var(--c-amber); background: var(--c-amber-wash);
  border-color: var(--c-amber-line);
}
/* 标签行:选中态用下划线而不是背景块 —— 背景块在白底上会变成第二种
   「卡片」,与内容区的卡片抢注意力。 */
.phead-bar .tabs { display: flex; gap: 2px; }
.phead-bar .tab {
  padding: 8px 13px 9px; background: none; border: 0; cursor: pointer;
  border-bottom: 2px solid transparent; margin-bottom: -1px;
  font: 500 var(--t-base)/var(--lh-2) var(--f-sans); color: var(--c-text-2);
  white-space: nowrap;
}
.phead-bar .tab:hover { color: var(--c-ink); }
.phead-bar .tab[aria-selected="true"] {
  color: var(--c-primary-deep); border-bottom-color: var(--c-primary);
}
.phead-bar .tab:focus-visible { outline: 2px solid var(--c-primary); outline-offset: -2px; }
/* 作业区里的页面内容照旧留边距 —— 头是通宽的,内容不是。 */
.main.wide > .stack, .main.wide > .note { padding: 0 26px; }

/* 侧栏的管线子抽屉 —— 「全部管线」下面折叠出已注册的几条,
   点一条直接进它的作业区(与从列表页点进去是同一个动作)。
   **不是把管线铺回侧栏**:默认收起,而且不再展开各自的子页。 */
.item-row { display: flex; align-items: stretch; }
.item-row .item { flex: 1; min-width: 0; padding-left: 4px; }
.caret {
  flex: none; width: 22px; padding: 0; cursor: pointer;
  background: none; border: 0; border-left: 3px solid transparent;
  font: 400 var(--t-micro)/1 var(--f-sans); color: var(--c-text-4);
}
.caret:hover { color: var(--c-text-2); background: var(--c-surface); }
.caret:focus-visible { outline: 2px solid var(--c-primary); outline-offset: -2px; }
.item.sub { padding-left: 33px; }
.item.sub .l { display: flex; align-items: center; gap: 8px; min-width: 0; }
.item.sub .nm {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-weight: 400;
}
.item.sub .d {
  width: 5px; height: 5px; border-radius: 50%; flex: none;
  background: transparent; box-shadow: inset 0 0 0 1.5px var(--c-text-off);
}
.item.sub .d[data-on="1"] { background: var(--c-text-off); box-shadow: none; }

/* ══ 管线概览的四段 ══════════════════════════════════════════════════════
 *
 * **class 名带前缀。** 第一版用了 `.top` 与 `.body` —— 全局早就有同名规则
 * (顶栏、主体布局),于是步骤名被套上深色背景与 52px 固定高,整块塌成
 * 竖排字。CSS 里没有作用域,短名字迟早撞;撞了不报错,只是长得不对。
 *
 * 十步拉成一张平表时,读起来像十件互不相干的待办 —— 看不出
 * 「前一段是后一段的前提」。所以分段,并在左边留一条竖线把一段串起来。
 * 走完的那一段整体压暗:注意力该在还没走完的那一段上。 */
.phase { display: flex; gap: 13px; padding: 13px 0 3px; }
.phase + .phase { border-top: 1px solid var(--c-line-weak); }
.phase[data-done="1"] { opacity: .62; }
.phase .ph {
  flex: 0 0 190px; display: flex; flex-wrap: wrap; align-items: baseline; gap: 7px;
  align-content: flex-start;
}
/* 序号用**阿拉伯数字**。曾经用的是「一二三四」—— 这个圆里字号是 10px,
   而「四」在 10px 上是一团墨。等宽是给数字用的,汉字进等宽只会回退。 */
.phase .ph .n {
  font: 600 var(--t-aux)/18px var(--f-mono); color: var(--c-text-4);
  width: 18px; height: 18px; border-radius: 50%; text-align: center;
  background: var(--c-surface-2); flex: none;
}
.phase[data-done="1"] .ph .n { background: var(--c-primary-tint); color: var(--c-primary-deep); }
.phase .ph .nm { font: 600 var(--t-lead)/var(--lh-1) var(--f-sans); color: var(--c-ink); }
.phase .ph .ct {
  font: 500 var(--t-micro)/1.6 var(--f-mono); color: var(--c-amber);
  padding: 1px 6px; border-radius: 7px; background: var(--c-amber-wash);
}
.phase .ph .ct[data-ok="1"] { color: var(--c-primary-deep); background: var(--c-primary-wash); }
.phase .ph .ph-why {
  flex: 1 1 100%; font: 400 var(--t-micro)/var(--lh-3) var(--f-sans);
  color: var(--c-text-3);
}
.phase .ph .ph-stuck {
  flex: 1 1 100%; font: 400 var(--t-micro)/var(--lh-2) var(--f-sans);
  color: var(--c-amber);
}
/* 段里的步骤:左边一条竖线把它们串成一段 */
.phase .psteps {
  flex: 1; min-width: 0; border-left: 2px solid var(--c-line);
  padding-left: 15px;
}
.phase[data-done="1"] .psteps { border-left-color: var(--c-primary-soft); }
.phase .st {
  display: flex; align-items: flex-start; gap: 10px; padding: 6px 0;
}
.phase .st + .st { border-top: 1px solid var(--c-line-weak); }
.phase .st .mk { font: 600 var(--t-base)/1.5 var(--f-mono); flex: none; width: 14px; }
/* 完成色走主色 —— 这套配色里没有绿。曾经写的是 `var(--c-ok)`,而那个变量
   **从来没定义过**:未定义的 var() 会让整条声明作废,于是「✔ 已完成」
   与正文同色,唯一该一眼认出来的记号反而没有颜色。 */
.phase .st .mk[data-s="done"] { color: var(--c-primary-deep); }
.phase .st .mk[data-s="blocked"] { color: var(--c-amber); }
.phase .st .mk[data-s="unbuilt"] { color: var(--c-text-off); }
.phase .st .st-txt { flex: 1; min-width: 0; }
.phase .st .st-hdr { display: flex; align-items: center; gap: 8px; }

/* 四段进度条(全部管线那张表)—— 一段一格,不合成一个百分比。
   合成之后「30%」既可能是对齐做完了、也可能是四段各做了一点,
   而这两种的下一步完全不同。 */
.pbar { display: flex; gap: 3px; }
.pbar .seg {
  flex: 1; min-width: 0; text-align: center; padding: 2px 0;
  border-radius: var(--r-3); background: var(--c-surface-2);
  font: 500 var(--t-micro)/1.6 var(--f-mono); color: var(--c-text-3);
}
.pbar .seg[data-ok="1"] { background: var(--c-primary-wash); color: var(--c-primary-deep); }
/* 有「平台未建」步骤的那一段:斜纹底,表示它**走不满** ——
   画成普通的未完成格子,会让人以为是这条管线自己的问题。 */
.pbar .seg[data-stuck="1"] {
  color: var(--c-text-4);
  background: repeating-linear-gradient(-45deg,
    var(--c-surface-2) 0 4px, var(--c-surface) 4px 8px);
}

/* ══ 定义页:表单 ════════════════════════════════════════════════════════
 *
 * 上一版每个字段是「名字 + 说明」挤在一行,后面一个单行 `input` ——
 * 而任务定义那五件填的是**句子**。单行框里只看得见开头十几个字,
 * 人得靠左右拖动读自己刚写的东西。
 *
 * 现在一件一块:名字(base)、判据(aux,弱)、输入框。三行三级,
 * 眼睛一眼分得出哪个是要填的、哪个是提示。 */
.fld {
  width: 100%; padding: 8px 11px; background: var(--c-card);
  border: 1px solid var(--c-line); border-radius: var(--r-5); outline: none;
  font: 400 var(--t-base)/var(--lh-2) var(--f-sans); color: var(--c-ink);
}
.fld:focus { border-color: var(--c-primary); }
.fld::placeholder { color: var(--c-text-off); }
.fld.narrow { width: auto; flex: none; }
/* 多行框跟着内容长,但**给个上限** —— 不封顶的话一段长回答会把
   下面三块整个推出屏幕,人以为页面只有这一块。 */
.fld.ta { min-height: 58px; max-height: 190px; resize: vertical; }
.fld-row { margin-bottom: 11px; }
.fld-row > label { display: block; margin-bottom: 1px; }
.fld-row > .s { margin-bottom: 5px; }
.fld-acts { margin-top: 12px; display: flex; gap: 8px; }
/* 块内小标题:一块里第二件事的分界。没有它,「填五句话」与「填一组声明」
   看起来是同一件事的两半。 */
.fld-subh {
  margin: 16px 0 0; padding-top: 12px; border-top: 1px solid var(--c-line-weak);
  font: 600 var(--t-micro)/1.6 var(--f-mono); letter-spacing: .11em;
  color: var(--c-text-3);
}
.fld-form { margin-top: 10px; }
.fld-row2 { display: flex; gap: 8px; margin-bottom: 8px; }
.fld-row2.end { align-items: center; margin-bottom: 0; }
.fld-ck { width: 15px; height: 15px; accent-color: var(--c-primary); }

/* 四块共用的块头 */
.blk-h { align-items: flex-start; }
.blk-l { display: flex; align-items: center; gap: 9px; min-width: 0; }
.blk-r { display: flex; align-items: center; gap: 8px; flex: none; }
.blk-mk { font: 600 var(--t-lead)/1 var(--f-mono); color: var(--c-text-4); }
.blk-mk[data-s="done"] { color: var(--c-primary-deep); }
.blk-mk[data-s="blocked"] { color: var(--c-amber); }
.blk-why { margin: 2px 0 13px; }

/* ══ 定义页:起草入口 ═══════════════════════════════════════════════════
 *
 * 业主 2026-08-15:「最好里面会接入一些 Agent 的一些使用入口……通过每个人
 * 自己的 Claude Code……去对齐想法,然后提炼内容。」
 *
 * 做成**一条横条而不是弹窗**:弹窗会把它变成「一个功能」,而它其实是
 * 这一页的常规做法 —— 手上有材料就先让 Agent 过一遍再来填。
 * 默认收起,展开才占地方 —— 已经会用的人不该每次都翻过它。 */
.df-bar { border-color: var(--c-primary-soft); background: var(--c-primary-wash); }
.df-hd { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; }
.df-steps { margin-top: 13px; border-top: 1px solid var(--c-primary-soft); padding-top: 4px; }
.df-step { display: flex; gap: 11px; padding: 11px 0; }
.df-step + .df-step { border-top: 1px solid var(--c-primary-soft); }
.df-n {
  flex: none; width: 19px; height: 19px; border-radius: 50%;
  background: var(--c-card); color: var(--c-primary-deep);
  font: 600 var(--t-aux)/19px var(--f-mono); text-align: center;
}
.df-txt { flex: 1; min-width: 0; }
.df-txt > .m { margin-bottom: 3px; }
/* 命令行照抄用等宽,并且**允许换行** —— 截断的话人复制走的是半条命令。 */
.df-cmd {
  padding: 3px 8px; border-radius: var(--r-4); background: var(--c-card);
  border: 1px solid var(--c-primary-soft);
  font: 400 var(--t-aux)/1.6 var(--f-mono); color: var(--c-primary-deep);
  word-break: break-all;
}

/* ══ 「这一页的数从哪来」════════════════════════════════════════════════
 *
 * 去掉演示数据之后剩下的**不是一张空表**。空表等于什么都没说;
 * 这一块要说清:本该显示什么、读哪张表、现在什么状况、要有数据得先发生什么。
 *
 * 画得**安静**:它不是错误,是如实的现状。用页底灰而不是红,
 * 只有真的读不到时才亮红 —— 「没有」与「读不到」是两件事。 */
.nd { background: var(--c-surface); }
.nd-h {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 10px; padding-bottom: 9px; border-bottom: 1px solid var(--c-line);
}
.nd-row { display: flex; gap: 16px; padding: 11px 0; }
.nd-row + .nd-row { border-top: 1px solid var(--c-line-weak); }
.nd-l { flex: 0 0 232px; min-width: 0; }
.nd-r { flex: 1; min-width: 0; }
.nd-tag {
  display: inline-block; margin-bottom: 3px;
  padding: 1px 7px; border-radius: var(--r-4);
  font: 500 var(--t-micro)/1.6 var(--f-mono);
  background: var(--c-surface-2); color: var(--c-text-2);
}
.nd-tag[data-s="empty"] { background: var(--c-amber-wash); color: var(--c-amber); }
.nd-tag[data-s="ready"] { background: var(--c-primary-tint); color: var(--c-primary-deep); }
.nd-tag[data-s="unreadable"] { background: var(--c-danger-wash); color: var(--c-danger); }
/* 「要有数据得先发生什么」—— 这一行最有用,给它一条竖线拎出来。 */
.nd-need {
  margin-top: 4px; padding-left: 9px; color: var(--c-text-2);
  border-left: 2px solid var(--c-line-mid);
}
.nd-land { margin-top: 3px; color: var(--c-text-4); }

/* 环境角标:线上与本地要一眼分得开 —— 分不开的话,人会拿本地的
   截图当线上证据。判不出来时写「环境未知」,那也要显眼。 */
.chip-state[data-env="本地"] { color: var(--c-amber); border-color: var(--c-amber); }
.chip-state[data-env="环境未知"] { color: var(--c-danger); border-color: var(--c-danger); }
/* ── 数据资源:目录 + 工作区 ──────────────────────────────────────────────
   两列。左边是**选什么**,右边是**对它做什么**。

   左列 sticky 且自己滚:不这么做的话,21 个对象把整页撑到 1353px,
   而右列只有 522px —— 中间空出 800 多像素,页面还得往下滚才看得完目录
   (2026-08-15 量出来的)。 */
.dwork {
  display: grid; grid-template-columns: 268px minmax(0, 1fr);
  gap: 13px; align-items: start;
}
.dcat {
  position: sticky; top: 12px;
  display: flex; flex-direction: column; gap: 8px;
  max-height: calc(100vh - 96px);
  padding: 11px 0 6px;
}
.dcat > .hd, .dfind { padding: 0 12px; }
/* 仓库地址:**一行,截断,完整值挂 title**。
   原来是 `word-break: break-all`,`bq://…ppi_foundation` 被从中间劈成两行
   (「ppi_foundati / on」)—— 而完整地址在选中表之后的表头里还会再出现一次。

   **不带祖先限定**:带的话它挪到别的容器里就一条样式都不生效,
   而 CSS 不会为此报错(守卫钉着这一条)。带前缀就够防重名了。 */
.dloc {
  font: 400 var(--t-micro)/1.55 var(--f-mono); color: var(--c-text-4);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.dlist { overflow-y: auto; overflow-x: hidden; flex: 1; min-height: 0; }

/* 组标题:一行说清「这类有几个」。点它开合 —— **计数一直在**,
   收起来的东西不会看起来像不存在。 */
.dgrp {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  width: 100%; cursor: pointer; padding: 7px 12px 5px; margin-top: 2px;
  background: none; border: 0; text-align: left;
  font: 600 var(--t-micro)/1.4 var(--f-mono); letter-spacing: .12em;
  color: var(--c-text-4);
}
.dgrp:hover { color: var(--c-text-2); }
.dgrp:focus-visible { outline: 2px solid var(--c-primary); outline-offset: -2px; }
.dgrp .n { font-weight: 400; letter-spacing: 0; }

/* 目录行:**grid 而不是 flex**。flex 下长表名会把行数那一格挤到溢出,
   实测三个快照名把「2,342,909」截成「2,342,」—— 数字被截掉一半比不显示更坏。
   grid 两列固定,名字自己省略号,数字永远完整。 */
.drow {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 9px;
  align-items: baseline; width: 100%; text-align: left; cursor: pointer;
  padding: 6px 12px; background: transparent; border: 0;
  border-left: 3px solid transparent;
  font: 400 var(--t-base)/1.5 var(--f-sans); color: var(--c-text);
}
.drow:hover { background: var(--c-surface); }
.drow[aria-current="page"] {
  background: var(--c-primary-wash); color: var(--c-primary-deep);
  border-left-color: var(--c-primary); font-weight: 500;
}
.drow:focus-visible { outline: 2px solid var(--c-primary); outline-offset: -2px; }
.drow .nm { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.drow .n {
  font: 400 var(--t-aux)/1.5 var(--f-mono); color: var(--c-text-4);
  white-space: nowrap;
}

/* 工作区表头:表名 + 类型 + 规模 + 位置,**一行说完**。
   原来这三样散在页副标题、卡片标题、卡片正文三处。 */
.dhead {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  padding: 12px 15px; border-bottom: 1px solid var(--c-line-weak);
}
.dhead .nm { font: 600 var(--t-lead)/1.4 var(--f-mono); color: var(--c-ink); }
.dmeta { font: 400 var(--t-aux)/1.5 var(--f-sans); color: var(--c-text-3); }
/* 表头里的地址推到最右;字体等属性继承上面那条不带祖先的 `.dloc`,
   这里**只加位置**,不重复一遍字体。 */
.dhead .dloc { margin-left: auto; }

/* 空态:居中,占住工作区 —— 顶在左上角的一张小卡片看起来像没加载完。 */
.dempty {
  display: flex; align-items: center; justify-content: center;
  min-height: 240px; padding: 28px;
  font: 400 var(--t-base)/1.7 var(--f-sans); color: var(--c-text-3);
  text-align: center;
}
/* 查询那一行操作栏:与上面的条件区分开。 */
.dbar {
  display: flex; align-items: center; gap: 9px; flex-wrap: wrap;
  margin-top: 11px; padding-top: 11px;
  border-top: 1px solid var(--c-line-weak);
}
