/* 本文件由"按面拆分 CSS"生成（2026-10-11 monorepo 拆分），逐字节保留原格式。
   归属规则：只被 ui 包用到的规则归本包；被两个以上包用到、或扫不到引用的历史遗留
   （动态拼出来的类名扫不到）、以及含全局选择器（body、html、星号、:root…）的规则统一留在 ui 层。
   改样式时先看"这条规则谁在用"，再决定写进哪个包。 */

/* 自托管字体（SIL OFL 1.1，许可证与来源见 public/fonts/LICENSE-OFL.txt）
   为什么不再用 Google Fonts @import：中国大陆网络下 fonts.googleapis.com / fonts.gstatic.com
   经常不可达，字体请求会阻塞或超时，界面退化成系统字体甚至长时间无样式。
   现在改为同源 woff2 子集，离线/内网也能稳定显示；font-display:swap 保证字体未到位时先渲染回退字体。
   子集范围：拉丁字母 + 数字 + 常用符号（含 ¥ → ≈ ≤ ≥ × ÷ — … • 等），
   中文不在子集内（体积不可控），继续按 --font-sans 栈回退到系统字体 PingFang SC / Microsoft YaHei。
   重新生成：bash scripts/subset-fonts.sh（需要 fontTools+brotli） */
@font-face{
  font-family:'IBM Plex Sans';font-style:normal;font-weight:400;font-display:swap;
  src:url('/fonts/ibm-plex-sans-400.woff2') format('woff2');
}

@font-face{
  font-family:'IBM Plex Sans';font-style:normal;font-weight:500;font-display:swap;
  src:url('/fonts/ibm-plex-sans-500.woff2') format('woff2');
}

@font-face{
  font-family:'IBM Plex Sans';font-style:normal;font-weight:600;font-display:swap;
  src:url('/fonts/ibm-plex-sans-600.woff2') format('woff2');
}

@font-face{
  font-family:'JetBrains Mono';font-style:normal;font-weight:400;font-display:swap;
  src:url('/fonts/jetbrains-mono-400.woff2') format('woff2');
}

@font-face{
  font-family:'JetBrains Mono';font-style:normal;font-weight:500;font-display:swap;
  src:url('/fonts/jetbrains-mono-500.woff2') format('woff2');
}

/* 仅含 Summer 签名所需字面（S u m m e r + 空格），3.3KB；新增人格名请重跑子集脚本 */
@font-face{
  font-family:'Caveat';font-style:normal;font-weight:600;font-display:swap;
  src:url('/fonts/caveat-600.woff2') format('woff2');
}


/* Design tokens — ui-ux-pro-max design system (Dark Mode OLED)
   间距标尺（唯一依据，只用这五档）：4 / 8 / 12 / 16 / 24
   - 4  图标与文字、紧凑控件内距
   - 8  同组元素之间（按钮间距、表单行内）
   - 12 卡片内距、移动端页面留白
   - 16 卡片之间、桌面端页面留白、区块内分隔
   - 24 大区块之间（页面级段落） */
/* 亮色主题：覆盖同名 CSS 变量即可全局生效（组件内颜色已全部走 var()）。
   色相基准 = 冷调石板灰（slate），刻意**不带暖黄**：
   上一版是暖白底 #FFF8F4 + 米黄面 #EFE6DE + 棕调线 #D8C8BB，大面积暖色叠在一起
   会发灰发脏（第一眼的"没洗干净"感），与主色绿同框时脏感更明显。
   这一版把"暖"从底色收回到品牌点缀（Summer 玫瑰/落日渐变、琥珀风险色），
   底色用中性偏冷的灰、面用纯白 —— 白卡片浮在浅冷灰画布上，干净、通透、不发黄。 */
:root[data-theme="light"]{
  /* 画布浅冷灰 + 纯白内容面：白/画布 1.10，分区读得出，又不会让整屏发灰 */
  --bg:#F1F4F8; --panel:#FFFFFF; --panel2:#E9EEF5; --line:#CFD9E4;
  /* 文字改用石板灰：标题 #1E293B 对白 14.6:1；次级 #475569 对白 7.6:1、
     对浅冷灰画布 6.9:1，两处都远高于 4.5:1。 */
  --txt:#1E293B; --dim:#475569;
  /* 代码块与高亮（2026-10-10）：亮色下用深饱和色，保证在白底代码块上 ≥4.5:1 */
  --code-bg:#F6F8FB; --tk-c:#64748B; --tk-s:#0F766E; --tk-k:#7C3AED; --tk-n:#B45309;
  --tk-v:#0369A1; --tk-key:#92400E; --tk-tag:#0369A1; --tk-sec:#7C3AED;
  --tk-flag:#64748B; --tk-punct:#64748B; --tk-hunk:#64748B;
  --tk-add:#15803D; --tk-del:#B91C1C;
  /* 正文/强调两层：正文退一档，强调用 --txt。见 .x-markdown 的说明 */
  --txt-body:#334155;
  --accent:#15803D; --accent-fg:#FFFFFF;
  /* 落在 accent-soft 软底上的文字色：#15803D 对淡绿底只有 4.38:1（差一点不到 4.5），
     深一档到 #166534 → 6.1:1（行 hover 时 5.6:1）。深色主题下主色本身已够，见下。 */
  --accent-ink:#166534;
  /* 语义色统一按"最深底色 #E9EEF5"取值（2026-10-11 视觉验收 P2-7）。
     原来 red/amber/summer 只按白底校过，落到 --panel2 上分别只有 4.14 / 4.31 / 3.94，
     差一点不到 4.5 —— 而"差一点"在读小字时就是读不出来。统一降到 -700/-800 档：
       red    #DC2626 → #B91C1C（最差 5.55）
       amber  #B45309 → #92400E（最差 6.08）
       summer #DB2777 → #BE185D（最差 5.18） */
  --amber:#92400E; --purple:#6D28D9; --red:#B91C1C;
  /* 白底上玫瑰色需加深才够对比；阴影改为轻投影 */
  --summer:#BE185D; --summer-2:#EA580C;
  --shadow-push:-12px 0 32px rgba(15,23,42,.18);
}

/* 主题切换过渡：仅颜色，不触发布局 */
body,.panel,.card,aside,.ant-x-bubble{transition:background-color .25s ease,color .25s ease,border-color .25s ease}


:root{
  /* 大屏自适应标尺：1120 起步，随断点放大到 4K；
     --chat-max 是"阅读列"上限——超宽屏下正文不跟着拉长，保持行长可读 */
  --sidebar-w:240px;
  --chat-max:100%;
  --empty-max:560px;

  --bg:#0F172A; --panel:#1B2336; --panel2:#272F42; --line:#334155;
  --txt:#F8FAFC; --dim:#94A3B8;
  /* 代码块与高亮（2026-10-10）：暗色下用中高明度色，避免在深底上发糊 */
  --code-bg:#0B1220; --tk-c:#7C8AA0; --tk-s:#7DD3A0; --tk-k:#C792EA; --tk-n:#F0A868;
  --tk-v:#7CC4F0; --tk-key:#F0C674; --tk-tag:#7CC4F0; --tk-sec:#C792EA;
  --tk-flag:#94A3B8; --tk-punct:#94A3B8; --tk-hunk:#94A3B8;
  --tk-add:#4ADE80; --tk-del:#F87171;
  /* 暗色下正文用最亮的白会让加粗失去"亮度"这条通道，只剩字重；退到 #CBD5E1
     （对方块底 9.6:1，仍远超 4.5:1），强调回到 --txt 才有可见的亮度差 */
  --txt-body:#CBD5E1;
  --accent:#22C55E; --accent-fg:#0F172A;
  --accent-ink:#22C55E;   /* 软底上 5.4:1，无需加深 */

  /* 危险色提到 -400 档（2026-10-11 视觉验收 P2-7）：#EF4444 落在 --panel2 #272F42 上
     只有 3.55:1、--panel 上 4.16:1，小字读不出来。改 #F87171 → 最差 4.83:1。
     amber / purple / summer 在深色下本就 ≥4.9，不动。 */
  --amber:#F59E0B; --purple:#A78BFA; --red:#F87171;
  --summer:#FF6B9A; --summer-2:#FFA94D;
  --summer-grad:linear-gradient(135deg,#FFA94D 0%,#FF6B9A 100%); /* 落日汽水：橙→西瓜粉 */
  --shadow-push:-12px 0 32px rgba(0,0,0,.55);
  --font-sans:'IBM Plex Sans',-apple-system,'PingFang SC','Microsoft YaHei',system-ui,sans-serif;
  --font-mono:'JetBrains Mono','SF Mono',Menlo,monospace;
}

*{box-sizing:border-box;margin:0;padding:0}

html{font-size:16px}   /* rem 基准，不是排版档位：绝不能挂 --fs-base（紧凑档会变 16.5px，整站 rem 跟着变） */
 /* rem 基准：不是排版档位，刻意保留裸值 */
/* 页面内边距抽成变量：`.os-topbar` 要用它把这段间距收进自己的盒子（否则固定时跳一下），
   控制台整屏工作台则要把它归零（否则 100dvh 被顶出视口，凭空多出 2×24px 页面滚动）。
   同一个值只能有一个来源 —— 这两处必须共用，改一处不能漏另一处。 */
:root{--page-pad-y:24px;--page-pad-x:16px}

body{background:var(--bg);color:var(--txt);font-family:var(--font-sans);line-height:var(--lh-normal);padding:var(--page-pad-y) var(--page-pad-x)}

/* 控制台（会话工作台）= 整屏：不要页面内边距，也不要有页面滚动条。
   用 :has() 精确限定，其它页面（首页/预检/指南/维修间/后台）不受影响。
   不支持 :has() 的浏览器只是保留旧的 48px 溢出，不会坏。 */
/* ⚠️ 必须用**后代**选择器：React 挂在 #root 里，.os-shell 不是 body 的直接子元素
   （写成 `> .os-shell` 一条都不会命中 —— 实测控制台仍是 48px 溢出 + header 112px）。 */
body:has(.os-shell.as-console){padding:0;--page-pad-y:0px}

.wrap{max-width:960px;margin:0 auto}

.wrap-admin{max-width:1080px;margin:0 auto}

h1{font-size:var(--fs-2xl);margin-bottom:var(--sp-1);font-weight:600}

.sub{color:var(--dim);font-size:var(--fs-sm);margin-bottom:var(--sp-6)}

button{cursor:pointer}

button:disabled{cursor:not-allowed}

input[type=text],textarea{background:var(--panel2);border:1px solid var(--line);border-radius:var(--r-md);color:var(--txt);padding:var(--sp-2-5) var(--sp-3);font-size:var(--fs-base);font-family:var(--font-sans);width:100%}

/* 无障碍：键盘焦点可见 */
:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:var(--r-sm)}

/* 交互过渡 150–300ms */
a,button{transition:color .2s ease,background .2s ease,border-color .2s ease,opacity .2s ease}

/* 数字/成本用等宽字体 */
.mono{font-family:var(--font-mono)}
@media (prefers-reduced-motion: reduce) {

  *,*::before,*::after{animation-duration:.01ms !important;transition-duration:.01ms !important}
}


/* 轮次锚点：长会话里跳回某一轮。
   滚动条回答"在哪儿"，锚点回答"这是第几轮" —— 两者互补，不是重复。
   视觉是一根短横，但按钮本身留了 28×12 的热区（纯 2px 横线点不中）。
   移动端隐藏：热点太小够不着，且窄屏本身要省横向空间。 */
.turn-nav{
  position:absolute;right:var(--sp-1);top:50%;transform:translateY(-50%);
  display:flex;flex-direction:column;align-items:flex-end;gap:var(--sp-1);
  padding:var(--sp-1);z-index:20;
}

.turn-dot{
  width:28px;height:12px;padding:0;border:0;background:transparent;cursor:pointer;
  display:flex;align-items:center;justify-content:flex-end;
}

.turn-dot::before{
  content:'';display:block;width:16px;height:2px;
  border-radius:var(--r-full);background:var(--line);
  transition:background-color .15s ease,width .15s ease;
}

.turn-dot:hover::before{background:var(--dim)}

.turn-dot:focus-visible{outline:2px solid var(--accent);outline-offset:2px}

/* 当前轮不单靠颜色：横线同时变长 */
.turn-dot[aria-current="true"]::before{background:var(--accent);width:24px}
@media (max-width:767px) {
 .turn-nav{display:none}
}
@media (prefers-reduced-motion: reduce) {
 .turn-dot::before{transition:none}
}
@media (max-width:767px) {

  /* 气泡与 header / 输入框共用同一 8px 内边距 → 三者左边缘对齐。
     原先这里还有一条 `.app-shell .chat-scroll{padding-inline:8px}`，随 X 对话组件退役一起删了。 */

  .x-markdown p{margin-block:0 .9em}

  .x-markdown p:last-child{margin-block-end:0}

  .x-markdown li{margin-block:.35em}

  .x-markdown h1,.x-markdown h2,.x-markdown h3{margin-block:1.1em .5em}


  body{padding:var(--sp-3) var(--sp-3) calc(12px + env(safe-area-inset-bottom))}

  .grid3{grid-template-columns:1fr}

  /* 悬浮球在手机上正好压住正文与输入框；手机端改从「我的 → 反馈」进（同一份表单）。
     用 CSS 而不是 JSX 三元：断点归 @media 管是这个仓库的既有规则。 */
  /* !important 必要：这颗球用内联 style 写了 display:flex，内联优先级高于任何选择器。 */
  .fb-ball{display:none !important}

  /* 触控目标 ≥40px */
  .fb-btn,.nps-b{min-width:40px;min-height:36px;font-size:var(--fs-base)}

  /* 输入 16px 防 iOS 聚焦缩放 */
  input,textarea{font-size:var(--fs-base) !important}

  h1{font-size:var(--fs-2xl)}
}

/* 产品面应用壳（.app-shell）的**全部**布局规则已移到 app.css（AppShell 组件那一套）——
   这里曾经还留着一份旧对话壳的同名规则（flex + 100vw + calc(100dvh − 48px) + overflow:hidden），
   两份定义同优先级、靠"谁后加载"分胜负：结果是 App 面既拿不到 100dvh 的锁高，
   又白白继承了一条 overflow:hidden（内容超出视口的部分被裁掉且滚不到），
   再叠上 body 的 24/16 页面留白 —— 整页会滚，侧导与顶栏跟着滚走（2026-10-11 用户反馈）。
   **同一个类名只能有一处定义**：App 面外壳的规则全在 app.css。 */

/* 与页面底色**看得出差别**的内容面，用于：侧栏、AI 回答气泡、输入框。
   两套主题都取 --panel：深色下 #1B2336 对画布 #0F172A 是 1.72；
   浅色下纯白面对浅冷灰画布（--bg #F1F4F8）是 1.10 ——
   "白面浮在浅灰画布上"，边界清楚同时保持通透。
   浅色**不再**改成更暗的 --panel2：那会把气泡与输入框一起染灰，整屏发闷。 */
:root{--surface:var(--panel)}


/* 首屏出口（2026-10-06）：价值先行 —— 资产库入口与激活入口并列，别让"要码"成为第一屏唯一信息 */
.first-exits{display:flex;flex-wrap:wrap;align-items:center;justify-content:center;gap:var(--sp-3);margin-top:var(--sp-5);}

.first-exits-hint{flex-basis:100%;text-align:center;font-size:var(--fs-xs);color:var(--dim);}

.first-exits-link{font-size:var(--fs-sm);color:var(--accent-ink);text-decoration:none;border-bottom:1px solid transparent;padding-bottom:1px;background:none;border-top:0;border-left:0;border-right:0;cursor:pointer;font-family:inherit;}

.first-exits-link:hover{border-bottom-color:currentColor;}

.first-exits-link--btn{font-weight:600;}


/* 旧对话壳的侧栏/窄轨/页头（.sidebar / .side-rail / .chat-head：整列滑出 + 浮层展开钮 +
   粘顶页头）已随那套 UI 一起删除 —— 它们引用的 .app-shell[data-side] 状态与 App 面的
   218px 侧栏无关，留着只会让人以为 App 侧栏还有折叠态。App 侧栏在 app.css，只有展开/抽屉两态。 */
/* ============================================================================
   一级导航 + 二级视图排版
   ----------------------------------------------------------------------------
   桌面：身份卡 = 品牌行 + 竖排导航（侧栏内、会话列表之上）。
   移动：同一张卡横过来 —— 品牌一行 + 图标行，导航不再占据屏幕底部。
   **刻意不做底部导航**（参考千问三端）：56px + 安全区在键盘弹出时吃掉约 18% 的可见聊天区，
   而使用频率是「对话 ≫ 资产库 > 我的」——不值得为两个低频入口常驻一条固定栏。
   方向与边框全部由 @media 决定，不在 JSX 里写断点三元（既有规则三）。
   ============================================================================ */
.side-head{padding:var(--sp-4) var(--sp-4) 0}

.side-head-row{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-2)}

/* 品牌位：目前只有一行站名（17px）。
   曾有一行「商业顾问智能体」小字，已移除 —— 它把品牌位读成了"标题 + 副标题"，
   而这里**将来会放一张带公司品牌的 logo 图**，副标题会与它抢位置。
   放图时把 align-items 从 baseline 改成 center（baseline 是给纯文字对齐全用的）。 */
.side-brand{display:flex;align-items:baseline;gap:var(--sp-2);min-width:0}

/* 站名：纯文字，用界面前景色。
   曾做成字标（落日渐变字 + 手写笔触），已按用户判断还原 —— 不用艺术字。 */
.side-brand-name{font-size:var(--fs-lg);letter-spacing:.01em}

/* 不画分隔线：功能区靠「标题字重/字号/灰度 + 间距」区分。
   线会把侧栏切成几个互不相干的盒子，而它本来是一个连续的空间。 */
/* 导航内容（图标/文字）必须与品牌、搜索框、会话标题落在**同一条竖线**上（16px）。
   做法：负外边距把胶囊外拉 8px，图标就落在 16；胶囊底色因此比内容多出 8px 的呼吸。
   此前 .nav-item 自己带 12px 内距、外层没有负边距 —— 图标落在 28px，比其余内容右 12px（实测）。 */
.primary-nav{
  display:flex;flex-shrink:0;flex-direction:column;gap:var(--sp-1);
  padding:var(--sp-3) 0 var(--sp-1);margin-inline:calc(-1 * var(--sp-2));
}

.nav-item{
  display:flex;align-items:center;gap:var(--sp-2);position:relative;
  min-height:44px;padding:0 var(--sp-2);
  border:0;border-radius:var(--r-md);background:transparent;color:var(--dim);
  font:inherit;font-size:var(--fs-md);cursor:pointer;text-align:left;
}

.nav-item:hover{background:var(--hover)}

.nav-item:focus-visible{outline:2px solid var(--accent);outline-offset:2px}

/* 选中态不单靠颜色：**字重加粗** + 底色 + 左侧竖条，色觉异常下同样能分辨。
   加粗是千问的做法：一眼能看出"我在哪一页"，比只靠底色更明确。 */
.nav-item[aria-current="page"]{color:var(--accent-ink);background:var(--accent-soft);font-weight:600}

.nav-item[aria-current="page"]::before{
  content:'';position:absolute;left:0;top:8px;bottom:8px;width:2px;border-radius:var(--r-full);background:var(--accent);
}

.nav-icon{display:flex;font-size:var(--fs-lg);line-height:1}

.nav-label{line-height:1}

/* 会话列表：标题固定在滚动容器**之外**，容器内只有可滚动的会话条目。
   标题字号/颜色沿用原分组标题（12px + 次级灰）；横向与条目文字对齐 ——
   Conversations 自身 padding-inline 8 + 条目内距 8 = 16（移动端 4 + 8 = 12）。 */
.side-conv{display:flex;flex-direction:column;flex:1;min-height:0}

.side-conv-title{flex-shrink:0;font-size:var(--fs-xs);color:var(--dim);padding:var(--sp-2) var(--sp-4) var(--sp-1)}

.side-conv-scroll{flex:1;min-height:0;overflow-y:auto}

.side-conv-more{text-align:center;font-size:var(--fs-2xs);color:var(--dim);padding:var(--sp-2) 0 var(--sp-3)}
@media (max-width:767px) {

  .side-conv-title{padding-inline:var(--sp-3)}
}


/* ---- 二级视图（资产库 / 详情 / 我的）：与对话页同一套「页头 + 限宽内容列」----
   对话页 = 全宽页头（在滚动区之外）+ 由 --chat-max 限宽居中的内容；这三页此前是
   "内距铺满 + 内容裸平铺在画布上"：2560 下正文能拉到 2200px 以上，且只有「我的」有卡片，
   资产库与详情是裸平铺 —— 与对话页明显不是一套。
   现在统一：页头 = 粘顶的窄条 chrome（与对话页 header 一样常驻、同样 16px 内距）；
   内容列 = --chat-max 限宽居中；内容一律用卡片（--panel）浮在画布（--bg）上。 */
.view-scroll{flex:1;min-height:0;overflow-y:auto}

.view-head{
  position:sticky;top:0;z-index:5;
  display:flex;align-items:center;gap:var(--sp-2);
  padding:var(--sp-3) var(--sp-4) var(--sp-2);
  background:var(--bg);
}

/* 页头统一高度。对话页由 32px 动作按钮撑到 52px（12 + 32 + 8）；
   二级视图在桌面没有按钮（menuButton=null），只剩 20px 标题 → 只有 40px，
   标题中心比侧栏「展开侧栏」按钮高 6px（实测 cy 22 vs 28）。
   显式给同一 min-height：桌面收起侧栏时标题与展开按钮严格同一水平线，
   也和对话页标题对齐；移动端本来由 40px 汉堡撑到 58px，不受影响。 */
.chat-head,.view-head{min-height:52px}

.view-head-title{
  font-size:var(--fs-base);font-weight:600;color:var(--txt);line-height:var(--lh-tight);
  min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}

.view-head-actions{margin-inline-start:auto;display:flex;align-items:center;gap:var(--sp-2);flex-shrink:0}

/* 面包屑进页头：去掉自身底距、吃满剩余宽度（详情页用它承载"返回列表 + 当前条目"） */
.view-head .crumbs{margin-bottom:0;flex:1;min-width:0;flex-wrap:nowrap;font-size:var(--fs-sm)}

/* 面包屑的"上级"链接与分隔符不许收缩：CJK 可任意断行，flex 会把它们压到 1 字宽变成竖排
   （实测移动端出现「资/产/库」竖排）。该省略的是当前位置标题，它已有 ellipsis。 */
.view-head .crumbs .crumb-link,
.view-head .crumbs .crumb-sep{flex:0 0 auto;white-space:nowrap}

.view-container{width:100%;max-width:var(--chat-max);margin-inline:auto;padding:0 var(--sp-4) var(--sp-6)}

/* 卡片：画布上的内容面。--flush 给"行自带内距"的列表用（分隔线通栏、hover 满宽） */
.view-card--flush{padding:0;overflow:hidden}

.view-card{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-lg);padding:var(--sp-4);margin-bottom:var(--sp-3)}

.view-card:last-child{margin-bottom:0}

.view-card-title{font-size:var(--fs-md);font-weight:600;color:var(--txt);margin-bottom:var(--sp-2)}

/* 设置行：标签居左、控件居右，同一行。用于"就一个开关/选择器"的卡片 —— 
   否则标题与控件各占一行，整张卡只有两个小元素却横竖都空一大截。 */
.view-card-row{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-3)}

.view-card-row .view-card-title{margin-bottom:0}

.view-card-text{margin:0 0 var(--sp-3);font-size:var(--fs-sm);color:var(--dim);line-height:var(--lh-normal)}

.view-card-text:last-child{margin-bottom:0}

/* 键值行：**标签定宽 + 值紧跟其后**，不用 space-between。
   space-between 在宽卡片里会把两者扯到两端 —— 实测 1920 下卡片 1624px 宽，
   标签与值相距约 1400px，眼睛连不起来，等于读不出"哪个值属于哪个标签"。
   定宽用 min-width 而非 flex-basis：短标签统一对齐成列，长标签可以自己撑开。 */
.view-row{display:flex;align-items:center;gap:var(--sp-3);min-height:32px}

.view-row-label{flex:0 0 auto;min-width:72px;font-size:var(--fs-sm);color:var(--dim)}

.view-row-value{font-size:var(--fs-2xs);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* 内测限额：细进度条 + 百分比。条与数字是同一个量，再报绝对数只会多一次心算 */
.quota{display:flex;align-items:center;gap:var(--sp-2);flex:1;min-width:0}

.quota-track{flex:0 1 220px;height:6px;border-radius:var(--r-full);background:var(--track);overflow:hidden}

.quota-fill{height:100%;border-radius:var(--r-full);background:var(--accent);transition:width .2s ease}

.quota-text{font-size:var(--fs-2xs);color:var(--dim);white-space:nowrap}
@media (max-width:767px) {

  /* 身份卡：品牌一行 + 导航横排一行（千问抽屉形态）。
     卡片用 --panel2 压在抽屉的 --panel 上形成层级，而不是再加一道重边框。 */
  .side-head{
    margin:0 var(--sp-3) var(--sp-2);
    padding:var(--sp-3);
    background:var(--panel2);
    border:1px solid var(--line);
    border-radius:var(--r-lg);
  }

  .side-brand{margin-bottom:var(--sp-3)}

  .primary-nav{flex-direction:row;padding-bottom:0;border-bottom:0}

  /* 横排后「左侧竖条」语义失效：改用图标与文字的颜色区分 */
  .primary-nav .nav-item{
    flex:1;flex-direction:column;justify-content:center;gap:var(--sp-0-5);
    min-height:48px;padding:0;font-size:var(--fs-2xs);text-align:center;
  }

  .primary-nav .nav-item[aria-current="page"]{background:transparent}

  .primary-nav .nav-item[aria-current="page"]::before{display:none}

  .primary-nav .nav-icon{font-size:var(--fs-xl)}

  /* 移动端页头与对话页同一套内距（body 已给 12px，这里再补 10px，与 .chat-head 一致） */
  .view-head{gap:var(--sp-2-5);padding:calc(8px + env(safe-area-inset-top)) var(--sp-2-5) var(--sp-2-5)}

  .view-container{padding:0 var(--sp-2-5) var(--sp-5)}
}

/* 导航徽标：变更提醒的可发现性 */
.nav-badge{
  margin-inline-start:auto;min-width:18px;height:18px;padding:0 var(--sp-1);
  display:inline-flex;align-items:center;justify-content:center;
  border-radius:var(--r-full);background:var(--red);color:#fff;
  font-size:var(--fs-2xs);font-weight:600;
}

/* 视图内的弱化要点列表（与资产卡片的 notes 同款观感） */
.view-list{margin:0 0 var(--sp-2);padding-inline-start:18px;font-size:var(--fs-xs);color:var(--dim);line-height:var(--lh-normal)}

.view-list li{margin:0 0 var(--sp-1)}

.view-list b{color:var(--txt);font-weight:600}


/* 计划勾选：序号位变成勾选框（位置不变、不额外占宽） */
.dg-title-row{display:flex;align-items:baseline;justify-content:space-between;gap:var(--sp-2)}

.dg-progress{font-size:var(--fs-2xs);color:var(--accent);flex-shrink:0}

.dg-check{
  flex-shrink:0;width:22px;height:22px;padding:0;
  border:1px solid var(--line);border-radius:var(--r-full);
  /* 背景必须**不透明**：它同时承担"盖住竖线"的职责，transparent 会让线从圈里透出来。
     --panel 与所在 .panel-card 同色，观感不变。 */
  background:var(--panel);color:var(--dim);font:inherit;font-size:var(--fs-2xs);
  cursor:pointer;line-height:1;display:inline-flex;align-items:center;justify-content:center;
  /* 必须与 .dg-num 一样抬到竖线之上：.dg-step::before 是绝对定位的连线，
     非定位元素（按钮默认 static）会被它盖住 —— 实测序号被竖线劈成两半。 */
  position:relative;z-index:1;
}

.dg-check:hover{border-color:var(--accent);color:var(--accent)}

.dg-check:focus-visible{outline:2px solid var(--accent);outline-offset:2px}

.dg-check[aria-checked="true"]{border-color:var(--accent);background:var(--accent);color:var(--accent-fg)}

/* 勾掉的步骤弱化，但不隐藏：用户要能回看自己做到了哪一步 */
.dg-step-done .dg-step-label{color:var(--dim)}


/* 卡组预览：用 iframe 隔离 —— brand.css 会改 body，直接渲染会污染后台自身 */
.deck-frame-wrap{overflow-x:auto;border:1px solid var(--line);border-radius:var(--r-lg);background:#fff}

/* **min-width 是硬要求，不能省**：brand.css 有 @media (max-width:800px) 会把卡片改成
   calc(100vw - 32px) + min-height:auto。iframe 一旦窄于 800px，导出的 PNG 就是移动端布局
   （实测 780px 视口 → 748×353 而不是 750×960）。后台右栏在笔记本上很容易不足 800px。 */
.deck-frame{width:100%;min-width:900px;height:640px;border:0;background:#fff;display:block}

.deck-warn{margin-bottom:var(--sp-3)}


/* ---- 资产库（公开资产通用查询）---- */
.asset-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp-2);margin-bottom:var(--sp-3)}

/* 筛选卡内最后一行不留底距，否则卡片底部会多出一截空白 */
.asset-filter-card .asset-toolbar:last-child{margin-bottom:0}

.asset-filter-label{font-size:var(--fs-2xs);color:var(--dim);margin-inline-start:var(--sp-2)}

.asset-count{font-size:var(--fs-2xs);color:var(--dim);margin-inline-start:auto}

.asset-chip{
  border:1px solid var(--line);background:transparent;color:var(--dim);
  border-radius:var(--r-full);padding:var(--sp-0-5) var(--sp-3);
  min-height:32px;font:inherit;font-size:var(--fs-2xs);cursor:pointer;
}

.asset-chip:hover{background:var(--hover)}

.asset-chip:focus-visible{outline:2px solid var(--accent);outline-offset:2px}

/* 选中态用边框+底色+文字色三重区分，不单靠颜色 */
.asset-chip[aria-pressed="true"]{border-color:var(--accent);color:var(--accent-ink);background:var(--accent-soft)}

/* 列表：一行一条（不是卡片）。卡片把摘要/备注/出处全塞进一屏，
   信息密度上不去、扫读也慢 —— 分层交给 List → Detail。 */
.al-list{display:flex;flex-direction:column}

/* 放进卡片后：顶部分隔线由卡片边框承担，行内距改用卡片内距（--sp-4），左右不再贴边 */
.view-card--flush .al-list{border-top:0}

.view-card--flush .al-row{padding-inline:var(--sp-4)}

.al-row{
  display:flex;gap:var(--sp-3);align-items:flex-start;justify-content:space-between;
  padding:var(--sp-3) var(--sp-2);border-bottom:1px solid var(--line);
  color:inherit;text-decoration:none;
}

/* 整行是 <a> 的列表行：可点提示由**底色**给，不叠 hover 的变暗 ——
   整行变暗会让"这一行被选中"和"鼠标在这儿"两件事看起来一样。
   （改前这里是为了压掉全局的 hover 下划线；现在全局已经没有下划线，
   这条规则留下来固定"行级只用一种反馈"这个意图。） */
.al-row:hover{background:var(--hover);opacity:1;text-decoration:none}

.al-row:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}

.al-main{display:flex;flex-direction:column;gap:var(--sp-1);min-width:0;flex:1}

.al-title{font-size:var(--fs-base);font-weight:600;color:var(--txt)}

.al-tags{display:flex;flex-wrap:wrap;gap:var(--sp-1)}

/* 摘要压成一行：列表只回答「要不要点进去」，细节在详情页 */
.al-sum{
  font-size:var(--fs-xs);color:var(--dim);line-height:var(--lh-normal);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}

.al-side{display:flex;flex-direction:column;align-items:flex-end;gap:var(--sp-1);flex-shrink:0}

.al-meta,.al-upd{font-size:var(--fs-2xs);color:var(--dim);white-space:nowrap}
@media (max-width:767px) {

  /* 窄屏把右侧信息挪到标题下面一行，否则标题被挤成两三个字一换行。
     align-items 必须一起改：基础规则的 flex-start 在竖排下等于"按 max-content 撑开"，
     而摘要 .al-sum 是 nowrap → 实测整块 506px、溢出到 561（父行只有 312），
     被卡片裁掉且够不着。竖排要的是 stretch（每行占满宽度）。 */
  .al-row{flex-direction:column;align-items:stretch;gap:var(--sp-1)}

  .al-side{flex-direction:row;align-items:center;gap:var(--sp-2)}
}


/* 面包屑：List ⇄ Detail 的前进后退就靠它。用真链接，不吃 JS 拦截。 */
.crumbs{display:flex;align-items:center;gap:var(--sp-2);margin-bottom:var(--sp-3);font-size:var(--fs-xs);flex-wrap:wrap}

.crumb-link{color:var(--accent);text-decoration:none;padding:var(--sp-1) 0}

/* 行内链接也不加下划线（用户 2026-10-13）—— 链接身份由 --accent 说明 */
.crumb-link:hover{opacity:.82}

.crumb-sep{color:var(--dim)}

.crumb-cur{color:var(--dim)}

/* 详情页 */
.vd-title{margin:0 0 var(--sp-2);font-size:var(--fs-lg);font-weight:600;color:var(--txt);line-height:var(--lh-tight)}

/* 详情标题进页头（与面包屑同一行）：去掉块级底距，颜色/字号沿用页头规格 */
.view-head .vd-title{margin:0;font-size:var(--fs-base);color:var(--txt)}

/* 卡片内的段落：最后一段不留底距，避免卡片底部多出一截空白 */
.view-card .vd-summary:last-child,
.view-card .vd-tags:last-child,
.view-card .vd-meta:last-child{margin-bottom:0}

.view-card .vd-sec:last-child{margin-bottom:0}

.vd-tags{display:flex;flex-wrap:wrap;gap:var(--sp-1);margin-bottom:var(--sp-2)}

.vd-meta{font-size:var(--fs-2xs);color:var(--dim)}

.vd-summary{margin:0 0 var(--sp-4);font-size:var(--fs-base);color:var(--txt);line-height:var(--lh-normal)}

.vd-sec{margin-bottom:var(--sp-4)}

.vd-sec-title{margin:0 0 var(--sp-2);font-size:var(--fs-sm);font-weight:600;color:var(--txt)}

.vd-notes{margin:0;padding-inline-start:18px;font-size:var(--fs-sm);color:var(--dim);line-height:var(--lh-normal)}

.vd-notes li{margin:0 0 var(--sp-1)}

.vd-src{margin:0;padding-inline-start:18px;font-size:var(--fs-sm);line-height:var(--lh-normal)}

.vd-src li{margin:0 0 var(--sp-1)}

.vd-src a{color:var(--accent);text-decoration:none}

.vd-src a:hover{opacity:.82}

/* 形态卡槽位：把内部 JSON 读成"文档大纲" ——
   话是段落、结构是小标题+子块、短标量是紧凑键值、出处元信息落段末。
   （按 JSON 原样平铺会乱：摘要缩在标签列后面、tiers 这类结构键被当成一行、出处插在事实中间。） */
.vd-slot{scroll-margin-top:64px}
                       /* 目录跳转时让开粘顶页头 */
.vd-slot-no{color:var(--dim);font-size:var(--fs-2xs);margin-inline-end:var(--sp-2);vertical-align:2px}

.vd-toc{display:flex;flex-wrap:wrap;gap:var(--sp-1);margin-top:var(--sp-3);padding-top:var(--sp-3);border-top:1px solid var(--line)}

.vd-toc-item{
  border:1px solid var(--line);background:transparent;color:var(--dim);cursor:pointer;
  border-radius:var(--r-full);padding:var(--sp-0-5) var(--sp-2-5);font:inherit;font-size:var(--fs-2xs);
}

.vd-toc-item:hover{border-color:var(--accent);color:var(--accent)}

.vd-toc-item:focus-visible{outline:2px solid var(--accent);outline-offset:2px}


.vd-p{margin:0 0 var(--sp-2);font-size:var(--fs-sm);color:var(--txt);line-height:var(--lh-read)}

.vd-p:last-child{margin-bottom:0}

.vd-sub{margin:0 0 var(--sp-2)}

/* 结构键的小标题：它表示"下面这组是什么"，不是内容本身 */
.vd-cap{font-size:var(--fs-2xs);color:var(--dim);margin:var(--sp-2) 0 var(--sp-1);letter-spacing:.02em}

/* 同级的每一项之间用一条细线切开 —— 这是取消缩进之后唯一的"分组"信号 */
.vd-h{
  margin:var(--sp-4) 0 var(--sp-2);padding-top:var(--sp-3);
  border-top:1px solid var(--line);
  font-size:var(--fs-md);font-weight:600;color:var(--txt);line-height:var(--lh-tight);
}

/* 置信度跟在条目标题后（"个人主体 官方"）：它是这条的属性，不是单独一段内容 */
.vd-tmeta{font-size:var(--fs-2xs);font-weight:400;color:var(--dim);margin-inline-start:var(--sp-2)}

/* 注意不要写成 :first-child 例外：每个条目标题都是**它自己那组**的第一个子节点，
   一旦豁免，所有分隔线都会消失（踩过）。*/
.vd-ul{margin:0 0 var(--sp-2);padding-inline-start:18px;font-size:var(--fs-sm);line-height:var(--lh-read)}

.vd-ul > li{margin:0 0 var(--sp-1)}

/* 紧凑键值：只有"短标量"进得来（真正的正文已经走段落了） */
.vd-kvtable{margin:0 0 var(--sp-2);display:flex;flex-direction:column;gap:var(--sp-0-5)}

.vd-kvrow{display:flex;gap:var(--sp-2);font-size:var(--fs-sm);line-height:var(--lh-normal)}

.vd-kvrow dt{flex:0 0 92px;color:var(--dim);font-size:var(--fs-xs);padding-top:var(--sp-0-5)}

.vd-kvrow dd{margin:0;flex:1;min-width:0;color:var(--txt)}

/* **不做嵌套缩进**：层级用字号与分隔线表达，不用左边距 ——
   靠缩进表达层级，结果是"一层套一层"的梯子（用户明确否掉的）。 */
.vd-group{margin:0}

.vd-group > *:last-child{margin-bottom:0}

.vd-cite{font-size:var(--fs-xs);color:var(--dim);line-height:var(--lh-normal);margin:0 0 var(--sp-2)}

.vd-cite .vd-sep{color:var(--line)}

.vd-link{color:var(--accent);text-decoration:none;overflow-wrap:anywhere}

.vd-link:hover{opacity:.82}

.vd-json{margin:0;font-size:var(--fs-2xs);color:var(--dim);white-space:pre-wrap;overflow-wrap:anywhere}

.vd-foot{font-size:var(--fs-2xs);color:var(--dim);margin-bottom:var(--sp-4)}
@media (max-width:767px) {

  .view-head-actions .ask-label{display:none}
}

.asset-foot{margin-top:var(--sp-2);font-size:var(--fs-2xs);color:var(--dim)}


/* 底部：触屏滚动加载 / 鼠标分页。两种形态互斥，由输入方式决定（见 AssetsView 的 useCoarsePointer） */
.asset-sentinel{height:1px}

.asset-more{display:flex;justify-content:center;padding:var(--sp-4) 0}

.asset-more-end{text-align:center;padding:var(--sp-4) 0;font-size:var(--fs-xs);color:var(--dim)}

.asset-page{display:flex;justify-content:center;padding:var(--sp-4) 0}


/* 长词/链接换行，防横向溢出 */
.x-markdown,.x-markdown *{overflow-wrap:anywhere}

/* admin */
.kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:var(--sp-3);margin-bottom:var(--sp-4)}

/* 超链接：**全局无下划线**（用户 2026-10-13：所有超链接移除默认下划线样式）。
   连着 hover 一起去掉，而不是只去掉默认态：下划线在这里本来被当作"这是行内链接"的信号，
   但一页里同时有行内链接 / 整行链接 / 按钮三种可点形态时，"hover 才浮出下划线"比
   一直不浮出更吵 —— 鼠标扫过列表，下划线逐行闪现。
   去掉之后靠**颜色**（--accent）说明"这是链接"，hover 用轻微变暗说明"它响应了"。
   这套正是落地页早就采用的做法（它原先在 .mk-shell 里覆盖共享层的 hover 下划线），
   现在共享层与它一致，那层覆盖也就不需要了。 */
a{color:var(--accent);text-decoration:none}

a:hover{opacity:.82}

h2{font-size:var(--fs-base);margin-bottom:var(--sp-3);font-weight:600}

.match-match{color:var(--accent)}
 .match-partial{color:var(--amber)}
 .match-nomatch{color:var(--red)}

.up{color:var(--accent)}
 .down{color:var(--red)}


/* XMarkdown 深色适配 */
/* Markdown 正文 vs 加粗强调：**两条通道**，不只靠字重。
   中文字形走系统回退字体（IBM Plex Sans 不含 CJK），小字号下 400→700 的字重差
   在暗色底上尤其弱 —— 实测"贴近才看得出"（用户反馈）。
   做法：正文退一档用 --txt-body，强调回到 --txt 并显式 700，
   于是加粗同时"更亮 + 更粗"，扫读时一眼能跳到重点。 */
/* 包自己用 --text-color 上色，且写成 inherit；它的样式靠 lazy chunk **后注入**，
   同特异性的 color 声明会盖掉我们直接写的。所以不能写 color，要把它的变量拿回来 ——
   用 :root 前缀抬一级特异性（0,2,0 > 0,1,0），与注入顺序无关。 */
:root .x-markdown{--text-color:var(--txt-body)}

.x-markdown strong,.x-markdown b{color:var(--txt);font-weight:700}

.x-markdown pre{background:var(--panel2) !important;border:1px solid var(--line);border-radius:var(--r-md)}

.x-markdown code{font-family:var(--font-mono)}

.x-markdown table{border-color:var(--line)}

.x-markdown th,.x-markdown td{border:1px solid var(--line);padding:var(--sp-1) var(--sp-2)}

.x-markdown blockquote{border-left:2px solid var(--accent);color:var(--dim);padding-left:var(--sp-2);margin:var(--sp-2) 0}

.x-markdown a{color:var(--accent)}


/* ===== 滚动条专项 ===== */
/* 防滚动条出现/消失引起的布局抖动（CLS） */
html{scrollbar-gutter:stable}

/* Firefox：细滚动条 + 主题色 */
*{scrollbar-width:thin;scrollbar-color:var(--line) transparent}

/* WebKit：6px 悬浮式，滑块 hover 提亮 */
::-webkit-scrollbar{width:6px;height:6px;background:transparent}

::-webkit-scrollbar-track{background:transparent}

::-webkit-scrollbar-thumb{background:var(--line);border-radius:var(--r-sm)}

::-webkit-scrollbar-thumb:hover{background:var(--dim)}

::-webkit-scrollbar-corner{background:transparent}

/* 聊天流/抽屉：滚动边界不穿透（防 iOS 页面橡皮筋） */
.chat-scroll,.ant-drawer-body,table-scroll{overscroll-behavior:contain}
@media (max-width:767px) {

  ::-webkit-scrollbar{width:0;height:0;display:none}

  *{scrollbar-width:none}
}

/* 代码块/表格独立细滚动条（横向） */
.x-markdown pre::-webkit-scrollbar{height:4px}

/* Summer 品牌动效：AI 气泡入场（淡入上浮 200ms，reduced-motion 全局降级） */
@keyframes summer-enter{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
 /* 流式更新中的末条不重复动画 */
/* Summer 等待语：玫瑰色图标 */
.summer-loading .anticon{color:var(--summer)}

/* 等待语打字机动效：文案逐字打出 / 删掉，光标随行移动。
   宽度由隐藏的 sizer 撑住（所有等待语里最宽的一条）—— 气泡边框不能跟着每个字抖，
   否则每 55ms 动一次边，比不做动效还吵。 */
.type-wrap{display:inline-grid;vertical-align:bottom}

.type-wrap>*{grid-area:1/1}

.type-sizer{display:inline-grid;visibility:hidden}

.type-sizer>*{grid-area:1/1;white-space:nowrap}

.type-live{white-space:nowrap}

.type-cursor{
  display:inline-block;width:2px;height:1.05em;margin-inline-start:2px;
  background:currentColor;vertical-align:-.16em;
  animation:type-blink 1s steps(1,end) infinite;
}

@keyframes type-blink{0%,49%{opacity:1}50%,100%{opacity:0}}
@media (prefers-reduced-motion: reduce) {

  .type-cursor{animation:none;opacity:1}
}

/* 像素风头像：禁用浏览器平滑插值，保持像素锐利 */
.pixelated{image-rendering:pixelated;image-rendering:-moz-crisp-edges;image-rendering:crisp-edges}


/* 人格：头像与艺术签名 */
.agent-avatar{display:block;object-fit:cover;image-rendering:pixelated;image-rendering:-moz-crisp-edges;image-rendering:crisp-edges}

.agent-signature{position:relative;display:inline-block;line-height:1;padding-bottom:var(--sp-1-5)}

.agent-signature-text{
  font-family:'Caveat','Bradley Hand','Segoe Script','Snell Roundhand',cursive;
  font-weight:600;letter-spacing:.01em;
  background:var(--summer-grad);-webkit-background-clip:text;background-clip:text;
  -webkit-text-fill-color:transparent;color:transparent;
}

.agent-signature-swash{position:absolute;left:0;right:0;bottom:0;width:100%;height:10px;overflow:visible}
@supports not ((-webkit-background-clip:text) or (background-clip:text)) {

  .agent-signature-text{color:var(--summer);-webkit-text-fill-color:currentColor}
}
@media (min-width: 1440px) {

  :root{--chat-max:960px;--empty-max:720px}
}
@media (min-width: 1920px) {

  :root{--sidebar-w:264px;--gap-lg:32px}
}
@media (min-width: 2560px) {

  :root{--sidebar-w:288px;--gap-lg:40px}
}
@media (min-width: 3200px) {

  :root{--sidebar-w:304px;--gap-lg:48px}
}


/* 阅读列：会话区内容（气泡/输入/头部）居中于 --chat-max 宽度内。
   滚动条仍在整列右缘，阅读行长不随屏幕无限拉长。 */
.chat-scroll{padding-inline:max(0px, calc((100% - var(--chat-max)) / 2))}


/* 键盘可达性：容器可聚焦滚动 */
.chat-scroll:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}


/* ============================================================================
   后台管理控制台 —— 只保留 antd 覆盖不到的部分
   组件一律用 antd：Layout/Sider/Menu/Header/Content、Card/Statistic、Tabs/Table、
   List/Descriptions/Segmented/Bubble、Form/InputNumber/Alert/Progress、Empty/Skeleton。
   本文件负责：全屏壳、导航两行文案、卡片标题+口径说明、漏斗行、会话滚动区、响应式。
   ============================================================================ */

:root{
  --glass-bg:rgba(27,35,54,.78);
  --hover:rgba(148,163,184,.10);
  --accent-soft:rgba(34,197,94,.14);
  --track:rgba(148,163,184,.20);
  /* 内容区上限宽（2026-10 内容区统一）：控制台与后台共用同一条。
     原先是后台专有的 --admin-max，前台全宽 —— 同一个产品在 4K 屏上两套行宽。
     只限内容区，不限顶栏/侧栏：chrome 仍然铺满视口。 */
  --content-max:1280px;
}

:root[data-theme="light"]{
  --glass-bg:rgba(255,255,255,.82);
  --hover:rgba(15,23,42,.05);
  --accent-soft:rgba(21,128,61,.10);
  --track:rgba(15,23,42,.10);
}
@media (min-width:1440px) {
 :root{--content-max:1440px}
}
@media (min-width:1920px) {
 :root{--content-max:1600px}
}
@media (min-width:2560px) {
 :root{--content-max:1840px}
}

.dim{color:var(--dim)}


/* 后台为全屏应用壳：移除 body 页面留白，由 Layout 自行管理 */
body.admin-body-lock{padding:0;background:var(--bg)}


/* KPI：断点列宽（xl=4 列、xxl=6 列）。antd 的 xxl=3 会在 1600px 时排成 8 列，
   卡片从 265px 被压到 147px，出现"屏越大卡越窄" */
.admin-kpi-col{height:auto}
@media (min-width:1600px) {

  .admin-kpi-col{flex:0 0 16.6667% !important;max-width:16.6667% !important}
}


/* 卡片标题：主标题 + 口径说明（只用 Card 的 title 插槽，不另造组件） */
.card-title{display:flex;flex-direction:column;gap:var(--sp-0-5);line-height:var(--lh-snug)}

.card-title-main{font-size:var(--fs-md);font-weight:600;display:inline-flex;align-items:center;gap:var(--sp-1-5)}

.card-title-desc{font-size:var(--fs-xs);font-weight:400;color:var(--dim)}

.h-full{height:100%}

.tab-toolbar{display:flex;align-items:center;gap:var(--sp-2);padding:var(--sp-3) var(--sp-4);flex-wrap:wrap}

.spacer{flex:1}

.tab-count{font-size:var(--fs-xs)}

.tab-badge{font-style:normal;font-size:var(--fs-2xs);color:var(--dim);margin-left:var(--sp-1)}

.cell-text{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;max-width:100%;overflow-wrap:anywhere}

.feed-line{display:flex;align-items:baseline;gap:var(--sp-2);flex-wrap:wrap}

.feed-text{flex:1;min-width:0;font-size:var(--fs-sm);overflow-wrap:anywhere}

.feed-time{margin-inline-start:auto;white-space:nowrap}

.kpi-title{display:inline-flex;align-items:center;gap:var(--sp-1);font-size:var(--fs-xs)}

.kpi-hint{display:block;font-size:var(--fs-2xs);line-height:var(--lh-snug);margin-top:var(--sp-1)}


/* 图表容器 */
.chart{display:flex;flex-direction:column;gap:var(--sp-2)}

/* 分类条形榜（事件构成/按天费用）：HTML 实现，条长按最大值归一，主题自适应 */
.bar-list{list-style:none;display:flex;flex-direction:column;gap:var(--sp-2-5);margin:0;padding:var(--sp-0-5) 0}

.bar-list li{display:grid;grid-template-columns:minmax(56px,88px) minmax(0,1fr) auto;align-items:center;gap:var(--sp-3)}

.bar-label{font-size:var(--fs-xs);color:var(--dim);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

.bar-track{height:10px;border-radius:var(--r-full);background:var(--track);overflow:hidden}

.bar-track i{display:block;height:100%;border-radius:var(--r-full);background:var(--accent);min-width:2px}

.bar-value{font-size:var(--fs-sm);min-width:64px;text-align:right}

.chart-head{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-2);min-height:24px;font-size:var(--fs-xs)}


/* 漏斗：antd Progress 逐级展示 */
.funnel{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:var(--sp-2-5)}

.funnel-row{display:flex;align-items:center;gap:var(--sp-3)}

.funnel-label{width:104px;flex:0 0 104px;font-size:var(--fs-xs);color:var(--dim);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

.funnel-value{width:52px;text-align:right;font-size:var(--fs-sm)}

.funnel-pct{width:52px;text-align:right;font-size:var(--fs-xs);color:var(--dim)}

.funnel-delta{width:100px;display:inline-flex;align-items:center;gap:var(--sp-1-5);justify-content:flex-end;font-size:var(--fs-2xs)}

.funnel-worst{margin-inline-end:0}


/* 会话：左列表 + 右详情 */
.sessions-grid{display:grid;grid-template-columns:minmax(280px,360px) minmax(0,1fr);gap:var(--sp-4);align-items:start}

.session-list{max-height:min(58vh,560px);overflow-y:auto}

.session-item-title{font-size:var(--fs-sm);font-weight:500}

.session-desc{margin-bottom:var(--sp-3)}

.sd{padding:var(--sp-4)}

.sd-head{display:flex;flex-direction:column;gap:var(--sp-2);padding-bottom:var(--sp-3);border-bottom:1px solid var(--line);margin-bottom:var(--sp-3)}

.sd-title{font-size:var(--fs-base);font-weight:600;margin:0}

/* 详情卡高度与视口联动：原先 sd-msgs 固定 min(58vh,600px)，卡片被撑到 794px，
   "同步流水"被推出 900px 首屏（y=889.5），现在整页可控 */
.sessions-detail{height:min(68vh,700px);display:flex;flex-direction:column}

.sessions-detail .sd{display:flex;flex-direction:column;flex:1;min-height:0}

.sessions-detail .sd-msgs{flex:1;min-height:0;max-height:none;overflow-y:auto;padding-right:var(--sp-1)}


/* LLM 配置表单：桌面三列、窄屏单列 */
.llm-form{display:grid;grid-template-columns:minmax(240px,1fr) minmax(160px,220px) auto;gap:0 var(--sp-4);align-items:start}
@media (max-width:1023px) {
 .llm-form{grid-template-columns:1fr}
}
@media (max-width:1279px) {
 .sessions-grid{grid-template-columns:minmax(0,1fr)}
}
@media (max-width:767px) {

  .tab-toolbar{padding:var(--sp-3)}

  .cell-text{max-width:72vw}

  .funnel-label{width:76px;flex-basis:76px}

  .funnel-delta{width:auto}

  .sd{padding:var(--sp-3)}

  .sd-msgs{max-height:none}

  .session-list{max-height:none}

  .sessions-detail,
  .sessions-detail .sd{height:auto}
}


/* 移动端侧栏宽度：侧栏与渐隐层共用，避免两处数值漂移 */
:root{--drawer-w:min(84%, 340px); --drawer-gap:var(--sp-3)}


/* ============================================================================
   设计令牌 —— 全项目唯一的尺寸来源
   ----------------------------------------------------------------------------
   规则一：组件里禁止写裸数值。font-size / line-height / border-radius / gap
           一律引用 var(--fs-*) / var(--lh-*) / var(--r-*) / var(--sp-*)。
   规则二：加新尺寸前先看能不能复用现有档位；不能复用才加档，并在此登记。
   规则三：移动端差异集中在本文件末尾的 @media 里覆盖令牌，
           不要在 JSX 里写 isMobile ? a : b 这种三元。
   守护：scripts/check-tokens.sh 会拦住漏网的裸数值。
   ============================================================================ */
:root{
  /* ---- 字号：9 档，命名对齐 Tailwind 的 text-*，降低认知成本 ---- */
  /* 2026-10-11 视觉验收 P2-9：--fs-2xs 原为 11px，实测在 1x 屏上发糊，且低于 12px 的可读下限。
     11px 这个档位已取消，与 --fs-xs 合并 —— "徽标/免责声明"与"说明文字"的层级差改由颜色
     （--dim）与字重承担，不再靠字号。档位名字保留，避免全仓改引用。 */
  --fs-2xs:12px;   /* 徽标 / 免责声明 / 极次要元信息（与 --fs-xs 同尺寸，见上） */
  --fs-xs:12px;    /* 说明文字 / 图表标签 / 错误提示 */
  --fs-sm:13px;    /* 辅助文本 / 列表次级信息 */
  --fs-md:14px;    /* 紧凑正文（后台卡片标题） */
  --fs-base:16px;  /* 正文基准：阅读正文、输入框、UI 通用 */
  --fs-lg:17px;    /* 强调正文 / 小标题 */
  --fs-xl:19px;    /* 区块标题 / 大图标 */
  --fs-2xl:22px;   /* 页面标题 */
  --fs-3xl:24px;   /* 数据大字（KPI） */

  /* ---- 行高：4 档 ---- */
  --lh-tight:1.25;   /* 单行标题 */
  --lh-snug:1.4;     /* 紧凑多行 */
  --lh-normal:1.6;   /* 界面默认 */
  --lh-read:1.8;     /* 阅读正文（长回答） */

  /* ---- 圆角：4 档 ---- */
  --r-sm:4px;        /* 小控件、标签 */
  --r-md:8px;        /* 输入框、按钮 */
  --r-lg:12px;       /* 卡片、面板 */
  --r-full:999px;    /* 胶囊、头像 */

  /* ---- 间距：4px 基栅 + 半档。档位名 × 4 = 像素值（--sp-1-5 = 6px）。
     半档不是随手加的：2/6/10px 都在用（图标与文字之间的紧贴间距），
     硬凑到 4px 栅格会改变既有视觉密度。 */
  --sp-0-5:2px;
  --sp-1:4px;
  --sp-1-5:6px;
  --sp-2:8px;
  --sp-2-5:10px;
  --sp-3:12px;
  --sp-4:16px;
  --sp-5:20px;
  --sp-6:24px;
  --sp-8:32px;
  --ctl-xs:26px;      /* 行内微按钮（表格里紧贴文字） */
  --ctl-sm:30px;      /* 表格 / 工具条动作 */
  --ctl-md:34px;      /* 页面级动作（次级） */
  --ctl-lg:40px;      /* 主操作（与共享 .btn 一致） */
  --ctl-touch:44px;   /* 触屏最小触达 */
}
@media (max-width:767px) {

  :root{
    --fs-base:16.5px;
    --fs-2xl:19px;
    --fs-3xl:20px;
  }
}


/* 被推走的残片向右渐隐：推挤式在窄屏上必然裁断文字，硬切像"被砍一刀"，
   渐隐读起来像"退到背景"。color-mix 不支持时该声明整体失效，
   回退为纯色 var(--bg)（残片完全隐去），不会更差。 */
.drawer-fade{
  /* 从内容左缘起渐隐，不覆盖那条呼吸缝（缝里本来就是纯底色） */
  position:fixed;top:0;bottom:0;right:0;left:calc(var(--drawer-w) + var(--drawer-gap));z-index:89;
  pointer-events:none;
  background:var(--bg);
  background:linear-gradient(to right,color-mix(in srgb,var(--bg) 45%,transparent),var(--bg));
}


/* ============================================================================
   草图（sketch）——轻量示意图
   ----------------------------------------------------------------------------
   设计约束（来自需求对齐）：图只画骨架与重点。
   工期、成本、政策链接一律不进图——那是"报表感"的根源，它们属于正文。
   形态由模型按当轮内容组合：串行 / 分支 / 对比 + 旁注。
   ============================================================================ */
/* ============================================================================
   问卷（form）——把澄清问题做成可填写的表单
   ----------------------------------------------------------------------------
   用原生 input（radio/checkbox/text）而不是自绘控件：键盘、读屏、表单语义都是白送的。
   选项渲染成胶囊，视觉与草图一致，移动端好点。
   ============================================================================ */
/* 表单：紧凑优先、移动端优先。
   移动端单列，触控目标 44px 不缩水；宽屏让短选项自动分栏 ——
   否则一列排到底、右侧大片空白（截图里约 60% 宽度被浪费）。 */
.form-q{margin-top:var(--sp-3)}

.form-q:first-of-type{margin-top:var(--sp-2)}

/* 题号：让用户能对着说"第 3 题"，也便于扫读自己填到哪了。
   tabular-nums 让 1–9 与 10+ 的宽度一致，多题时左侧不会参差。 */
.form-q-num{color:var(--dim);margin-inline-end:var(--sp-1);font-variant-numeric:tabular-nums}

.form-q-label{font-size:var(--fs-sm);font-weight:600;margin-bottom:var(--sp-1)}

/* 表单里的两个文本控件**共用一条外观规则**。
   曾经各写一份，结果一处漏了 background：textarea 掉回全局的 textarea{--panel2}、
   number input 掉回浏览器默认白底 —— 同一张问卷里两个框长得不像一个组件（用户截图）。
   合并后只有"差异项"（min-height / resize）分开写，结构上不再可能漂移。 */
.form-input,.form-textarea{
  width:100%;box-sizing:border-box;border:1px solid var(--line);border-radius:var(--r-md);
  background:var(--bg);color:inherit;font-family:inherit;font-size:var(--fs-sm);
  padding:var(--sp-2) var(--sp-3);
}

.form-input{min-height:40px}

.form-textarea{min-height:72px;resize:vertical}

.form-input:focus-visible,.form-textarea:focus-visible{outline:2px solid var(--accent);outline-offset:1px}

/* 选项用**可见的**原生 radio / checkbox —— 这是 Web 表单的常识形态。
   之前把原生控件视觉隐藏、只用胶囊配色表达选中，用户看不出这是单选还是多选。 */
.form-opts{display:grid;grid-template-columns:1fr;gap:0}

.form-opt{display:flex;align-items:center;gap:var(--sp-2);min-height:44px;font-size:var(--fs-sm);cursor:pointer;padding:0 var(--sp-1);border-radius:var(--r-sm)}

.form-opt input{width:18px;height:18px;flex-shrink:0;margin:0;accent-color:var(--accent)}

.form-opt input:focus-visible{outline:2px solid var(--accent);outline-offset:2px}

.form-opt-done{cursor:default;color:var(--dim)}

.form-opt-done input{accent-color:var(--dim)}

.form-readonly{background:transparent;border-color:transparent}

/* 不铺满：通栏按钮在一个表单里视觉重量过大，与它的实际重要性不符 */
.form-submit{margin-top:var(--sp-3);width:auto;padding-inline:var(--sp-6);min-height:40px;border:0;border-radius:var(--r-md);background:var(--accent);color:var(--accent-fg);font-family:inherit;font-size:var(--fs-base);font-weight:600;cursor:pointer}

.form-submit:disabled{opacity:.45;cursor:not-allowed}
@media (min-width:600px) {

  .form-opts{grid-template-columns:repeat(auto-fit,minmax(200px,1fr));column-gap:var(--sp-4)}

  .form-opt{min-height:38px}
}

.form-done{font-size:var(--fs-2xs);color:var(--dim);margin-top:var(--sp-2)}

.form-ans{font-size:var(--fs-xs);color:var(--dim);margin-top:var(--sp-0-5)}



/* ============================================================================
   图型通用样式（flow / compare / applicability / risk）
   依 docs/diagram-primitives.md：一个组件只画一种图。
   ============================================================================ */
/* 卡片标题是标题不是正文：行高跟着正文的 1.75 走，会在卡片顶部多出半个行距，
   看起来"上内距比左右大"（对比卡实测：上 23px vs 左 18px）。
   .sk-title 早就是 --lh-tight，这里补齐，三张卡片的标题才一致。 */
.dg-title{font-size:var(--fs-base);font-weight:600;line-height:var(--lh-tight);margin-bottom:var(--sp-3)}


/* 版本不匹配时的兜底提示：宁可显示一行说明，也不让内容无声消失 */
.dg-stale{margin-top:var(--sp-3);padding:var(--sp-2) var(--sp-3);border:1px dashed var(--line);border-radius:var(--r-md);font-size:var(--fs-xs);color:var(--dim)}


/* ---- flow：有序步骤 ---- */
/* 序号列宽是连线定位的唯一基准：连线必须落在序号圆心。
   写死 16px 会与「序号 width/2 = 10px」差 6px —— 这个错我在草图那根竖线上犯过一次，
   这次又犯了，所以改成共用变量。 */
/* 竖线对齐：**不要逐段画线**。
   此前每步之间插一个固定 16px 高的 .dg-link —— 注定对不齐，原因有两个：
     ① 真实间距由行的内容高度决定（有无备注、文字几行），固定值对不上
     ② 步骤行用 align-items:baseline，圆心位置随文字基线漂移，不是常量
   现改为：每行画一条**覆盖整行**的竖线，且行与行**相接**（用 padding 不用 gap），
   相邻两行的线天然连成一条，**根本没有接缝**。
   首尾两行再裁到圆心 —— top 对齐后圆心 = padding-top + 圆半径，是常量。 */
/* --dg-num-mt 必须是变量：圆的 margin-top 决定圆心位置，而竖线端点由圆心算出。
   （写死 2px 会让线头比圆心高 2px —— 虽然被不透明的圆盖住看不出来，但账不对。） */
.dg-flow{list-style:none;margin:0;padding:0;--dg-num-w:20px;--dg-num-mt:2px;--dg-gap:var(--sp-2)}

.dg-step{position:relative;padding-block:var(--dg-gap)}

.dg-step::before{content:'';position:absolute;top:0;bottom:0;left:calc(var(--dg-num-w) / 2 - 1px);width:2px;background:var(--line)}

.dg-step:first-child::before{top:calc(var(--dg-gap) + var(--dg-num-mt) + var(--dg-num-w) / 2)}

.dg-step:last-child::before{bottom:auto;height:calc(var(--dg-gap) + var(--dg-num-mt) + var(--dg-num-w) / 2)}

/* 并行步骤：线画成虚线（不等待上一步），另有「可与上一步并行」文字兜底 */
.dg-step.dg-parallel::before{background:none;border-inline-start:2px dashed var(--line)}

/* 连线：从上一个步骤底部垂到本步骤顶部。并行时改虚线，与串行区分开 */
/* flex-start（原为 baseline）—— 圆心位置才是常量，竖线端点才可计算 */
.dg-step-head{display:flex;align-items:flex-start;gap:var(--sp-2)}

.dg-num{flex-shrink:0;width:var(--dg-num-w);height:var(--dg-num-w);border-radius:var(--r-full);background:var(--accent);color:var(--accent-fg);font-size:var(--fs-2xs);font-weight:600;line-height:1;display:inline-flex;align-items:center;justify-content:center;font-variant-numeric:tabular-nums;position:relative;z-index:1;margin-top:var(--dg-num-mt)}

.dg-step-label{font-size:var(--fs-base);font-weight:600}

.dg-duration{font-size:var(--fs-xs);color:var(--dim);margin-inline-start:auto;white-space:nowrap}

.dg-parallel-tag{font-size:var(--fs-2xs);color:var(--dim);margin:var(--sp-0-5) 0 0 calc(var(--dg-num-w) + var(--sp-2))}

.dg-step-note{font-size:var(--fs-sm);color:var(--dim);margin:var(--sp-0-5) 0 0 calc(var(--dg-num-w) + var(--sp-2));line-height:var(--lh-snug)}


/* ---- compare：选项 × 维度 ---- */
.dg-scroll{overflow-x:auto}

.dg-table{width:100%;border-collapse:collapse;font-size:var(--fs-sm)}

.dg-table th,.dg-table td{padding:var(--sp-2) var(--sp-2);text-align:start;vertical-align:top;border-bottom:1px solid var(--line);line-height:var(--lh-snug)}

.dg-table thead th{font-weight:600;border-bottom:1px solid var(--line)}

.dg-table tbody th{font-weight:500;color:var(--dim);white-space:nowrap}

/* best 只做强化：取值本身不同，不靠底色也能读 */
.dg-best{color:var(--accent);font-weight:600}


/* ---- applicability ---- */
.dg-list{list-style:none;margin:0;padding:0}

/* flex + duration 自动靠右：此前是普通块级，工期直接贴在标题后面
   （"税务信息确认与按期申报1天"），因为 margin-inline-start:auto 只在 flex 里生效 */
/* 刻意不画分隔线：每行上下各留 8px，行距本身就分得开；
   再加一条通栏线会把"清单"读成"表格"（用户要求移除）。 */
.dg-item{display:flex;align-items:baseline;flex-wrap:wrap;gap:0 var(--sp-2);padding:var(--sp-2) 0}

.dg-item-ok .dg-step-label::before{content:'✓ ';color:var(--accent)}


/* ---- risk ---- */
/* 与 .dg-item 同一条道理：行距已经分开了，通栏线只会把清单读成表格（用户要求移除） */
.dg-risk{display:flex;gap:var(--sp-2);padding:var(--sp-2) 0}

/* 等级用文字徽标而非只靠颜色，色盲用户也能读 */
.dg-level{flex-shrink:0;width:20px;height:20px;border-radius:var(--r-sm);font-size:var(--fs-2xs);font-weight:600;line-height:1;display:inline-flex;align-items:center;justify-content:center}

.dg-risk-high .dg-level{background:var(--red);color:#fff}

.dg-risk-medium .dg-level{background:var(--amber);color:#fff}

.dg-risk-low .dg-level{background:var(--track);color:var(--txt)}

.dg-risk-body{min-width:0}

.dg-risk-text{font-size:var(--fs-sm);line-height:var(--lh-snug)}

/* 规避方法与风险描述**同等重要**：同样字号、同样正文色。
   区分靠"规避"二字，不靠把内容缩小变灰 —— 那样等于告诉用户后者可以不看。 */
.dg-risk-fix{font-size:var(--fs-sm);color:var(--txt);margin-top:var(--sp-1);line-height:var(--lh-snug)}

.dg-risk-fix b{color:var(--accent);font-weight:600;margin-inline-end:var(--sp-1)}


/* ============================================================================
   决策分叉图（decision）
   ----------------------------------------------------------------------------
   几条**并列可选**的路。不画连接线 —— 竖干线是「顺序」的隐喻，
   而并列关系靠「编号 + 等权重卡片」表达。
   ============================================================================ */
/* 问句与卡片之间不画横线：卡片自带边框，中间再来一条是重复的边界（用户要求移除）。
   padding-bottom 保留 —— 那是间距，不是线。 */
.dc-question{font-size:var(--fs-base);font-weight:600;line-height:var(--lh-tight);padding-bottom:var(--sp-2)}

.dc-list{list-style:none;margin:var(--sp-3) 0 0;padding:0;display:flex;flex-direction:column;gap:var(--sp-2)}

.dc-card{display:flex;gap:var(--sp-3);align-items:flex-start;border:1px solid var(--line);border-radius:var(--r-md);padding:var(--sp-3)}

/* 编号是「并列」的信号：字母标记让三项读起来是 A/B/C 而不是第一步第二步 */
.dc-mark{flex-shrink:0;width:22px;height:22px;border-radius:var(--r-full);border:1px solid var(--line);font-size:var(--fs-2xs);font-weight:600;line-height:1;display:inline-flex;align-items:center;justify-content:center;color:var(--dim)}

.dc-body-text{min-width:0}

/* 选项 = 用户要选的那条，醒目；代价 = 后果，用正文色。
   **不做配色**：并列选项等权重，且配色既不可解码（无图例）又与文字重复。 */
.dc-when{font-size:var(--fs-base);font-weight:600;line-height:var(--lh-snug)}

.dc-then{font-size:var(--fs-sm);margin-top:var(--sp-0-5);line-height:var(--lh-snug);color:var(--dim)}


/* ============================================================================
   落地流程（竖向流程图）
   ----------------------------------------------------------------------------
   移动端优先：节点通栏、竖直连线。
   冗余设计——序号 ① 与连线同时表达顺序：即使连线在窄屏上不显眼，
   序号本身也能让用户立刻读懂先后关系。这是移动端流程图最重要的一条。
   ============================================================================ */
.flow{display:flex;flex-direction:column}

/* 结构化视图的统一外壳：所有图共用同一张卡片的边距/边框/底色 */
/* 一个回答有多个视图时的横向 snap 轮播（见 src/views.tsx）。
   为什么不用 Tabs：移动端实测 ① 控件自带下划线/间距，像外来的组件
   ② 标签多了被 antd 折叠成「…」下拉 ③ 切换时两屏高度不同导致页面跳动。
   轮播用原生滑动，且滚动容器高度取最高那屏 —— 切换不跳。 */
.vc{margin-top:var(--sp-4);margin-bottom:var(--sp-4)}

.vc-head{display:flex;align-items:center;gap:var(--sp-2);margin-bottom:var(--sp-2)}

.vc-dots{display:flex;align-items:center;flex-shrink:0}

/* 视觉圆点 8px，按钮撑到 28px 保证可点。主切换手段是滑动，圆点是次要入口 */
.vc-dot{width:28px;height:28px;padding:0;border:0;background:none;display:inline-flex;align-items:center;justify-content:center;cursor:pointer}

.vc-dot::before{content:'';width:8px;height:8px;border-radius:var(--r-full);background:var(--line)}

.vc-dot[aria-current="true"]::before{background:var(--accent)}

.vc-dot:focus-visible{outline:2px solid var(--accent);outline-offset:-2px;border-radius:var(--r-full)}

/* 裁剪框：高度由组件按当前屏设置（跟随内容），使短图下方不留空白。
   非当前屏在屏幕外，超出部分被裁掉不影响观感。 */
.vc-clip{overflow:hidden;transition:height .18s ease;position:relative}

/* 非触屏的左右导航，放在标题行右侧。
   **不做两侧悬浮** —— 那会盖住卡片右端的工期文字（实测挡住了「40 天」的末位）。
   **触屏设备不渲染**：媒体查询判定"有鼠标/触控板"，比 JS 检测触屏可靠。 */
.vc-navs{display:none;gap:var(--sp-1);flex-shrink:0;margin-inline-start:auto}
@media (hover: hover) and (pointer: fine) {

  .vc-navs{display:inline-flex}

  .vc-nav{
    display:inline-flex;align-items:center;justify-content:center;
    width:24px;height:24px;padding:0;cursor:pointer;
    border:1px solid var(--line);border-radius:var(--r-full);
    background:var(--panel);color:var(--txt);
  }

  .vc-nav:disabled{opacity:.35;cursor:default}
}

/* 箭头用 CSS 画：右下两条边框旋转 45°。‹ › 这类字形与 ⌃ ⌄ 一样大小不一 */
.vc-nav::before{content:'';display:block;width:7px;height:7px;border-right:2px solid currentColor;border-bottom:2px solid currentColor}

.vc-prev::before{transform:rotate(135deg) translate(-1px,-1px)}

.vc-next::before{transform:rotate(-45deg) translate(-1px,-1px)}
@media (prefers-reduced-motion: reduce) {
.vc-clip{transition:none}
}

/* align-items:flex-start —— 让每屏取自然高度，不被最高的那屏拉伸 */
.vc-track{display:flex;align-items:flex-start;overflow-x:auto;scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch;scrollbar-width:none}

.vc-track::-webkit-scrollbar{display:none}

.vc-slide{flex:0 0 100%;min-width:0;scroll-snap-align:start}

/* 每屏内的卡片不再叠间距，否则屏底会多出一截空白 */
.vc-slide .panel-card{margin-top:0;margin-bottom:0}


/* 下边距是必要的：卡片后面常紧跟正文，贴在一起会读成同一块内容 */
.panel-card{
  margin-top:var(--sp-4);margin-bottom:var(--sp-4);
  border:1px solid var(--line);border-radius:var(--r-lg);background:var(--panel);
  /* 四边同值：原来是 12/16，上下的"硬边"元素（按钮）看着比左右紧 */
  padding:var(--sp-4);
}

/* 首行文字自带约 2px 的行高留白（16px × 1.25 行高的半行距），
   从外边距里扣掉，视觉四边才真的一样（实测 17.5 / 17.5 / 17）。 */
.panel-card > :first-child{margin-top:calc(-1 * var(--sp-0-5))}

.panel-card > :last-child{margin-bottom:0}

/* 卡片是所在容器的首/末元素时不留外边距。
   实测（对话里的表单卡）：气泡上沿→标题墨迹 35px，而左沿→墨迹只有 17px ——
   多出来的 16px 就是这条 margin-top（卡片和气泡同色，看不出来源，只觉得"上边距大"）。 */
.panel-card:first-child{margin-top:0}

.panel-card:last-child{margin-bottom:0}

/* 标题不需要 1.6 的行高：16px × 1.6 = 25.6，上下各留 ~5px 空白，
   顶部就比左右多出半个行距，四边看起来不等距。 */
.sk-title{line-height:var(--lh-tight)}

.flow-node{border:1px solid var(--line);border-radius:var(--r-md);background:var(--bg);padding:var(--sp-2) var(--sp-3)}

.flow-node-head{display:flex;align-items:baseline;gap:var(--sp-2);flex-wrap:wrap}

.flow-seq{flex-shrink:0;width:19px;height:19px;border-radius:var(--r-full);background:var(--accent);color:var(--accent-fg);font-size:var(--fs-2xs);font-weight:600;line-height:1;display:inline-flex;align-items:center;justify-content:center}

.flow-title{font-size:var(--fs-base);font-weight:600}

.flow-day{font-size:var(--fs-2xs);color:var(--dim);margin-inline-start:auto;white-space:nowrap}

.flow-meta{font-size:var(--fs-2xs);color:var(--dim);margin-top:var(--sp-0-5)}

/* 不要在文字上叠 opacity：会把本已偏浅的次级色再压一档，直接跌出对比度要求 */
.flow-summary{font-size:var(--fs-sm);margin-top:var(--sp-1);line-height:var(--lh-snug)}

.flow-links{display:flex;flex-wrap:wrap;gap:0 var(--sp-3);margin-top:var(--sp-1)}

.flow-links a{font-size:var(--fs-2xs);color:var(--accent)}

/* 连线：一根竖线 + 底部箭头。用伪元素而非嵌套 SVG，省一层 DOM */
.flow-link{position:relative;height:26px;display:flex;justify-content:center}

.flow-link::before{content:'';width:1px;height:100%;background:var(--line)}

.flow-link::after{content:'';position:absolute;bottom:0;left:50%;transform:translateX(-50%);border-inline:4px solid transparent;border-top:5px solid var(--line)}

/* 终点：两侧横线夹住文字 */
.flow-done{display:flex;align-items:center;gap:var(--sp-3);margin:var(--sp-2) 0}

.flow-done::before,.flow-done::after{content:'';flex:1;height:1px;background:var(--line)}

.flow-done span{font-size:var(--fs-xs);font-weight:600;color:var(--accent);white-space:nowrap}

/* 非阻塞项：横向小胶囊，不占流程主线 */
.flow-later{display:flex;flex-wrap:wrap;gap:var(--sp-1) var(--sp-2);margin-top:var(--sp-1)}

.flow-chip{font-size:var(--fs-2xs);color:var(--dim);border:1px solid var(--line);border-radius:var(--r-full);padding:var(--sp-0-5) var(--sp-2)}

.flow-head{display:flex;align-items:baseline;gap:var(--sp-3);flex-wrap:wrap;margin-top:var(--sp-2)}

.flow-head b{font-size:var(--fs-xl);font-weight:600}

.flow-head span{font-size:var(--fs-2xs);color:var(--dim);margin-inline-start:4px}


/* 侧栏底部：激活状态（激活码 + 今日积分，不展示金额） */
.side-access{
  border-top:1px solid var(--line);
  padding:var(--sp-2) var(--sp-4) var(--sp-2-5);
  display:flex;flex-direction:column;gap:var(--sp-1);
}

.side-access-row{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-2);min-width:0}

.side-access-label{font-size:var(--fs-2xs);color:var(--dim);flex-shrink:0}

/* 本文件由"按面拆分 CSS"生成（2026-10-11 monorepo 拆分），逐字节保留原格式。
   归属规则：只被 ui 包用到的规则归本包；被两个以上包用到、或扫不到引用的历史遗留
   （动态拼出来的类名扫不到）、以及含全局选择器（body、html、星号、:root…）的规则统一留在 ui 层。
   改样式时先看"这条规则谁在用"，再决定写进哪个包。 */


.os-shell.as-console .console-wrap { display: flex; flex-direction: column; min-height: 0; }

.os-shell.as-console .console-grid { flex: 1; min-height: 0; align-items: stretch; }

/* 高度约束必须**从网格项一路传到时间线**，中间断一层就会按内容撑开
   （实测踩过两次：网格项其实是 section.panel，.col-main 在它里面；且 grid 默认 align-items:start）。 */
.os-shell.as-console .console-grid > section { display: flex; flex-direction: column; min-height: 0; overflow: hidden; }

.os-shell.as-console .col-main { flex: 1; min-height: 0; overflow: hidden; }

.os-shell.as-console .col-main .timeline { flex: 1; min-height: 0; max-height: none; overflow-y: auto; }

.os-topbar { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-5) 0 var(--sp-5);
  /* 2026-10-09 用户要求：头部升级为固定 Header（滚动时导航与"维修间"始终在手边）。

     2026-10-10 用户报"进入固定状态时跳一下" —— 实测根因**不是高度**，而是**盒子起点**：
       body 有 padding-top:24px，所以静止时 header 的盒子是 y=24..112（88 高）， 一滚动到 y=0 就贴顶固定；视觉上就是上方那 var(--sp-6) 在贴顶瞬间被"吞掉"。 修法：把这 var(--sp-6) **收进 header 自己的盒子**（负 margin 抵消 body 的 padding，再补进 padding-top）。 于是盒子从 y=0 开始、高 112，静止与固定**是同一个盒子**，从头到尾没有任何位移。 副作用（也是收益）：margin-box 仍是 20+24+48+20=88，控制台那套 100dvh 布局的流量不变， 而 `height:100dvh` 不再被 body 的 var(--sp-6) padding 顶出去 —— 这就是之前量到的 48px 页面级溢出的来源。 */ margin-top: calc(-1 * var(--page-pad-y)); padding-top: calc(20px + var(--page-pad-y));
  position: sticky; top: 0; z-index: 30; background: var(--bg); }

.os-topbar::after { content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 1px; background: var(--line); }

.os-topbar .brand { display: flex; align-items: center; gap: var(--sp-2-5); text-decoration: none; color: var(--txt); min-height: 44px; }

.os-topbar .brand strong { font-size: var(--fs-lg); letter-spacing: .2px; }

.os-topbar .brand span { color: var(--dim); font-size: var(--fs-sm); }

.os-topbar .spacer { flex: 1; }


.code-block { position: relative; background: var(--bg); border: 1px solid var(--line); border-radius: var(--r-md); padding: var(--sp-3) 44px var(--sp-3) var(--sp-3); font-family: var(--font-mono); font-size: var(--fs-sm); overflow-x: auto; }

.code-block code { white-space: pre; color: var(--accent-ink); }

[data-theme="dark"] .code-block code { color: var(--accent); }

/* 窄屏让命令**换行**，而不是横向滚动（2026-10-11 视觉验收 P1-5）。
   为什么不能靠 .code-block 的 padding-right 给按钮留位置：那是**滚动内容末尾**的内距，
   scrollLeft=0 时完全不起作用 —— 绝对定位的 .copy-btn 会直接压在第一屏的命令文本上
   （线上实测 390px：容器内容宽 282px、文本 408px，"ops.spark-studio.cn/c" 那一段被按钮盖住）。
   改成 pre-wrap 后容器不再横向溢出，右侧那 44px 内距才真的成为按钮的专用空档。 */
@media (max-width: 860px) {
  .code-block code { display: block; white-space: pre-wrap; overflow-wrap: anywhere; }
}

.copy-btn { position: absolute; top: 6px; right: 6px; width: 32px; height: 32px; display: inline-flex; align-items: center; justify-content: center; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--panel2); color: var(--dim); cursor: pointer; transition: color .2s ease, background .2s ease, border-color .2s ease; }

.copy-btn:hover { color: var(--txt); border-color: var(--accent); }

.copy-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }


.section { margin-top: 40px; }

.section > h2 { font-size: var(--fs-xl); margin-bottom: var(--sp-2); }

.section > p.sub { color: var(--dim); font-size: var(--fs-sm); margin-bottom: var(--sp-4); }

.hm-row { display: flex; flex-direction: column; gap: var(--sp-1-5); }

.hm-k { color: var(--dim); font-size: var(--fs-xs); }

.hm-item.danger { color: var(--red); }

.hm-item.danger:hover { border-color: var(--red); }

@keyframes ros-pulse { 0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 45%, transparent); } 70% { box-shadow: 0 0 0 8px transparent; } 100% { box-shadow: 0 0 0 0 transparent; } }

/* 「↓ 回到最新」：自动跟随被用户上翻关掉后的出口（2026-10-10 用户要求"一键到达底部"）。
   定位容器包在滚动区**外面**，否则按钮会跟着内容滚走。
   ⚠️ 这个容器必须**在布局上透明**：时间线的高度本来由
   `.os-shell.as-console .col-main .timeline { flex: 1; min-height: 0 }` 决定（受控高度 → 内部滚动）；
   中间插一层普通 block，时间线就会退回"内容高度"（实测 10369px），
   然后被 `.os-shell` 的 overflow:hidden 整段裁掉、滚不动，而且页面看起来只有 800px 高。
   所以 wrapper 要接手同一套 flex 尺寸，让时间线在它内部继续 flex。 */
.timeline-wrap, .drawer-timeline-wrap { position: relative; display: flex; flex-direction: column; min-height: 0; }

.os-shell.as-console .col-main .timeline-wrap { flex: 1; min-height: 0; }

.jump-bottom { position: absolute; right: 14px; bottom: 12px; z-index: 6;
  display: inline-flex; align-items: center; gap: var(--sp-1); padding: var(--sp-1-5) var(--sp-3);
  border-radius: var(--r-full); border: 1px solid var(--line); background: var(--panel2);
  color: var(--txt); font-size: var(--fs-sm); cursor: pointer;
  box-shadow: 0 6px 18px color-mix(in srgb, black 30%, transparent); }

.jump-bottom:hover { border-color: var(--accent); color: var(--accent); }

.jump-bottom:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

button.proc-wait { cursor: pointer; transition: background .15s ease; text-align: left; }

button.proc-wait:hover { background: color-mix(in srgb, var(--amber) 18%, transparent); }

button.proc-wait:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }


/* 阶段条：只有 Agent 产出 final 诊断报告后才渲染 */
.phase-bar { border: 1px solid var(--accent); background: color-mix(in srgb, var(--accent) 8%, transparent); border-radius: var(--r-lg); padding: var(--sp-3) 14px; }

.phase-bar.repair { border-color: var(--amber); background: color-mix(in srgb, var(--amber) 10%, transparent); }

.phase-text { color: var(--txt-body); font-size: var(--fs-sm); line-height: 1.65; }

.dt-row.err .dt-body { color: var(--red); }

/* 策略 chip（枚举值 + 箭头）：不写"审批策略"四个字 —— 枚举本身就说明了它是什么 */
.cm-chip { display: inline-flex; align-items: center; height: 28px; padding: 0 var(--sp-2-5);
  border: 1px solid var(--line); border-radius: var(--r-md); background: transparent;
  color: var(--dim); font-size: var(--fs-sm); cursor: pointer; white-space: nowrap; }

.cm-chip:hover:not(:disabled) { background: var(--panel2); color: var(--txt); }

.cm-chip[aria-expanded="true"], .cm-chip.active { color: var(--txt); border-color: var(--accent); }

.cm-chip:disabled { opacity: .5; cursor: not-allowed; }
@media (max-width: 1023px) {

  .os-shell.as-console .console-grid { grid-template-columns: minmax(0, 1fr); align-items: start; }

  .os-shell.as-console .console-grid > section { overflow: visible; }

  .os-shell.as-console .col-main { overflow: visible; }

  /* 过程区高度上限按"行动区必须留在首屏"倒推：手机上一屏 844px 里，
     身份带 96 + 过程区标题/摘要/阶段约 130 + 行动区（提示+阶段条+输入坞）约 410，
     留给时间线的就是 ~45% 视口高。上限给死了，行动区的主动作才不会被顶出首屏。 */
  .os-shell.as-console .col-main .timeline { flex: none; min-height: 240px; max-height: 45vh; overflow-y: auto; }

  /* 窄屏下由**页面**滚动，wrapper 不能再抢 flex 高度（否则又会把内容压进内部滚动） */
  .os-shell.as-console .col-main .timeline-wrap { flex: none; min-height: 0; }
}


.panel-title { font-size: var(--fs-sm); color: var(--dim); text-transform: uppercase; letter-spacing: .06em; margin-bottom: var(--sp-2-5); }

.countdown.warn { color: var(--amber); }


/* 面板标题是大写化的小标签，但人名/专名不能被折成 VERA 这种样子 */
.no-caps { text-transform: none; letter-spacing: 0; }

@keyframes ros-blink { 0%, 60%, 100% { opacity: .25; } 30% { opacity: 1; } }

.cmd-head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); padding: var(--sp-2-5) var(--sp-3); background: var(--panel2); border-bottom: 1px solid var(--line); }

.cmd-head .cmd-id { font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--dim); }

.cmd-head .spacer { flex: 1; }

.cmd-rationale { color: var(--dim); font-size: var(--fs-sm); }

.cmd-fact.sub .cf-v { color: var(--txt-body); }

.cmd-meta { display: flex; flex-wrap: wrap; gap: var(--sp-3); color: var(--dim); font-size: var(--fs-xs); font-family: var(--font-mono); }

.btn { display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-1-5); min-height: 40px; padding: 0 var(--sp-4); border-radius: var(--r-md); border: 1px solid var(--line); background: var(--panel2); color: var(--txt); font-size: var(--fs-sm); font-weight: 600; cursor: pointer; transition: background .2s ease, border-color .2s ease, opacity .2s ease; }

.btn:hover { border-color: var(--accent); }

.btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.btn:disabled { opacity: .5; cursor: not-allowed; }

.btn.primary { background: var(--accent); color: var(--accent-fg); border-color: var(--accent); }

.btn.danger { color: var(--red); border-color: color-mix(in srgb, var(--red) 55%, transparent); }

.btn.danger:hover { background: color-mix(in srgb, var(--red) 12%, transparent); border-color: var(--red); }

.btn.ghost { background: transparent; }


/* 内容卡 = **一份配方**（2026-10 内容区统一）。
   此前同一个控制台里并存四种卡片：.panel(20px/--r-lg)、.app-block(14px/--r-md)、
   .app-card(12px14px/--r-md)、.ws-stat(12px14px/--r-md) —— 同屏三张卡三种圆角与内距。
   现在底面/描边/圆角/内距只此一条，其余四个类名都是它的别名（各面仍用自己语义化的名字）。
   **不给 margin**：卡片间距归内容区页容器 .app-page 的 gap 管，卡片自己带 margin 会叠成两倍。 */
.side-card, .panel, .app-block, .app-card, .ws-stat, .stat {
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-lg); padding: var(--sp-4); }

.approve-card .panel-title { display: flex; align-items: center; gap: var(--sp-2); }

.accept-card.done .panel-title { color: var(--txt); }

/* 输入坞里的异常态提示（#9 · A）：额度常驻右栏，这里只在"不能继续"时说话。 */
/* 右栏额度：数字 + 进度条（用户 2026-10-09「做成进度条」） */
/* ⚠️ 必须写成 `.side-card .kv.quota-row`（而不是 `.side-card .quota-row`）：
   额度行同时带 `kv` 类，而 `.side-card .kv { display:flex }` 在同优先级下**写得更靠后**，
   于是会赢 —— 实测结果就是进度条轨道宽度 **0px**（彩色填充全在 0 宽里，用户完全看不见）。 */
.side-card .kv.quota-row { display: grid; grid-template-columns: 3.4em minmax(40px, 1fr) auto; align-items: center; gap: var(--sp-2-5); }

.dv-acts .btn { min-height: 32px; }

.side-card .kv { display: flex; justify-content: space-between; gap: var(--sp-2-5); padding: var(--sp-1-5) 0; font-size: var(--fs-sm); border-bottom: 1px dashed var(--line); }

.side-card .kv:last-child { border-bottom: none; }

/* 可点击的 kv 行（概览里的「会话总数 / 当前在线」） */
.side-card button.kv { width: 100%; background: transparent; border: 0; border-bottom: 1px dashed var(--line); color: inherit; font: inherit; text-align: left; cursor: pointer; }

.side-card button.kv:last-child { border-bottom: none; }

.side-card button.kv:hover { color: var(--accent); }

.side-card button.kv:hover .v { color: var(--accent); }

.side-card button.kv:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.side-card .kv .k { color: var(--dim); }

.side-card .kv .v { font-family: var(--font-mono); text-align: right; word-break: break-all; }

.field { display: flex; flex-direction: column; gap: var(--sp-1-5); margin-top: var(--sp-2-5); }

.field label { font-size: var(--fs-xs); color: var(--dim); }

.field input, .field textarea, .field select { background: var(--panel2); border: 1px solid var(--line); border-radius: var(--r-md); color: var(--txt); padding: var(--sp-2-5) var(--sp-3); font-size: var(--fs-sm); font-family: var(--font-sans); width: 100%; }

/* 表单控件的状态：后台真的会禁用输入框（只读会话），此前没有 disabled 样式、也没有 hover */
.field input:hover:not(:disabled), .field textarea:hover:not(:disabled), .field select:hover:not(:disabled) { border-color: color-mix(in srgb, var(--accent) 40%, var(--line)); }

.field input:focus-visible, .field textarea:focus-visible, .field select:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

.field input:disabled, .field textarea:disabled, .field select:disabled { color: var(--dim); background: color-mix(in srgb, var(--panel2) 60%, var(--bg)); cursor: not-allowed; }

.field textarea { font-family: var(--font-mono); resize: vertical; min-height: 76px; }

@keyframes ros-spin { to { transform: rotate(360deg); } }

.offline-note .btn { min-height: 32px; }


/* .code-num 已随会话详情里的「手动输入接入码」面板删除（2026-10-13）：
   那是它唯一的使用者（放大的 6 位接入码）。 */

/* ---------- 换码动效：逐字替换（用户 2026-10-13）----------
   "旧码无规则渐次消失、新码逐步替换"。每个位置一个槽，旧字与新字可以同时在（旧字绝对定位压住新字），
   两边各带一个**随机**延时（延时由 CopyCode 按 text 记忆，见那里的 useRevealDelays）。
   只用 opacity + 一点点位移/缩放：这几个属性走合成层，不动布局 —— 6 个字逐个换时不会把盒子撑跳。 */
.rv-slot { position: relative; display: inline-block; }

/* 旧字压在槽位上，且**不许被选中** —— 动效那半秒里手动选码会连它一起选走，
   拿到的就是"旧+新"拼接的 12 位（复制按钮走的是 text 属性，不受影响）。 */
.rv-old { position: absolute; inset: 0; user-select: none; animation: rv-out .26s ease both; }

.rv-new { display: inline-block; animation: rv-in .3s ease both; }

@keyframes rv-out {
  to { opacity: 0; transform: translateY(-.22em) scale(.84); }
}

@keyframes rv-in {
  from { opacity: 0; transform: translateY(.22em) scale(.84); }
}

/* 减少动效：直接切换（保留"换过了"这个事实，但不做逐字演出） */
@media (prefers-reduced-motion: reduce) {
  .rv-old, .rv-new { animation: none; }
  .rv-old { display: none; }
}

/* 自研下拉：原生 select 的弹层由系统绘制，暗色下不可控 */
.sel { position: relative; width: 100%; }

.sel-btn { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); width: 100%; min-height: 40px; padding: 0 var(--sp-2-5) 0 var(--sp-3); background: var(--panel2); border: 1px solid var(--line); border-radius: var(--r-md); color: var(--txt); font-size: var(--fs-sm); font-family: var(--font-sans); cursor: pointer; }

.sel-btn:hover { border-color: var(--accent); }

.sel-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.sel-btn:disabled { opacity: .5; cursor: not-allowed; }

.sel-btn .sel-val { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.sel-btn .sel-caret { color: var(--dim); flex-shrink: 0; }

.sel-pop { position: absolute; z-index: 30; top: calc(100% + 4px); left: 0; min-width: 100%; max-height: 260px; overflow: auto; margin: 0; padding: var(--sp-1); list-style: none; background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-md); box-shadow: 0 12px 32px color-mix(in srgb, black 35%, transparent); }

.sel-opt { padding: var(--sp-2) var(--sp-2-5); border-radius: var(--r-sm); font-size: var(--fs-sm); color: var(--txt); cursor: pointer; white-space: nowrap; }

.sel-opt.is-active { background: var(--panel2); }

.sel-opt.is-on { color: var(--accent); font-weight: 600; }

/* chip 变体：输入坞底行里的紧凑下拉（定宽、28px，弹层向上开 —— 它在页面底部） */
.sel-as-chip { width: auto; }

.sel-as-chip .sel-btn { width: auto; min-height: 28px; height: 28px; padding: 0 var(--sp-2) 0 var(--sp-2-5); gap: var(--sp-1-5);
  background: transparent; color: var(--dim); font-size: var(--fs-sm); }

.sel-as-chip .sel-btn:hover:not(:disabled) { background: var(--panel2); color: var(--txt); border-color: var(--line); }

.sel-as-chip .sel-btn[aria-expanded="true"] { color: var(--txt); border-color: var(--accent); }

.sel-as-chip .sel-pop { top: auto; bottom: calc(100% + 8px); min-width: 260px; }

.sel-as-chip .sel-opt { padding: var(--sp-2) var(--sp-2-5); }

.sel-as-chip .sel-hint { display: block; margin-top: var(--sp-0-5); color: var(--dim); font-size: var(--fs-xs); white-space: normal; }


/* 状态标签 */
.tag { display: inline-flex; align-items: center; gap: var(--sp-1); font-size: var(--fs-xs); line-height: 1; padding: var(--sp-1) var(--sp-2-5); border-radius: var(--r-full); border: 1px solid var(--line); color: var(--dim); white-space: nowrap; }

.tag.ok { color: var(--accent-ink); border-color: color-mix(in srgb, var(--accent) 50%, transparent); }

[data-theme="dark"] .tag.ok { color: var(--accent); }

.tag.warn { color: var(--amber); border-color: color-mix(in srgb, var(--amber) 50%, transparent); }

.tag.danger { color: var(--red); border-color: color-mix(in srgb, var(--red) 55%, transparent); }

.tag.off { color: var(--dim); }

/* 内联反馈：紧贴触发它的控件（App 与 Admin 共用；此前只在 App 包里定义，后台拿不到样式） */
.inline-msg { display: inline-flex; align-items: center; gap: var(--sp-1-5); font-size: var(--fs-sm); line-height: 1.4; }

.inline-msg.ok { color: var(--accent-ink); }

[data-theme="dark"] .inline-msg.ok { color: var(--accent); }

.inline-msg.err { color: var(--red); }

.inline-msg.info { color: var(--dim); }

/* 仅供读屏的文本：共享组件（如 CopyCode 的复制反馈）依赖它 */
.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; }

@keyframes caret-blink { 0%, 100% { opacity: 1; } 50% { opacity: 0; } }


/* Agent 消息的 Markdown 渲染 */
.md { font-size: var(--fs-sm); line-height: 1.75; }

.md-p { margin: 0 0 var(--sp-2); }

.md-p:last-child { margin-bottom: 0; }

.md-h { font-size: var(--fs-base); font-weight: 600; margin: var(--sp-3) 0 var(--sp-1-5); }

.md-ul, .md-ol { margin: var(--sp-1-5) 0 var(--sp-2-5); padding-left: var(--sp-5); }

.md-ul { list-style: disc; }

.md-ol { list-style: decimal; }

.md-ul li, .md-ol li { margin: 3px 0; }

.md-pre { background: var(--bg); border: 1px solid var(--line); border-radius: var(--r-sm); padding: var(--sp-2-5); overflow-x: auto; margin: var(--sp-2) 0; }

/* ⚠️ `display:block` 必须有：`<code>` 默认是 inline，而它的子元素 `.md-line` 是 block。
   inline 盒里放 block 子元素会生成"匿名块盒"，于是 code 自己撑出一整个行盒 ——
   实测内容上下各多出 21px 空白（code 盒 145px，实际 5 行只有 105px），
   视觉上就是首行上方、末行下方各一块空槽（用户 2026-10-10 圈出的两个方块）。 */
.md-pre code { display: block; font-size: var(--fs-xs); white-space: pre; background: none; padding: 0; }

/* ── 表格（2026-10-10：GFM 表格支持）───────────────────────────────────────
   诊断报告里最常用的表达就是"字段 | 值 | 说明"。窄屏允许横向滚动，
   而不是把表格压成一行字。 */
.md-table-wrap { overflow-x: auto; margin: var(--sp-2-5) 0; }

.md-table { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); }

.md-table th, .md-table td { border: 1px solid var(--line); padding: var(--sp-1-5) var(--sp-2-5); text-align: left; vertical-align: top; line-height: 1.55; }

.md-table thead th { background: var(--panel2); color: var(--txt); font-weight: 600; white-space: nowrap; }

.md-table tbody tr:nth-child(even) { background: color-mix(in srgb, var(--panel2) 45%, transparent); }

.md-table code, .md-p code, .md-ul code, .md-ol code, .md-quote code {
  font-size: var(--fs-xs); background: var(--panel2); border: 1px solid var(--line);
  border-radius: var(--r-sm); padding: 1px 5px; white-space: nowrap; }


/* ── 代码块：语言标签 + 行号 + 高亮 ─────────────────────────────────────── */
.md-code { border: 1px solid var(--line); border-radius: var(--r-sm); overflow: hidden; margin: var(--sp-2-5) 0; background: var(--code-bg); }

.md-code-head { display: flex; align-items: center; justify-content: space-between; padding: var(--sp-1) var(--sp-2-5);
  border-bottom: 1px solid var(--line); background: var(--panel2); }

.md-lang { font-size: var(--fs-xs); color: var(--dim); letter-spacing: .04em; }

.md-code .md-pre { margin: 0; border: 0; border-radius: 0; background: none; padding: var(--sp-1-5) 0; }

.md-line { display: block; white-space: pre; min-height: 1.5em; }

.md-line:hover { background: color-mix(in srgb, var(--panel2) 55%, transparent); }

/* 行号不可选中：复制代码时不该把行号带走 */
.md-ln { display: inline-block; width: 3.4em; padding-right: var(--sp-3); text-align: right;
  color: var(--dim); opacity: .55; user-select: none; -webkit-user-select: none; }

.md-lc { white-space: pre; }

.tk-c { color: var(--tk-c); font-style: italic; }

.tk-s { color: var(--tk-s); }

.tk-k { color: var(--tk-k); }

.tk-n { color: var(--tk-n); }

.tk-v { color: var(--tk-v); }

.tk-key { color: var(--tk-key); }

.tk-tag { color: var(--tk-tag); }

.tk-sec { color: var(--tk-sec); font-weight: 600; }

.tk-flag { color: var(--tk-flag); }

.tk-punct { color: var(--tk-punct); }

.tk-hunk { color: var(--tk-hunk); }

.tk-add { color: var(--tk-add); }

.tk-del { color: var(--tk-del); }

.md-quote { border-left: 3px solid var(--line); padding-left: var(--sp-2-5); color: var(--dim); margin: var(--sp-2) 0; }

.md-hr { border: 0; border-top: 1px solid var(--line); margin: var(--sp-3) 0; }

.md code { background: var(--panel2); padding: 1px 5px; border-radius: var(--r-sm); font-size: .92em; }

.md a { color: var(--accent-ink); }

[data-theme="dark"] .md a { color: var(--accent); }


/* 确认弹窗（危险操作二次确认） */
.modal-mask { position: fixed; inset: 0; background: color-mix(in srgb, black 55%, transparent); display: flex; align-items: center; justify-content: center; padding: var(--sp-5); z-index: 200; }

.modal-box { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-lg); padding: var(--sp-5); width: min(560px, 100%); max-height: 82vh; overflow: auto; box-shadow: 0 24px 64px color-mix(in srgb, black 45%, transparent); }

.modal-title { font-size: var(--fs-lg); margin-bottom: var(--sp-2-5); }

.modal-body { color: var(--txt-body); font-size: var(--fs-sm); line-height: 1.75; }

.modal-body .kv { margin: var(--sp-1-5) 0; }

.modal-actions { display: flex; justify-content: flex-end; gap: var(--sp-2-5); margin-top: 18px; }


.danger-note { color: var(--red); font-size: var(--fs-sm); }

.muted { color: var(--dim); }

.mono { font-family: var(--font-mono); }

.row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2-5); }

/* .spacer 默认也是 flex:1，会把命令摘要挤成两个字符（实测出现过 "l's"）——这里必须让它不可伸张 */
.cmd-sum .spacer { flex: 0 0 8px; }


/* ============ 消息卡片体系 ============
   规则来自 design-system/recoveryos/MASTER.md：
   只用既有 token（--panel/--line/--accent/--amber/--red），层次靠 elevation 而不是随手换边框色。
   每一类消息 = 一种表面 + 一条左轨色 + 一个角色标签，扫一眼就能分清"谁在说话、要不要我做事"。 */
:root {
  --e1: 0 1px 2px color-mix(in srgb, black 20%, transparent);
  --e2: 0 8px 24px color-mix(in srgb, black 26%, transparent);
}

.tl-msg { border: 1px solid var(--line); border-left: 3px solid var(--line); border-radius: var(--r-md); background: var(--panel); padding: var(--sp-2-5) 14px; }

/* 提示：低一层，靠左轨色区分种类 */
/* 提示卡：标签与正文同行，单行提示不该占 100px（截图实测过） */
.tl-msg.notice { background: transparent; color: var(--txt-body); padding: var(--sp-2) var(--sp-3); }

.tl-msg.sys { padding: 0; }

.tl-msg.notice.consent-approved { border-left-color: var(--accent); }

.tl-msg.notice.consent-denied, .tl-msg.notice.stop-blocked { border-left-color: var(--red); }

/* 错误：danger 表面 + danger 左轨 */
.tl-msg.error { border-left-color: var(--red); background: color-mix(in srgb, var(--red) 7%, transparent); color: var(--red); }

/* 系统：无卡片，居中细字 */
.tl-msg.sys { border: 0; background: none; text-align: center; color: var(--dim); font-size: var(--fs-xs); padding: var(--sp-0-5) 0; }


/* ============ 剩余次数（额度）============
   无障碍要求（ui-ux-pro-max: Contextual Live Badge Updates）：
   要播报带上下文的整句，而不是光秃秃一个数字。 */
.quota { display: flex; gap: 14px; align-items: center; flex-wrap: wrap; padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--line); border-radius: var(--r-md); background: var(--panel); }

.quota-item { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-sm); }

.quota-k { color: var(--dim); }

.quota-v { font-family: var(--font-mono); font-size: var(--fs-base); font-weight: 600; }

.quota-v em { font-style: normal; color: var(--dim); font-weight: 400; font-size: var(--fs-sm); }

.quota-bar { width: 54px; height: 5px; border-radius: var(--r-full); background: var(--panel2); overflow: hidden; }

.quota-bar i { display: block; height: 100%; background: var(--accent); }

.quota-item.diag .quota-bar i { background: var(--accent); }

.quota-item.diag .quota-v { color: var(--accent-ink); }

[data-theme="dark"] .quota-item.diag .quota-v { color: var(--accent); }

.quota-item.repair .quota-bar i { background: var(--amber); }

.quota-item.repair .quota-v { color: var(--amber); }

.quota-item.zero .quota-v { color: var(--red); }

@keyframes ro-ring {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 34%, transparent), 0 0 16px 0 color-mix(in srgb, var(--accent) 16%, transparent); }
  50% { box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 20%, transparent), 0 0 32px 7px color-mix(in srgb, var(--accent) 26%, transparent); }
}

.ro-glow { animation: ro-ring 1.4s ease-in-out infinite; border-radius: var(--r-lg); }

/* 只读徽标里的圆点与荧光同一个心跳（1.4s）；文字始终是主信号，环只是同义强调 */
@keyframes ro-dot { 0%, 100% { opacity: .45; } 50% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {

  .ro-glow { animation: none; box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 32%, transparent); }
}

.req-actions .btn { flex: 1; }


/* ============================================================
   信息架构改版：对外四页 + 会话详情（见 OsApp 的站点地图）
   新增的只有"导航 / 站点地图卡 / 预检问卷 / 维修间表格"四组，
   颜色一律走既有 token，不新造变量。
   ============================================================ */

/* ---------- 顶部导航 ---------- */
.os-nav { display: flex; align-items: center; gap: var(--sp-1); flex-wrap: wrap; }
@media (max-width: 720px) {

  .os-topbar { flex-wrap: wrap; gap: var(--sp-2); padding-bottom: var(--sp-3); }

  .os-topbar .spacer { display: none; }

  .os-nav { width: 100%; }
}


/* ---------- 页脚站点地图 ---------- */
.os-foot { margin-top: 56px; padding-top: var(--sp-5); border-top: 1px solid var(--line); font-size: var(--fs-sm); line-height: 1.7; }

.os-foot p { margin: 0 0 var(--sp-2-5); }

.os-foot-nav { display: flex; flex-wrap: wrap; gap: var(--sp-4); }

.os-foot-nav a { color: var(--dim); text-decoration: none; }

.os-foot-nav a:hover { color: var(--accent); }

.os-foot-nav a:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.pk-result.ok { border-color: color-mix(in srgb, var(--accent) 45%, transparent); }

.pk-result.ok .pk-verdict { color: var(--accent-ink); border-color: var(--accent); }

[data-theme="dark"] .pk-result.ok .pk-verdict { color: var(--accent); }

.ws-alert.danger { border-color: var(--red); background: color-mix(in srgb, var(--red) 10%, transparent); }

.ws-alert.danger > svg { color: var(--red); }

/* 指标格：一个数 + 一行口径。`.ws-stat`（工作台原来那套）与 `.stat`（2026-10 给后台概览
   新增的同一件东西）是**同一份实现的两个名字** —— 布局也在这里给，别让它在各包各写一份
   （改前 .ws-stat 的 flex 布局在 app 包，后台想用就得再抄一遍）。 */
/* text-align 必须**显式**给（用户 2026-10-13："怎么有的左对齐，有的居中对齐？"）。
   后台概览那六格里有三个是**可点击的 `<button>`**（点了去会话列表），另外三个是 `<div>`；
   而 button 的 UA 样式里 text-align 是 center —— 同一件东西于是长成两副样子，
   去看 CSS 又找不到任何一条 text-align。控制台那几格是 div，所以一直是左对齐的（同一份实现）。
   左对齐也是这一族该有的样子：数字、标题、口径都从同一条左边线起，跨格扫读才对得齐。 */
.stat, .ws-stat { display: flex; flex-direction: column; gap: var(--sp-1); text-align: left; }

.stat .k, .ws-stat .k { color: var(--dim); font-size: var(--fs-xs); }

.stat .v, .ws-stat .v { font-family: var(--font-mono); font-size: var(--fs-xl); font-weight: 600; font-variant-numeric: tabular-nums; }

.stat .v.accent, .ws-stat .v.accent { color: var(--accent-ink); }

[data-theme="dark"] .stat .v.accent, [data-theme="dark"] .ws-stat .v.accent { color: var(--accent); }

.stat .v.warn, .ws-stat .v.warn { color: var(--amber); }

.stat .v.danger, .ws-stat .v.danger { color: var(--red); }

.stat .sub, .ws-stat .sub { font-size: var(--fs-2xs); color: var(--dim); }

.stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--sp-4); }
@media (max-width: 767px) {
 .stat-grid { grid-template-columns: repeat(auto-fit, minmax(132px, 1fr)); }
}

.ws-ops-in .btn { min-height: 36px; }

.ws-links { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-4); margin-top: var(--sp-3); }
@media (max-width: 860px) {
 .ws-links { grid-template-columns: 1fr; }
}
@media (max-width: 1023px) {

  /* 手机上这两个才是真正用手指点的：抬到 44px（WCAG 2.2 的 24px 只是下限，
     而"一手拿手机一手在恢复模式里敲命令"是这个产品最常见的使用姿势）。 */
  .ws-ops-in .btn { min-height: 44px; }
}



/* ===== 账户页（A3）：资产是主角，额度在摘要里，主行动只有一个 ===== */
.acct { max-width: 940px; }

.acct-head { display: flex; flex-wrap: wrap; gap: var(--sp-2-5); align-items: flex-start; justify-content: space-between; }

.acct-when { color: var(--dim); font-size: var(--fs-xs); }

.acct-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: var(--sp-3); margin-top: var(--sp-4); }

.acct-card { border: 1px solid var(--line); border-radius: var(--r-md); padding: var(--sp-3) 14px; background: var(--panel2); }

.acct-k { color: var(--dim); font-size: var(--fs-xs); margin: 0 0 var(--sp-1); }

.acct-v { font-size: var(--fs-xl); font-weight: 600; margin: 0; font-variant-numeric: tabular-nums; }

.acct-card .btn { margin-top: var(--sp-2-5); }

.acct-note { margin-top: 14px; font-size: var(--fs-xs); }

/* 表单：一列到底，别让"注册"和"登录"的字段混在一起看不出当前在填哪个 */
.acct-tabs { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin: var(--sp-4) 0 var(--sp-3); }

.acct-tab { border: 1px solid var(--line); background: var(--panel); color: var(--dim);
  border-radius: var(--r-full); padding: var(--sp-1-5) var(--sp-3); font-size: var(--fs-sm); cursor: pointer; }

.acct-tab.is-on { color: var(--txt); border-color: color-mix(in srgb, var(--accent) 55%, transparent); }

/* 恢复码：一次性、必须显眼，所以给它自己的块 + 等宽字体 */
.acct-recovery { margin-top: var(--sp-5); border: 1px dashed color-mix(in srgb, var(--amber) 60%, transparent);
  border-radius: var(--r-md); padding: 14px var(--sp-4); background: color-mix(in srgb, var(--amber) 7%, transparent); }


/* ============================================================
   窄屏触控目标：一律 44×44（2026-10-11 视觉验收 P2-6）
   ⚠️ 必须放在**文件末尾**。媒体查询**不增加特异性**，同特异性的规则按源序胜出 ——
   .btn 的基础规则在本文件中段（min-height:40px）、.copy-btn 在文件前段（32×32），
   把这条写在它们之前会被直接盖掉。第一版就踩了这个坑：实测 .btn 仍是 40px、
   复制按钮仍是 32×32，而 CSS 里明明写着 44px。
   ============================================================ */
@media (max-width: 860px) {
  .btn { min-height: 44px; }

  /* 复制按钮是窄屏最常被点错的一个（就贴在命令旁边，点偏了既没复制到又会误触）。
     放大后右内距必须跟着让位，否则又回到"绝对定位的按钮压住命令文本"那个老问题（P1-5）。 */
  .code-block { padding-right: 56px; }

  .copy-btn { width: 44px; height: 44px; }
}

/* ---------- 命令卡（.cmd*）：从 app 包的 console.css 搬来（2026-10-13）----------
   后台的会话详情要用同一套"命令卡"语言（折叠成一行、点开看输出），而它原来只长在
   app 包里 —— admin 引不到就会在后台再抄一份。放到共享层后两面共用一套类名。 */



.cmd { border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--panel); overflow: hidden; }


.cmd-body { padding: var(--sp-3); display: flex; flex-direction: column; gap: var(--sp-2-5); }


.cmd-fact { display: flex; gap: var(--sp-2); font-size: var(--fs-sm); line-height: 1.6; margin: 0; }


.cmd-fact .cf-k { flex: 0 0 4.6em; color: var(--dim); }


.cmd-fact .cf-v { color: var(--txt); }


.cmd-label { font-size: var(--fs-xs); color: var(--dim); letter-spacing: .06em; margin: var(--sp-2-5) 0 var(--sp-1); }


.cmd-command { font-family: var(--font-mono); font-size: var(--fs-sm); background: var(--bg); border: 1px solid var(--line); border-radius: var(--r-sm); padding: var(--sp-2-5) var(--sp-3); white-space: pre-wrap; word-break: break-all; }


.cmd-output { font-family: var(--font-mono); font-size: var(--fs-sm); background: var(--bg); border: 1px solid var(--line); border-radius: var(--r-sm); padding: var(--sp-2-5) var(--sp-3); max-height: 340px; overflow: auto; white-space: pre-wrap; word-break: break-word; color: var(--txt-body); }


.cmd-output.empty { color: var(--dim); font-family: var(--font-sans); }


.cmd-sum { display: flex; align-items: center; gap: 9px; width: 100%; background: none;
  border: 0; padding: 9px var(--sp-3); cursor: pointer; color: inherit; text-align: left; font: inherit; }


.cmd-sum:hover { background: var(--panel2); }


.cmd-sum:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }


.cmd-one { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: var(--fs-sm); color: var(--txt-body); }


.cmd-st { font-size: var(--fs-sm); white-space: nowrap; }


.cmd-caret { flex: 0 0 auto; font-size: var(--fs-2xs); color: var(--dim); }

/* ---------- 过程区（时间线）：从 app 包的 console.css 搬来（2026-10-13）----------
   后台的会话详情现在渲染**同一段过程**（同一个 ProcessStream + 同一套类名），
   所以这些规则必须在共享层 —— 否则后台会长出第二套"看起来差不多"的样式。 */

.timeline { max-height: min(64vh, 760px); overflow-y: auto; overscroll-behavior: contain; padding-right: var(--sp-1); }

.timeline { display: flex; flex-direction: column; gap: var(--sp-3); }

.timeline > * { flex: 0 0 auto; }

.tl-msg .tl-who { display: block; font-size: var(--fs-2xs); letter-spacing: .08em; text-transform: uppercase; color: var(--dim); margin-bottom: var(--sp-1); }

.tl-msg .tl-body { font-size: var(--fs-sm); line-height: 1.75; }

.tl-msg.agent { border-left-color: var(--accent); box-shadow: var(--e1); }

.tl-msg.agent .tl-who { color: var(--accent-ink); }

[data-theme="dark"] .tl-msg.agent .tl-who { color: var(--accent); }

.tl-msg.notice .tl-who { display: inline; margin-bottom: 0; margin-right: var(--sp-2); }

.tl-msg.notice .tl-body { display: inline; }

.tl-msg.notice.question, .tl-msg.notice.round-limit { border-left-color: var(--amber); }

.tl-msg.notice.command-intent { border-left-color: var(--accent); }

/* 本文件由"按面拆分 CSS"生成（2026-10-11 monorepo 拆分），逐字节保留原格式。
   归属规则：只被 ui 包用到的规则归本包；被两个以上包用到、或扫不到引用的历史遗留
   （动态拼出来的类名扫不到）、以及含全局选择器（body、html、星号、:root…）的规则统一留在 ui 层。
   改样式时先看"这条规则谁在用"，再决定写进哪个包。 */


.mk-top .brand { display: flex; align-items: center; gap: var(--sp-2-5); text-decoration: none; color: var(--txt); }

.mk-top .brand strong { font-size: var(--fs-md); }

.mk-top .brand span span { font-size: var(--fs-xs); color: var(--dim); }


/* ---------- App 外壳：左栏 + 顶栏 + 内容 ---------- */
/* App 面 = **整屏外壳**，两条口径缺一不可（2026-10-11 用户反馈）：
     ① 四周不留边距：body 的 24/16 页面留白必须在 App 面收掉 —— 否则壳是一张
        四周留缝、还多出 16px 横向溢出的卡片（实测壳 x=16/y=24，文档宽 1526 > 视口 1510）；
     ② 壳锁死视口高、**页面级不滚动**，滚动只发生在 .app-content 里 —— 侧导与顶栏
        因此在任何滚动位置都不动。此前壳没有自己的高度，靠 body 滚动，实测整页滚 48px 时
        侧导与顶栏的 top 从 24 → −24 → −35 **跟着滚走**（用户原话"侧导、吊顶会随滚动条滚动"）。
   与 .os-shell.as-console 同一套口径；别退回 sticky —— 页面级不滚动时 chrome 不需要 sticky。
   另：styles.css 里那条 html{scrollbar-gutter:stable}（防 CLS）在 App 面必须收掉 ——
   页面级都不滚了，留着的只是右侧一条 11px 的假边距（实测 gutter=stable 时壳宽 1499，
   改 auto 后 1510 = 视口宽）。body 顺带锁 overflow，防子像素舍入凭空生出一条页面滚动条。 */
html:has(.app-shell) { scrollbar-gutter: auto; }

body:has(.app-shell) { padding: 0; overflow: hidden; }

/* 认证面的品牌块不再自成一派（2026-10 品牌统一）：AuthShell 直接用外壳的
   `.app-brand` / `.app-brand-logo` / `.app-brand-text` 与面身份牌 `.app-surface-tag`
   （见 console-shell.css），三面同一份 logo.svg + 同一个标题。
   `.auth-top .brand*` 那三条旧规则（fs-md 标题 + 自己的一行副标题）随之删除。 */

/* 本文件由"按面拆分 CSS"生成（2026-10-11 monorepo 拆分）。
   归属规则：只被 landing 包用到的规则归本包；含全局选择器（body、html、:root…）的规则留在 ui 层。
   2026-10 静态化 + 重设计：分带（.lp-band）、光效（.lp-glow）、卡片与版式原语都在本文件，
   四个页面（首页 / 操作指南 / 自助预检 / 404）共用同一套；子页面的构件见文件末尾。 */



/* 营销面导航项。选择器必须写 .mk-nav —— MarketingShell 用的是 <nav className="mk-nav">，
   从前的 .os-nav 是复制旧外壳留下的名字：标记层已经零引用（os.css 里只剩一条孤儿容器规则），
   于是这几个 .nav-link 规则一条都没命中，三个导航项只吃到全局 a{color:var(--accent)}：
   **同色、无当前页、无命中区、无 hover**（2026-10-11 线上视觉验收 P1-2，实测三项计算值完全一致）。
   换回 .mk-nav 后，"当前页 = 绿字 + 描边 + 面板底"这层信息才回来，也不再和右上角主 CTA 同色。 */
/* 头部控件统一高度：**一个令牌、四类控件**（导航项 / 主题 / CTA / 汉堡）。
   改前是三条各自写"40"的规则，而且大半用 `min-height`（只有下限）：
   导航项与 CTA 的内容一旦比 40 高（换字体、换语言、浏览器缩放出小数行高…）就会长高，
   而主题按钮是固定 `height: 40` —— 并排看就是"按钮没对齐"（用户 2026-10-13 反馈）。
   现在统一 `height: var(--mk-ctl)` + `min-height: 0`：谁都长不高，对齐是**结构保证**，
   不靠三个数字碰巧相等。窄屏抬到 44px（触控门槛）也只改这一处。 */
.mk-top { --mk-ctl: 40px; }
.mk-top .nav-link,
.mk-top .btn,
.mk-top .mk-burger { height: var(--mk-ctl); min-height: 0; }
.mk-top .mk-theme { width: var(--mk-ctl); height: var(--mk-ctl); min-height: 0; }

.mk-nav .nav-link {
  display: inline-flex; align-items: center; padding: 0 16px;
  border-radius: var(--r-md); border: 1px solid transparent;
  color: var(--txt-body); font-size: var(--fs-sm); text-decoration: none; white-space: nowrap;
  transition: color .2s ease, border-color .2s ease, background .2s ease;
}

.mk-nav .nav-link:hover { color: var(--txt); border-color: var(--line); }

.mk-nav .nav-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.mk-nav .nav-link.is-on { color: var(--accent-ink); border-color: var(--line); background: var(--panel); }

[data-theme="dark"] .mk-nav .nav-link.is-on { color: var(--accent); }

.pk-progress { margin-top: 24px; }

.pk-progress-top { display: flex; align-items: center; justify-content: space-between; gap: 12px; font-size: var(--fs-sm); margin-bottom: 8px; }

.pk-bar { height: 4px; border-radius: var(--r-full); background: var(--panel2); overflow: hidden; }

.pk-bar i { display: block; height: 100%; background: var(--accent); transition: width .3s ease; }
@media (prefers-reduced-motion: reduce) {
 .pk-bar i { transition: none; }}


.link-btn { background: none; border: 0; padding: 4px 0; color: var(--dim); font: inherit; font-size: var(--fs-sm); cursor: pointer; display: inline-flex; align-items: center; gap: 6px; }

.link-btn:hover { color: var(--accent); }

.link-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }


.pk-card, .pk-result {
  margin-top: 16px; background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: 22px;
}

.pk-q { font-size: clamp(20px, 2.6vw, 26px); line-height: 1.35; }

.pk-hint { color: var(--dim); font-size: var(--fs-sm); line-height: 1.7; margin-top: 10px; }


.pk-options { display: flex; flex-direction: column; gap: 10px; margin-top: 20px; }

.pk-opt {
  display: flex; flex-direction: column; gap: 3px; text-align: left; width: 100%;
  min-height: 60px; padding: 12px 16px; cursor: pointer;
  background: var(--panel2); border: 1px solid var(--line); border-radius: var(--r-md);
  color: var(--txt); font: inherit; transition: border-color .2s ease, background .2s ease;
}

.pk-opt:hover { border-color: var(--accent); }

.pk-opt:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.pk-opt-label { font-size: var(--fs-base); font-weight: 600; }

.pk-opt-detail { color: var(--dim); font-size: var(--fs-sm); line-height: 1.6; }



/* 硬门槛题里的自测方法：直接摊开，不是折叠的"点这里看帮助"。
   左轨 + 低一层表面，和选项按钮区分开 —— 它是阅读材料，不是可点的东西。 */
.pk-help { margin-top: 16px; padding: 14px 16px; background: var(--panel2); border: 1px solid var(--line);
  border-left: 3px solid var(--accent); border-radius: var(--r-md); }

.pk-help-title { display: flex; align-items: center; gap: 8px; font-size: var(--fs-sm); font-weight: 600; color: var(--txt); }

.pk-help-title svg { color: var(--accent); flex-shrink: 0; }

.pk-help-groups { display: flex; flex-direction: column; gap: 10px; margin-top: 10px; }

.pk-help-row { display: flex; flex-direction: column; gap: 2px; }

.pk-help-row dt { color: var(--txt); font-size: var(--fs-sm); font-weight: 600; }

.pk-help-row dd { margin: 0; color: var(--txt-body); font-size: var(--fs-sm); line-height: 1.7; }

.pk-help-foot { margin-top: 12px; padding-top: 10px; border-top: 1px dashed var(--line);
  color: var(--dim); font-size: var(--fs-sm); line-height: 1.7; }
@media (min-width: 720px) {

  /* 宽屏把"哪种芯片"和"怎么做"并排，三段竖排会把选项挤到屏幕外 */
  .pk-help-row { flex-direction: row; gap: 12px; }

  .pk-help-row dt { flex: 0 0 210px; }

  .pk-help-row dd { flex: 1; }}


.pk-result.refer { border-color: rgba(245, 158, 11, .5); }

.pk-verdict { display: inline-flex; align-items: center; gap: 8px; font-size: var(--fs-sm); font-weight: 600; border-radius: var(--r-full); padding: 5px 14px; border: 1px solid var(--line); }

.pk-result.refer .pk-verdict { color: var(--amber); border-color: rgba(245, 158, 11, .5); }

.pk-code { margin-top: 12px; color: var(--dim); font-size: var(--fs-sm); }

/* 题号与分类是两个字段（原先是 "PK-01 · 硬件 · 进液" 那种中点串），
   用间距分开就够 —— 多一个分隔符就是多一个要读的符号。 */
.pk-code .mono { margin-right: var(--sp-2); }

.pk-block { font-size: var(--fs-sm); text-transform: uppercase; letter-spacing: .06em; color: var(--dim); margin: 22px 0 10px; }

.pk-list { display: flex; flex-direction: column; gap: 8px; padding-left: 20px; list-style: disc; color: var(--txt-body); font-size: var(--fs-sm); line-height: 1.75; }

.pk-next { margin-top: 8px; }

/* eligible 的下一步只剩两条路（自己动手 / 我们接手）—— 一行按钮，没有解释文字。
   窄屏自动换行并各占一行，两根手指都够得着。 */
.pk-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 4px; }
.pk-actions .btn { min-height: 44px; }
@media (max-width: 560px) { .pk-actions { flex-direction: column; align-items: stretch; }}

.gd-faq-item { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-lg); padding: 16px; }

.gd-faq-item h3 { font-size: var(--fs-base); margin-bottom: 6px; }

.gd-faq-item p { color: var(--dim); font-size: var(--fs-sm); line-height: 1.7; }

/* ============================================================
   App 面（SaaS 化）与认证面外壳。
   颜色/字体**沿用 recoveryOS token**（design-system/recoveryos/MASTER.md：
   深色底 #0F172A、卡片 #1B2336、主色绿 #22C55E、等宽 JetBrains Mono），
   这里只补"布局与密度"：左侧栏 + 顶栏 + 内容区，按 data-dense dashboard 口径
   （正文 13–14px、8/12/16 间距刻度、数字等宽对齐）。
   营销面（首页/预检/指南）继续用 os.css 的 .os-* 体系 —— 两套外壳不共享布局类。
   ============================================================ */

/* ---------- 营销外壳 ---------- */
.mk-shell { max-width: 1200px; margin: 0 auto; padding: 0 20px 60px; }

.mk-top { position: sticky; top: 0; z-index: 20; display: flex; align-items: center; gap: 14px;
  padding: 12px 0; background: color-mix(in srgb, var(--bg) 92%, transparent); backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--line); }

.mk-nav { display: flex; gap: 4px; }

.mk-cta { display: flex; gap: 8px; align-items: center; flex: 0 0 auto; }

/* 窄屏顶栏不许换行/被挤扁（2026-10-11 线上视觉验收 P1-1）。
   线上 390px 实测：整条头部高 102px，副标题折成 2 行、`登录`（47×44）竖排成"登/录"、
   `注册 / 开通`（62×64）折成三行"注册/开/通" —— 移动端第一屏唯一的转化入口就是这个样子。
   两条根因：品牌块是 flex 项但没给 min-width:0（默认 min-width:auto = 内容宽，不肯收缩），
   CTA 里的 .btn 没有 nowrap（按钮乐意折行）。这里把两个都钉住。 */
.mk-top .brand { min-width: 0; overflow: hidden; }

.mk-top .brand > span { min-width: 0; overflow: hidden; }

.mk-top .brand strong { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.mk-cta .btn { white-space: nowrap; }

/* 窄屏导航按钮：只在 ≤860px 出现（桌面有整行导航，不需要它）。 */
.mk-burger { display: none; background: transparent; border: 1px solid var(--line); border-radius: var(--r-md);
  color: var(--txt); cursor: pointer; }

@media (max-width: 860px) {

  /* 窄屏头部（2026-10 改 grid 后重写；原来是给 flex 头部写的 order/flex-wrap，已失效）。
     三列显式定位：品牌（可截断） | 动作区（主题 + CTA） | 汉堡；
     导航展开时整行落到第二行（disclosure，不遮内容、不需要浮层）。 */
  .mk-top { grid-template-columns: minmax(0, 1fr) auto auto; gap: 10px; }

  /* justify-self: stretch 是必须的：默认 start 会让品牌块按内容撑开、越过自己的列压住动作区 */
  .mk-top .brand { grid-column: 1; grid-row: 1; justify-self: stretch; min-width: 0; overflow: hidden; }

  .mk-cta { grid-column: 2; grid-row: 1; }

  .mk-burger { grid-column: 3; grid-row: 1; display: inline-flex; align-items: center;
    justify-content: center; min-width: var(--mk-ctl); }

  .mk-nav { grid-column: 1 / -1; grid-row: 2; display: none; }

  .mk-top.nav-open .mk-nav { display: flex; }

  .mk-nav { gap: 6px; }

  /* 高度不再写在这里：窄屏展开的导航项也是 .mk-top .nav-link，跟着 --mk-ctl（44px）走 */
  .mk-nav .nav-link { flex: 1 0 auto; justify-content: center; padding: 0 14px; border-color: var(--line); }

  /* 窄屏压缩动作区：主题 36、CTA 收窄内距，给品牌让出空间 */


  .mk-cta .btn { padding: 0 14px; }}

@media (max-width: 560px) {

  /* 副标题在窄屏是纯噪声（页脚与标题里都有），收掉它给 CTA 腾出位置 */
  .mk-top .brand span span { display: none; }

  .mk-top { gap: 10px; }

  .mk-cta { gap: 6px; }

  .mk-cta .btn { padding: 0 12px; }}


/* 内联 SVG 图标（静态化后替代 @ant-design/icons；stroke 跟随文字颜色） */
.ic { width: 1em; height: 1em; vertical-align: -0.125em; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }

.copy-btn.is-ok { color: var(--accent); }


/* ============================================================
   2026-10 首页重设计：终端优先（lp-* 前缀，只用于首页）。
   令牌全部沿用 :root 变量，亮暗两套自动成立，不新造颜色。 */

/* ---------- 仿真终端窗 ---------- */
.lp-term { background: color-mix(in srgb, var(--panel2) 88%, black); border: 1px solid var(--line);
  border-radius: var(--r-lg); box-shadow: 0 24px 48px rgba(0,0,0,.35); overflow: hidden;
  font-family: var(--font-mono); font-size: var(--fs-xs); line-height: 1.75; }

.lp-term-bar { display: flex; align-items: center; gap: 6px; padding: 9px 12px;
  background: var(--panel2); border-bottom: 1px solid var(--line); }

.lp-term-dot { width: 10px; height: 10px; border-radius: 50%; background: var(--line); }

.lp-term-dot:nth-child(1) { background: #EF4444; } .lp-term-dot:nth-child(2) { background: #F59E0B; } .lp-term-dot:nth-child(3) { background: #22C55E; }

.lp-term-title { margin-left: 8px; color: var(--dim); font-size: var(--fs-2xs); }

.lp-term-body { padding: 14px 16px 18px; color: var(--txt-body); overflow-x: auto; }

.lp-term-body > span { display: block; word-break: break-all; }

.lp-term-body > span + span { margin-top: 2px; }

.lp-term-body .t-prompt { color: var(--accent); }

.lp-term-body .t-cmd { color: var(--txt); }

.lp-term-body .t-ok { color: var(--accent); }

.lp-term-body .t-warn { color: var(--amber); }

.lp-term-body .t-dim { color: var(--dim); }

.lp-term-body .t-block { display: block; padding: 10px 12px; margin: 8px 0; border: 1px solid var(--line);
  border-left: 2px solid var(--amber); border-radius: var(--r-md); background: var(--panel); }

.lp-term-body .t-btns { display: inline-flex; gap: 8px; margin-top: 8px; }

.lp-term-body .t-btn { font-family: var(--font-mono); font-size: var(--fs-2xs); padding: 3px 12px;
  border-radius: var(--r-sm); border: 1px solid var(--line); color: var(--txt-body); }

/* 假终端里的「批准执行」**不实心**（用户 2026-10-13："批准执行按钮弱化，
   让'先花 3 分钟做预检'成为视觉核心"）。
   它原来是实心 accent 胶囊 + 600 字重，与首屏真正的 CTA（那个 48px 实心绿胶囊）
   长得几乎一样 —— 一屏里出现两个"最亮的东西"，视线被拉进示意图里，
   而示意图是**说明**，真正要人点的是 CTA。
   改成描边式：语义还在（绿色=批准），量级掉到与「拒绝」同一档。
   注：这一对是 <span> 不是按钮（整个假终端 aria-hidden），所以只影响观感。 */
.lp-term-body .t-btn.ok {
  background: transparent;
  border-color: color-mix(in srgb, var(--accent) 55%, var(--line));
  color: var(--accent);
  font-weight: 500;
}

/* ---------- 安全边界 checklist ---------- */
.lp-safe { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }

.lp-safe-item { border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--panel);
  padding: 16px 18px; }

.lp-safe-item h3 { display: flex; align-items: center; gap: 8px; margin: 0 0 6px; font-size: var(--fs-base); }

.lp-safe-item h3 .ic { color: var(--accent); }

/* 平台 mark：实心、无描边、用平台自己的品牌色（见 :root 的 --xhs 登记）。
   尺寸略大于本站描边图标（1.15em）：实心 mark 视觉重量比同等高度的描边小，
   与旁边的文字放一起会显得偏小。 */
/* 平台 mark 的尺寸：1.7em 是按**视觉高度**校准的，不是随手放大 ——
   ① .btn 的字号是 --fs-sm(13px)，原来 1.15em ≈ 15px，而小红书这个 24×24 路径只占视框
      高度的 ~79%，实渲染出来比「让我们接手」还小（用户 2026-10-14 实拍指出"logo 太小"）；
   ② 1.7em ≈ 22px 盒子 → 视觉约 17.5px，与 13px 字重的文案齐平，读起来是"品牌 + 文案"而不是小图标；
   ③ 不写 vertical-align：它是 .btn（inline-flex）的 flex 子项，vertical-align 对 flex 项无效
      （和光标那次同一个坑），居中的活由 .btn 的 align-items: center 干。 */
.ic-brand { width: 1.7em; height: 1.7em; fill: var(--xhs); stroke: none; }

.lp-safe-item p { color: var(--txt-body); font-size: var(--fs-sm); line-height: 1.7; margin: 0; }

.lp-safe-item code { font-family: var(--font-mono); font-size: var(--fs-2xs); background: var(--panel2);
  padding: 1px 5px; border-radius: var(--r-sm); }

@media (max-width: 760px) { .lp-safe { grid-template-columns: 1fr; }}


/* ============================================================
   2026-10 二次重设计：标准开发者产品落地页骨架（uupm.cc 式）
   居中 Hero → 数据带 → 功能矩阵 → How it works → 安全边界 → 定价 → 尾部 CTA */

/* ---------- 居中 Hero ---------- */
.lp-hero2 { text-align: center; /* 顶部 76px = 原 40px 内距 + 被移除的 kicker 胶囊占位 36px，
     这样去掉胶囊后标题及其后所有内容的纵向位置完全不变 */
  padding: 76px 0 40px; max-width: 860px; margin: 0 auto; }

.lp-hero2 h1 { font-size: clamp(30px, 4.2vw, 50px); line-height: 1.14; margin: 22px 0 30px; }

/* 重点词渐变（2026-10 定稿：D9「品牌双色」= 品牌绿 → 玫红）
   为什么不用绿→橙：两色相邻且夹着黄，sRGB 插值必然经过低饱和橄榄（发脏）；
   绿→玫红跨过冷暖分野，中间落在青绿→蓝紫一段，全程保持饱和。
   --hl-to 是为渐变新增的落地页局部令牌（玫红不在既有色板里），两套主题各取一档（实测对比度）：
     暗色 #EC4899 对 #0F172A 5.06:1（大字号门槛 3:1）
     亮色 #DB2777 对 #F1F4F8 4.17:1
   两端之间的整段（绿→玫红）实测最低也在 7:1 量级，字面全程清晰。
   实现结构沿用参考站 .gradient-text：透明字 + 背景裁剪，末端给纯色不混色。 */
/* 悬浮导航胶囊的圆角：18px 是为 56px 高的胶囊定的
   （--r-lg=12 偏方、--r-full=999 会变成体育场形），与 --hl-to 一样属本包局部令牌。 */
/* 平台 mark 的颜色：小红书红（#FF2442）是**平台自己的品牌色**，不是我们的语义色，
   所以单独一个局部令牌而不是借用 --red（借用会让"红=危险"这条语义被污染）。
   与 --hl-to 一样属本包局部令牌：深浅两套主题同一个值 —— 这是别人的品牌色，不该跟着我们的主题变。 */
:root { --hl-to: #DB2777; --r-pill: 18px; --xhs: #FF2442; }

[data-theme="dark"] { --hl-to: #EC4899; }

.lp-hero2 h1 .hl,
.lp-final h2 .hl {
  /* 两行是刻意的渐进增强：老浏览器解析不了 in oklch，整条声明被丢弃 → 退回上一行 sRGB 版；
     新浏览器用第二行。实测对比：sRGB 直插在绿↔玫红的中点会掉进**灰绿**（近互补色的插值陷阱），
     oklch 插值则沿暖色走（绿→金→橙→红→玫），全程保持饱和。 */
  background: linear-gradient(90deg, var(--accent) 0%, var(--hl-to) 100%);
  background: linear-gradient(in oklch longer hue 90deg, var(--accent) 0%, var(--hl-to) 100%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
}

.lp-hero2 .lead { color: var(--txt-body); font-size: var(--fs-lg); line-height: 1.65; margin: 0 auto 28px; max-width: 640px; }

/* 命令行片段（uupm 的 `$ ▋` 对应物）：真复制控件，不是装饰 */
.lp-cmdbar { display: flex; align-items: stretch; gap: 0; max-width: 560px; margin: 0 auto 24px;
  border: 1px solid var(--line); border-radius: var(--r-md); background: var(--panel2); overflow: hidden; }

/* 命令条内部：容器统一 10px 内距 + 两端元素各自贴边 ——
   文字左间距与按钮右间距因此严格相等（基类 .code-block 的 12/44 padding 是给绝对定位按钮留的，必须清掉） */
.lp-cmdbar .code-block { flex: 1; display: flex; align-items: center; gap: 10px;
  margin: 0; padding: 0 10px; border: 0; background: none; overflow: visible; }

.lp-cmdbar .code-block code { flex: 1; min-width: 0; padding: 12px 0; text-align: left; }

.lp-cmdbar .copy-btn { position: static; align-self: center; min-width: 44px; min-height: 36px; margin-right: 8px;
  border: 1px solid var(--line); border-radius: var(--r-md); background: var(--panel); display: inline-flex;
  align-items: center; justify-content: center; cursor: pointer; color: var(--dim); margin-right: 0; }

.lp-cmdbar .copy-btn:hover { color: var(--txt); border-color: var(--accent); }

.lp-fstep-head { display: grid; gap: 6px; align-content: center; }

.lp-fstep-head::before { counter-increment: lpstep; content: counter(lpstep, decimal-leading-zero);
  font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--accent); letter-spacing: .14em; }

/* 窗口栏：三个圆点 + 标题（+ 右侧小牌）。与 .lp-term-bar 同配方，故意这么像 —— 同一个产品 */
.lp-frame-bar { display: flex; align-items: center; gap: 6px; padding: 8px 12px;
  background: var(--panel2); border-bottom: 1px solid var(--line); }
.lp-frame-dot { width: 9px; height: 9px; border-radius: var(--r-full); background: var(--line); }
.lp-frame-dot:nth-child(1) { background: #EF4444; }
.lp-frame-dot:nth-child(2) { background: #F59E0B; }
.lp-frame-dot:nth-child(3) { background: #22C55E; }
.lp-frame-title { margin-left: 6px; color: var(--dim); font-size: var(--fs-2xs);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-family: var(--font-mono); }
.lp-frame-badge { margin-left: auto; flex: 0 0 auto; font-size: var(--fs-2xs); color: var(--accent);
  border: 1px solid color-mix(in srgb, var(--accent) 45%, var(--line)); border-radius: var(--r-full);
  padding: 0 var(--sp-2); }

.lp-frame-body { padding: var(--sp-4) var(--sp-5); display: flex; flex-direction: column;
  gap: var(--sp-2); font-family: var(--font-mono); font-size: var(--fs-2xs); line-height: 1.7;
  color: var(--txt-body); }
.lp-frame-body > * { min-width: 0; }
.lp-opt-mark { width: 16px; height: 16px; border-radius: var(--r-sm); border: 1px solid var(--line);
  flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; }
.lp-opt-mark.is-yes { background: var(--accent); border-color: var(--accent); color: var(--accent-fg); }
.lp-opt-mark.is-yes .ic { width: 11px; height: 11px; stroke-width: 2.6; }
.lp-frame-body .t-prompt { color: var(--accent); }
.lp-frame-body .t-cmd { color: var(--txt); }
.lp-frame-body .t-ok { color: var(--accent); }

/* 窄屏：取消交替（文字在上、样子在下），并收到一栏 */
@media (max-width: 860px) {
  /* 每块材料也放宽到整栏（窄屏没有"让宽度"这回事） */
  .lp-frame-body { padding: var(--sp-3) var(--sp-4); }}



/* ---------- 尾部 CTA band ---------- */
.lp-final { text-align: center; padding: 0; }

.lp-final h2 { font-size: clamp(28px, 3.2vw, 44px); margin: 0 0 14px; }

.lp-final .sub { color: var(--dim); max-width: 640px; margin: 0 auto 32px;
  font-size: var(--fs-base); line-height: 1.75; }

.lp-final .lead { color: var(--txt-body); max-width: 560px; margin: 0 auto 24px; line-height: 1.7; }

.lp-final .lp-cta { justify-content: center; margin-bottom: 20px; }

.lp-checks { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px 20px;
  color: var(--dim); font-size: var(--fs-sm); }

.lp-checks li { display: inline-flex; align-items: center; gap: 6px; list-style: none; }

.lp-checks .ic { color: var(--accent); }


/* ============================================================
   2026-10 三次迭代：同类产品（claude.com/product、codex、trae）对标
   ① 大幅产品视觉 ② 故障场景行 ③ FAQ */

/* 宽幅终端视觉：hero 文案下方居中，替代窄侧栏窗 */
.lp-shot { max-width: 880px; margin: 8px auto 0; text-align: left; }

.lp-shot .lp-term { font-size: var(--fs-sm); }

/* FAQ：复用指南页 gd-faq 的视觉口径，首页给精简版 */
.lp-faq { max-width: 760px; margin: 0 auto; }

.lp-faq .gd-faq-item { border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--panel);
  padding: 16px 18px; }

.lp-faq .gd-faq-item + .gd-faq-item { margin-top: 10px; }

.lp-faq h3 { margin: 0 0 6px; font-size: var(--fs-base); }

.lp-faq p { color: var(--txt-body); font-size: var(--fs-sm); line-height: 1.75; margin: 0; }

.lp-term-body .t-cmdline { display: flex; align-items: center; gap: 10px; }

.lp-term-body .t-cmdline .t-cmd { flex: 1; }



/* ---------- 密度规则（uupm 对标）：节间距拉大，一节一个主张 ---------- */
.lp-page .section { margin-top: 112px; }
/* 头部是 fixed 悬浮胶囊（top:14px + 自身高度）：锚点 / hash 跳转落到节上时，
   标题必须让出头部的高度，否则「它怎么工作」的 h2 会被压在导航下面（实测踩过）。 */
.lp-page .section[id] { scroll-margin-top: 96px; }

.lp-page .section h2 { margin-bottom: 28px; }

/* 数据带是 hero 的收尾，不算独立节 */
.link-btn { background: none; border: 0; padding: 0; color: var(--accent); cursor: pointer;
  font-size: var(--fs-sm); text-decoration: none; }



/* 终端窗行距统一：行与行 10px、块状结论上下 12px、按钮行 14px，整体工整 */
.lp-term-body { padding: 18px 20px 20px; line-height: 1.8; }

.lp-term-body > span + span { margin-top: 10px; }

.lp-term-body .t-block { margin: 12px 0; }

.lp-term-body .t-btns { margin-top: 14px; gap: 10px; }

.lp-term-body .t-cmdline { display: block; }


/* 头部品牌区对齐：图标与双行文字垂直居中，两行同左缘、行距收紧 */
.mk-top .brand { align-items: center; }

/* 头部品牌区 = logo + 单行产品名（去掉副标题后：字号上调一档，与 logo 同轴居中） */
.mk-top .brand .brand-text { display: flex; align-items: center; min-width: 0; }

.mk-top .brand strong { font-size: var(--fs-lg); line-height: 1; letter-spacing: .01em; }

.mk-top .brand img { flex: 0 0 auto; align-self: center; }


/* ---------- 头部：悬浮胶囊导航（uupm 式）----------
   fixed + 居中限宽 + 毛玻璃；logo 左 / 导航中 / 动作右。 */
.mk-top { position: fixed; top: 14px; left: 0; right: 0; z-index: 50;
  margin: 0 auto; width: min(1240px, calc(100% - 32px));
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 16px;
  padding: 10px 20px; border: 1px solid var(--line); border-radius: var(--r-pill);
  background: color-mix(in srgb, var(--panel2) 78%, transparent);
  backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
  box-shadow: 0 12px 32px rgba(0,0,0,.25); }

.mk-top .spacer { display: none; }

/* stretch 而非 start：品牌块必须被自己的列约束住，否则按内容撑开、越过列压住动作区
   （窄屏加主题切换后暴露：品牌文字盖住按钮） */
.mk-top .brand { justify-self: stretch; min-width: 0; }

.mk-nav { justify-self: center; }

.mk-cta { justify-self: end; display: inline-flex; align-items: center; gap: 10px; }

.mk-burger { justify-self: end; }

/* fixed 头部占位：三页正文统一让出头部高度 */
.mk-shell { padding-top: 92px; }

@media (max-width: 860px) {

  .mk-top { width: calc(100% - 24px); top: 10px; padding: 8px 14px; }

  .mk-shell { padding-top: 80px; }}


/* ---------- 一节一屏 + 节间背景分区（uupm 式）----------
   band = 全出血背景层；.lp-inner = 1200px 内容列。
   深/浅交替：is-deep 用品牌深底 + 顶部辉光，默认带用 panel 提亮。 */
/* 落地页的壳：全出血（限宽交给分带内的 .lp-inner）。
   首页、指南、预检、404 四页统一 —— 之前只有首页带这个类，
   另外三页被 .mk-shell 的 1200 限宽压成居中面板，分带两侧露出底色。 */
.mk-shell.lp-full { max-width: none; padding: 0; }

/* 高度由内容决定：上下各 104px 呼吸，密的内容自然撑开、疏的内容不硬撑成空屏 */
.lp-band { padding: 104px 24px; }

/* 内容列限宽：**只列明确的类名**。
   这里曾经写成 `.lp-band > p, .lp-band > div:not(.lp-glow)`，踩过三次：
     ① 命中 .lp-aurora/.lp-orb → 极光只铺中间 1160px，两侧留黑边；
     ② 装饰层包了一层后命中 .lp-glow → 同样只铺中间；
     ③ 命中预检的 .pk-progress/.pk-card（:not() 让权重升到 0,2,1，连后来加的
        `.lp-band > .pk-*` 都压不住）→ 进度条被撑到 1112px、比问题卡宽。
   所以不要再加通用标签选择器；新内容块请显式加进这一行。 */
.lp-band > .lp-inner, .lp-band > .section,
.lp-band > .lp-hero2, .lp-band > .lp-shot, .lp-band > .lp-final,
.lp-band > p { width: 100%; max-width: 1160px; margin-left: auto; margin-right: auto; }

/* 纯色分区（不用任何渐变）：深带 = 页面底色，浅带 = 底色提亮 + 上下细线收边 */
.lp-band.is-deep { background: var(--bg); }

.lp-band:not(.is-deep) { background: color-mix(in srgb, var(--panel) 58%, var(--bg));
  border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }

/* band 内的 .section 不再吃旧的节间距 */
.lp-band .section { margin-top: 0; }

/* 各章统一版式：居中标题 + 标题到内容 40px；卡片内文字仍左对齐 */
/* 章节标题：大字号（参考图量级）+ 标题下一行小字描述 */
.lp-band .section h2 { text-align: center; font-size: clamp(28px, 3vw, 42px);
  margin: 0 0 14px; letter-spacing: .01em; }

.lp-band .section .sub { text-align: center; margin: 0 auto 44px; max-width: 640px;
  color: var(--dim); font-size: var(--fs-base); line-height: 1.75; }

/* hero band：首屏，内容本身就接近一屏，只需收紧上、放宽下 */
.lp-band-hero { padding: 44px 24px 112px; }

/* 尾部 CTA band：内容居中 + 一层纯色品牌色调收尾（不用渐变），与上一节明确分区 */

.lp-band-final { padding: 128px 24px; }

.lp-band > .lp-final { border: 0; border-radius: 0; background: none; box-shadow: none;
  text-align: center; padding: 0; margin: 0; min-height: 0; }


/* ---------- 页脚：多栏（uupm 式），暂以占位承接未来条目 ---------- */
/* 页脚 = 全出血的纯色深底块（比上一节更深，无渐变），内容居中限宽 */
/* 页脚：top 方向不留外边距与内边距（与上一段紧贴，只由 border-top 收边） */
.mk-foot { background: color-mix(in srgb, var(--bg) 88%, black); border-top: 1px solid var(--line);
  margin-top: 0; padding-top: 0; }

.mk-foot-inner { max-width: 1160px; margin: 0 auto; padding: 56px 24px 36px; }

.mk-foot-grid { display: grid; grid-template-columns: 1.7fr 1fr 1fr 1fr; gap: 48px 40px; align-items: start; }

.mk-foot-brand .brand { display: flex; align-items: center; gap: 10px; text-decoration: none; color: var(--txt); }

/* 与头部同一套对齐：logo 与单行产品名同轴居中（17px），描述另起一段 */
.mk-foot-brand .brand-text { display: flex; align-items: center; min-width: 0; }

.mk-foot-brand .brand-text strong { font-size: var(--fs-lg); line-height: 1; letter-spacing: .01em; }

.mk-foot-desc { margin: 16px 0 0; max-width: 320px; color: var(--dim); font-size: var(--fs-sm); line-height: 1.9; }

.mk-foot-col { display: flex; flex-direction: column; gap: 12px; }

.mk-foot-col h3 { margin: 0 0 6px; font-size: var(--fs-md); font-weight: 600; color: var(--txt); }

.mk-foot-col a, .mk-foot-col span { color: var(--dim); font-size: var(--fs-sm); line-height: 1.5; text-decoration: none; }

.mk-foot-col a:hover { color: var(--accent); }

.mk-foot-col .soon { display: inline-flex; align-items: center; gap: 8px; color: var(--dim); opacity: .7; }

/* 占位标签与分隔线在亮/暗两套页脚底色上都要看得见：用 dim 的透明混合，不依赖 --line */
.mk-foot-soon { font-size: var(--fs-2xs); border: 1px dashed color-mix(in srgb, var(--dim) 45%, transparent);
  border-radius: var(--r-full); padding: 1px 8px; }

.mk-foot-bar { display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap;
  margin-top: 56px; padding-top: 24px; border-top: 1px solid color-mix(in srgb, var(--dim) 35%, transparent); }

.mk-foot-bar p { margin: 0; font-size: var(--fs-xs); }

@media (max-width: 860px) {

  .mk-foot-inner { padding: 40px 20px 28px; }

  .mk-foot-grid { grid-template-columns: 1fr 1fr; gap: 32px 24px; }

  .mk-foot-brand { grid-column: 1 / -1; }}


/* 窄屏：章节呼吸收一档，字号与内距同步收敛 */
@media (max-width: 860px) {

  .lp-band, .lp-band-final { padding: 64px 20px; }

  .lp-band-hero { padding: 28px 20px 72px; }

  .lp-band .section h2 { margin-bottom: 28px; }}


/* 首页整页全出血：收掉 body 的 16px 横向留白与滚动条槽 —— 分带与页脚通到视口边缘
   （与 App 面 body:has(.app-shell) 同一套口径，四个落地页统一收掉；
   各页内容自身有 .mk-shell 的左右内距，因此不会贴边） */
body:has(.mk-shell) { padding: 0; }

html:has(.mk-shell) { scrollbar-gutter: auto; }



/* ---------- 仅供读屏的文本 ----------
   落地页不加载 App 包的 CSS，需要自带一份标准实现：必须 absolute + 裁剪，
   否则（1）复制成功后的状态文案会显示在页面上；（2）它在 flex 容器里占位，
   会把命令条右端挤出多一格 gap（两端间距因此不等）。 */
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0; }


/* ---------- 头部主题切换（暗 ↔ 亮）----------
   与导航、CTA 同一排：40×40，方形圆角，图标随当前主题切换（暗色显示太阳＝点它变亮）。 */
.mk-theme { display: inline-flex; align-items: center; justify-content: center;
  flex: 0 0 auto; border: 1px solid var(--line);
  border-radius: var(--r-md); background: var(--panel); color: var(--txt-body); cursor: pointer;
  transition: color .15s ease, border-color .15s ease; }

.mk-theme:hover { color: var(--txt); border-color: var(--accent); }

.mk-theme:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.mk-theme .ic { width: 18px; height: 18px; }


/* 窄屏头部列定义（必须放在文件最后：上面的基础 .mk-top 模板 grid-template-columns: 1fr auto 1fr
   是按"导航居中"设计的，窄屏要改成"动作区与汉堡贴右"，靠源序胜出） */
@media (max-width: 860px) {

  .mk-top { grid-template-columns: minmax(0, 1fr) auto auto; }

  .mk-burger { justify-self: end; }}


/* ---------- 首屏 / 尾部 CTA 的背景光效（扒自参考站的两层实现） ----------
   2026-10：重点词渐变定为 D9c（绿→青→蓝→紫→玫，oklch 绕远色相），
   背景同步换成同族冷色：绿（起点）+ 玫红（终点）+ 紫（中段），不再用琥珀。
   ① .lp-aurora：三团径向渐变打底 —— 顶部一团（圆心抬到盒子上方 → 形成顶部光晕）、
      右中一团（玫红）、左下一团（紫）；用 color-mix 生成带 alpha 的同色，衰减到全透明。
   ② .lp-orb：三枚大圆 + blur(64px) 的实体光球，各自长周期不规则漂移 ——
      这是"极光"有体积感的关键，只有渐变层会显得平。
   亮色降透明度（参考站 light 用 60%、dark 用 100%）；尊重 prefers-reduced-motion。
   注意：这段注释必须整体闭合。上一次插入 D9c 说明时把注释闭合符提前打上，导致后面
   几行变成裸 token、把紧接着的 `.lp-band.is-deep{overflow:hidden}` 整条吞掉（极光溢出分带）。 */
.lp-band.is-deep { position: relative; overflow: hidden; }

/* 装饰层容器：负责裁剪 + **底部渐隐**。
   没有这层遮罩时，光晕会在分带底边被硬切（实测边界处色差 Δ=57，肉眼是一条横缝）；
   现在用 6 段曲线把淡出拉长到 48% 行程（52%→100%），并把光晕源头整体上移，
   使分带底部本来就弱 —— 否则再长的斜坡也会被看成一条暗带。 */
.lp-glow { position: absolute; inset: 0; max-width: none; margin: 0; overflow: hidden; pointer-events: none; z-index: 0;
  -webkit-mask-image: linear-gradient(180deg,
    #000 0%, #000 52%, rgba(0,0,0,.86) 70%, rgba(0,0,0,.6) 83%, rgba(0,0,0,.3) 93%, transparent 100%);
  mask-image: linear-gradient(180deg,
    #000 0%, #000 52%, rgba(0,0,0,.86) 70%, rgba(0,0,0,.6) 83%, rgba(0,0,0,.3) 93%, transparent 100%); }

.lp-band.is-deep > .lp-inner,
.lp-band.is-deep > .lp-final { position: relative; z-index: 1; }

/* max-width/margin 必须显式归位：上面那条 `.lp-band > div { max-width: 1160px; margin: auto }`
   会把装饰层也当成内容列约束住（实测极光层只有 1160 宽而不是整段 1440）。 */
.lp-glow > .lp-aurora { position: absolute; inset: -14%; max-width: none; margin: 0; pointer-events: none; opacity: .6;
  will-change: transform; animation: lp-flow-aurora 34s ease-in-out infinite;
  background:
    radial-gradient(80% 80% at 50% -20%, color-mix(in srgb, var(--accent) 30%, transparent), transparent),
    radial-gradient(56% 52% at 80% 40%, color-mix(in srgb, var(--hl-to) 20%, transparent), transparent),
    radial-gradient(58% 54% at 18% 62%, color-mix(in srgb, var(--purple) 30%, transparent), transparent); }

[data-theme="dark"] .lp-glow > .lp-aurora { opacity: 1; }

.lp-glow > .lp-orb { position: absolute; max-width: none; margin: 0; border-radius: 50%; filter: blur(64px);
  pointer-events: none; opacity: .55; will-change: transform; }

[data-theme="dark"] .lp-glow > .lp-orb { opacity: 1; }

.lp-glow > .lp-orb-a { top: 25%; left: 25%; width: 384px; height: 384px;
  background: color-mix(in srgb, var(--accent) 30%, transparent);
  animation: lp-flow-a 15s ease-in-out infinite; }

.lp-glow > .lp-orb-b { bottom: 28%; right: 24%; width: 336px; height: 336px;
  background: color-mix(in srgb, var(--hl-to) 28%, transparent);
  animation: lp-flow-b 20s ease-in-out infinite; animation-delay: -7s; }

/* 第三枚（紫，中段色）：最小、最慢，专门打散前两枚的相位关系 */
.lp-glow > .lp-orb-c { top: 52%; left: 14%; width: 300px; height: 300px;
  background: color-mix(in srgb, var(--purple) 32%, transparent);
  animation: lp-flow-c 26s ease-in-out infinite; animation-delay: -17s; }

/* ---------- 烟雾式流动 ----------
   只动 transform / opacity：走合成器线程，不触发布局与重绘。
   三个周期 15 / 20 / 26 秒互质，加上负延迟错相 → 组合周期极长，肉眼看不出循环。 */
@keyframes lp-flow-aurora {

  0%, 100% { transform: translate3d(0, 0, 0) scale(1); }

  25% { transform: translate3d(-2.5%, 1.5%, 0) scale(1.06); }

  50% { transform: translate3d(2%, -2%, 0) scale(1.02); }

  75% { transform: translate3d(1.5%, 2.5%, 0) scale(1.08); }
}

@keyframes lp-flow-a {

  0%, 100% { transform: translate3d(0, 0, 0) scale(1); }

  22% { transform: translate3d(9%, -8%, 0) scale(1.16); }

  48% { transform: translate3d(-7%, 6%, 0) scale(0.9); }

  73% { transform: translate3d(7%, 9%, 0) scale(1.11); }
}

@keyframes lp-flow-b {

  0%, 100% { transform: translate3d(0, 0, 0) scale(1); }

  28% { transform: translate3d(-10%, -6%, 0) scale(1.18); }

  53% { transform: translate3d(6%, 7%, 0) scale(0.88); }

  79% { transform: translate3d(-7%, 5%, 0) scale(1.14); }
}

@keyframes lp-flow-c {

  0%, 100% { transform: translate3d(0, 0, 0) scale(1); }

  33% { transform: translate3d(9%, -7%, 0) scale(1.18); }

  66% { transform: translate3d(-7%, -9%, 0) scale(0.92); }
}

@media (max-width: 860px) {

  .lp-glow > .lp-orb-a { width: 256px; height: 256px; }

  .lp-glow > .lp-orb-b { width: 224px; height: 224px; }

  .lp-glow > .lp-orb-c { width: 180px; height: 180px; }}

@media (prefers-reduced-motion: reduce) {

  .lp-glow > .lp-orb,
  .lp-glow > .lp-aurora { animation: none; }}


/* ---------- 链接 hover ----------
   共享层已经全局去掉下划线、并统一成"变暗"（ui/styles.css：`a:hover{opacity:.82}`），
   所以改前这里那层"覆盖共享层 hover 下划线"的补丁已无必要（2026-10-13 删除）。
   只剩一条：按钮/导航/页脚本来就有底色或描边反馈，再叠一层变暗反而脏。 */
.link-btn:hover { opacity: .82; }


/* ---------- 窄屏：头部控件统一到 44px（触控门槛） ----------
   必须放文件最后：基础 `.mk-theme` 等规则在文件后段，同权重时源序靠后者胜出，
   写在前面媒体块里会被覆盖（实测踩过一次：主题切换停在 40px）。 */
@media (max-width: 860px) {

  /* 触控门槛：整排控件一起抬到 44px —— 只改这一处，不会再出现"某个控件漏掉" */
  .mk-top { --mk-ctl: 44px; }}


/* ============================================================
   子页面（guide / precheck / 404）沿用落地页规范：
   同一套分带背景、同一套标题层级（居中大标题 + 一行小字）、同一套卡片语言。
   这里只补子页面独有的构件；分带/光效/卡片基类全部复用首页那套。 */

/* 页面级 hero：首屏不需要首页那么大的顶距（首页要留出大视觉） */
.lp-hero2.is-page { padding: 56px 0 40px; }

.lp-hero2 .lead { margin-bottom: 0; }

/* 徽标行（7 步 / 5 个问题 …）：与首页 hero 同一套胶囊样式 */
.lp-hero2 .meta { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; margin-top: 22px; }

.lp-hero2 .meta .badge { font-size: var(--fs-xs); color: var(--txt-body); border: 1px solid var(--line);
  background: var(--panel); border-radius: var(--r-full); padding: 4px 12px; }

/* 四列版卡片网格（操作指南的四个前提） */
.lp-safe.lp-safe-4 { grid-template-columns: repeat(4, 1fr); }

@media (max-width: 1024px) { .lp-safe.lp-safe-4 { grid-template-columns: repeat(2, 1fr); }}

@media (max-width: 560px) { .lp-safe.lp-safe-4 { grid-template-columns: 1fr; }}

/* 分组小标题（在另一台设备上 / 在故障机上操作 / 回到另一台设备） */
.lp-group { text-align: center; font-size: var(--fs-sm); font-weight: 600; color: var(--dim);
  letter-spacing: .04em; margin: 44px 0 16px; }

.lp-group:first-of-type { margin-top: 0; }

/* 步骤列表：编号 + 正文的卡片，纵向排列（比首页的四步卡承载更多内容） */
.lp-steps { display: flex; flex-direction: column; gap: 14px; max-width: 880px; margin: 0 auto; }

.lp-step-card { display: grid; grid-template-columns: 56px minmax(0, 1fr); gap: 18px;
  border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--panel); padding: 20px 22px; }

.lp-step-no { font-family: var(--font-mono); font-size: var(--fs-xl); font-weight: 600; color: var(--accent); line-height: 1.2; }

.lp-step-body h3 { margin: 0 0 8px; font-size: var(--fs-lg); }

.lp-step-body > p { margin: 0 0 12px; color: var(--txt-body); font-size: var(--fs-sm); line-height: 1.8; }

/* "做完会看到"：左侧色条 + 淡底，与正文明确分开 */
.lp-see { border-left: 2px solid var(--accent); border-radius: 0 var(--r-sm) var(--r-sm) 0;
  background: color-mix(in srgb, var(--accent) 7%, transparent);
  padding: 10px 14px; margin: 0 0 12px !important; font-size: var(--fs-sm); line-height: 1.75; color: var(--txt-body); }

.lp-see strong { color: var(--accent); }

@media (max-width: 560px) {

  .lp-step-card { grid-template-columns: 1fr; gap: 10px; }}

/* 章节内的按钮行：居中 */
/* CTA 行基类：之前**只有后代规则、没有基类**（首页靠 hero 的 text-align:center 碰巧居中），
   子页面里没有 text-align，按钮就贴了左边缘。这里补上 flex 容器与居中。 */
.lp-cta { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; }

.lp-cta-row { justify-content: center; margin: 32px 0 0; }

.lp-hero2 .lp-cta { justify-content: center; margin-bottom: 20px; }

/* 章节内的补充说明行 */
.lp-inline-note { max-width: 720px; margin: 32px auto 14px; text-align: center; line-height: 1.8; }

/* 404 卡片底部按钮 */
.lp-safe-cta { margin: 14px 0 0 !important; }

/* ---------- 自助预检的交互流（由 assets/precheck.js 渲染，类名保持不变） ---------- */
/* 进度与卡片在分带内居中成 860px 一列。
   必须带上 `.lp-band >` 前缀：这些元素是分带的直接子 div，会被上面那条
   `.lp-band > div { max-width: 1160px }` 命中（实测进度条被撑到 1112、比问题卡宽）。 */
.lp-band > .pk-progress,
.lp-band > .pk-card,
.lp-band > .pk-result,
.pk-progress, .pk-card, .pk-result { width: 100%; max-width: 860px; margin-left: auto; margin-right: auto; }

.pk-progress { margin-top: 0; margin-bottom: 18px; }

.pk-card, .pk-result { margin-top: 0; padding: 26px 24px; border-radius: var(--r-lg); }

.pk-q { text-align: center; }

.pk-hint { text-align: center; }

.pk-options { gap: 12px; }

.pk-opt { border-radius: var(--r-md); padding: 14px 16px; text-align: left; background: var(--panel2); }

.pk-opt:hover { background: var(--panel); }

.pk-help { border-radius: var(--r-md); }

.pk-verdict { padding: 6px 16px; }

.pk-block { font-size: var(--fs-sm); }

.pk-list { padding-left: 22px; }

.pk-result.ok { border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); }

.pk-result.refer { border-color: color-mix(in srgb, var(--amber) 45%, var(--line)); }

/* 结论文案与按钮行居中 */
.pk-result .pk-q, .pk-result .pk-code, .pk-result .pk-verdict { text-align: center; }

.pk-result .pk-verdict { margin: 0 auto; }

.pk-result .row { justify-content: center; }


/* ---------- 自助预检：进页面直接答题 ----------
   只有一行标题（给 SEO 与方位感），下面立刻是进度与第 1 题。 */
/* 表单起步的页面：不需要首页那种大留白，但必须让过悬浮导航
   （导航 14px 偏移 + 60px 高 = 底边 74px）。
   2026-10-13 去掉页头之后留白从 108 收到 88 —— 那 20px 原本是给标题留的呼吸，
   现在第一眼就是进度条与题目，再往上顶一点才像"进来就能答题"。 */
.lp-band-precheck { padding-top: 88px; }


/* 第三种结论状态：先自测一步再判断（例如不通电先换充电器）——
   既不是"能接入"也不是"必须送修"，用中性色，避免误读成送修。 */
.pk-result.defer { border-color: color-mix(in srgb, var(--txt-body) 28%, var(--line)); }

.pk-result.defer .pk-verdict { color: var(--txt-body); border-color: color-mix(in srgb, var(--txt-body) 32%, var(--line)); }


/* ---------- 预检选项里的安全关键短语 ----------
   "这类机器不能通电""有起火风险，立刻断电"被当成普通小字读过去是要出事的，
   所以单列语气色，并给整张选项卡加同色左边框（扫一眼就能分辨哪几项是红线）。 */
.pk-opt[data-tone] { border-left-width: 3px; }

.pk-opt[data-tone="danger"] { border-left-color: color-mix(in srgb, var(--red) 70%, var(--line)); }

.pk-opt[data-tone="warn"] { border-left-color: color-mix(in srgb, var(--amber) 70%, var(--line)); }

.pk-opt[data-tone="ok"] { border-left-color: color-mix(in srgb, var(--accent) 55%, var(--line)); }

/* ---------- 是/否 的一眼可认标记（用户 2026-10-13）----------
   用户："隐含是、否逻辑的选项，需要通过样式隐含是、否逻辑，比如绿色一般代表 yes，
   用户就直接关注这个选项就行了，而非写卷子考试一样每个选项都读一遍。"
   实现复用 tone 那条**左侧色条**的视觉语法（同一套语言，不另造一套），并且更进一步：
   连主文案也走绿色，标签前再给一个 ✓ —— 因为 tone 那条只是"提醒注意"，
   而这里要的是"**扫一眼就定位**"，只给一条 3px 边不够。
   否的那一项刻意不打任何标记：不打，绿色才有指向性。 */
.pk-opt[data-mark="yes"] {
  border-color: color-mix(in srgb, var(--accent) 42%, var(--line));
  border-left: 3px solid var(--accent);
}
.pk-opt[data-mark="yes"] .pk-opt-label { color: var(--accent-ink); }
[data-theme="dark"] .pk-opt[data-mark="yes"] .pk-opt-label { color: var(--accent); }

/* 「教我一下」不是二选一里的另一个答案，所以给**灰 ?**而不是绿色：
   三个选项里两个绿的，一眼可认就失效了。 */
.pk-opt[data-mark="help"] { border-left: 3px solid color-mix(in srgb, var(--dim) 45%, var(--line)); }
.pk-opt[data-mark="help"] .pk-opt-label { color: var(--txt-body); }

/* 标记图标：跟主文案同一行，继承 currentColor（所以 yes 自然是绿的） */
.pk-opt-mark { width: 1.05em; height: 1.05em; vertical-align: -0.16em; margin-right: 6px; }

.pk-emph { font-weight: 600; }

.pk-emph.is-danger { color: var(--red); }

.pk-emph.is-warn { color: var(--amber); }

.pk-emph.is-ok { color: var(--accent); }


/* ---------- 预检的独立引导步骤（怎么进恢复模式 / 怎么排除供电 / 怎么联网）----------
   题目卡只留"判断标准 + 选项"；教学内容单独一屏，信息量与题目分开，扫读负担小。 */
.pk-guide .pk-guide-kicker { display: flex; align-items: center; justify-content: center; gap: 8px;
  margin: 0 0 10px; font-size: var(--fs-xs); letter-spacing: .06em; color: var(--accent); }

.pk-guide .pk-q { margin-bottom: 8px; }

.pk-guide .pk-help-groups { margin-top: 22px; gap: 18px; }

.pk-guide .pk-help-row { gap: 6px; }

.pk-guide .pk-help-row dt { font-size: var(--fs-base); }

.pk-guide .pk-help-row dd { font-size: var(--fs-sm); line-height: 1.8; }


/* ---------- 结论卡的第四档语气：danger（红）----------
   红 = 强烈建议送修（进液 / 冒烟鼓包这类有腐蚀或起火风险的），
   与琥珀色"建议送修"（摔落 / 不通电 / 进不了恢复 / 连不上网）区分开。 */
.pk-result.danger { border-color: color-mix(in srgb, var(--red) 55%, var(--line)); }

.pk-result.danger .pk-verdict { color: var(--red); border-color: color-mix(in srgb, var(--red) 55%, var(--line)); }

.pk-result.danger .pk-code .mono { color: var(--red); }


/* ---------- 引导屏的两种结构 ---------- */
/* ① 互斥分支（pick）：先选一支，只显示那一支 —— 避免一屏并排 3 段互斥说明 */
.pk-pick { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; margin: 22px 0 16px; }

.pk-pick-tab { min-height: 40px; padding: 0 16px; border-radius: var(--r-full); border: 1px solid var(--line);
  background: var(--panel2); color: var(--txt-body); font-size: var(--fs-sm); font-family: inherit;
  cursor: pointer; transition: color .18s ease, border-color .18s ease, background .18s ease; }

.pk-pick-tab:hover { color: var(--txt); border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); }

.pk-pick-tab.is-on { color: var(--accent-ink); border-color: color-mix(in srgb, var(--accent) 55%, var(--line));
  background: color-mix(in srgb, var(--accent) 10%, var(--panel)); }

[data-theme="dark"] .pk-pick-tab.is-on { color: var(--accent); }

.pk-pick-tab:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.pk-pick-body { border: 1px solid var(--line); border-radius: var(--r-md); background: var(--panel2);
  padding: 16px 18px; font-size: var(--fs-sm); line-height: 1.85; color: var(--txt-body); }

/* ② 先后步骤（steps）：带序号的清单 */
.pk-steps-list { list-style: none; margin: 22px 0 0; padding: 0; display: flex; flex-direction: column; gap: 14px; }

.pk-steps-list li { display: grid; grid-template-columns: 22px minmax(0, 1fr); gap: 12px; align-items: start; }

.pk-steps-n { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px;
  margin-top: 2px; border-radius: var(--r-full); background: color-mix(in srgb, var(--accent) 14%, transparent);
  color: var(--accent); }

.pk-steps-n svg { width: 13px; height: 13px; }

.pk-steps-text strong { display: block; font-size: var(--fs-base); margin-bottom: 4px; }

.pk-steps-text p { margin: 0; color: var(--txt-body); font-size: var(--fs-sm); line-height: 1.8; }


/* ---------- 引导屏里的有序步骤 ----------
   "按住电源键 → 出现选项 → 点继续"这类描述必须是有序列表，不能糊成一段话。 */
.pk-ol { margin: 0; padding-left: 22px; display: flex; flex-direction: column; gap: 7px;
  font-size: var(--fs-sm); line-height: 1.8; color: var(--txt-body); }

.pk-ol li::marker { color: var(--accent); font-weight: 600; }

.pk-body-p { margin: 0; font-size: var(--fs-sm); line-height: 1.85; color: var(--txt-body); }

.pk-steps-text .pk-ol { margin-top: 6px; }

/* ============================================================
   「它怎么工作」= 双轨串行动画（2026-10-14 第四版，用户定稿口径）
   上线：智能体 → 故障机（下发）；下线：故障机 → 智能体（回传）。
   拍点表嵌在页面里（#how-script，application/json），landing.js 的播放器
   **严格 one by one** 执行：同一时刻只有一个动作短语、一次过线或一行日志。
   命令行逐字敲出；光标始终跟最新一行。
   无 JS / reduced-motion：页面自带静态终态，播放器不动它。
   ============================================================ */

.lp-route-rail { display: flex; justify-content: flex-end; margin-bottom: var(--sp-4); }

/* 单 Card 连续时间线：一个 stage 从头播到尾（接入 → 诊断修复，不清屏） */
.lp-stage { display: grid; grid-template-columns: minmax(0, 1fr) minmax(150px, 168px) minmax(0, 1fr);
  gap: var(--sp-4); align-items: stretch; }

/* 两台设备：简化窗栏 + 控制台材料（深底等宽 = 机器在说话；面板底 = 给人读的界面） */
.lp-dev { margin: 0; display: flex; flex-direction: column; overflow: hidden; position: relative;
  height: 336px;              /* 双 Card 高度固定（含窗栏），内容区内部滚动 */
  border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--panel);
  box-shadow: 0 18px 40px rgba(0, 0, 0, .32); }
.lp-dev-head { display: flex; align-items: center; gap: 6px; padding: 8px var(--sp-3);
  background: var(--panel2); border-bottom: 1px solid var(--line); }
.lp-wdot { width: 9px; height: 9px; border-radius: var(--r-full); flex: 0 0 auto; }
.lp-wdot:nth-child(1) { background: #EF4444; }
.lp-wdot:nth-child(2) { background: #F59E0B; }
.lp-wdot:nth-child(3) { background: #22C55E; }
.lp-logo { width: 16px; height: 16px; flex: 0 0 auto; }
.lp-wtitle { margin-left: var(--sp-2); font-size: var(--fs-2xs); color: var(--dim);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* 终端体：滚动只发生在它内部（浮层在 figure 层，不跟着滚） */
.lp-term-wrap { flex: 1; min-height: 0; display: flex; }
.lp-dev-body { flex: 1; display: flex; flex-direction: column; gap: 7px; padding: var(--sp-4);
  overflow-y: auto; scrollbar-width: thin; scrollbar-color: var(--line) transparent;
  font-family: var(--font-mono); font-size: var(--fs-2xs); line-height: 1.75;
  color: var(--txt-body); position: relative; }
.lp-dev.is-mac .lp-dev-body { background: color-mix(in srgb, var(--panel2) 88%, black); }

/* 控制台行：纯文本 + 语义色，没有 icon（非 TUI 口径，用户 2026-10-14 定） */
.lp-ln { display: flex; gap: var(--sp-2); flex-wrap: wrap; align-items: baseline; }
.lp-msg { font-family: var(--font-sans); border: 1px solid var(--line);
  border-radius: var(--r-md); padding: 6px 10px; background: var(--panel2);
  align-self: stretch; }
.lp-ln.is-ok { color: var(--accent); }
.lp-ln.is-dim { color: var(--dim); }
.lp-ln.is-live { color: var(--txt); }
.lp-ln i { font-style: normal; color: var(--dim); }
.lp-ln b { font-weight: 400; letter-spacing: .12em; color: var(--accent); }
/* 提示符行：始终是最后一行，但**紧贴上一条输出**（mac Terminal 真实行为），
   不钉面板底部 —— 面板底下留白是假终端才有的样子。 */
.lp-pline { margin-top: 0; }
.lp-prompt { font-style: normal; color: var(--accent); flex: 0 0 auto; }
.lp-caret { display: inline-block; width: .55em; height: 1em; margin-left: 1px;
  background: var(--accent); }
/* 提示符行垂直居中：12px 字形在 21px 行盒里本身就近居中，居中后光标块与字形盒
   偏差 <1px（flex 的 baseline 对齐实测反而高 1.5px —— 像素实测校准，别改回）。 */
.lp-pline { align-items: center; }


@media (prefers-reduced-motion: no-preference) {
  .lp-caret { animation: lp-blink 1s steps(2, start) infinite; }
  @keyframes lp-blink { 0%, 100% { opacity: 1 } 50% { opacity: 0 } }
  /* 播放中追加的行逐行落（静态终态的行不做入场，避免无 JS 页面闪动） */
  .js-playing .lp-ln { animation: lp-ln-in .28s ease-out both; }
  @keyframes lp-ln-in { from { opacity: 0; transform: translateY(-3px); } }
  .js-playing .lp-desktop { transition: opacity .35s ease-out; }
}

/* ---------- 通道：两根方向恒定的平行线 ----------
   上（is-down）：智能体 → 故障机；下（is-up）：故障机 → 智能体。
   短语区是**单个槽位**：严格串行的播放器保证同一时刻只有一个短语，文本直接替换。 */
.lp-chan { display: flex; flex-direction: column; justify-content: center; gap: 16px; min-width: 0; }
.lp-acts { position: relative; height: 1.9em; }
.lp-act { position: absolute; left: 50%; top: 0; transform: translate(-50%, 3px);
  white-space: nowrap; font-size: var(--fs-2xs); color: var(--txt-body); opacity: 0;
  transition: opacity .25s ease-out, transform .25s ease-out; }
.lp-act.is-on { opacity: 1; transform: translate(-50%, 0); }
.lp-line { position: relative; display: block; height: 8px; }
.lp-line::before { content: ""; position: absolute; left: 0; right: 0; top: 3px;
  height: 1px; background: var(--line); }
.lp-line::after { content: ""; position: absolute; top: 1px;
  border-top: 3.5px solid transparent; border-bottom: 3.5px solid transparent; }
.lp-line.is-down::after { right: 0; border-left: 5px solid var(--dim); }
.lp-line.is-up::after { left: 0; border-right: 5px solid var(--dim); }
.lp-line::before, .lp-line::after { transition: background-color .2s ease, border-color .2s ease; }
.lp-line.is-active::before { background: var(--accent);
  box-shadow: 0 0 8px color-mix(in srgb, var(--accent) 45%, transparent); }
.lp-line.is-down.is-active::after { border-left-color: var(--accent); }
.lp-line.is-up.is-active::after { border-right-color: var(--accent); }
.lp-line .lp-sig { position: absolute; top: 1px; left: 0; width: 7px; height: 7px;
  border-radius: var(--r-full); background: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
  opacity: 0; }
@media (prefers-reduced-motion: no-preference) {
  .lp-line.is-down .lp-sig.is-run { animation: lp-travel 1s linear both; }
  .lp-line.is-up .lp-sig.is-run { animation: lp-travel-back 1s linear both; }
  /* 走完即淡出：不留一排停在线尾的圆点 */
  @keyframes lp-travel {
    0% { left: 0; opacity: 0 } 12% { opacity: 1 } 88% { opacity: 1 }
    100% { left: calc(100% - 7px); opacity: 0 } }
  @keyframes lp-travel-back {
    0% { left: calc(100% - 7px); opacity: 0 } 12% { opacity: 1 } 88% { opacity: 1 }
    100% { left: 0; opacity: 0 } }
}

/* ---------- macOS 终态三屏（按用户给的 UTM 虚拟机参考图重画）----------
   boot = 黑底 + Apple logo + 进度条；login = Tahoe 壁纸 + 日期时间 + admin + 密码框；
   desktop = 同一张壁纸 + 菜单栏 + Dock。三屏共用一块不滚动的浮层，逐个淡入。 */
.lp-desktop { position: absolute; inset: 0; z-index: 2; opacity: 0; pointer-events: none;
  overflow: hidden; }
.lp-desktop.is-on { opacity: 1; }
.lp-desktop.is-boot { background: #000; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 28px; }
.lp-apple { width: 54px; height: 54px; fill: #EDEDED; }
.lp-prog { display: block; width: 128px; height: 4px; border-radius: var(--r-full);
  background: rgba(255, 255, 255, .22); overflow: hidden; }
.lp-prog b { display: block; height: 100%; width: 0; border-radius: var(--r-full);
  background: #F2F2F2; }
@media (prefers-reduced-motion: no-preference) {
  .lp-desktop.is-boot.is-on .lp-prog b { animation: lp-boot 2.4s ease-in-out both; }
  @keyframes lp-boot { from { width: 0 } to { width: 100% } }
}

/* 壁纸：天空 → 雪山 → 湖水 → 近岸（表意 Tahoe 那张，不描摹） */
.lp-wall { position: absolute; inset: 0; display: block; }
.lp-wall i { position: absolute; left: 0; right: 0; display: block; }
.lp-w-sky { top: 0; height: 62%; background: linear-gradient(#2F6FB5, #7FB6DF); }
.lp-w-mtn { top: 34%; height: 34%;
  background: linear-gradient(#FBFDFE 0 15%, #B4C8D5 15% 42%, #7C94A5 42% 72%, #5A7385 72% 100%);
  clip-path: polygon(0 66%, 8% 50%, 16% 58%, 26% 36%, 36% 54%, 46% 32%, 56% 52%,
    66% 40%, 78% 54%, 88% 44%, 100% 58%, 100% 100%, 0 100%); }
.lp-w-lake { top: 64%; height: 24%;
  background: linear-gradient(#175F86 0, #1F7FA0 32%, #46B9BE 70%, #86DAD2 100%); }
.lp-w-shore { top: 86%; bottom: 0;
  background: linear-gradient(#86DAD2 0, #2C7E86 32%, #1D4E58 100%); }

/* 登录屏：日期 / 时间 / 头像 / 用户名 / 密码框 / 提示（同参考图的排布） */
.lp-login-box { position: relative; z-index: 2; height: 100%; display: flex;
  flex-direction: column; align-items: center; justify-content: center;
  gap: 6px; font-family: var(--font-sans); color: #fff;
  text-shadow: 0 1px 10px rgba(0, 0, 0, .35); }
.lp-login-date { margin: 0 0 14px; font-size: var(--fs-sm); opacity: .92; }
.lp-login-time { margin: -22px 0 18px; font-size: 46px; line-height: 1; font-weight: 300;
  letter-spacing: .02em; color: #CFE6F5; }
.lp-avatar { width: 46px; height: 46px; border-radius: var(--r-full);
  background: radial-gradient(circle at 50% 38%, #BEE89A, #6FBF4A);
  display: grid; place-items: center; box-shadow: 0 2px 10px rgba(0, 0, 0, .3); }
.lp-face { position: relative; width: 24px; height: 24px; }
.lp-face::before, .lp-face::after { content: ""; position: absolute; top: 6px; width: 5px;
  height: 6px; border-radius: var(--r-full); background: #24501C; }
.lp-face::before { left: 3px; } .lp-face::after { right: 3px; }
.lp-login-user { margin: 4px 0 12px; font-size: var(--fs-sm); }
.lp-pass { display: inline-flex; align-items: center; gap: 1px; min-width: 116px;
  padding: 5px 10px; border-radius: var(--r-full); background: rgba(255, 255, 255, .22);
  backdrop-filter: blur(6px); font-size: var(--fs-2xs); }
.lp-pass-ph { font-style: normal; opacity: .78; }
.lp-pass-dots { font-style: normal; letter-spacing: 1px; }
.lp-login-hint { margin: 8px 0 0; font-size: var(--fs-2xs); opacity: .72; }

/* 桌面屏：菜单栏 + Dock */
.lp-menubar { position: relative; z-index: 2; display: block; height: 14px;
  background: rgba(255, 255, 255, .28); backdrop-filter: blur(6px); }
.lp-dock { position: absolute; z-index: 2; left: 50%; bottom: 8px; transform: translateX(-50%);
  display: flex; gap: 5px; padding: 5px 7px; border-radius: var(--r-md);
  background: rgba(255, 255, 255, .24); backdrop-filter: blur(8px); }
.lp-dock b { width: 13px; height: 13px; border-radius: var(--r-sm); background: rgba(255, 255, 255, .62); }

/* 自动演示按钮（不自动播；reduced-motion 下不播） */
.lp-play { margin-left: auto; display: inline-flex; align-items: center; gap: var(--sp-2);
  font: inherit; font-size: var(--fs-sm); color: var(--dim); cursor: pointer; background: none;
  border: 1px dashed var(--line); border-radius: var(--r-full); padding: 6px var(--sp-4);
  transition: color .18s ease, border-color .18s ease; }
.lp-play:hover { color: var(--txt); border-color: var(--accent); }
.lp-i { width: 14px; height: 14px; flex: 0 0 auto; fill: currentColor; }
.lp-play .i-pause { display: none; }
.lp-play[aria-pressed="true"] .i-play { display: none; }
.lp-play[aria-pressed="true"] .i-pause { display: block; }
.lp-play:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { .lp-play { display: none; } }

/* 窄屏：两台设备竖排，两根线转 90° 仍保持各自方向（↓ 在上、↑ 在下） */
@media (max-width: 860px) {
  /* 移动端（用户 2026-10-14）：**垂直双屏**——两张 Card 直接上下叠，
     通道收成一小段**竖排双轨**：两根线旋转 90° 立在两张卡之间，信号圆点照旧沿线走，
     但**不画箭头、不出动作短语**（手机上一屏放不下，也不靠文字解释方向）。
     目标是 393×852 这种手机上整节一屏看全，所以 Card 高度也收一档。 */
  .lp-stage { grid-template-columns: minmax(0, 1fr); gap: var(--sp-2); }
  .lp-chan { min-width: 0; flex-direction: row; align-items: center; justify-content: center;
    gap: var(--sp-4); height: 52px; }
  .lp-acts { display: none; }
  .lp-line { width: 44px; flex: 0 0 auto; transform: rotate(90deg); }
  .lp-line::after { display: none; }
  .lp-dev { height: clamp(180px, 26vh, 240px); }
  .lp-dev-body { padding: var(--sp-3); gap: 5px; }
  .lp-route-rail { margin-bottom: var(--sp-3); }
  #how h2 { margin-bottom: 10px; }
  #how .sub { margin-bottom: 12px; }
}

/* ---------- 这一节的入场（脚本加 html.hw-anim 才生效）----------
   规范：400-600ms、ease-out；reduced-motion 与"脚本没跑"都必须给终态。 */
html.hw-anim .lp-route { opacity: 0; transform: translateY(14px);
  transition: opacity .5s ease-out, transform .5s ease-out; }
html.hw-anim .lp-route.is-in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  html.hw-anim .lp-route { opacity: 1; transform: none; transition: none; }
}
