/*!************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\
  !*** css ./node_modules/.pnpm/next@15.5.25_@playwright+test@1.63.0_@types+node@22.20.1_react-dom@19.2.8_react@19.2.8__react@19.2.8/node_modules/next/dist/build/webpack/loaders/css-loader/src/index.js??ruleSet[1].rules[14].oneOf[10].use[2]!./node_modules/.pnpm/next@15.5.25_@playwright+test@1.63.0_@types+node@22.20.1_react-dom@19.2.8_react@19.2.8__react@19.2.8/node_modules/next/dist/build/webpack/loaders/postcss-loader/src/index.js??ruleSet[1].rules[14].oneOf[10].use[3]!./app/tokens.css ***!
  \************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
/* ============================================================
 * 来源:frontend/app/tokens.css(Agentta 设计 token,UI 规范 v1,
 * Jacob 定案 2026-08-16)—— 逐字复制,不改一个值。
 *
 * devcenter/ 是独立 Next 应用(D3 定案:与产品 frontend/ 共享 tokens/
 * 视觉语言,但单独构建、只部署在厂商侧),两边没有共同的 workspace 包可
 * import,复制 + 本文件头注明来源是刀5 M1 报告里交代过的选择。frontend/
 * 那份改了,这份要跟着人工同步(两处都没有自动化校验,drift 靠评审)。
 *
 * 铁律不变:组件只消费本文件的 token,禁止裸 hex/rgb。
 * 切换机制:<html data-mode="light|dark" data-accent="...">;M1 只用默认
 * light + indigo(未接暗色/换色开关到 UI——不是本刀范围),token 本身
 * 原样保留以便后续刀直接接线,不用再复制一遍。
 * ============================================================ */

/* ---- 基础:light(默认) ---- */
:root {
  --bg: #f4f5f8;
  --surface: #ffffff;
  --nav: #ffffff;
  --ink: #23283a;
  --soft: #5f6577;
  --line: #dfe2ea;
  --line-faint: #eceef3; /* 表格行线:比框线淡一档;表头线用 --line 1.5px */
  --inputbg: #f4f5f8;
  --codeblk: #171a21;    /* 代码块恒深底(两种模式各自微调) */
  --shadow: 0 1px 3px rgb(0 0 0 / 5%);
  /* 语义色:通过/警示/危险 —— 与主题色分离,切主题色不动 */
  --ok: #0d8a5f;   --ok-soft: #e2f3ec;
  --warn: #b0762a; --warn-soft: #f7ecdd;
  --bad: #b4443c;  --bad-soft: #f9e9e7;
  /* 主题色默认 = indigo(C) */
  --acc: #4653c8; --acc-soft: #e8eafb; --on-acc: #ffffff;
}

/* ---- 基础:dark ---- */
:root[data-mode="dark"] {
  --bg: #14161f;
  --surface: #1c1f2b;
  --nav: #181b25;
  --ink: #e4e6ef;
  --soft: #969db3;
  --line: #2c3040;
  --line-faint: #242836;
  --inputbg: #14161f;
  --codeblk: #101218;
  --shadow: 0 1px 3px rgb(0 0 0 / 30%);
  --ok: #3fbf8c;   --ok-soft: #123326;
  --warn: #d9a05b; --warn-soft: #33291a;
  --bad: #e08078;  --bad-soft: #3a2422;
}

/* ---- 主题色色板(外观选择器的六个圆点;恒用 light 值以便识别) ---- */
:root {
  --swatch-indigo: #4653c8;
  --swatch-daybreak: #1677ff;
  --swatch-graphite: #171717;
  --swatch-teal: #146b5d;
  --swatch-ice: #0284c7;
  --swatch-violet: #7c3aed;
}

/* ---- 主题色六选(用户级偏好;暗色变体独立推导,非反色) ---- */
:root[data-accent="indigo"]   { --acc: #4653c8; --acc-soft: #e8eafb; --on-acc: #fff; }
:root[data-mode="dark"][data-accent="indigo"]   { --acc: #8b96f8; --acc-soft: #232848; --on-acc: #0f1115; }
:root[data-accent="daybreak"] { --acc: #1677ff; --acc-soft: #e6f4ff; --on-acc: #fff; }
:root[data-mode="dark"][data-accent="daybreak"] { --acc: #4096ff; --acc-soft: #111d2c; --on-acc: #0f1115; }
:root[data-accent="graphite"] { --acc: #171717; --acc-soft: #ececec; --on-acc: #fff; }
:root[data-mode="dark"][data-accent="graphite"] { --acc: #e5e5e5; --acc-soft: #2e2e2e; --on-acc: #111; }
:root[data-accent="teal"]     { --acc: #146b5d; --acc-soft: #e3efec; --on-acc: #fff; }
:root[data-mode="dark"][data-accent="teal"]     { --acc: #34b39a; --acc-soft: #12332c; --on-acc: #0f1115; }
:root[data-accent="ice"]      { --acc: #0284c7; --acc-soft: #e0f2fe; --on-acc: #fff; }
:root[data-mode="dark"][data-accent="ice"]      { --acc: #38bdf8; --acc-soft: #12303f; --on-acc: #06222e; }
:root[data-accent="violet"]   { --acc: #7c3aed; --acc-soft: #f1eafd; --on-acc: #fff; }
:root[data-mode="dark"][data-accent="violet"]   { --acc: #a78bfa; --acc-soft: #2a2140; --on-acc: #171226; }

/* ---- 固定色(同步自 frontend/app/tokens.css 21b 那一节,只取 Dev Center 目前用到的
 * 一个;其余 --paper/--on-solid/--overlay-* 这边还没有消费方,按"用到再同步"。
 * - --codeblk-ink:代码块前景色,恒配 --codeblk(恒深底)使用,和它一样刻意不随
 *   主题切换(add-app-registration 刀12 的取回命令块 .cmdBlock 用它——之前拿
 *   --surface 当前景,dark 模式下 surface 也是深色,字会消失)。
 * ---- */
:root {
  --codeblk-ink: #dbe1ee;
}

/*!*************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\
  !*** css ./node_modules/.pnpm/next@15.5.25_@playwright+test@1.63.0_@types+node@22.20.1_react-dom@19.2.8_react@19.2.8__react@19.2.8/node_modules/next/dist/build/webpack/loaders/css-loader/src/index.js??ruleSet[1].rules[14].oneOf[10].use[2]!./node_modules/.pnpm/next@15.5.25_@playwright+test@1.63.0_@types+node@22.20.1_react-dom@19.2.8_react@19.2.8__react@19.2.8/node_modules/next/dist/build/webpack/loaders/postcss-loader/src/index.js??ruleSet[1].rules[14].oneOf[10].use[3]!./app/globals.css ***!
  \*************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
/* Dev Center 外壳样式——token 来自 ./tokens.css(唯一色源,与 frontend/ 同源
   见该文件头注释)。布局借鉴 frontend/app/globals.css 的 .shell/.nav/.mobileTabs
   纪律(同一视觉语言),但 Dev Center 页面形状不同(表格 + 三栏工作台为主,
   没有聊天流),没有逐字照抄整份文件。 */

* { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: -apple-system, "PingFang SC", "Hiragino Sans GB", "Noto Sans CJK SC", sans-serif;
  font-size: 14px;
  line-height: 1.6;
}
a { color: inherit; text-decoration: none; }
button { font: inherit; cursor: pointer; }
input, textarea, select { font: inherit; }

input:where(:not([type="checkbox"]):not([type="radio"]):not([type="file"])),
:where(select),
:where(textarea) {
  background: var(--inputbg);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 6px 10px;
}
:where(input, select, textarea):focus-visible { outline: 2px solid var(--acc); }

/* ---- shell ---- */
.shell { display: grid; grid-template-columns: 200px 1fr; grid-template-rows: 48px 1fr; height: 100vh; }
.topbar { grid-column: 1 / 3; display: flex; align-items: center; gap: 14px; padding: 0 16px;
  background: var(--surface); border-bottom: 1px solid var(--line); }
.brand { font-weight: 700; letter-spacing: .02em; }
.brand small { font-weight: 400; color: var(--soft); margin-left: 6px; font-size: 11.5px; }
.hamburger { display: none; background: none; border: none; color: var(--ink); padding: 4px; }
.topbarRight { margin-left: auto; display: flex; align-items: center; gap: 10px; }
.roleTag { font-size: 10.5px; color: var(--acc); background: var(--acc-soft); border-radius: 99px;
  padding: 1px 9px; font-weight: 600; }
.userName { font-size: 13px; color: var(--soft); }
.logoutBtn { font-size: 12.5px; border: 1px solid var(--line); background: var(--surface);
  border-radius: 6px; padding: 4px 11px; color: var(--ink); }
.logoutBtn:hover { border-color: var(--bad); color: var(--bad); }

/* grid-column/row 显式指定,不靠子元素 DOM 顺序做隐式网格自动布局——
   .navScrim 曾经只在移动端媒体查询里声明 display:none,桌面宽度下这条
   规则不存在(div 默认 display:block),它就会被自动布局算法塞进
   row2/col1(挤开 .nav 到 col2、把 .main 挤到隐式 row3),整个桌面布局
   在真机截图核验时才现形(1440px 视口下侧栏内容跑到主区域、主内容整个
   掉到下面)。现在 .navScrim 默认 display:none(下方规则)双保险,这里再
   显式钉住 .nav/.main 的网格位置,以后 .shell 底下加别的兄弟元素不会
   重演这个坑。 */
.navScrim { display: none; }
.nav { grid-column: 1 / 2; grid-row: 2 / 3; border-right: 1px solid var(--line); background: var(--surface); padding: 10px 8px; overflow-y: auto; }
.nav .sect { font-size: 10.5px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--soft); margin: 14px 8px 4px; }
.nav .sect:first-child { margin-top: 2px; }
.navItem { display: flex; gap: 8px; align-items: center; padding: 7px 9px;
  border-radius: 6px; color: var(--ink); font-size: 13.5px; }
.navItem:hover { background: var(--bg); }
.navItem.on { background: var(--acc-soft); color: var(--acc); font-weight: 600; }
.navItem .dim { margin-left: auto; font-size: 10px; color: var(--soft); border: 1px solid var(--line);
  border-radius: 999px; padding: 0 6px; }
/* 顶栏收件箱未处理数角标(刀5 M6)——复用 .chip/.chip-bad 的视觉语言,只加
   margin-left:auto 把它推到 navItem 这一行的最右侧(与 .dim 同一个位置,
   两者互斥:admin 看角标,fde 看 "admin" 提示,见 Shell.tsx navTrailer())。 */
.navBadge { margin-left: auto; }
/* 底部"运维手册"条目——刀5 M9 时它不是路由链接(没有对应页面/不外链),
   用 default 光标而不是 .navItem 继承来的 pointer/hover 高亮。刀5 M11 补上
   了 /help/ops 页面(见 Shell.tsx 该处注释)之后它是一个真的可点击 Link,
   只保留自己的纵向两行布局,光标/hover 高亮都改回继承 .navItem 的默认值。 */
.navHelp { flex-direction: column; align-items: flex-start; gap: 2px; }
.navHelp .dimNote { font-size: 10.5px; word-break: break-all; }

/* overflow-x:hidden 是硬保证,不是靠猜——很宽的表格/日志内容应该只让
   .tableWrap/.diffBox 这类容器自己出现内部横向滚动条(它们各自已经声明了
   overflow-x:auto/overflow:auto),不应该把 .main 这层 grid track 撑宽,
   见 docs/development/dev-center-design.md §十七"一个真机核验过程中排查过、
   确认不是 bug 的疑点"与"缺口清单"第4条——真机核验已经用
   document.documentElement.scrollWidth 对比 window.innerWidth 确认过页面
   本身不会溢出,这里额外加这条规则把"外层页面永不出现水平滚动"从"目前
   观测到的浏览器行为"升级成"CSS 层面的硬约束",不依赖 grid 自动最小尺寸
   这类容易被未来改动打破的隐式行为。 */
.main { grid-column: 2 / 3; grid-row: 2 / 3; overflow-y: auto; overflow-x: hidden; padding: 22px 26px; }
.pageHead { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; flex-wrap: wrap; }
.pageTitle { font-size: 18px; font-weight: 700; margin: 0; }
.pageSub { color: var(--soft); font-size: 12.5px; }
.pageActions { margin-left: auto; display: flex; gap: 8px; }

/* ---- buttons ---- */
.btn { border: 1px solid var(--line); background: var(--surface); color: var(--ink);
  border-radius: 7px; padding: 7px 16px; font-size: 13px; font-weight: 600; }
.btn:hover { border-color: var(--acc); color: var(--acc); }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btnPrimary { border: none; background: var(--acc); color: var(--on-acc); border-radius: 7px;
  padding: 7px 16px; font-size: 13px; font-weight: 600; }
.btnPrimary:disabled { opacity: .55; cursor: not-allowed; }
.btnDanger { border: 1px solid var(--bad); background: var(--surface); color: var(--bad);
  border-radius: 7px; padding: 7px 16px; font-size: 13px; font-weight: 600; }
.btnDanger:hover { background: var(--bad-soft); }
.miniBtn { font-size: 12px; border: 1px solid var(--line); background: var(--surface);
  border-radius: 6px; padding: 3px 11px; color: var(--ink); }
.miniBtn:hover { border-color: var(--acc); color: var(--acc); }
.miniBtn:disabled { opacity: .5; cursor: not-allowed; }
.linkBtn { background: none; border: none; color: var(--acc); font-size: 12.5px; padding: 0; }

/* ---- table ---- */
.tableWrap { overflow-x: auto; border: 1px solid var(--line); border-radius: 10px; background: var(--surface); }
table.data { border-collapse: collapse; width: 100%; font-size: 13px; min-width: 560px; }
table.data th { text-align: left; font-size: 11px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--soft); padding: 9px 12px; border-bottom: 1.5px solid var(--line); white-space: nowrap; }
table.data td { padding: 8px 12px; border-bottom: 1px solid var(--line-faint); vertical-align: top; }
table.data tr:last-child td { border-bottom: none; }
table.data tr:hover td { background: var(--bg); }
/* 收件箱 drift.report 行按 checked/ok 上色(刀5 M6,见 lib/format.ts
   driftRowTone())——hover 时让位给既有的 .data tr:hover 高亮,只是失去这次
   悬停期间的色调,不是 bug。 */
.rowDriftOk td { background: var(--ok-soft); }
.rowDriftWarn td { background: var(--warn-soft); }
.rowDriftBad td { background: var(--bad-soft); }
/* 刀5 M7:重试(retry)成功后高亮新产生的那一行 release(见 releases/page.tsx
   highlightRelease)——没有单独的 release 详情路由,用这个代替任务原文
   "router.push 到新 release 行"字面动作(见该文件顶部注释里的说明)。 */
.rowHighlight td { background: var(--acc-soft); }

/* ---- chips / status ---- */
.chip { display: inline-flex; align-items: center; gap: 4px; border-radius: 99px; padding: 2px 10px;
  font-size: 11px; font-weight: 600; background: var(--bg); color: var(--soft); border: 1px solid var(--line-faint); white-space: nowrap; }
.chip-ok { background: var(--ok-soft); color: var(--ok); border-color: transparent; }
.chip-warn { background: var(--warn-soft); color: var(--warn); border-color: transparent; }
.chip-bad { background: var(--bad-soft); color: var(--bad); border-color: transparent; }
.chip-acc { background: var(--acc-soft); color: var(--acc); border-color: transparent; }
/* add-model-profiles 网关三态里的 absent(未写过凭证)——比裸灰 .chip(unknown
   用)更"淡出",只降低不透明度,不改变颜色语义,见 lib/format.ts gatewayStateChip
   头注释("runner 问不到"是 unknown,不是 absent,两者视觉上要分得开)。 */
.chip-dim { opacity: .55; }
.mono { font-family: ui-monospace, Menlo, monospace; font-size: 12px; }
.dimNote { color: var(--soft); font-size: 12.5px; }
.cardTitle { font-size: 14px; font-weight: 700; margin: 18px 0 8px; }
.glob { display: inline-block; font-family: ui-monospace, Menlo, monospace; font-size: 11px;
  background: var(--bg); border: 1px solid var(--line-faint); border-radius: 5px; padding: 1px 6px;
  margin: 1px 3px 1px 0; }

/* ---- forms ---- */
.formCard { background: var(--surface); border: 1px solid var(--line); border-radius: 10px;
  padding: 16px 18px; margin: 12px 0 18px; max-width: 640px; }
.formGrid { display: grid; grid-template-columns: 1fr 1fr; grid-gap: 12px 14px; gap: 12px 14px; }
.field { display: flex; flex-direction: column; gap: 4px; font-size: 12.5px; color: var(--soft); }
.field.full { grid-column: 1 / -1; }
.field input, .field select, .field textarea { color: var(--ink); }
.formActions { display: flex; gap: 8px; margin-top: 14px; align-items: center; }
.formNote { font-size: 12px; color: var(--soft); }
.err { background: var(--bad-soft); color: var(--bad); border-radius: 8px; padding: 9px 13px; font-size: 13px; }
.ok { background: var(--ok-soft); color: var(--ok); border-radius: 8px; padding: 9px 13px; font-size: 13px; }
.empty { border: 1px dashed var(--line); border-radius: 10px; padding: 20px;
  color: var(--soft); background: var(--surface); font-size: 13px; text-align: center; }

/* ---- toast ---- */
.toastStack { position: fixed; right: 16px; bottom: 16px; display: flex; flex-direction: column;
  gap: 8px; z-index: 40; max-width: min(360px, 90vw); }
.toast { background: var(--ink); color: var(--surface); border-radius: 8px; padding: 9px 14px;
  font-size: 12.5px; box-shadow: 0 6px 20px rgb(0 0 0 / 18%); }
.toast.toastErr { background: var(--bad); }
.toast.toastOk { background: var(--ok); }

/* ---- login ---- */
.loginWrap { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 20px; }
.loginCard { background: var(--surface); border: 1px solid var(--line); border-radius: 12px;
  padding: 32px 30px; width: 340px; max-width: 100%; box-shadow: 0 8px 30px rgb(0 0 0 / 8%); }
.loginCard h1 { margin: 0 0 4px; font-size: 22px; }
.loginCard p { margin: 0 0 18px; color: var(--soft); font-size: 13px; }
.loginCard label { display: block; font-size: 12.5px; color: var(--soft); margin: 12px 0 4px; }
.loginCard input { width: 100%; border: 1px solid var(--line); border-radius: 7px;
  padding: 8px 11px; background: var(--bg); color: var(--ink); }
.loginCard input:focus { outline: 2px solid var(--acc); border-color: transparent; }
.loginBtn { width: 100%; margin-top: 18px; background: var(--acc); color: var(--on-acc);
  border: none; border-radius: 7px; padding: 9px 0; font-weight: 600; }
.loginBtn:disabled { opacity: .6; }
.loginHint { margin-top: 16px; font-size: 11.5px; color: var(--soft); line-height: 1.6; }

/* ---- receipt table(11 门) ---- */
.gateGrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); grid-gap: 8px; gap: 8px; }
.gateCell { border: 1px solid var(--line-faint); border-radius: 8px; padding: 8px 10px;
  display: flex; align-items: center; justify-content: space-between; gap: 8px; font-size: 12.5px; background: var(--bg); }
.gateCell.pass { border-color: transparent; background: var(--ok-soft); color: var(--ok); }
.gateCell.fail { border-color: transparent; background: var(--bad-soft); color: var(--bad); }
.gateName { font-family: ui-monospace, Menlo, monospace; font-size: 11.5px; }
.tagSoft { font-size: 10px; color: var(--soft); border: 1px solid var(--line); border-radius: 99px;
  padding: 1px 6px; margin-left: 6px; }
/* 部署回执 steps 里两类需要醒目区分的失败(刀5 M7,见 _ui/DeploySteps.tsx
   isPlaneRestartStep/isPlatformDriftFailure)——放在 .gateCell.fail 规则之后
   (同一特异性 (0,2,0),源码顺序决定覆盖),不然会被更早声明的 .fail 背景色
   盖掉。plane-restart 用 warn(黄,"这是运维事件,不是这次部署真的错了")；
   platformDrift 仍保留 bad(红,是真的失败)但加一圈醒目描边区分于普通失败。 */
.gateCell.planeRestart { outline: 2px solid var(--warn); background: var(--warn-soft); color: var(--warn); }
.gateCell.platformDrift { outline: 2px solid var(--bad); }
.stepCallout { margin-top: 6px; font-size: 11.5px; font-weight: 600; white-space: normal; }
.gateCell.planeRestart .stepCallout { color: var(--warn); }
.gateCell.platformDrift .stepCallout { color: var(--bad); }

/* ---- session workbench: 3 columns(左事件流 / 中输入 / 右 diff+操作) ---- */
.wbGrid { display: grid; grid-template-columns: minmax(260px, 1.3fr) minmax(220px, .9fr) minmax(260px, 1.1fr);
  grid-gap: 14px;
  gap: 14px; height: calc(100vh - 48px - 44px); }
.wbCol { display: flex; flex-direction: column; min-height: 0; background: var(--surface);
  border: 1px solid var(--line); border-radius: 10px; overflow: hidden; }
.wbColHead { padding: 8px 12px; border-bottom: 1px solid var(--line-faint); font-size: 12.5px;
  font-weight: 700; display: flex; align-items: center; gap: 8px; }
.wbEvents { flex: 1 1; overflow-y: auto; padding: 10px 12px; display: flex; flex-direction: column; gap: 8px; }
.evtCard { border: 1px solid var(--line-faint); border-radius: 8px; padding: 7px 10px; font-size: 12.5px; }
.evtCard.evtUser { background: var(--acc-soft); border-color: transparent; }
.evtCard.evtErr { background: var(--bad-soft); border-color: transparent; }
.evtType { font-size: 10.5px; color: var(--soft); text-transform: uppercase; letter-spacing: .04em;
  margin-bottom: 3px; display: flex; gap: 6px; align-items: center; }
.evtBody { white-space: pre-wrap; word-break: break-word; }
.evtTool { font-family: ui-monospace, Menlo, monospace; font-size: 11.5px; color: var(--soft);
  background: var(--bg); border-radius: 6px; padding: 4px 8px; margin-top: 4px; overflow-x: auto; }
.sendRow { display: flex; gap: 8px; padding: 10px 12px; border-top: 1px solid var(--line); }
.sendInput { flex: 1 1; border: 1px solid var(--line); border-radius: 8px; padding: 8px 11px;
  background: var(--bg); color: var(--ink); resize: none; }
.diffBox { flex: 1 1; overflow: auto; padding: 10px 12px; font-family: ui-monospace, Menlo, monospace;
  font-size: 11.5px; white-space: pre-wrap; word-break: break-word; }
.diffAdd { background: var(--ok-soft); }
.diffDel { background: var(--bad-soft); }
.wbActions { display: flex; gap: 8px; padding: 10px 12px; border-top: 1px solid var(--line); flex-wrap: wrap; }
.wbTabs { display: none; }

/* ---- mobile (断点 768) ---- */
@media (max-width: 768px) {
  .shell { grid-template-columns: 1fr; }
  .hamburger { display: flex; align-items: center; }
  .nav { position: fixed; left: 0; top: 48px; bottom: 0; width: min(260px, 82vw); z-index: 25;
    transform: translateX(-100%); transition: transform .15s ease; box-shadow: 4px 0 18px rgb(0 0 0 / 12%); }
  .nav.navOpen { transform: translateX(0); }
  .navScrim { display: none; position: fixed; inset: 48px 0 0 0; background: rgb(0 0 0 / 30%); z-index: 24; }
  .navScrim.navScrimOn { display: block; }
  .main { padding: 14px 14px 24px; }
  .userName { display: none; }
  .formGrid { grid-template-columns: 1fr; }
  .tableWrap table.data { min-width: 0; }
  table.data thead { display: none; }
  table.data tr { display: block; border-bottom: 1px solid var(--line); padding: 8px 0; }
  table.data tr:hover td { background: none; }
  table.data td { display: flex; justify-content: space-between; gap: 10px; border: none; padding: 3px 4px; text-align: right; }
  table.data td::before { content: attr(data-label); color: var(--soft); font-size: 11px; text-align: left; }
  .wbGrid { display: block; height: auto; }
  .wbCol { display: none; margin-bottom: 12px; height: 64vh; }
  .wbCol.wbColOn { display: flex; }
  .wbTabs { display: flex; gap: 4px; margin-bottom: 10px; border-bottom: 1px solid var(--line); }
  .wbTabBtn { flex: 1 1; background: none; border: none; padding: 8px 0; font-size: 12.5px;
    color: var(--soft); border-bottom: 2px solid transparent; }
  .wbTabBtn.on { color: var(--acc); border-bottom-color: var(--acc); font-weight: 600; }
}

/* ---- 租户(add-tenant-root 刀10) ---- */
/* 顶栏「租户视角」下拉——与 .roleTag/.userName 同一行,窄一点的 select。 */
.tenantView { display: flex; align-items: center; gap: 6px; }
.tenantView select { padding: 3px 8px; font-size: 12.5px; max-width: 180px; }
.tenantViewNote { display: flex; align-items: center; gap: 6px; margin: -6px 0 12px; flex-wrap: wrap; }
.tabular { font-feature-settings: "tnum"; font-variant-numeric: tabular-nums; }
/* 六盏灯的圆点:ok 绿 / fail 红 / skipped 灰 / unknown 描边——语义色只来自
   tokens.css(--ok/--bad/--soft/--line),不随主题色变;列表页缩略与详情页
   明细共用同一组 class(lib/tenants.ts lampClass())。 */
.lampRow { display: inline-flex; gap: 5px; align-items: center; }
.lamp { display: inline-block; width: 10px; height: 10px; border-radius: 50%;
  border: 1.5px solid transparent; flex: none; }
.lamp-ok { background: var(--ok); }
.lamp-fail { background: var(--bad); }
.lamp-skipped { background: var(--soft); opacity: .55; }
.lamp-unknown { background: transparent; border-color: var(--line); }
/* 详情页:四块环境卡 / 六盏灯明细 / 六步向导 共用的卡片网格。 */
.cardGrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); grid-gap: 12px; gap: 12px; }
.card { background: var(--surface); border: 1px solid var(--line); border-radius: 10px; padding: 12px 14px; }
.card .cardTitle { margin: 0 0 8px; display: flex; align-items: center; gap: 8px; }
.card .cardTitle .lampRow { margin-left: auto; }
.cardBody { font-size: 13px; }
.cardBody .mono { word-break: break-all; }
.cardActions { display: flex; gap: 6px; margin-top: 10px; flex-wrap: wrap; align-items: center; }
.probeMsg { margin-top: 6px; font-size: 12.5px; white-space: pre-wrap; word-break: break-word; }
.probeMsg.probeFail { color: var(--bad); }
.probeMsg.probeOk { color: var(--ok); }
/* 向导:一列有序步骤,序号圆圈按状态上色。 */
.wizard { display: flex; flex-direction: column; gap: 8px; }
.wizStep { display: grid; grid-template-columns: 28px 1fr; grid-gap: 10px; gap: 10px; align-items: start;
  background: var(--surface); border: 1px solid var(--line); border-radius: 10px; padding: 10px 12px; }
.wizStep.wizOn { border-color: var(--acc); box-shadow: 0 0 0 2px var(--acc-soft); }
.wizNo { width: 26px; height: 26px; border-radius: 50%; display: flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 700; border: 1.5px solid var(--line); color: var(--soft); background: var(--bg); }
.wizNo.done { background: var(--ok-soft); color: var(--ok); border-color: transparent; }
.wizNo.skipped { background: var(--bg); color: var(--soft); border-color: transparent; opacity: .7; }
.wizNo.pending { background: var(--warn-soft); color: var(--warn); border-color: transparent; }
.wizHead { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.wizHead strong { font-size: 13.5px; }
.wizMeta { font-size: 12px; color: var(--soft); margin-top: 2px; }
.wizHint { font-size: 12.5px; margin-top: 4px; }
.wizHint.missing { color: var(--warn); }
.wizForm { display: flex; gap: 6px; margin-top: 8px; flex-wrap: wrap; align-items: center; }
.wizForm input { flex: 1 1; min-width: 180px; }
/* 新租户落地的向导横幅。 */
.banner { background: var(--acc-soft); color: var(--acc); border-radius: 8px; padding: 9px 13px;
  font-size: 13px; margin-bottom: 14px; }
/* 「无权访问」壳(add-project-members 刀11)——复用工作台 21a access-denied 的
   形状(图标 + 标题 + 原因 + 下一步),不是 .empty 那种一句话虚线框。 */
.accessDenied { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 6px;
  padding: 40px 20px; background: var(--surface); border: 1px solid var(--line); border-radius: 12px; max-width: 560px; }
.accessDenied .icon { color: var(--soft); }
.accessDenied h2 { margin: 6px 0 0; font-size: 17px; }
.accessDenied p { margin: 0; color: var(--soft); font-size: 13px; }
/* 成员区(add-project-members 刀11):详情页里的小表 + 加人表单一行。 */
.memberAdd { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin: 10px 0; }
.memberAdd select { min-width: 200px; }
@media (max-width: 768px) {
  .tenantView .dimNote { display: none; }
  .tenantView select { max-width: 120px; }
}

/* ---- 应用注册(add-app-registration 刀12) ---- */
/* 三步向导:顶部一行步骤指示(序号圆圈复用 .wizNo 的视觉),下面是当前步的表单
   卡片。宽度放开到 900px——第 2 步的能力/角色表格比 .formCard 的 640 宽。 */
.appWizard { background: var(--surface); border: 1px solid var(--line); border-radius: 10px;
  padding: 16px 18px; margin: 12px 0 18px; max-width: 900px; }
.appSteps { display: flex; gap: 14px; align-items: center; flex-wrap: wrap; margin-bottom: 14px;
  padding-bottom: 12px; border-bottom: 1px solid var(--line-faint); }
.appStep { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--soft); }
.appStep.on { color: var(--ink); font-weight: 600; }
.appStep .wizNo.on { background: var(--acc-soft); color: var(--acc); border-color: transparent; }
.appStepArrow { color: var(--line); }
/* key 校验反馈:一行小字跟在输入框下面,三态(检查中 / 可用 / 已存在或非法)。 */
.keyCheck { font-size: 12px; margin-top: 2px; min-height: 18px; }
.keyCheck.ok { color: var(--ok); }
.keyCheck.bad { color: var(--bad); }
/* 第 2 步:能力 / 角色两张小表 + 授权三元组一行三个下拉。 */
.declTable { width: 100%; border-collapse: collapse; font-size: 13px; }
.declTable th { text-align: left; font-size: 11px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--soft); padding: 6px 8px; border-bottom: 1.5px solid var(--line); white-space: nowrap; }
.declTable td { padding: 5px 8px; border-bottom: 1px solid var(--line-faint); vertical-align: top; }
.declTable tr:last-child td { border-bottom: none; }
.declTable input, .declTable select { width: 100%; min-width: 0; }
.declTable input[type="checkbox"] { width: auto; }
.declTable .rowBtn { white-space: nowrap; width: 1%; }
.grantRow { display: grid; grid-template-columns: 1fr 90px 1fr auto; grid-gap: 6px; gap: 6px; align-items: center; margin-bottom: 4px; }
.roleBlock { border: 1px solid var(--line-faint); border-radius: 8px; padding: 10px 12px; margin-bottom: 8px; background: var(--bg); }
.roleHead { display: grid; grid-template-columns: 1fr 1fr auto; grid-gap: 8px; gap: 8px; align-items: center; margin-bottom: 8px; }
.roleGrantsTitle { font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: var(--soft); margin: 6px 0 4px; }
/* 敏感字段芯片输入:芯片 + 一个裸输入(回车 / 逗号加芯片,IME 期间的回车不算)。 */
.chipInput { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; background: var(--inputbg);
  border: 1px solid var(--line); border-radius: 6px; padding: 4px 8px; }
.chipInput input { border: none; background: transparent; padding: 3px 4px; flex: 1 1; min-width: 140px; }
.chipInput input:focus-visible { outline: none; }
.chipInput .chip button { background: none; border: none; color: inherit; padding: 0 0 0 2px; font-size: 12px; line-height: 1; }
.toggleRow { display: flex; gap: 18px; flex-wrap: wrap; align-items: center; }
.toggleRow label { display: flex; gap: 6px; align-items: center; font-size: 13px; color: var(--ink); }
.declGroup { margin-top: 14px; }
.declGroup .cardTitle { margin: 0 0 6px; font-size: 13px; }
/* 第 3 步 / 详情页:文件树(目录粗体,文件带字节数右对齐),一律等宽。 */
.fileTree { font-family: ui-monospace, Menlo, monospace; font-size: 12px; background: var(--bg);
  border: 1px solid var(--line-faint); border-radius: 8px; padding: 10px 12px; overflow-x: auto; }
.fileTree ul { list-style: none; margin: 0; padding-left: 16px; }
.fileTree > ul { padding-left: 0; }
.fileTree li { line-height: 1.7; white-space: nowrap; }
.fileTree .dir { font-weight: 700; }
.fileTree .bytes { color: var(--soft); margin-left: 10px; font-feature-settings: "tnum"; font-variant-numeric: tabular-nums; }
.treeSummary { display: flex; gap: 14px; align-items: center; flex-wrap: wrap; font-size: 12.5px; color: var(--soft); margin: 8px 0; }
/* 取回命令:一整行可选中的等宽块。 */
.cmdBlock { font-family: ui-monospace, Menlo, monospace; font-size: 12px; background: var(--codeblk); color: var(--codeblk-ink);
  border-radius: 8px; padding: 9px 12px; white-space: pre-wrap; word-break: break-all; -webkit-user-select: all; -moz-user-select: all; user-select: all; }
/* 列表页状态过滤:一行小芯片按钮。 */
.filterRow { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; margin-bottom: 12px; }
.filterBtn { font-size: 12px; border: 1px solid var(--line); background: var(--surface); border-radius: 99px;
  padding: 2px 11px; color: var(--soft); }
.filterBtn.on { background: var(--acc-soft); color: var(--acc); border-color: transparent; font-weight: 600; }
/* 详情页 manifest 摘要:键值两列。 */
.kv { display: grid; grid-template-columns: max-content 1fr; grid-gap: 4px 14px; gap: 4px 14px; font-size: 13px; }
.kv dt { color: var(--soft); margin: 0; }
.kv dd { margin: 0; word-break: break-all; }
@media (max-width: 768px) {
  .grantRow { grid-template-columns: 1fr 1fr; }
  .roleHead { grid-template-columns: 1fr; }
  .kv { grid-template-columns: 1fr; }
}

/* ---- 项目组合(add-project-composition 刀13) ---- */
/* 新建表单 / 详情页「编辑组合」共用(_ui/CompositionPicker.tsx):左边候选应用表
   (角色下拉),右边只读派生预览;窄屏叠成一列。表单卡加 .wide 放到 900px——
   与 .appWizard 同宽,两列才摆得下。 */
.formCard.wide { max-width: 900px; }
.compPicker { display: grid; grid-template-columns: 1fr 1fr; grid-gap: 14px; gap: 14px; align-items: start; }
.compHead { display: flex; gap: 8px; align-items: baseline; flex-wrap: wrap; font-size: 13px; font-weight: 700;
  color: var(--ink); margin-bottom: 6px; }
.compHead .dimNote { font-weight: 400; }
.compTable td { color: var(--ink); }
.compTable .compRoleCell { width: 1%; white-space: nowrap; }
.compTable select { min-width: 150px; }
/* 「待集成,将从 init/<key> 起步」比一般芯片长,允许折行。 */
.compPending { margin-left: 4px; white-space: normal; }
.compPreview { border: 1px solid var(--line-faint); border-radius: 8px; padding: 10px 12px; background: var(--bg); min-height: 80px; }
.compPreview .kv { margin-top: 4px; }
.compNotes { margin: 0; padding-left: 16px; font-size: 12.5px; color: var(--soft); }
.compNotes li { margin: 2px 0; }
.compStale { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; margin-top: 8px; }
.compStale .chip .linkBtn { font-size: 11px; margin-left: 4px; }
@media (max-width: 768px) {
  .compPicker { grid-template-columns: 1fr; }
}

