
/* ══════════════════════════════════════════════════════════════
 *  SOMA Design System v2 — Linear/Vercel/Raycast  inspired
 *  三层令牌架构：原语 → 语义 → 组件
 *  暖灰基调 · Inter + JetBrains Mono + Noto Sans SC · 低饱和强调色
 * ══════════════════════════════════════════════════════════════ */

/* ── Dark theme（默认）────────────────────────────────────────── */
:root {
  /* Layer 1: Primitives — warm gray（暖灰，非冷蓝灰） */
  --_n50: #fafaf9;  --_n100: #f5f5f4; --_n150: #eeeeed;
  --_n200: #e7e5e4; --_n250: #d6d3d1; --_n300: #b8b3ad;
  --_n400: #a1978d; --_n500: #78716c; --_n600: #57534e;
  --_n700: #44403c; --_n750: #3c3835; --_n800: #292524;
  --_n850: #1c1917; --_n900: #171412; --_n950: #0f0d0c;

  /* Accent primitives */
  --_green400: #4ade80; --_green500: #22c55e;
  --_red400: #f87171;   --_red500: #ef4444;
  --_amber400: #fbbf24; --_amber500: #f59e0b;
  --_violet400: #a78bfa; --_violet500: #8b5cf6;

  /* Layer 2: Semantics — Deep background with glass layers */
  --bg: #050505;
  --bg-hover: rgba(255, 255, 255, 0.06);
  --surface: #0a0a0a;
  --surface-2: #111111;
  --surface-3: #1a1a1a;
  --surface-elevated: #141414;

  --border: rgba(255, 255, 255, 0.04);
  --divider: rgba(255, 255, 255, 0.03);
  --border-strong: rgba(255, 255, 255, 0.08);
  --border-glow: rgba(255, 255, 255, 0.06);
  --scrollbar-hover: #444444;

  --text: #ffffff;
  --text-dim: #a0a0a0;
  --text-faint: #666666;

  --user: #e8c766;
  --agent: #c4b5fd;
  --success: #4ade80;
  --danger: #f87171;
  --color-warning: #fbbf24;
  --color-accent: #d9ac3f;
  --color-accent-hover: #bd9332;

  /* Typography — 顺序照 Cindy：拉丁 Inter → Windows UI 字 → 中文无衬线。
     ★ --font-mono 必须显式带中文回退：不然代码 / 路径 / 工具行里的汉字会掉到
       NSimSun（新宋体），10~11px 下笔画糊成一团（2026-10-25 CDP 实测）。 */
  --font-ui: 'Inter', 'Segoe UI', system-ui,
             'Microsoft YaHei UI', 'Microsoft YaHei', 'PingFang SC',
             'Hiragino Sans GB', 'Noto Sans SC', 'Source Han Sans SC',
             'HarmonyOS Sans SC', sans-serif;
  --font-mono: 'JetBrains Mono', 'Cascadia Code', 'Cascadia Mono', Consolas,
               'Courier New', 'Microsoft YaHei UI', 'Microsoft YaHei',
               'PingFang SC', 'Noto Sans SC', monospace;
  --font-title: var(--font-ui);

  /* Fluid type scale — clamp(min, preferred-vw, max)
     中文最小 12px（Cindy 的 meta 字号同样是 12px）：再小汉字的横竖笔画会粘在一起。
     外层 max(12px, …) 是硬下限：字号选「小」时根字号是 14px，0.75rem 只有 10.5px，
     光靠 rem 下限会重新掉到糊的区间（2026-10-25）。 */
  --text-xs: max(12px, clamp(0.75rem, 0.73rem + 0.15vw, 0.8125rem));
  --text-sm: max(12px, clamp(0.8125rem, 0.79rem + 0.18vw, 0.875rem));
  --text-base: clamp(0.875rem, 0.84rem + 0.2vw, 0.9375rem);
  --text-md: var(--text-base);
  --text-lg: clamp(1rem, 0.95rem + 0.3vw, 1.125rem);
  --text-xl: clamp(1.2rem, 1.1rem + 0.5vw, 1.4rem);
  --text-2xl: clamp(1.5rem, 1.3rem + 1vw, 2rem);

  /* Line heights */
  --lh-tight: 1.25;
  --lh-base: 1.6;
  --lh-code: 1.55;

  /* Spacing — 4px base, rem for user-scaling */
  --sp-1: 0.25rem;   /*  4 */
  --sp-2: 0.5rem;    /*  8 */
  --sp-3: 0.75rem;   /* 12 */
  --sp-4: 1rem;      /* 16 */
  --sp-5: 1.5rem;    /* 24 */
  --sp-6: 2rem;      /* 32 */
  --sp-8: 3rem;      /* 48 */

  /* 侧栏宽度 —— 用户拖出来的值由 JS 写在**元素**上（覆盖这里的默认值）。
     收起态那条规则写的是**字面量**（56px / 38px），不引用变量，
     所以折叠永远压得住；见下面 `.sidebar` 那段注释。 */
  --sidebar-w: 240px;
  --inspector-w: 248px;

  /* Radius — refined scale */
  --r-xs: 2px;
  --r-sm: 4px;
  --r-md: 8px;
  --r-lg: 12px;
  --r-xl: 16px;
  --r-full: 999px;

  /* Border width */
  --bw: 1px;
  --bw-accent: 2px;

  /* Shadows — layered elevation system with depth */
  --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.3);
  --shadow-sm: 0 2px 6px rgba(0, 0, 0, 0.35);
  --shadow-md: 0 4px 16px rgba(0, 0, 0, 0.4);
  --shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.45);
  --shadow-xl: 0 16px 48px rgba(0, 0, 0, 0.5);
  --shadow-pop: var(--shadow-xl);
  --shadow-glow-user: 0 0 0 1px var(--user), 0 0 20px rgba(232, 199, 102, 0.18);
  --shadow-glow-danger: 0 0 0 1px var(--danger), 0 0 20px rgba(248, 113, 113, 0.15);
  --shadow-inner: inset 0 1px 0 rgba(255, 255, 255, 0.1);

  /* Motion — easing + duration */
  --dur-fast: 80ms;
  --dur: 150ms;
  --dur-slow: 250ms;
  --dur-anim: 1.2s;
  --ease: cubic-bezier(0.4, 0, 0.2, 1);
  --ease-out: cubic-bezier(0, 0, 0.2, 1);
  --ease-in: cubic-bezier(0.4, 0, 1, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);

  /* Letter spacing */
  --ls-wide: 0.02em;
  --ls-wider: 0.05em;

  /* Aliases */
  --radius: var(--r-md);
  --radius-sm: var(--r-sm);

  /* Glassmorphism — dramatic 3D frosted glass with colored tints.
   * 2026-10-19 用户定稿：整体再降一档不透明度，让背景透出来立体感更强 */
  --glass-bg: rgba(255, 255, 255, 0.05);
  --glass-bg-strong: rgba(255, 255, 255, 0.09);
  --glass-bg-hover: rgba(255, 255, 255, 0.11);
  --glass-blur: 32px;
  --glass-blur-heavy: 56px;
  --glass-border: rgba(255, 255, 255, 0.18);
  --glass-border-strong: rgba(255, 255, 255, 0.25);
  --glass-highlight: rgba(255, 255, 255, 0.12);
  --glass-shadow: 0 8px 32px rgba(0, 0, 0, 0.5), 0 2px 8px rgba(0, 0, 0, 0.3);
  --glass-inner-glow: inset 0 1px 0 rgba(255, 255, 255, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.1);
  /* 品牌强调渐变（深色=金）：logo 渐变字、主按钮等（2026-10-19） */
  --accent-grad: linear-gradient(135deg, #f9e7ae 0%, #e8c766 48%, #c89a30 100%);

  /* Skeleton loading — subtle shimmer */
  --skeleton-base: rgba(255, 255, 255, 0.03);
  --skeleton-shine: rgba(255, 255, 255, 0.06);

  /* Selection */
  --selection: rgba(232, 199, 102, 0.22);

  --bg-image: url('../images/bg-dark.webp');
  --bg-art-opacity: 0.55;
  --bg-art-fallback:
    radial-gradient(1200px 800px at 8% 92%, rgba(74, 111, 165, .10), transparent 60%),
    radial-gradient(900px 700px at 92% 8%, rgba(201, 162, 39, .06), transparent 60%);

  color-scheme: dark;
}

/* ── Light theme — glassmorphism adapted for light backgrounds ── */
:root[data-theme="light"] {
  --bg: #f0f0f0;
  --bg-hover: rgba(0, 0, 0, 0.04);
  --surface: #ffffff;
  --surface-2: #fafafa;
  --surface-3: #f5f5f5;
  --surface-elevated: #ffffff;

  --border: rgba(0, 0, 0, 0.06);
  --divider: rgba(0, 0, 0, 0.04);
  --border-strong: rgba(0, 0, 0, 0.1);
  --border-glow: rgba(0, 0, 0, 0.05);
  --scrollbar-hover: #c0c0c0;

  --text: #1a1a1a;
  --text-dim: #666666;
  --text-faint: #858585;

  --user: #6f4e37;
  --agent: #8b6de8;
  --success: #16a34a;
  --danger: #dc2626;
  --color-warning: #d97706;
  --color-accent: #6f4e37;
  --color-accent-hover: #59412d;

  --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.04);
  --shadow-sm: 0 2px 6px rgba(0, 0, 0, 0.06);
  --shadow-md: 0 4px 16px rgba(0, 0, 0, 0.08);
  --shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.1);
  --shadow-xl: 0 16px 48px rgba(0, 0, 0, 0.12);
  --shadow-pop: var(--shadow-xl);
  --shadow-glow-user: 0 0 0 1px var(--user), 0 0 20px rgba(111, 78, 55, 0.12);
  --shadow-glow-danger: 0 0 0 1px var(--danger), 0 0 20px rgba(220, 38, 38, 0.1);
  --shadow-inner: inset 0 1px 0 rgba(255, 255, 255, 0.8);

  /* Glassmorphism — light mode with enhanced depth and clarity.
   * 2026-10-19 同步降不透明度，与深色一致让背景透出来 */
  --glass-bg: rgba(255, 255, 255, 0.55);
  --glass-bg-strong: rgba(255, 255, 255, 0.7);
  --glass-bg-hover: rgba(255, 255, 255, 0.8);
  --glass-blur: 32px;
  --glass-blur-heavy: 56px;
  --glass-border: rgba(0, 0, 0, 0.08);
  --glass-border-strong: rgba(0, 0, 0, 0.12);
  --glass-highlight: rgba(255, 255, 255, 0.8);
  --glass-shadow: 0 8px 32px rgba(0, 0, 0, 0.12), 0 2px 8px rgba(0, 0, 0, 0.06);
  --glass-inner-glow: inset 0 1px 0 rgba(255, 255, 255, 0.9), inset 0 -1px 0 rgba(0, 0, 0, 0.03);
  /* 品牌强调渐变（浅色=咖啡） */
  --accent-grad: linear-gradient(135deg, #8f6d4e 0%, #6f4e37 52%, #513928 100%);

  --skeleton-base: rgba(0, 0, 0, 0.03);
  --skeleton-shine: rgba(0, 0, 0, 0.06);

  --selection: rgba(111, 78, 55, 0.14);

  --bg-image: url('../images/bg-light.webp');
  --bg-art-opacity: 0.4;
  --bg-art-fallback:
    radial-gradient(1200px 800px at 8% 92%, rgba(74, 111, 165, .07), transparent 60%),
    radial-gradient(900px 700px at 92% 8%, rgba(201, 162, 39, .05), transparent 60%);

  color-scheme: light;
}

@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    --bg: #fafaf9;
    --bg-hover: rgba(0, 0, 0, 0.04);
    --surface: #ffffff;
    --surface-2: #f5f5f4;
    --surface-3: #eeeeed;
    --surface-elevated: #ffffff;
    --border: rgba(0, 0, 0, 0.08);
    --divider: rgba(0, 0, 0, 0.05);
    --border-strong: rgba(0, 0, 0, 0.14);
    --scrollbar-hover: #b8b3ad;
    --text: #171412;
    --text-dim: #78716c;
    --text-faint: #8f8680;
    --user: #6f4e37;
    --agent: #8b6de8;
    --success: #16a34a;
    --danger: #dc2626;
    --color-warning: #d97706;
    --color-accent: #6f4e37;
    --color-accent-hover: #59412d;
    --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.05);
    --shadow-sm: 0 1px 4px rgba(0, 0, 0, 0.07);
    --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08);
    --shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.12);
    --shadow-pop: var(--shadow-lg);
    --glass-bg: rgba(255, 255, 255, 0.55);
    --glass-bg-strong: rgba(255, 255, 255, 0.7);
    --glass-bg-hover: rgba(255, 255, 255, 0.8);
    --glass-border: rgba(0, 0, 0, 0.08);
    --glass-border-strong: rgba(0, 0, 0, 0.12);
    --glass-shadow: 0 8px 32px rgba(0, 0, 0, 0.12), 0 2px 8px rgba(0, 0, 0, 0.06);
    --glass-inner-glow: inset 0 1px 0 rgba(255, 255, 255, 0.9), inset 0 -1px 0 rgba(0, 0, 0, 0.03);
    --skeleton-base: rgba(0, 0, 0, 0.04);
    --skeleton-shine: rgba(0, 0, 0, 0.08);
    --selection: rgba(111, 78, 55, 0.14);
    --accent-grad: linear-gradient(135deg, #8f6d4e 0%, #6f4e37 52%, #513928 100%);
    --bg-image: url('../images/bg-light.webp');
    --bg-art-opacity: 0.4;
    --bg-art-fallback:
      radial-gradient(1200px 800px at 8% 92%, rgba(74, 111, 165, .07), transparent 60%),
      radial-gradient(900px 700px at 92% 8%, rgba(201, 162, 39, .05), transparent 60%);
    color-scheme: light;
  }
}

/* ── 背景主题切换（2026-10-20）──────────────────────────────
 * data-bg-theme 挂在 <html> 上，可选值：""(默认) / "taiji" / "book"。
 * 与 data-theme（dark/light）正交：taiji 和 book 各有深浅两张图，
 * CSS 用复合选择器 :root[data-theme="dark"][data-bg-theme="taiji"] 匹配。 */
:root[data-bg-theme="taiji"][data-theme="dark"],
:root[data-bg-theme="taiji"]:not([data-theme="light"]) {
  --bg-image: url('../images/bg-taiji-dark.webp');
  --bg-art-opacity: 0.6;
}
:root[data-bg-theme="taiji"][data-theme="light"] {
  --bg-image: url('../images/bg-taiji-light.webp');
  --bg-art-opacity: 0.45;
}
:root[data-bg-theme="book"][data-theme="dark"],
:root[data-bg-theme="book"]:not([data-theme="light"]) {
  --bg-image: url('../images/bg-book-dark.webp');
  --bg-art-opacity: 0.55;
}
:root[data-bg-theme="book"][data-theme="light"] {
  --bg-image: url('../images/bg-book-light.webp');
  --bg-art-opacity: 0.4;
}

* { box-sizing: border-box; margin: 0; padding: 0; }
[hidden] { display: none !important; }
::selection { background: var(--selection); }
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border); border-radius: var(--r-md); }
::-webkit-scrollbar-thumb:hover { background: var(--scrollbar-hover); }
/* 界面字号（2026-10-25）：正文全部走 rem 令牌，所以**只缩放根字号**就能
   整体放大/缩小，不会出现「正文大了、按钮没大」的错位。
   值由 js/theme.js 的 applyFontSize() 写在 <html> 的行内样式上；
   窄屏那条 14px 规则（views.css）也要乘同一个缩放。 */
:root { --ui-font-scale: 1; }
html { font-size: calc(16px * var(--ui-font-scale, 1)); }

html, body { height: 100%; }
body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-ui);
  font-size: var(--text-base);
  line-height: var(--lh-base);
  display: flex;
  height: 100vh;
  overflow: hidden;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* optimizeLegibility 在 Chrome/WebView2 上会强制几何精度并关掉部分字偶调整，
     小字号中文反而更糊；Cindy 用的是默认值（2026-10-25）。 */
  text-rendering: auto;
}
button { font-family: inherit; cursor: pointer; }
/* 表单控件跟随主题强调色 —— 否则浏览器默认蓝点和金/咖啡主题打架 */
input[type='checkbox'], input[type='radio'], input[type='range'], progress, meter {
  accent-color: var(--color-accent);
}

/* ── 背景图层（2026-10-19，Cindy「熵减」背景图）──────────────────────
 * 独立伪元素一层，不碰 --bg：主题层次全靠 --surface，直接铺 body 会把
 * 背景和卡片混在一起。图片挂掉时兜底渐变仍在（左下青、右上金，与图同义）。
 * 开关：设置 › 外观「界面背景」→ html[data-bg-art="off"]；
 * 高对比模式下自动关闭（应用建议硬约束②）。★ 减少动效不再关背景：
 * 背景是静态图、没有动画，真正的动效（转圈徽标等）在下面的全局
 * reduced-motion 块里照常被关 —— 用户系统动画全关时背景若也跟着消失，
 * 就永远看不到毛玻璃了（2026-10-19 实测：本机动画关 → 桌面窗口无背景）。
 * 不用 background-attachment: fixed（移动端掉帧），fixed 伪元素等价且更顺。 */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image: var(--bg-art-fallback), var(--bg-image);
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  opacity: var(--bg-art-opacity, 0.55);
  filter: blur(10px);
  transition: opacity var(--dur);
}
html[data-bg-art="off"] body::before { display: none; }
@media (prefers-contrast: more) {
  body::before { display: none; }
}

/* ── Layer 3: Utilities ─────────────────────────────────────── */

/* Skeleton loading shimmer */
.skeleton {
  background: var(--skeleton-base);
  border-radius: var(--r-sm);
  position: relative;
  overflow: hidden;
}
.skeleton::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, transparent, var(--skeleton-shine), transparent);
  animation: skeleton-shimmer 1.5s ease-in-out infinite;
}
@keyframes skeleton-shimmer {
  0% { transform: translateX(-100%); }
  100% { transform: translateX(100%); }
}

/* Glassmorphism panel */
.glass {
  background: var(--glass-bg);
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
  border: var(--bw) solid var(--glass-border);
}

/* View transition */
.view-fade-in {
  animation: viewFadeIn var(--dur-slow) var(--ease-out) both;
}
@keyframes viewFadeIn {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Micro-interaction: hover lift */
.hover-lift {
  transition: transform var(--dur) var(--ease),
              box-shadow var(--dur) var(--ease);
}
.hover-lift:hover {
  transform: translateY(-1px);
  box-shadow: var(--shadow-md);
}

/* Micro-interaction: button press */
.btn-press:active {
  transform: scale(0.97);
  transition: transform 60ms;
}

/* Focus ring */
.focus-ring:focus-visible {
  outline: 2px solid var(--user);
  outline-offset: 2px;
}

/* Reduced motion */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  .skeleton::after { animation: none; }
}

/* [local patch 2026-09-21] body is itself a flex container, so .app is a flex
   item whose width defaults to auto and collapses to fit its content. Measured
   before the fix: .app was 651px inside a 1440px viewport, squeezing .main to
   411px and #msg-input to 164px. flex:1 makes it fill the viewport. */
.app { display: flex; height: 100vh; flex: 1; min-width: 0; overflow: hidden; }
.nav-item, .btn {
  border: none; background: transparent;
  font-family: inherit; font-size: inherit; color: inherit;
}

/* ───────── 侧栏 — 真毛玻璃效果（3D 立体感）───────────────────────────── */
/* 宽度走**自定义属性** `--sidebar-w`，不走 inline style。
 * 原因（2026-10-22 用户报「折叠后宽度不变」）：inline style 的优先级
 * **高于**任何 class 规则 —— 拖拽把手存下来的宽一旦写成
 * `style.width = '300px'`，`.sidebar.collapsed { width: 56px }` 就再也
 * 压不住它，折叠只剩「图标变一列」、宽度纹丝不动（真机实测：
 * collapsed=true 而宽度还是 300px）。
 * 换成变量后，收起态那条规则写的是**字面量 56px**（不引用变量），
 * 选择器又更具体 → 折叠永远压得住；展开时变量还在 → 用户拖的宽度
 * 原样回来。 */
.sidebar {
  position: relative;
  width: var(--sidebar-w, 240px);
  flex: none;
  background: transparent;
  backdrop-filter: blur(var(--glass-blur-heavy));
  -webkit-backdrop-filter: blur(var(--glass-blur-heavy));
  border-right: var(--bw) solid var(--glass-border);
  box-shadow: var(--glass-shadow), var(--glass-inner-glow);
  display: flex;
  flex-direction: column;
  padding: var(--sp-3);
  overflow: hidden;
}

/* ── 左侧栏收起态（2026-10-02）────────────────────────────────
 * 用户要的：收起来以后功能入口变成**一列图标**。56px = 图标 + 两侧一点留白。
 * 收起时把「有宽度才好看」的全藏掉：搜索框、会话列表、状态行、品牌文字、
 * 导航文字。留下的只有：水滴头像、＋、折叠按钮、一列图标。 */
.sidebar.collapsed {
  width: 56px;
  padding: var(--sp-2) 0;
}
.sidebar.collapsed .brand-text,
.sidebar.collapsed .brand-sub,
.sidebar.collapsed .session-search,
.sidebar.collapsed .session-list,
.sidebar.collapsed #status {
  display: none;
}
.sidebar.collapsed #sidebar-top {
  flex-direction: column;
  justify-content: center;
  gap: var(--sp-2);
}
.sidebar.collapsed .nav {
  border-top: none;
}
/* 收起态：**图标下面显示两字标题**（用户要的"让用户更清楚图标的含义"）。
   竖排排列 —— 图标在上、两字在下，挤不出别的东西。 */
.sidebar.collapsed .nav-label {
  font-size: var(--text-xs);
  line-height: 1.1;
}
.sidebar.collapsed .nav-item {
  flex-direction: column;
  justify-content: center;
  gap: 3px;
  padding: var(--sp-1) 0;
  border-left-width: 0;
}
.sidebar.collapsed .nav-ic { width: auto; }

/* 左上角那一行：品牌 + ＋ + 折叠按钮（2026-10-02）。
   加了折叠按钮之后三者挤不下、自动换行成两行，所以显式排成一行。 */
#sidebar-top {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
}
#sidebar-top .brand {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;              /* 实在挤不下时裁掉，别把按钮顶出去 */
}

/* 收起 / 展开左侧栏的按钮（2026-10-02），在左上角紧挨着 ＋。 */
.side-toggle {
  border: none;
  background: transparent;
  color: var(--text-dim);      /* 2026-10-02：从 faint 加深一档（用户说箭头太不明显）*/
  cursor: pointer;
  font-family: inherit;
  font-size: var(--text-base);
  line-height: 1;
  padding: 0 var(--sp-1);
  display: inline-flex;
  align-items: center;
}
.side-toggle:hover { color: var(--user); }
/* 箭头 SVG（2026-10-02）：18px 的双线 chevron，比原来的单角括号明显得多 */
.side-toggle svg,
.insp-toggle svg {
  width: 18px;
  height: 18px;
  display: block;
}

/* ── 列宽拖拽把手（2026-10-02）────────────────────────────────
 * 贴在侧栏边缘的一条 5px 透明条：鼠标变成左右箭头，按住拖就改宽度。
 * 两侧各一个（左栏拖右边缘、右栏拖左边缘）。收起态没有宽度可调 → 隐掉。 */
.col-resize {
  position: absolute;
  top: 0; bottom: 0;
  width: 5px;
  cursor: col-resize;
  z-index: 6;
  background: transparent;
  transition: background var(--dur-fast);
}
.col-resize:hover { background: var(--user); }
.col-resize-right { right: 0; }
.col-resize-left { left: 0; }
/* 拖动过程中：整页光标统一、并且别把文字选中 */
body.col-resizing { cursor: col-resize; user-select: none; }
body.col-resizing .col-resize { background: var(--user); }
/* 拖动时把宽度过渡关掉 —— `.inspector` 平时有 `transition: width`（给折叠用），
   拖着走的时候会慢半拍，跟手很差。松手后过渡自动恢复，折叠动画不受影响。 */
body.col-resizing .sidebar,
body.col-resizing .inspector { transition: none; }
.sidebar.collapsed .col-resize,
.inspector.collapsed .col-resize { display: none; }
.brand {
  text-decoration: none;
  font-size: 0.9375rem; font-weight: 600; letter-spacing: .03em;
  color: var(--text);
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.brand:hover {
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--user);
}
/* 品牌标记：铸金水滴小灵（2026-10-19 用户定稿）。
   旧版是内联 SVG fill=currentColor 跟随 --user（更早是 ::before 画的 9px 圆点）。
   现在渐变/高光/投影全部写在 SVG 自身的 defs 里（index.html，与 logo.svg/favicon/logo.ico
   同一份配方），不再依赖 CSS 提供颜色 —— 金子不随主题变色。
   overflow: visible 让 SVG 的微投影伸出 32×32 画布时不被裁掉。 */
.brand-mark {
  width: 26px; height: 26px;   /* 2026-10-02 从 21px 调大（用户要求"稍微大一点"）*/
  display: block;
  flex: none;
  overflow: visible;
}
/* 品牌文字渐变（2026-10-19 用户定稿）：深色=金、浅色=咖啡，跟随 --accent-grad。
 * 注意 brand-mark（SVG）不走这里 —— background-clip:text 会把它裁没，它继续用 color: var(--user)。 */
.brand-text {
  background: var(--accent-grad);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
}
.brand .brand-sub {
  background: var(--accent-grad);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  opacity: .72;
  font-weight: 500;
  font-size: 0.8125rem;
  letter-spacing: .05em;
}
/* 新对话按钮（左上角 ＋） */
#new-session-btn {
  /* 2026-10-02：从「只有 ＋ 的 30px 方块」改成**带文字的胶囊**。
     用户要的：加号在前、文字在后，加底色、和文字强对比。
     底色用品牌色 --user、文字用页面底色 --bg —— 这两个在 8 套主题里
     都是对比最强的一对，不用另造颜色变量。 */
  min-width: 30px; height: 30px;
  display: inline-flex; align-items: center; justify-content: center;
  gap: 2px;
  border-radius: var(--r-md);
  border: var(--bw) solid transparent;
  background: var(--user);
  color: var(--bg);
  font-size: var(--text-xs); line-height: 1;   /* 小一号：240px 一条里要跟品牌挤着放 */
  padding: 0 6px;
  white-space: nowrap;
  cursor: pointer;
  transition: filter var(--dur), transform var(--dur-fast);
}
#new-session-btn:hover { filter: brightness(1.08); }
#new-session-btn:active { transform: scale(.96); }
#new-session-btn .ns-plus { font-size: var(--text-base); }
/* 侧栏收起时只剩加号 —— 文字放不下（用户说"宽度不够文字可以小一点"，
   这里是干脆不显示：56px 的条里连两字都放不开）。 */
.sidebar.collapsed #new-session-btn {
  width: 30px;
  padding: 0;
}
.sidebar.collapsed #new-session-btn .ns-label { display: none; }
.new-btn {
  width: 100%;
  background: transparent;
  border: var(--bw) solid var(--border);
  color: var(--text-dim);
  border-radius: var(--r-md);
  padding: var(--sp-2) var(--sp-3);
  font-family: inherit;
  font-size: var(--text-base);
  text-align: left;
  transition: border-color var(--dur), color var(--dur);
}
.new-btn:hover { border-color: var(--user); color: var(--text); }
.session-list { margin-top: var(--sp-4); flex: 1; overflow-y: auto; }
/* 会话条目。**只在这一处定义**（2026-09-30 合并）。
 *
 * 之前它被拆成两半：padding/border-radius/color 这些在这一处，
 * `display:flex / gap / flex-wrap` 在文件后面另一处 —— 靠 CSS 层叠拼起来才完整。
 * 后果是「在 CSS 里搜 .session 只看到一半属性」，我改定位时就先改错了地方。
 * 两处按属性合并没有歧义（没有同名属性相冲突），合完行为不变。 */
.session {
  position: relative;          /* 给右下角的「⋯」当定位上下文 */
  display: flex; align-items: center; gap: var(--sp-1); flex-wrap: wrap;
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-md);
  color: var(--text-dim);
  font-size: var(--text-base);
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  border: var(--bw) solid transparent;   /* 默认占住边框位，悬停不再跳 1px */
  border-left: 2px solid transparent;
}
.session:hover {
  background: var(--glass-bg-strong);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border: var(--bw) solid var(--glass-border);
  box-shadow: var(--glass-inner-glow);
  color: var(--text);
}
.session.active {
  background: var(--glass-bg-strong);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border: var(--bw) solid var(--glass-border-strong);
  box-shadow: var(--glass-shadow), var(--glass-inner-glow);
  color: var(--text);
  border-left: 2px solid var(--user);
}
.nav {
  border-top: var(--bw) solid var(--border);
  padding-top: var(--sp-3);
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.nav-item {
  display: flex;                 /* 图标 + 文字横排（收起时只剩图标）*/
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-md);
  color: var(--text-dim);
  cursor: pointer;
  font-size: var(--text-base);
  border-left: 2px solid transparent;
}
/* 导航图标（2026-10-02）：内联 SVG 线性图标。定宽让展开态的文字能左对齐。 */
.nav-ic {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  flex: none;
}
.nav-ic svg {
  width: 19px;
  height: 19px;
  display: block;
}
.nav-item:hover { 
  background: var(--glass-bg);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: var(--bw) solid var(--glass-border);
  box-shadow: var(--glass-inner-glow);
  color: var(--text); 
}
.nav-item.active {
  color: var(--text);
  border-left: 2px solid var(--user);
  background: var(--glass-bg-strong);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border: var(--bw) solid var(--glass-border-strong);
  box-shadow: var(--glass-shadow), var(--glass-inner-glow);
}
/* 2026-10-21：这里原来多了一个 `}` —— 浏览器会把**紧随其后的 `.status` 整条规则
   吞掉**（顶层的多余 `}` 是个解析错误，它会吃掉下一条规则）。
   结果是状态行一直没吃到样式。 */
.status {
  margin-top: var(--sp-3);
  padding-top: var(--sp-3);
  border-top: var(--bw) solid var(--border);
  font-size: var(--text-xs);
  color: var(--text-faint);
  display: flex;
  align-items: center;
  gap: var(--sp-2);
}
.status .dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--success);
}
.status .dot.idle { background: var(--text-faint); }

/* 用户信息条（2026-10-20）：侧栏底部，头像 + 用户名/角色 + 退出按钮 */
.user-bar {
  margin-top: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  border-top: var(--bw) solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
}
.user-info {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-width: 0;
  flex: 1;
}
.user-avatar {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--accent-grad);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.8125rem;
  font-weight: 600;
  flex: none;
}
.user-meta {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.user-name {
  font-size: var(--text-sm);
  font-weight: 500;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.user-role {
  font-size: var(--text-xs);
  color: var(--text-faint);
  white-space: nowrap;
}
.user-logout {
  flex: none;
  background: none;
  border: none;
  color: var(--text-faint);
  cursor: pointer;
  padding: 4px;
  border-radius: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: color .15s, background .15s;
}
.user-logout:hover {
  color: var(--danger, #e55);
  background: var(--bg-hover, rgba(255,255,255,.06));
}
/* 收起侧栏时隐藏用户信息条 */
.sidebar.collapsed .user-bar { display: none; }

/* ★ 状态栏语义色（2026-09-28）：setStatus(text, kind) 早就支持 ok/error/warning，
 *   但 CSS 里一直没这几个类 —— 十几处调用（删除失败/审批失败/连接失败…）全都
 *   退化成一行灰字，用户看不出是成功还是出事。
 *   只用现有四个语义色，不新增（08 卷 :320）：warning 的场景是「等待审批」，
 *   审批本来就是 agent 品红的语义。 */
.status-ok { color: var(--success); }
.status-error { color: var(--danger); }
.status-warning { color: var(--agent); }

/* 会话列表时间分组（§8.8-7：今天/昨天/本周/更早） */
/* 可折叠的分组标题（「已归档 (N)」）：能点、悬停有反馈 ——
   它和普通分组标题（纯文字、不可点）长得一样的话，用户不知道这里能点开。 */
.session-group-toggle {
  cursor: pointer;
  user-select: none;
}
.session-group-toggle:hover { color: var(--text); }
.session-group {
  margin: var(--sp-3) 0 var(--sp-1);
  padding: 0 var(--sp-3);
  font-size: var(--text-xs);
  color: var(--text-faint);
  user-select: none;
}
/* ★ 项目分组标题（2026-10-21）：比时间分组更醒目，区分两级分组 */
.session-group-project {
  margin-top: var(--sp-4);
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--text);
  text-transform: none;
  letter-spacing: 0;
  transition: color 0.15s;
}
.session-group-project:hover {
  color: var(--user);
}
.session-group-project:first-child {
  margin-top: var(--sp-2);
}
/* 时间分组标题（在项目内）：稍小、稍淡 */
.session-group-time {
  margin-top: var(--sp-2);
  font-size: var(--text-xs);
  color: var(--text-faint);
  font-weight: normal;
}
/* ★ 「查看更多」按钮（2026-10-21）：项目分组默认只显示 3 条，这是展开入口 */
.session-group-more {
  padding: var(--sp-1) var(--sp-3);
  font-size: var(--text-xs);
  color: var(--text-faint);
  transition: color 0.15s;
  user-select: none;
}
.session-group-more:hover {
  color: var(--user);
}
/* 2026-10-21：这里原来多了一个 `}` —— 浏览器把紧随其后的 `.session-search`
   整条规则吞掉了，所以「搜索对话」输入框一直是**浏览器默认样式**
   （没有底色/边框/内边距/margin-top），看起来就直挺挺贴在 logo 行下面。
   删掉多余的 `}` 之后这条规则才真正生效。 */
/* 会话搜索框（§v0.3 九-4） */
.session-search {
  width: 100%;
  /* 2026-10-21：8px → 16px（--sp-4）。用户原话「和上面的超秘 logo 一行距离太近，
     显得太拥挤」—— 8px 跟输入框自己的内边距一样大，看着像粘在品牌行上。
     16px 是侧栏自己的分段节奏（下面 .session-list 也是 --sp-4），
     品牌行 → 搜索框 → 会话列表 三段各留一档，不再挤成一坨。 */
  margin-top: var(--sp-4);
  background: var(--bg);
  border: var(--bw) solid var(--border);
  border-radius: var(--r-md);
  color: var(--text);
  padding: var(--sp-1) var(--sp-3);
  font-family: inherit;
  font-size: var(--text-sm);
  outline: none;
}
.session-search:focus { border-color: var(--user); }
/* 会话条目：标题 + hover 删除 */
.session .session-label { flex: 1; overflow: hidden; text-overflow: ellipsis; }
/* （`.session` 的布局属性已合并到文件前面那一处定义里，见那里的说明） */
/* 「⋯」更多操作（2026-09-30）：点它开**和右键同一个**菜单 ——
 * 不是所有用户都会想到「这里可以右键」，这个按钮就是那个功能的可见入口。
 *
 * **常驻但淡**，鼠标停上去变实。第一版做的是「悬停才出现」（`visibility: hidden`），
 * 用户反馈「一般用户会看不到」—— 对，靠悬停才现身的东西等于藏起来了；
 * 而完全常显又太吵。所以留一个低不透明度的常驻形态。
 *
 * 位置钉在条目**右下角**：那里是视线自然的落点，也不会和标题、时间抢横向位置。
 * （原来这里是单独的「删」按钮，被菜单取代了 —— 菜单里的删除有分组、标红、
 *   二次确认，比一个贴着时间戳的「删」字安全得多。）
 */
.session-more {
  position: absolute;
  right: 4px;
  bottom: 4px;
  border: none; background: transparent; cursor: pointer;
  color: var(--text-dim);
  font-size: var(--text-sm);
  font-family: inherit;
  padding: 0 var(--sp-1);
  border-radius: var(--r-sm);
  line-height: 1;
  /* `.5` 而不是更低 —— 先试过 `.35`，截图里几乎看不见；
     用户的原话是「一般的用户会看不到」，那就别再省这点视觉重量。 */
  opacity: .5;
  transition: opacity var(--dur-fast) var(--ease);
}
.session:hover .session-more { opacity: 1; }
.session-more:hover {
  color: var(--user);
  background: var(--surface);       /* 悬停给个小底，点起来更明确 */
}
/* ★ 会话行的时间标签（2026-09-28）：同名会话（一堆「新对话」）在列表里长得一模
 *   一样，删掉一条后剩下的整体上移，界面上看不出变化 —— 用户会以为没删掉。
 *   永久可见（不跟着 hover 藏），flex:none 让它不被长标题挤变形。 */
.session-time {
  flex: none; white-space: nowrap;
  color: var(--text-faint); font-size: var(--text-xs);
}
/* 删除确认条（§v0.3 九-5：红色，明示找不回来） */
.session-confirm {
  flex-basis: 100%;
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-1) var(--sp-2);
  margin: var(--sp-1) 0;
  background: rgba(255, 107, 107, .08);
  border: var(--bw) solid var(--danger);
  border-radius: var(--r-sm);
  font-size: var(--text-xs);
  color: var(--text-dim);
}
.session-confirm-yes {
  border: var(--bw) solid var(--danger); background: transparent;
  color: var(--danger); border-radius: var(--r-sm);
  padding: 0 var(--sp-2); font-size: var(--text-xs);
  font-family: inherit; cursor: pointer;
}
.session-confirm-no {
  border: var(--bw) solid var(--border); background: transparent;
  color: var(--text-dim); border-radius: var(--r-sm);
  padding: 0 var(--sp-2); font-size: var(--text-xs);
  font-family: inherit; cursor: pointer;
}

/* ── 会话管理（2026-09-30，对齐 Hermes）────────────────────── */

/* 条目第二行：模型名 · N 条。`flex-basis:100%` 独占一行（照 .session-confirm）。
   比标题小一档、更淡 —— 它是辅助信息，不该抢标题的注意力。 */
.session-meta {
  flex-basis: 100%;
  /* 右边留出「⋯」的位置 —— 它绝对定位在条目右下角，不留白会把「97 条」盖住 */
  padding-right: 18px;
  color: var(--text-faint);
  font-size: var(--text-xs);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* 置顶：左侧条换成强调色 + 标题前一个记号 */
.session.is-pinned { border-left-color: var(--user); }
.session.is-pinned .session-label::before { content: '固定 · '; font-size: var(--text-xs); }
/* 未读：标题加重 + 一个圆点 */
.session.is-unread .session-label { font-weight: 600; color: var(--text); }
.session.is-unread .session-label::after {
  content: ' ●';
  color: var(--user);
  font-size: var(--text-xs);
}
/* 归档：压暗一档（它同时会被收进列表末尾的折叠组） */
.session.is-archived { opacity: .6; }

/* ── 后台对话的状态标（2026-10-15 多对话并行）────────────────
 *
 * 用户可能同时开着好几个对话，侧栏要能一眼看出**每个现在什么状态**：
 *   转圈 → 正在跑 · 红点（呼吸）→ 卡在等你点「允许」 · 绿点 → 跑完了
 *
 * 为什么不用「只改左边框颜色」（那是第一版）：
 *   边框太细，而且 **「正在跑」和「选中了」在视觉上分不开**（`.session.active`
 *   也改左边框色）。状态里最要紧的就是「它还在动吗」—— 静态色块说不出来。
 *
 * ⚠️ 状态后缀类名**不许和聊天区的类重名**（2026-10-22 事故）：
 *   原来「等你确认」用的后缀是 `approval`，而聊天区的审批卡片也叫 `.approval`
 *   （tokens.css / views.css 各有一份）—— 同名 → 卡片的 padding / border /
 *   border-radius / backdrop-filter 全串到侧栏状态标上：10px 的小圆点被撑成
 *   35px 的红方块，还套了一圈品红边（用户反馈「红色方块很丑、红字也不协调」）。
 *   现在后缀统一走 `pending`（映射表 SESS_STATE_CLASS，在 main.js）。
 *
 * 为什么环用 border 而不是 conic-gradient 挖空：
 *   挖空得知道底色（悬停时底色还会变），8 套主题下必错。border 画环与背景无关。
 */
.sess-badge {
  flex: 0 0 auto;
  align-self: center;          /* 和小字一样：只管自己，不撑行高 */
  width: 10px; height: 10px;
  box-sizing: border-box;
  border-radius: 50%;
}

/* 正在跑：一圈底环 + 一段高亮，转起来（颜色跟 --user：深=金、浅=咖啡）。
   加一圈同色微光（2026-10-19）：转圈本身太小，暗色主题里不够扎眼。 */
.sess-badge.running {
  border: 2px solid color-mix(in srgb, var(--user) 25%, transparent);
  border-top-color: var(--user);
  animation: sess-spin .9s linear infinite;
  filter: drop-shadow(0 0 3px color-mix(in srgb, var(--user) 45%, transparent));
}
@keyframes sess-spin { to { transform: rotate(360deg); } }

/* 跑完了：绿点 */
.sess-badge.done { background: var(--success); }

/* 卡在等你点「允许」：品红点 + 呼吸（这个最要紧 —— 它在等你，
   不醒目就等于任务永远卡着没人管）。
   ★ 色系跟聊天区那张审批卡片一致（--agent 品红）：侧栏的点和聊天区的卡
     是同一件事，用户能对上号。**红色留给「出错」**（--danger，错误色）。 */
.sess-badge.pending {
  background: var(--agent);
  /* 静态光环兜底：开了「减少动效」时动画停了，这一圈还在（不然点变成裸圆点） */
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--agent) 22%, transparent);
  animation: sess-pulse 1.4s ease-in-out infinite;
}
@keyframes sess-pulse {
  0%, 100% { box-shadow: 0 0 0 3px color-mix(in srgb, var(--agent) 26%, transparent); }
  50%      { box-shadow: 0 0 0 6px color-mix(in srgb, var(--agent) 0%, transparent); }
}

/* 叠加的小字状态（跑着 / 等你确认 / 已完成）。
   `flex: 0 0 auto` + 标题是 `flex: 1` —— 小字自然贴到右边，不挤标题。
 *
 * ⚠️ **压扁过**（2026-10-15 用户反馈：「侧栏显示的确认按钮有点太大了，
 * 可以把高度降低」）。原来 `line-height: 1.6` + 上下没有 padding 约束，
 * 整个胶囊比标题还高，把侧栏那一行**撑起来了** —— 列表看起来松松垮垮。
 * 现在 `line-height: 1` + 1px 上下边距 + `align-self: center`：
 * 高度锁在 ~14px（低于行高），它只影响自己，不影响那一行。
 */
.sess-state {
  flex: 0 0 auto;
  align-self: center;          /* 垂直居中，绝不拉伸行高 */
  font-size: var(--text-xs);
  line-height: 1;              /* ★ 关键：不撑高那一行 */
  padding: 1px var(--sp-1);
  border-radius: 999px;
  white-space: nowrap;
  /* 状态色统一走 --sess-c（下面四条规则各给一个色）：
     底色 = 同色淡底，字 = 同色但**往正文色里压一点**（color-mix）——
     浅色主题下 --agent 这类中明度色直接当小字用对比度不够，压暗一档才读得清。 */
  --sess-c: var(--text-dim);
  background: color-mix(in srgb, var(--sess-c) 16%, transparent);
  color: color-mix(in srgb, var(--sess-c) 84%, var(--text));
  font-weight: 600;
}
/* 出错了：红色 —— 颜色按 08-界面设计稿 的约定走（红 = 错误 / 失败状态）。
   ★ 之前是橙色，跟「进行中」的金色挤在一起，两种暖色分不开。 */
.sess-badge.failed { background: var(--danger); }

/* 四个状态各一个色（同一套色只干一件事，不串味）：
   进行中 = 主题色 --user（深=金、浅=咖啡，跟输入框旁的转圈同色）
   等你确认 = 品红 --agent（**跟聊天区的审批卡片同色** —— 侧栏的点和聊天区
     的卡是同一件事；原来这里用红色，和「出错」撞车、也和「进行中」不协调）
   已完成 = 绿 --success
   出错 = 红 --danger */
.sess-state.running { --sess-c: var(--user); }
.sess-state.pending { --sess-c: var(--agent); }
.sess-state.done { --sess-c: var(--success); }
.sess-state.failed { --sess-c: var(--danger); }

/* 整行淡染色（main.js:markSessionBadge 挂 `is-task-running` 类）：
 * 扫一眼先看到「这行在动」，不用逐条读小字。
 * 用**内阴影**而不是改 background —— hover/active 的玻璃底色不会被
 * 盖掉，两层叠着走；999px 是「铺满整行」的惯用写法。 */
.session.is-task-running {
  box-shadow: inset 0 0 0 999px color-mix(in srgb, var(--user) 7%, transparent);
}
/* ★ 「等你确认」**不染整行**（2026-10-20 用户反馈「红色块太大」，
 *   2026-10-22 再反馈「红色方块和红色字体不协调」）：
 *   它只由左侧的品红小点 + 右侧的「等你确认」小胶囊两个记号承担 ——
 *   整行染色太抢眼，反而把真正要点「允许」的那张卡压下去了。 */

/* 用户开了「减少动效」就别转 —— 前庭敏感的人会难受 */
@media (prefers-reduced-motion: reduce) {
  .sess-badge.running { animation: none; border-top-color: var(--user); }
  .sess-badge.pending { animation: none; }
}

/* 就地改名：与删除确认条同一套「独占一行」的做法 */
.session-rename {
  flex-basis: 100%;
  display: flex; align-items: center; gap: var(--sp-1);
  margin: var(--sp-1) 0;
}
.session-rename-input {
  flex: 1; min-width: 0;
  background: var(--surface);
  border: var(--bw) solid var(--user);
  border-radius: var(--r-sm);
  color: var(--text);
  font-family: inherit;
  font-size: var(--text-xs);
  padding: 2px var(--sp-2);
}
.session-rename-ok, .session-rename-no {
  border: var(--bw) solid var(--border); background: transparent;
  color: var(--text-dim); border-radius: var(--r-sm);
  padding: 0 var(--sp-2); font-size: var(--text-xs);
  font-family: inherit; cursor: pointer;
}
.session-rename-ok { border-color: var(--user); color: var(--user); }

/* ── 会话右键菜单 ────────────────────────────────────────────
 * `position: fixed` + 挂 body：挂在列表项里会被 `.session-list` 的
 * `overflow-y: auto` 裁掉一半。
 * z-index 65：在 kbd-panel 遮罩（60）之上、noscript（9999）之下。
 */
.session-menu {
  position: fixed;
  z-index: 65;
  min-width: 176px;
  padding: var(--sp-1);
  background: var(--surface);
  border: var(--bw) solid var(--border);
  border-radius: var(--r-md);
  box-shadow: 0 10px 30px -12px rgba(0, 0, 0, .5);
}
.session-menu-item {
  display: block;
  width: 100%;
  text-align: left;
  border: none;
  background: none;
  color: var(--text);
  font-family: inherit;
  font-size: var(--text-sm);
  padding: var(--sp-1) var(--sp-2);
  border-radius: var(--r-sm);
  cursor: pointer;
  white-space: nowrap;
}
.session-menu-item:hover { background: var(--surface-2); }
/* 删除不可逆 —— 用 danger 色，和 `.session-confirm-yes` 同一套语义。
   底色用 color-mix 派生（主题自适应），不写死红色。 */
.session-menu-item.is-danger { color: var(--danger); }
.session-menu-item.is-danger:hover {
  background: color-mix(in srgb, var(--danger) 12%, transparent);
}
.session-menu-sep {
  height: 1px;
  margin: var(--sp-1) var(--sp-2);
  background: var(--divider);
}
/* 粘贴折叠 chip（§v0.3 九-1） */
.paste-chip {
  display: flex; align-items: center; gap: var(--sp-2);
  margin-bottom: var(--sp-1);
  padding: var(--sp-1) var(--sp-3);
  background: var(--surface-2);
  border: var(--bw) solid var(--border);
  border-radius: var(--r-md);
  font-size: var(--text-sm);
}
.paste-chip-pre {
  flex-basis: 100%;
  font-family: var(--font-mono); font-size: var(--text-xs);
  color: var(--text-dim); white-space: pre-wrap; word-break: break-all;
  margin: var(--sp-1) 0 0;
}
.paste-chip-x {
  border: none; background: transparent; color: var(--text-faint);
  cursor: pointer; font-size: var(--text-base); font-family: inherit;
}
.paste-chip-x:hover { color: var(--danger); }
/* 排队提示条：运行中输入的消息排在这里，任务结束后自动发送。
   存在的意义是让用户**看得见自己的话去哪了** —— 不然会以为消息丢了而重发。 */
.queue-hint {
  display: flex; align-items: center; gap: var(--sp-2);
  margin-bottom: var(--sp-1);
  padding: var(--sp-1) var(--sp-3);
  background: var(--surface-2);
  border: var(--bw) solid var(--border);
  border-left: var(--bw-accent) solid var(--user);
  border-radius: var(--r-md);
  font-size: var(--text-sm);
  color: var(--text-dim);
}
.queue-hint span { flex: 1; }
/* 附件 chip：拖进来/粘进来的文件，发送前可以逐个撤掉 */
.attach-chips {
  display: flex; flex-wrap: wrap; gap: var(--sp-1);
  margin-bottom: var(--sp-1);
}
.attach-chip {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px var(--sp-2);
  background: var(--surface-2);
  border: var(--bw) solid var(--border);
  border-radius: var(--r-md);
  font-size: var(--text-xs);
  color: var(--text-dim);
}
/* 拖拽悬停：让用户知道「松手就会附上」 */
.composer-drag {
  outline: 2px dashed var(--user);
  outline-offset: -4px;
  border-radius: var(--r-md);
}
/* 快捷键帮助表（`?` 打开）—— 内容由 shortcuts.js 的 registry 生成 */
.kbd-panel {
  position: fixed; inset: 0; z-index: 60;
  display: flex; align-items: center; justify-content: center;
  background: rgba(0, 0, 0, .45);
}
.kbd-card {
  width: min(560px, 92vw);
  max-height: 80vh;
  overflow: auto;
  background: var(--surface-1, var(--surface-2));
  border: var(--bw) solid var(--border);
  border-radius: var(--r-md);
  box-shadow: 0 12px 40px rgba(0, 0, 0, .35);
}
.kbd-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--sp-3) var(--sp-4);
  border-bottom: var(--bw) solid var(--border);
  font-weight: 600;
}
.kbd-close {
  border: none; background: transparent; color: var(--text-faint);
  cursor: pointer; font-size: var(--text-lg); font-family: inherit;
}
.kbd-close:hover { color: var(--danger); }
.kbd-list { padding: var(--sp-2) var(--sp-4) var(--sp-4); }
.kbd-row {
  display: flex; align-items: baseline; gap: var(--sp-3);
  padding: var(--sp-2) 0;
  border-bottom: var(--bw) solid var(--border-soft);
}
.kbd-row:last-child { border-bottom: none; }
.kbd-row kbd {
  min-width: 104px;
  padding: 2px 8px;
  font-family: var(--font-mono); font-size: var(--text-xs);
  background: var(--surface-2);
  border: var(--bw) solid var(--border);
  border-radius: var(--r-sm);
  text-align: center;
}
.kbd-label { flex: 1; }
.kbd-hint { color: var(--text-faint); font-size: var(--text-xs); }
.kbd-panel > .kbd-list, .kbd-panel > .kbd-head { }
/* 用户消息上的「从这儿分叉」（悬停才出现，不打扰阅读） */
.item-user { position: relative; }
.fork-btn {
  position: absolute; top: 4px; right: 8px;
  opacity: 0;
  padding: 2px 8px;
  font-size: var(--text-xs); font-family: inherit;
  color: var(--text-dim);
  background: var(--surface-2);
  border: var(--bw) solid var(--border);
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: opacity var(--dur-fast);
}
.item-user:hover .fork-btn { opacity: 1; }
.fork-btn:hover { color: var(--user); border-color: var(--user); }
/* 「回退代码」排在「从这儿分叉」左边（两个按钮同时出现时） */
.rewind-btn { right: 106px; }
.rewind-btn:hover { color: var(--danger); border-color: var(--danger); }
.fork-btn:disabled { opacity: .5; cursor: default; }
/* 命令面板（Ctrl+K）：菜单要「先知道去哪找」，它只要「记得名字」 */
.cmd-card { display: flex; flex-direction: column; }
.cmd-input {
  width: 100%;
  padding: var(--sp-3) var(--sp-4);
  border: none; border-bottom: var(--bw) solid var(--border);
  background: transparent; color: var(--text);
  font-size: var(--text-base); font-family: inherit;
  outline: none;
}
.cmd-list { padding: var(--sp-1) 0 var(--sp-2); max-height: 52vh; overflow: auto; }
.cmd-row {
  display: flex; align-items: baseline; gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-4);
  cursor: pointer;
}
.cmd-row.is-active { background: var(--surface-2); }
.cmd-label { flex: 1; }
.cmd-empty { padding: var(--sp-3) var(--sp-4); color: var(--text-faint); }
/* 卡片右上角的「复制」（悬停才出现，不打扰阅读） */
.cmd, .filechange { position: relative; }
.copy-btn {
  position: absolute; top: 6px; right: 8px;
  opacity: 0;
  padding: 2px 8px;
  font-size: var(--text-xs); font-family: inherit;
  color: var(--text-dim);
  background: var(--surface-2);
  border: var(--bw) solid var(--border);
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: opacity var(--dur-fast);
}
.cmd:hover .copy-btn, .filechange:hover .copy-btn { opacity: 1; }
.copy-btn:hover { color: var(--user); border-color: var(--user); }
/* 每轮统计摘要（⏱ 用时 · 工具 · 改动）—— 一行，别抢戏 */
.turn-stats {
  margin: var(--sp-2) 0 var(--sp-3);
  padding: var(--sp-1) 0;
  font-size: var(--text-xs);
  color: var(--text-faint);
  border-top: 1px dashed var(--border);
  text-align: center;
  letter-spacing: .3px;
}
/* 会话列表加载失败——让它看得见（不然和「还没有对话」分不清） */
.session-error {
  margin: var(--sp-2) var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  font-size: var(--text-xs);
  color: var(--danger);
  background: var(--surface-2);
  border: var(--bw) solid var(--border);
  border-radius: var(--r-sm);
}
/* 快捷键重绑（设置 → 快捷键） */
.sc-field {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-3);
}
.sc-key {
  min-width: 118px;
  padding: 4px 10px;
  font-family: var(--font-mono); font-size: var(--text-xs);
  color: var(--text);
  background: var(--surface-2);
  border: var(--bw) solid var(--border);
  border-radius: var(--r-sm);
  cursor: pointer;
}
.sc-key:hover { border-color: var(--user); }
.sc-key.is-listening { border-color: var(--user); color: var(--user); }
/* 快捷键说明行（§v0.3 九-3） */
.composer-hint {
  max-width: 860px; margin: var(--sp-1) auto 0;
  font-size: var(--text-xs); color: var(--text-faint);
  padding-left: var(--sp-3);
}
/* 回看模式横幅（点开历史会话）
 *
 * **浮动在顶部**：以前它是消息流里的第一个元素，往上翻两屏就看不见了 ——
 * 用户读到一半想「接着聊」或者「回到当前对话」，得先滚回最顶上，
 * 而他在回看模式下本来就是在往上看历史，等于每次都要反向滚一遍。
 *
 * sticky 生效的条件在滚动链路上没有 `overflow:hidden`（这里满足：
 * `.stream` 是滚动容器，`.stream-inner` / `#messages` 都没有截断）。
 * `top` 用负的 `.stream` 上内边距 —— 否则会贴在 padding 内边缘，顶上留一条缝。
 */
.replay-banner {
  position: sticky;
  top: calc(-1 * var(--sp-5));   /* 抵掉 .stream 的上 padding */
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  margin-bottom: var(--sp-4);
  /* sticky 元素**必须有背景**，否则下方内容滚过时会从它身子里透出来 */
  background: var(--surface-2);
  border: var(--bw) solid var(--border);
  border-radius: var(--r-md);
  font-size: var(--text-sm);
  color: var(--text-dim);
  /* 一点阴影，让它看起来是「浮」在内容之上 */
  box-shadow: 0 4px 12px -6px rgba(0, 0, 0, .25);
}
/* ──「当前问题」浮动条（2026-09-30，参考 Hermes）─────────────────
 *
 * 用户往上翻历史时，得随时知道**现在正在解决什么** —— 否则滑两屏就忘了
 * 自己问的是什么、agent 又在忙什么。新消息一来就替换内容（用户要的是
 * 「最新那一个问题」，不是历史列表）。
 *
 * 与 `.replay-banner` 同一个套路：sticky + 必须有不透明背景（否则下方内容
 * 滚过时会从它身子里透出来），`top` 用负的 `.stream` 上内边距抵掉那条缝。
 */
.current-task {
  position: sticky;
  top: calc(-1 * var(--sp-5));
  z-index: 22;                  /* 压在 replay-banner（20）之上 */
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  margin-bottom: var(--sp-3);
  /* 底色带「用户色」调子，和用户气泡是同一族 —— 一眼看出这是「我问的话」 */
  background: color-mix(in srgb, var(--user) 10%, var(--surface));
  border: var(--bw) solid var(--border);
  border-left: var(--bw-accent) solid var(--user);
  border-radius: var(--r-md);
  font-size: var(--text-sm);
  box-shadow: 0 4px 12px -6px rgba(0, 0, 0, .25);
  /* 长问题截成一行（完整内容就在下面的消息里） */
  overflow: hidden;
}
/* `hidden` 属性要能真的藏起来（display:flex 会盖过它的默认行为） */
.current-task[hidden] { display: none; }
.current-task-tag {
  flex: 0 0 auto;
  color: var(--user);
  font-weight: 600;
}
.current-task-text {
  flex: 1 1 auto;
  min-width: 0;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ── 工具调用进度条（2026-10-21）──────────────────────────────────
 * 用户原话：「调用工具的记录是否可以改成一行固定显示，左右滚动，
 * 用户不需要看这些记录，只需要知道当前的状态即可」。
 *
 * 设计：
 * - 固定显示在对话区顶部（sticky，和 current-task 同层）
 * - 水平滚动，每个工具调用是一个紧凑的 chip
 * - chip 显示：工具名 + 状态图标（运行中/完成/失败）
 * - 点击 chip 可展开查看详情（tooltip 或 popover）
 * - 没有工具调用时隐藏（hidden）
 */
.tool-call-bar {
  position: sticky;
  top: calc(-1 * var(--sp-5));
  z-index: 21;                  /* 略低于 current-task（22） */
  display: flex;
  align-items: center;
  padding: var(--sp-2) var(--sp-3);
  margin-bottom: var(--sp-3);
  background: var(--surface);
  border: var(--bw) solid var(--border);
  border-radius: var(--r-md);
  box-shadow: 0 2px 8px -4px rgba(0, 0, 0, .15);
  overflow: hidden;
}
.tool-call-bar[hidden] { display: none; }

/* 水平滚动容器 */
.tcb-track {
  display: flex;
  gap: var(--sp-2);
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
  flex: 1;
  padding-bottom: 2px;          /* 给滚动条留空间 */
}
.tcb-track::-webkit-scrollbar {
  height: 4px;
}
.tcb-track::-webkit-scrollbar-track {
  background: transparent;
}
.tcb-track::-webkit-scrollbar-thumb {
  background: var(--border);
  border-radius: 2px;
}
.tcb-track::-webkit-scrollbar-thumb:hover {
  background: var(--text-faint);
}

/* 单个工具调用 chip */
.tcb-chip {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  padding: var(--sp-1) var(--sp-2);
  background: var(--surface-2);
  border: var(--bw) solid var(--border);
  border-radius: var(--r-sm);
  font-size: var(--text-xs);
  color: var(--text);
  cursor: pointer;
  transition: all 0.15s ease;
  white-space: nowrap;
  position: relative;
}
.tcb-chip:hover {
  background: var(--surface-3);
  border-color: var(--user);
}
.tcb-chip:active {
  transform: scale(0.97);
}

/* 状态图标 */
.tcb-icon {
  flex: 0 0 auto;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  display: inline-block;
}
.tcb-icon.pending {
  background: var(--text-faint);
}
.tcb-icon.running {
  background: var(--agent);
  animation: tcb-pulse 1.4s ease-in-out infinite;
}
.tcb-icon.completed {
  background: var(--success);
}
.tcb-icon.error {
  background: var(--danger);
}

@keyframes tcb-pulse {
  0%, 100% { opacity: 0.4; transform: scale(0.9); }
  50% { opacity: 1; transform: scale(1.1); }
}

/* 工具名 */
.tcb-name {
  flex: 0 0 auto;
  font-weight: 500;
}

/* 详情弹出层（点击 chip 显示） */
.tcb-popover {
  position: absolute;
  top: 100%;
  left: 0;
  margin-top: var(--sp-1);
  min-width: 280px;
  max-width: 400px;
  background: var(--surface);
  border: var(--bw) solid var(--border);
  border-radius: var(--r-md);
  box-shadow: 0 8px 16px -4px rgba(0, 0, 0, .25);
  padding: var(--sp-3);
  z-index: 30;
  font-size: var(--text-sm);
}
.tcb-popover-title {
  font-weight: 600;
  margin-bottom: var(--sp-2);
  color: var(--text);
}
.tcb-popover-args {
  background: var(--bg);
  border: var(--bw) solid var(--border);
  border-radius: var(--r-sm);
  padding: var(--sp-2);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-dim);
  white-space: pre-wrap;
  word-break: break-all;
  max-height: 200px;
  overflow-y: auto;
}

/* 空状态里可点击的「试试说」建议 */
.example-link {
  color: var(--user);
  text-decoration: none;
  cursor: pointer;
}
.example-link:hover { text-decoration: underline; }

/* ───────── 主区 ──────────────────────────────────────────── */
.main { flex: 1; display: flex; flex-direction: column; min-width: 0; }

/* ───────── 右侧信息面板 ────────────────────────────────────
   把「引擎一直在算、界面一直没显示」的东西摆出来：
   上下文用了多少、这一轮跑了多久、调了几次工具、今天花了多少。
   以前这些只活在事件流里，用户唯一的反馈是 gauge 上那句「快满了」。 */
.inspector {
  position: relative;            /* 拖拽把手靠它定位（2026-10-02） */
  width: var(--inspector-w, 248px);   /* 同 .sidebar：宽度走变量，收起态才压得住 */
  flex: none;
  display: flex;
  flex-direction: column;
  background: transparent;
  backdrop-filter: blur(var(--glass-blur-heavy));
  -webkit-backdrop-filter: blur(var(--glass-blur-heavy));
  border-left: var(--bw) solid var(--glass-border);
  box-shadow: var(--glass-shadow), var(--glass-inner-glow);
  overflow: hidden;
  transition: width var(--dur);
}
.inspector.collapsed { width: 38px; }
.inspector.collapsed .insp-body { display: none; }
.insp-head {
  height: 48px; flex: none;
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 var(--sp-3);
  border-bottom: var(--bw) solid var(--border);
  font-size: var(--text-sm); color: var(--text-dim);
  white-space: nowrap;
}
.inspector.collapsed .insp-head > span { display: none; }
.insp-toggle {
  border: none; background: transparent;
  color: var(--text-dim);      /* 2026-10-02：同上，加深一档 */
  cursor: pointer; font-family: inherit; font-size: var(--text-base);
  display: inline-flex; align-items: center;
}
.insp-toggle:hover { color: var(--user); }
.insp-body { flex: 1; overflow: auto; padding: var(--sp-2); }
.insp-block {
  margin-bottom: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  /* 2026-10-19 用户定稿：右侧填充改半透明，背景虚化透出来 */
  background: color-mix(in srgb, var(--surface-2) 55%, transparent);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: var(--bw) solid var(--border);
  border-radius: var(--r-md);
}
.insp-title {
  font-size: var(--text-xs); color: var(--text-faint);
  margin-bottom: var(--sp-2);
}
.insp-bar-line {
  display: flex; justify-content: space-between; align-items: baseline;
  font-size: var(--text-xs); margin-bottom: 5px;
}
.insp-state { color: var(--success); }
.insp-num { color: var(--text-dim); font-family: var(--font-mono); }
.insp-bar { height: 6px; background: var(--bg); border-radius: var(--r-sm); overflow: hidden; }
.insp-bar-fill { height: 100%; background: var(--user); transition: width var(--dur-slow); }
.insp-bar-fill.is-hot { background: var(--danger); }
.insp-foot { font-size: var(--text-xs); color: var(--text-faint); margin-top: 5px; }
.insp-kv {
  display: flex; justify-content: space-between;
  font-size: var(--text-xs); padding: 2px 0;
}
.insp-k { color: var(--text-faint); }
.insp-v { color: var(--text); font-family: var(--font-mono); }
.view { flex: 1; display: none; flex-direction: column; overflow: hidden; }
.view.active { display: flex; }

/* 会话头（标题 + 用量条） */
.head {
  height: 48px;
  flex: none;
  border-bottom: var(--bw) solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 var(--sp-5);
}
.head-title { font-size: var(--text-base); color: var(--text-dim); }
.head-right { display: flex; align-items: center; gap: var(--sp-3); }
/* 会话头用量胶囊（§4.5 入口） */
.head-pill {
  border: var(--bw) solid var(--border); background: var(--surface);
  color: var(--text-dim); border-radius: var(--r-full);
  padding: 0 var(--sp-3); font-size: var(--text-xs);
  font-family: inherit; cursor: pointer; line-height: 20px;
}
.head-pill:hover { border-color: var(--user); color: var(--user); }
/* 当前项目（2026-10-06 项目化）—— 顶部最左那个胶囊。
   比普通 .head-pill 显眼一档：用户要「一眼看出我现在在哪个项目里干活」。 */
.head-left { display: flex; align-items: center; gap: var(--sp-3); min-width: 0; }
.head-project {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  max-width: 340px; color: var(--text); font-weight: 600;
}
.head-project:hover { border-color: var(--user); color: var(--user); }
.head-project-icon { color: var(--user); }
.head-project.is-empty { color: var(--text-faint); font-weight: 400; }
.head-project.is-empty .head-project-icon { color: var(--text-faint); }
#project-label {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  max-width: 260px;
}
.head-caret { color: var(--text-faint); font-size: 0.625rem; }

/* 项目选择面板（views/projectPicker.js，2026-10-06 项目化） */
.proj-picker {
  position: fixed; z-index: 900; width: 360px; max-height: 70vh;
  overflow-y: auto; padding: var(--sp-2);
  background: var(--surface); border: var(--bw) solid var(--border);
  border-radius: var(--r-md); box-shadow: var(--shadow-pop);
  font-size: var(--text-sm);
}
.pp-head {
  padding: var(--sp-2) var(--sp-3); color: var(--text-faint);
  font-size: var(--text-xs);
}
.pp-row {
  display: flex; align-items: baseline; gap: var(--sp-2); width: 100%;
  padding: var(--sp-2) var(--sp-3); border: 0; border-radius: var(--r-sm);
  background: transparent; color: var(--text); font: inherit;
  text-align: left; cursor: pointer;
}
.pp-row:hover { background: var(--surface-2); }
.pp-row.is-current { color: var(--user); font-weight: 600; }
.pp-row.is-missing { color: var(--text-faint); }
.pp-row:disabled { cursor: not-allowed; opacity: .55; }
.pp-row-label { flex: none; }
.pp-row-note {
  flex: 1; min-width: 0; color: var(--text-faint); font-size: var(--text-xs);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  text-align: right;
}
.pp-sep {
  margin: var(--sp-2) var(--sp-3); padding-top: var(--sp-2);
  border-top: var(--bw) solid var(--border); color: var(--text-faint);
  font-size: var(--text-xs);
}
.pp-x {
  flex: none; margin-left: auto; border: 0; background: transparent;
  color: var(--danger); font: inherit; font-size: var(--text-xs);
  cursor: pointer; padding: 0 var(--sp-1);
}
.head-pill-danger { border-color: var(--danger); color: var(--danger); }
.head-pill-danger:hover { border-color: var(--danger); color: var(--danger); background: rgba(255,107,107,.12); }
/* 续聊灰线（§v0.3 四） */
.replay-divider {
  text-align: center; color: var(--text-faint); font-size: var(--text-xs);
  margin: var(--sp-3) 0; user-select: none;
}
/* 用量页 */
.usage-today { font-size: var(--text-lg); margin-bottom: var(--sp-1); }
.usage-today b { color: var(--user); font-weight: 600; }
.usage-row {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-1) 0; font-size: var(--text-base);
}
.usage-op { flex: none; width: 90px; color: var(--text-dim); }
.usage-op2 { flex: 1; color: var(--text); }
.usage-bar {
  flex: 1; height: 6px; background: var(--surface-2);
  border-radius: var(--r-sm); overflow: hidden;
}
.usage-fill { display: block; height: 100%; background: var(--user); border-radius: var(--r-sm); }
.usage-n { flex: none; color: var(--text-faint); font-size: var(--text-sm); text-align: right; }
.usage-when { flex: none; width: 110px; color: var(--text-faint); font-size: var(--text-sm); font-family: var(--font-mono); }
.usage-tag-wrap { flex: none; color: var(--text-dim); font-size: var(--text-xs); }
.usage-tag { font-size: var(--text-xs); padding: 0 5px; border-radius: var(--r-sm); }
.usage-tag.real { color: var(--user); background: var(--selection-soft); }
.usage-tag.est { color: var(--text-dim); background: var(--surface-2); }

/* 上下文用量条 */
.gauge {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--text-xs);
  color: var(--text-dim);
  white-space: nowrap;
}
.gauge-bar {
  width: 120px;
  height: 4px;
  background: var(--surface-2);
  border-radius: var(--r-xs);
  overflow: hidden;
}
.gauge-fill {
  height: 100%;
  width: 0;
  background: var(--user);
  border-radius: var(--r-xs);
  transition: width var(--dur-slow), background var(--dur-slow);
}
.gauge.warn .gauge-fill { background: var(--user); }
.gauge.err .gauge-fill { background: var(--danger); }
/* [local patch 2026-09-21] main.js applies these class names directly to the
   fill element, which matched no rule at all. */
.gauge-fill.gauge-user { background: var(--user); }
.gauge-fill.gauge-warning { background: var(--user); }
.gauge-fill.gauge-danger { background: var(--danger); }

/* ───────── 消息流（流式文档） ─────────────────────────────── */
.stream {
  flex: 1;
  overflow-y: auto;
  padding: var(--sp-5) 0;
  /* 2026-10-19 用户定稿：62% 衬底 —— 比之前的 88% 更透，背景在对话区
   * 也能透出虚化质感；白字对深底仍有充足对比度（对比度套件实测通过） */
  background: color-mix(in srgb, var(--surface) 62%, transparent);
  display: flex;
  flex-direction: column;
  align-items: center;
  /* 08卷 §3.9: 滚动条 10px、轨道透明、滑块 --border、悬停 var(--scrollbar-hover) */
  scrollbar-width: thin;
}
.stream::-webkit-scrollbar { width: 10px; }
.stream::-webkit-scrollbar-track { background: transparent; }
.stream::-webkit-scrollbar-thumb { background: var(--border); border-radius: var(--r-md); }
.stream::-webkit-scrollbar-thumb:hover { background: var(--scrollbar-hover); }
.stream-inner {
  width: 100%;
  max-width: 860px;
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
}
/* 用户消息：青色左边条，左对齐，全宽引用块，无气泡背景 */
/* ⚠️ `.item-user` / `.item-agent` 的**唯一定义在 views.css**（它最后加载）。
   这里原本还留着一份重复的 —— 两份是按属性逐条层叠的，删的时候极容易把
   只写在一边的属性（比如 `white-space: pre-wrap`）弄丢。2026-09-30 合并掉了。 */
.item-agent .cursor {
  display: inline-block;
  width: 2px;
  height: 1em;
  background: var(--agent);
  vertical-align: text-bottom;
  margin-left: 2px;
  animation: blink var(--dur-anim) step-end infinite;
}
@keyframes blink { 50% { opacity: 0; } }

/* 思考：默认折叠成一行的 details */
.reasoning,
.toolcall {
  margin-left: var(--sp-2);
}
.reasoning summary,
.toolcall summary {
  color: var(--text-faint);
  font-size: var(--text-sm);
  cursor: pointer;
  list-style: none;
}
.reasoning summary::-webkit-details-marker { display: none; }
.reasoning summary::before {
  content: "› ";
  color: var(--agent);
}
.reasoning.open summary::before { content: "˄ "; }

/* 过程旁白（2026-10-01）：模型中间每轮说的「我先…」「做完了…」收在这里，
   默认收起。正文只留**最终答复** —— 用户原话「回复的内容总是有重复的……
   用户需要的是最终自己要的结果」。
   和 .reasoning 同款形态（details + 箭头），但多一条左边框，和思考过程
   在视觉上分得开（思考是「它在想」，旁白是「它在做」）。 */
.narration { margin-bottom: var(--sp-2); }
.narration summary {
  color: var(--text-faint);
  font-size: var(--text-sm);
  cursor: pointer;
  list-style: none;
  user-select: none;
}
.narration summary::-webkit-details-marker { display: none; }
.narration summary::before {
  content: "▸ ";
  color: var(--agent);
}
.narration.open summary::before { content: "▾ "; }
.narration-body {
  margin-top: var(--sp-2);
  padding-left: var(--sp-2);
  border-left: var(--bw) solid var(--border);
  color: var(--text-dim);
  font-size: var(--text-sm);
  line-height: 1.6;
}
/* ↑ 这里**不要**加 `white-space: pre-wrap`：旁白里也可能有列表和代码块，
   折叠体是 renderMarkdown 出来的 HTML（.reasoning-body 是纯文本，才有那行）。 */
.reasoning-body {
  margin-top: var(--sp-2);
  padding-left: var(--sp-2);
  color: var(--text-dim);
  font-size: var(--text-sm);
  line-height: 1.6;
  white-space: pre-wrap;
}

/* 工具调用：单行 */
.toolcall-body {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-dim);
  background: var(--bg);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-sm);
  margin-top: var(--sp-2);
  white-space: pre-wrap;
}

/* 计划：步骤 + 状态图标 */
.plan {
  border: var(--bw) solid var(--border);
  border-radius: var(--r-md);
  padding: var(--sp-3);
  background: var(--surface-2);
}
.plan-title {
  font-size: var(--text-sm);
  color: var(--text-dim);
  margin-bottom: var(--sp-2);
}
.plan-step {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--text-base);
  padding: 2px 0;
}
.plan-step .ic { width: 14px; text-align: center; font-size: var(--text-sm); }
.plan-step.done { color: var(--text-faint); }
.plan-step.done .ic { color: var(--success); }
.plan-step.doing .ic { color: var(--user); animation: spin var(--dur-anim) linear infinite; }
.plan-step.todo .ic { color: var(--text-faint); }
@keyframes spin { 0% { transform: rotate(0); } 100% { transform: rotate(360deg); } }

/* 命令执行：等宽块 + 右上角状态 */
.cmd {
  border: var(--bw) solid var(--border);
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--bg);
}
.cmd-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  border-bottom: var(--bw) solid var(--border);
}
.cmd-name {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cmd-status { font-size: var(--text-xs); white-space: nowrap; }
.cmd-status.ok { color: var(--success); }
.cmd-status.run { color: var(--user); }
.cmd-status.err { color: var(--danger); }
.cmd-body {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-dim);
  padding: var(--sp-3);
  white-space: pre-wrap;
  overflow-x: auto;
}
.cmd.collapsible .cmd-body {
  display: none;
}
.cmd.collapsible.collapsed .cmd-body { max-height: 0; overflow: hidden; padding: 0; }

/* 文件改动：文件名 + n/−n 徽标 + diff */
.filechange {
  border: var(--bw) solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface-2);
  overflow: hidden;
}
.fc-head {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  border-bottom: var(--bw) solid var(--border);
  font-size: var(--text-sm);
}
.fc-title { color: var(--text); }
.badge { display: inline-flex; gap: 2px; }
.badge .add {
  color: var(--success);
  font-family: var(--font-mono);
  background: rgba(61, 220, 132, .1);
  padding: 1px 4px;
  border-radius: var(--r-sm);
}
.badge .del {
  color: var(--danger);
  font-family: var(--font-mono);
  background: rgba(255, 107, 107, .1);
  padding: 1px 4px;
  border-radius: var(--r-sm);
}
.fc-files { padding: var(--sp-2) var(--sp-3) var(--sp-3); }
/* 结果回执行（重设计稿 §4.2）：✓ 已保存 + 打开按钮 */
.fc-receipt {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  border-top: var(--bw) solid var(--border);
  font-size: var(--text-sm);
}
.fc-receipt-ok { color: var(--success); }
.fc-open-btn {
  padding: var(--sp-1) var(--sp-3);
  font-size: var(--text-sm);
}
.fc-file { display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-1) 0; font-size: var(--text-sm); }
.fc-file > span:first-child { color: var(--text); font-family: var(--font-mono); }
.diff { margin-left: var(--sp-2); }
.d-ctx { color: var(--text-faint); font-family: var(--font-mono); font-size: var(--text-xs); padding: 0 2px; }
.d-del { color: var(--danger); font-family: var(--font-mono); font-size: var(--text-xs); padding: 0 2px; background: rgba(255, 107, 107, .08); }
.d-add { color: var(--success); font-family: var(--font-mono); font-size: var(--text-xs); padding: 0 2px; background: rgba(61, 220, 132, .08); }

/* 审批卡片：品红边框、四要素、五按钮 */
.approval {
  border: 2px solid var(--agent);
  border-radius: var(--r-lg);
  background: var(--surface-2);
  padding: var(--sp-4);
}
.ap-head {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  color: var(--agent);
  font-size: var(--text-lg);
  margin-bottom: var(--sp-3);
}
.ap-action { font-size: var(--text-base); margin-bottom: var(--sp-3); color: var(--text); }
.ap-action code,
.ap-cmd {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  background: var(--bg);
  border-radius: var(--r-sm);
  padding: var(--sp-2) var(--sp-3);
  color: var(--text);
  display: block;
  margin-top: var(--sp-1);
  overflow-x: auto;
}
.ap-meta {
  display: grid;
  grid-template-columns: 80px 1fr;
  gap: var(--sp-1) var(--sp-3);
  font-size: var(--text-sm);
  margin-bottom: var(--sp-4);
}
.ap-meta dt { color: var(--text-faint); }
.ap-meta dd { color: var(--text-dim); font-family: var(--font-mono); overflow-wrap: anywhere; }
.ap-btns { display: flex; gap: var(--sp-2); flex-wrap: wrap; }
/* §4.3 危险级：红边框 + 提示行 */
.approval.dangerous { border-color: var(--danger); }
.approval.dangerous .ap-head { color: var(--danger); }
.ap-first {
  font-size: var(--text-sm);
  color: var(--text-faint);
  margin: calc(-1 * var(--sp-1)) 0 var(--sp-3);
}
.ap-note {
  font-size: var(--text-xs);
  color: var(--text-faint);
  margin-top: var(--sp-2);
}
.ap-details { margin-bottom: var(--sp-3); }
.ap-details summary {
  color: var(--text-faint);
  font-size: var(--text-sm);
  cursor: pointer;
}
.ap-details pre,
.ap-preview {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-dim);
  background: var(--bg);
  border-radius: var(--r-sm);
  padding: var(--sp-2) var(--sp-3);
  margin-top: var(--sp-2);
  overflow-x: auto;
  white-space: pre-wrap;
  word-break: break-all;
}
.ap-secondary {
  font-size: var(--text-sm);
  color: var(--text-faint);
  margin-bottom: var(--sp-3);
}
/* 聚合卡逐条列表（§v0.3 一） */
.ap-batch { margin-bottom: var(--sp-3); }
.ap-batch-row {
  font-family: var(--font-mono); font-size: var(--text-sm);
  color: var(--text-dim); padding: 1px 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ap-batch-row.danger { color: var(--danger); }
.ap-link { color: var(--user); text-decoration: none; }
.ap-link:hover { text-decoration: underline; }
/* 决策后缩成一行（§4.3 状态：已允许/已拒绝） */
.approval-done {
  font-size: var(--text-sm);
  color: var(--success);
  padding: var(--sp-1) var(--sp-3);
}
.approval-done.is-denied { color: var(--text-faint); }

/* 通用按钮 — 毛玻璃立体效果 */
.btn {
  font-family: inherit;
  font-size: var(--text-base);
  padding: var(--sp-2) var(--sp-4);
  border-radius: var(--r-md);
  cursor: pointer;
  border: var(--bw) solid var(--glass-border);
  background: var(--glass-bg);
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
  color: var(--text-dim);
  box-shadow: var(--glass-inner-glow);
  transition: all var(--dur);
}
.btn:hover { 
  border-color: var(--glass-border-strong); 
  color: var(--text);
  background: var(--glass-bg-hover);
  box-shadow: var(--glass-shadow), var(--glass-inner-glow);
}
.btn:focus-visible { outline: 2px solid var(--user); outline-offset: 2px; }
.btn:disabled { opacity: .4; pointer-events: none; }
.btn-primary { border-color: var(--user); color: var(--user); background: color-mix(in srgb, var(--user) 7%, transparent); }
.btn-primary:hover { background: color-mix(in srgb, var(--user) 14%, transparent); border-color: var(--user); }
.btn-persist { border-color: var(--agent); color: var(--agent); background: rgba(139, 92, 246, 0.08); }
.btn-persist:hover { background: rgba(139, 92, 246, 0.15); border-color: var(--agent); }
.btn-danger { border-color: var(--danger); color: var(--danger); background: rgba(248, 113, 113, 0.08); }
.btn-danger:hover { background: rgba(248, 113, 113, 0.15); border-color: var(--danger); }

/* ───────── 输入区 ─────────────────────────────────────────── */
.composer {
  flex: none;
  position: relative;          /* 「回到底部」按钮的定位基准 */
  padding: var(--sp-3) var(--sp-5) var(--sp-5);
  border-top: var(--bw) solid var(--divider);
}

/* ── 回到底部（2026-09-30）────────────────────────────────────
 *
 * 只在用户**已经往上翻**（离开底部）时出现 —— 那时候他要的是「一键回去」。
 * 故意不自动把他拽回去：正在读历史时被强行拉到最新，比找不到按钮更烦。
 *
 * 定位用 `bottom: 100%` 而不是固定偏移：输入框会随内容长高，
 * 算死一个像素值迟早会压到它身上。
 */
.jump-bottom {
  position: absolute;
  right: var(--sp-5);
  bottom: calc(100% + var(--sp-2));
  z-index: 30;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: var(--bw) solid var(--border);
  background: var(--surface);
  color: var(--text-dim);
  font-size: var(--text-lg);
  line-height: 1;
  cursor: pointer;
  box-shadow: 0 4px 14px -6px rgba(0, 0, 0, .35);
  transition: color var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease);
}
/* `display:flex` 会盖过 `[hidden]` 的默认行为，得显式关掉 */
.jump-bottom[hidden] { display: none; }
.jump-bottom:hover { color: var(--user); border-color: var(--user); }
.composer-inner { max-width: 860px; margin: 0 auto; }
.steer-hint {
  font-size: var(--text-xs);
  color: var(--user);
  margin-bottom: var(--sp-1);
  padding-left: var(--sp-3);
  display: none;
}
.steer-hint.show { display: block; }
.input-row {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  background: transparent;
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
  border: var(--bw) solid var(--glass-border-strong);
  border-radius: var(--r-lg);
  padding: var(--sp-2) var(--sp-3);
  box-shadow: var(--glass-shadow), var(--glass-inner-glow);
}
.input-row:focus-within { border-color: var(--user); }
.input-row input, .input-row textarea {
  flex: 1;
  background: transparent;
  border: none;
  outline: none;
  color: var(--text);
  font-family: inherit;
  font-size: var(--text-base);
  /* [local patch 2026-09-21] index.html uses <textarea id="msg-input">, but the
     rules here only matched `input`, so the composer textarea rendered with the
     browser default look. resize:none keeps it a one-line composer. */
  resize: none;
  line-height: 1.5;
  padding: 0;
  /* 高度由 JS 的 autoGrowInput() 按内容撑（参考 Reasonix）；
     这里只给上限。原来 140px 太矮 —— 写长一点的指令就看不到自己写的前半段了。
     改高度的过渡要短，否则打字时会觉得输入框在「追」光标。 */
  max-height: 260px;
  overflow-y: hidden;
  transition: height var(--dur-fast) var(--ease);
}
.input-row input::placeholder, .input-row textarea::placeholder { color: var(--text-faint); }
.btn-send { border-color: var(--user); color: var(--user); padding: var(--sp-2) var(--sp-4); }
.btn-stop { border-color: var(--danger); color: var(--danger); }
.btn-send:hover { background: rgba(90, 200, 250, .12); }
.btn-stop:hover { background: rgba(255, 107, 107, .12); }

/* ───────── 内嵌终端面板（§v0.3 五） ─────────────────────── */
#term-panel {
  flex: none;
  height: 40%;
  min-height: 180px;
  display: flex;
  flex-direction: column;
  border-top: var(--bw) solid var(--border);
  background: var(--bg);
}
.term-head {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--sp-1) var(--sp-4);
  border-bottom: var(--bw) solid var(--border);
  font-size: var(--text-xs);
  color: var(--text-faint);
}
.term-close {
  border: none; background: transparent; color: var(--text-faint);
  cursor: pointer; font-size: var(--text-sm); font-family: inherit;
}
.term-close:hover { color: var(--danger); }
.term-out {
  flex: 1;
  overflow-y: auto;
  padding: var(--sp-2) var(--sp-4);
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  line-height: 1.6;
}
.term-line { white-space: pre-wrap; word-break: break-all; color: var(--text); }
.term-line.user { color: var(--user); }
.term-line.ok { color: var(--success); }
.term-line.err { color: var(--danger); }
.term-line.dim { color: var(--text-faint); }
.term-line.warn { color: var(--agent); }
.term-input-row {
  flex: none;
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-4);
  border-top: var(--bw) solid var(--border);
}
.term-prompt { color: var(--user); font-family: var(--font-mono); font-size: var(--text-sm); }
.term-input {
  flex: 1;
  background: transparent;
  border: none;
  outline: none;
  color: var(--text);
  font-family: var(--font-mono);
  font-size: var(--text-sm);
}

/* 空状态（.empty）与首启三选一（.fr-guide）的样式已于 2026-10-02 删除 ——
   新对话页换成了技能卡片墙，样式在 views.css 的 `.home*` / `.pf-*`。 */

/* ── 项目内 Markdown 排版（.item-agent / .reasoning-body 内） ── */
.md-p { margin: var(--sp-2) 0; }
.md-h1, .md-h2, .md-h3 { margin: var(--sp-3) 0 var(--sp-2); line-height: 1.3; }
.md-h1 { font-size: var(--text-lg); }
.md-h2 { font-size: var(--text-md); }
.md-h3 { font-size: var(--text-base); }
.md-li { padding: 2px 0; }
.md-table {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-dim);
  margin: var(--sp-2) 0;
  border: var(--bw) solid var(--border);
  border-radius: var(--r-sm);
  padding: var(--sp-2) var(--sp-3);
  overflow-x: auto;
  white-space: nowrap;
}
.todo-item { font-size: var(--text-base); }
/* 2026-10-01 补：这些以前**不渲染**，用户看到的是 `---` `####` `**x**` 本身 */
.md-hr { border:none; border-top:var(--bw) solid var(--border); margin:var(--sp-3) 0; }
.md-quote {
  border-left: 3px solid var(--border);
  padding: var(--sp-1) 0 var(--sp-1) var(--sp-3);
  margin: var(--sp-2) 0;
  color: var(--text-dim);
}
.md-p a, .md-li a, .md-quote a { color: var(--user); text-decoration: underline; }
.md-p del, .md-li del { color: var(--text-faint); }
.md-p code.inline-code, .md-li code.inline-code, .md-quote code.inline-code {
  font-family: var(--font-mono);
  font-size: max(12px, .9em);
  background: var(--surface-2, rgba(255,255,255,.06));
  border-radius: var(--r-sm, 4px);
  padding: 1px 4px;
}
.code-block {
  background: var(--bg);
  border: var(--bw) solid var(--border);
  border-radius: var(--r-sm);
  padding: var(--sp-2) var(--sp-3);
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  color: var(--text-dim);
  overflow-x: auto;
  white-space: pre-wrap;
  margin: var(--sp-2) 0;
}
.inline-code {
  background: var(--bg);
  padding: 0 4px;
  border-radius: var(--r-sm);
  font-size: max(12px, .9em);
  color: var(--user);
  font-family: var(--font-mono);
}

/* 通用小标签 */
.badge-label {
  font-size: var(--text-xs);
  color: var(--text-faint);
  background: var(--surface-2);
  border: var(--bw) solid var(--border);
  border-radius: var(--r-sm);
  padding: 0 var(--sp-1);
}

/* 禁用 JavaScript 时的兜底遮罩（仅无 JS 时显示，样式走令牌） */
.noscript-fallback {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text);
  font: 16px/1.5 system-ui, sans-serif;
  z-index: 9999;
}

/* 08卷 §二：视口 < 900px 时侧栏自动收起为图标条（窄栏、仅入口，无文字标签） */
@media (max-width: 900px) {
  .sidebar {
    width: 72px !important;
    padding: var(--sp-2);
  }
  .sidebar .brand {
    font-size: 0;
    margin: 0 0 var(--sp-1) 0;
    width: 100%;
    text-align: center;
  }
  .sidebar .brand::before {
    margin: 0 var(--sp-2) 0 0;
    display: inline-block;
  }
  #new-session-btn {
    width: 100%;
    font-size: var(--text-sm);
    margin-bottom: var(--sp-2);
  }
  #session-list {
    display: none;
  }
  .nav {
    border-top: none;
    padding-top: var(--sp-2);
  }
  .nav-item {
    padding: var(--sp-1) var(--sp-2);
    font-size: var(--text-xs);
    border-left: none;
    text-align: center;
  }
  .inspector {
    display: none;
  }
}

@media (max-width: 600px) {
  .sidebar {
    width: 56px !important;
    padding: var(--sp-1);
  }
  .sidebar .brand-text,
  .sidebar .brand-sub,
  .sidebar .session-search,
  .sidebar .session-list,
  .sidebar #status,
  .sidebar .ns-label,
  #sidebar-toggle {
    display: none;
  }
  .sidebar .nav-label {
    font-size: var(--text-xs);
  }
  .head {
    padding: 0 var(--sp-2);
    gap: var(--sp-2);
  }
  .head-project {
    max-width: 132px;
  }
  #project-label {
    max-width: 92px;
  }
  .head-right {
    gap: var(--sp-1);
    min-width: 0;
  }
  #usage-pill,
  #term-btn,
  .gauge {
    display: none;
  }
  #model-pick {
    max-width: 112px;
  }
  .composer {
    padding: var(--sp-2);
  }
  .tool-row {
    overflow-x: auto;
  }
  .tool-cwd,
  #sc-help-btn {
    display: none;
  }
  .input-row {
    gap: var(--sp-2);
    padding: var(--sp-2);
  }
  .input-row .btn {
    padding-left: var(--sp-2);
    padding-right: var(--sp-2);
  }
  .statusbar {
    gap: var(--sp-2);
    padding: var(--sp-1) var(--sp-2);
  }
  .statusbar .sb-item + .sb-item::before {
    margin-right: var(--sp-2);
  }
  .sb-model,
  .sb-compact,
  .sb-usage {
    display: none;
  }
}

/* ───────── 设置页：二级导航 + 分页 ───────────────────────────
   以前设置页是「一页七行」。现在配置里能调的项多了，一页铺开会有二十几行、
   每行还带控件 —— 所以改成左侧二级导航。
   二级导航**长在视图内部**，不动 index.html 的一级导航。 */
.settings-shell {
  display: flex;
  height: 100%;
  min-height: 0;
}
.settings-nav {
  width: 152px;
  flex: none;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--sp-4) var(--sp-2);
  border-right: var(--bw) solid var(--border);
  overflow-y: auto;
}
.settings-nav-item {
  border: none;
  background: transparent;
  font-family: inherit;
  font-size: var(--text-base);
  color: var(--text-dim);
  text-align: left;
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-md, 6px);
  cursor: pointer;
}
.settings-nav-item:hover { background: var(--surface-2, rgba(255,255,255,.04)); color: var(--text); }
.settings-nav-item.active {
  background: var(--surface-2, rgba(255,255,255,.06));
  color: var(--user);
  font-weight: 600;
}
.settings-pane {
  flex: 1;
  min-width: 0;
  overflow-y: auto;
  padding: var(--sp-5) var(--sp-6);
}
.pane-head { margin-bottom: var(--sp-5); }
.pane-title { font-size: var(--text-lg); color: var(--text); margin-bottom: var(--sp-1); }
.pane-note { font-size: var(--text-sm); color: var(--text-faint); }

.pane-field {
  margin-bottom: var(--sp-5);
  max-width: 620px;
}
.pane-label {
  display: block;
  font-size: var(--text-sm);
  color: var(--text-dim);
  margin-bottom: var(--sp-2);
}
.pane-hint {
  font-size: var(--text-xs);
  color: var(--text-faint);
  margin-top: var(--sp-1);
  line-height: 1.6;
}
.pane-input {
  font-family: inherit;
  font-size: var(--text-base);
  color: var(--text);
  background: var(--surface-2, rgba(255,255,255,.04));
  border: var(--bw) solid var(--border);
  border-radius: var(--r-md, 6px);
  padding: var(--sp-2) var(--sp-3);
  min-width: 200px;
}
.pane-input:focus { outline: none; border-color: var(--user); }
.pane-input-narrow { min-width: 0; width: 110px; }
/* 路径这类长文本输入：占满一行再换行，别被压成 200px 的小盒子 */
.pane-input-grow { flex: 1 1 320px; min-width: 0; }
.pane-inline { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.pane-readonly {
  font-size: var(--text-base);
  color: var(--text-dim);
  padding: var(--sp-2) 0;
  word-break: break-all;
}
.pane-switch {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  cursor: pointer;
  font-size: var(--text-base);
  color: var(--text);
}
.pane-radios { display: flex; flex-direction: column; gap: var(--sp-2); }
.growth-pane { max-width: 720px; }
.growth-pane .pane-label { margin-top: var(--sp-5); }
.growth-weights,
.growth-experiences,
.growth-skills,
.growth-history { display: flex; flex-direction: column; gap: var(--sp-2); }
.growth-weight {
  display: grid;
  grid-template-columns: minmax(120px, 180px) 1fr 48px;
  align-items: center;
  gap: var(--sp-3);
  font-size: var(--text-sm);
  color: var(--text-dim);
}
.growth-weight-bar {
  height: 6px;
  border-radius: var(--r-full);
  background: var(--glass-bg-strong);
  overflow: hidden;
}
.growth-weight-fill {
  display: block;
  height: 100%;
  border-radius: var(--r-full);
  background: var(--accent-grad);
}
.growth-weight-val { text-align: right; color: var(--text-faint); }
.growth-exp {
  padding: var(--sp-2) var(--sp-3);
  border: var(--bw) solid var(--border);
  border-radius: var(--r-md, 6px);
  background: var(--surface-2, rgba(255,255,255,.04));
}
.growth-exp-top {
  display: flex;
  justify-content: space-between;
  gap: var(--sp-2);
  font-size: var(--text-xs);
  color: var(--text-faint);
  margin-bottom: 2px;
}
.growth-exp-cue { color: var(--text-dim); }
.growth-exp-lesson { font-size: var(--text-sm); color: var(--text); line-height: 1.55; }
.growth-skill,
.growth-history-row {
  padding: var(--sp-2) var(--sp-3);
  border-left: 2px solid var(--glass-border-strong);
  font-size: var(--text-sm);
  color: var(--text-dim);
  overflow-wrap: anywhere;
}
.pane-radio {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 2px var(--sp-2);
  align-items: baseline;
  cursor: pointer;
  font-size: var(--text-base);
  color: var(--text);
}
.pane-radio .pane-hint { grid-column: 2; margin-top: 0; }
.pane-radio-t { font-size: var(--text-base); }
/* 界面字号四档（2026-10-25）—— 外观页与顶栏 Aa 弹层是同一份状态 */
.font-size-grid { display: flex; gap: var(--sp-2); flex-wrap: wrap; }
.font-size-card {
  flex: 1 1 96px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface-2, rgba(255, 255, 255, 0.04));
  cursor: pointer;
  text-align: left;
}
.font-size-card:hover { border-color: var(--border-strong); }
.font-size-card.is-active {
  border-color: var(--user);
  background: color-mix(in srgb, var(--user) 10%, transparent);
}
.font-size-card .fs-label { font-size: var(--text-base); color: var(--text); }
.font-size-card.is-active .fs-label { color: var(--user); }
.font-size-card .fs-hint { font-size: var(--text-xs); color: var(--text-faint); }
.pane-list { list-style: none; padding: 0; margin: 0 0 var(--sp-4); }
.pane-list-item {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) 0;
  border-bottom: var(--bw) solid var(--border);
  font-size: var(--text-sm);
  flex-wrap: wrap;
}
.audit-list {
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-height: 340px;
  overflow-y: auto;
}
.audit-row {
  display: grid;
  grid-template-columns: 88px 62px minmax(80px, 160px) 1fr;
  gap: var(--sp-2);
  align-items: baseline;
  padding: var(--sp-2) var(--sp-3);
  border-bottom: var(--bw) solid var(--border);
  font-size: var(--text-sm);
  color: var(--text-dim);
}
.audit-time {
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.audit-what { color: var(--text); overflow-wrap: anywhere; }
.audit-detail { color: var(--text-faint); text-align: right; }

/* 错误报告分页（设置 → 错误报告，仅管理员） */
.er-card {
  padding: var(--sp-3);
  border: 1px solid var(--glass-border);
  border-radius: var(--r-md);
  background: var(--glass-bg);
  margin-bottom: var(--sp-3);
}
.er-top {
  display: flex;
  align-items: baseline;
  gap: var(--sp-3);
  font-size: var(--text-xs);
  color: var(--text-faint);
}
.er-user { color: var(--text-dim); }
.er-chip {
  margin-left: auto;
  padding: 1px 8px;
  border-radius: var(--r-full);
  border: 1px solid color-mix(in srgb, var(--danger) 45%, transparent);
  background: color-mix(in srgb, var(--danger) 12%, transparent);
  color: var(--danger);
  font-size: var(--text-xs);
}
.er-chip.resolved {
  border-color: var(--border);
  background: transparent;
  color: var(--text-faint);
}
.er-msg {
  margin: var(--sp-2) 0;
  font-size: var(--text-sm);
  color: var(--text);
  overflow-wrap: anywhere;
}
.er-detail { margin: var(--sp-2) 0; font-size: var(--text-xs); }
.er-detail summary { cursor: pointer; color: var(--text-faint); }
.er-line {
  display: grid;
  grid-template-columns: 92px 1fr;
  gap: var(--sp-2);
  padding: var(--sp-1) 0;
  border-bottom: var(--bw) solid var(--border);
}
.er-label { color: var(--text-faint); }
.er-value {
  color: var(--text-dim);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.er-btn {
  padding: 4px 14px;
  border-radius: var(--r-full);
  border: 1px solid var(--border-strong);
  background: var(--surface-elevated, transparent);
  color: var(--text);
  font: inherit;
  font-size: var(--text-xs);
  cursor: pointer;
}
.er-btn:hover { border-color: var(--color-accent); color: var(--color-accent); }
.er-btn:disabled { opacity: 0.5; cursor: default; }
.pane-x {
  margin-left: auto;
  border: var(--bw) solid var(--border);
  background: transparent;
  color: var(--text-faint);
  font-family: inherit;
  font-size: var(--text-xs);
  padding: 2px var(--sp-2);
  border-radius: var(--r-sm, 4px);
  cursor: pointer;
}
.pane-x:hover { color: var(--danger); border-color: var(--danger); }
.pane-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: var(--sp-3);
  max-width: 720px;
}
.cap-item {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--sp-2);
  border: var(--bw) solid var(--border);
  border-radius: var(--r-md, 6px);
}
.cap-key { font-size: var(--text-xs); color: var(--text-faint); }

/* ───────── 服务提供方卡片（设置 → 模型）─────────────────── */
.pane-sep {
  height: var(--bw);
  background: var(--border);
  margin: var(--sp-5) 0;
  max-width: 620px;
}
.prov-card {
  border: var(--bw) solid var(--border);
  border-radius: var(--r-md);
  padding: var(--sp-3);
  margin-bottom: var(--sp-3);
  max-width: 620px;
  background: var(--surface);
}
.prov-top {
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  margin-bottom: var(--sp-1);
}
.prov-name { font-size: var(--text-base); font-weight: 600; color: var(--text); }
.prov-kind {
  font-size: var(--text-xs);
  color: var(--text-faint);
  border: var(--bw) solid var(--border);
  border-radius: var(--r-full);
  padding: 0 var(--sp-2);
}
.prov-hint {
  font-size: var(--text-xs);
  color: var(--text-faint);
  margin-top: 2px;
  word-break: break-all;
}
.prov-card .pane-inline { margin-top: var(--sp-2); }

/* 删掉这家提供方（2026-09-30）。`margin-left:auto` 把它推到卡片右上角 ——
   和名字、类型拉开距离，免得误点。危险语义用 danger 色。 */
.prov-del {
  margin-left: auto;
  border: none;
  background: none;
  color: var(--text-faint);
  font-family: inherit;
  font-size: var(--text-base);
  line-height: 1;
  padding: 0 var(--sp-1);
  cursor: pointer;
  border-radius: var(--r-sm);
}
.prov-del:hover { color: var(--danger); background: var(--surface-2); }

/* 「测试连接」和它的结果（2026-09-30）。
   **故意不复用 `.pane-x`** —— 那个是列表项里的删除「×」：`margin-left:auto`
   把它推到行最右，hover 还变 danger 红。测试不是危险操作，红色是错的暗示，
   而且按钮该紧挨着结果文字，不该被推到另一头。 */
.prov-test {
  border: var(--bw) solid var(--border);
  background: transparent;
  color: var(--text-dim);
  font-family: inherit;
  font-size: var(--text-xs);
  padding: 2px var(--sp-3);
  border-radius: var(--r-sm, 4px);
  cursor: pointer;
  white-space: nowrap;
}
.prov-test:hover { color: var(--user); border-color: var(--user); }
.prov-test:disabled { opacity: .55; cursor: default; }

/* 结果就近贴在按钮右边。它可能是「✗ 密钥不对（401）—— 检查粘贴时有没有多带
   空格，或者这把已经被吊销」这种长句，得能换行而不是把卡片撑破。
   `min-width: 0` 是 flex 里的老规矩：不写的话内容不收缩，卡片会被顶宽。 */
.prov-test-out {
  flex: 1 1 200px;
  min-width: 0;
  font-size: var(--text-xs);
  color: var(--text-dim);
  word-break: break-word;
}

/* 「＋ 添加服务提供方」和它展开出来的表单 */
.prov-add { margin-top: var(--sp-2); }
.prov-add-form {
  margin-top: var(--sp-3);
  padding: var(--sp-3);
  border: var(--bw) dashed var(--border);
  border-radius: var(--r-md);
  max-width: 620px;
  background: var(--surface);
}
.prov-add-form .pane-inline { margin-top: var(--sp-2); }

/* 服务地址和模型名是**长文本**（`https://api.deepseek.com`、一串模型名），
   用 `.pane-input` 的默认宽度会被截成「deepseek-chat, deepseek-」这样，
   用户根本看不清自己填了什么。让它们撑满剩余宽度。
   `min-width: 0` 是 flex 里的老规矩：不写的话内容不会收缩，框会被撑破。 */
.prov-card .pane-inline .pane-input,
.prov-add-form .pane-inline .pane-input {
  flex: 1 1 auto;
  min-width: 0;
}
/* 但「上下文窗口」那个窄框保持窄 —— 它只有四五位数字 */
.prov-card .pane-inline .pane-input-narrow { flex: 0 0 auto; }
.prov-add-form .pane-hint { flex: 0 0 72px; }   /* 标签列对齐，别一条长一条短 */

@media (max-width: 600px) {
  .settings-shell { flex-direction: column; }
  .settings-nav {
    width: 100%;
    flex-direction: row;
    flex: none;
    overflow-x: auto;
    overflow-y: hidden;
    padding: var(--sp-2);
    border-right: none;
    border-bottom: var(--bw) solid var(--border);
  }
  .settings-nav-item {
    flex: none;
    white-space: nowrap;
    padding: var(--sp-2) var(--sp-3);
  }
  .settings-pane { padding: var(--sp-3); }
  .pane-input { min-width: 0; max-width: 100%; }
}

/* ───────── 工具行（输入框上方） ───────────────────────────────
   一排贴着输入框的小按钮。视觉上刻意做得很轻：它服务于输入，
   不该跟输入框抢注意力 —— 所以无底色、无边框，只在悬停时亮起来。 */
.tool-row {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
  padding: 0 var(--sp-1) var(--sp-2);
}
.tool-btn {
  border: none;
  background: transparent;
  font-family: inherit;
  font-size: var(--text-xs);
  color: var(--text-faint);
  padding: 3px var(--sp-2);
  border-radius: var(--radius-sm, 4px);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  max-width: 60%;
}
.tool-btn:hover { color: var(--user); background: var(--selection-soft); }

/* 审批档位下拉（2026-09-30）。和「＋文件」同层，但它是**选择器**不是动作
   按钮 —— 给一条细边框，免得看着像「点了就执行」。
   非默认档再加个边框色：一眼看得出自己不在常规档上（「不知道当前是什么档」
   正是这个功能要解决的痛点之一）。**不用 danger 色**：「全放行」是用户
   主动选的正当档位，红边框会让他以为界面在报错。 */
#approval-mode {
  border: var(--bw) solid var(--border);
  color: var(--text-dim);
  max-width: none;
  cursor: pointer;
}
#approval-mode:hover { color: var(--user); border-color: var(--user); }
#approval-mode.mode-warn { border-color: var(--danger); color: var(--danger); }
#approval-mode.mode-calm { border-color: var(--agent); color: var(--agent); }
#approval-mode:disabled { opacity: .5; cursor: default; }

/* 「全放行」的确认弹层（2026-10-01）。仿帮助面板的「遮罩 + 卡片」，
   但文案是分段的（会发生什么 / 底线在哪），所以 body 用 pre-wrap 保住换行。
   z-index 66：高过 toast(50) 和帮助面板(60)，免得被盖住。 */
.mode-mask {
  position: fixed; inset: 0; z-index: 66;
  background: rgba(0, 0, 0, .5);
  display: flex; align-items: center; justify-content: center; padding: 1rem;
}
.mode-card {
  background: var(--surface, #1a1a22);
  border: var(--bw) solid var(--border);
  border-radius: var(--r-md, 10px);
  box-shadow: 0 12px 40px rgba(0, 0, 0, .5);
  max-width: 460px; width: 100%;
  padding: var(--sp-4, 1.2rem);
}
.mode-card-h { font-size: var(--text-lg, 1.1rem); font-weight: 700; margin-bottom: .6rem; }
.mode-card-b {
  white-space: pre-wrap; font-size: var(--text-base, .95rem);
  color: var(--text-dim); line-height: 1.7;
}
.mode-card-row { display: flex; justify-content: flex-end; gap: .6rem; margin-top: 1.1rem; }
.tool-spacer { flex: 1; }
/* 工作目录：路径可能很长，截断但要保留可辨识的尾部（盘符那种开头没用） */
.tool-cwd { min-width: 0; }
.tool-cwd #cwd-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  direction: rtl;      /* 从尾部截断：留「…\项目名」而不是「C:\Users\…」 */
  text-align: left;
}
.tool-cwd-icon { flex: none; opacity: .7; }

/* ───────── 底部状态栏 ──────────────────────────────────────────
   一行横贯主区底部的常驻指标。定位是「随时瞟一眼」：不需要点开、
   不会被收起、不抢视线 —— 所以用最弱的字色 + 一条上边框。
   margin-top:auto 是必需的：各视图高度不满时把它顶到底部，
   否则它会浮在内容下面而不是贴在底边。 */
.statusbar {
  margin-top: auto;
  flex: none;
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-1) var(--sp-4);
  border-top: var(--bw) solid var(--border);
  background: var(--surface);
  font-size: var(--text-xs);
  color: var(--text-faint);
  white-space: nowrap;
  overflow: hidden;
}
/* 项之间用「·」分隔。放在每个非首项前面，比硬编码分隔符好：
   以后加一项不用同时改两处（分隔符漏加会看着像两项粘一起）。 */
.statusbar .sb-item + .sb-item::before {
  content: '·';
  margin-right: var(--sp-3);
  opacity: .5;
}
.sb-item { overflow: hidden; text-overflow: ellipsis; }
/* 模型名放左边留白之后，用量推最右 —— 中间那串是「过程」，两头是「配置」和「成本」 */
.sb-model { color: var(--text-dim); }
.sb-usage { margin-left: auto; }
.sb-item.is-hot { color: var(--danger); }


/* ── 产出预览层（2026-10-07）──────────────────────────────────
 * 文本类产出（.md / 代码 / 日志）**在界面里直接看**，不再依赖系统
 * 有没有关联程序 —— `.md` 在不少机器上就是没有，用户点了「打开」
 * 只会毫无反应（实测）。想编辑的走层里的「用系统程序打开」。 */
.pv-mask {
  position: fixed; inset: 0; z-index: 60;
  display: flex; align-items: center; justify-content: center;
  background: rgba(0, 0, 0, .55); padding: var(--sp-4);
}
.pv-panel {
  display: flex; flex-direction: column;
  width: min(900px, 96vw); max-height: 88vh;
  background: var(--surface-2);
  border: var(--bw) solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-pop);
  overflow: hidden;
}
.pv-head {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4);
  border-bottom: var(--bw) solid var(--border);
}
.pv-title {
  flex: 1; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: var(--text-lg); color: var(--text);
}
.pv-acts { display: flex; gap: var(--sp-2); flex: none; }
.pv-body {
  padding: var(--sp-4); overflow: auto;
  font-size: var(--text-base); color: var(--text);
}
.pv-pre {
  margin: 0; font-family: var(--font-mono); font-size: var(--text-sm);
  white-space: pre-wrap; word-break: break-word;
}
.pv-err { color: var(--danger); }

/* 图片 / PDF 预览（2026-10-22）：出图和报告类产物**在界面里直接看**。
 * 原来只有文本类走预览层，出图只能甩给系统的看图程序。 */
.pv-img {
  display: block;
  margin: 0 auto;
  max-width: 100%;
  max-height: 74vh;
  object-fit: contain;
  border-radius: var(--radius-sm);
}
.pv-frame {
  display: block;
  width: 100%;
  height: 74vh;
  border: var(--bw) solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-1);
}

/* ═══ 视觉风格（2026-10-16 恢复配色选项）════════════════════════
 * 四个风格只覆盖**中性色 + 形状令牌**（底色/文字/圆角/线宽/动效/标题字体）。
 * 四个语义色（--user/--success/--danger/--agent）全风格恒定 ——
 * 硬规则2「不许新增第五个语义色」，浅色下沿用 :root[data-theme="light"]
 * 里已有的同族降深值，所以语义色一处定义、处处一致。
 *
 * 选择器刻意用裸 [data-style]（不限定 :root）：设置页的风格卡片
 * 带同名属性，卡片上的 var() 预览因此渲染真值。
 *
 * 级联（与文件头 53–69 行的基础浅/深块共存）：
 *   [data-style]                     该风格·深色 + 形状   (0,1,0)
 *   [data-style][data-theme="light"] 该风格·浅色          (0,2,0)
 *   @media 块                        跟随系统 + OS 浅色时  (0,2,0)
 * 未选风格（<html> 无 data-style）时这些块整体不匹配，界面回到设计稿原色。 */

/* ── 书院气：纸的质感 ─────────────────────────────────────── */
[data-style="shuyuan"] {
  --r-xs: 1px;  --r-sm: 2px;  --r-md: 4px;  --r-lg: 6px;
  --bw: 1px;  --bw-accent: 2px;
  --dur: .22s;  --dur-fast: .12s;  --dur-slow: .35s;  --dur-anim: 1.4s;
  --ease: cubic-bezier(.22, .61, .36, 1);   /* 慢起缓收，像翻纸 */
  /* 衬线只给大字号标题用；SimSun 不再显式列出 —— 它没有像样的屏幕字形，
     小字下最容易糊（Cindy 全站不用衬线）。 */
  --font-title: "Noto Serif SC", "Source Han Serif SC", "Songti SC", serif;

  --bg: #1A1714;          /* 墨夜 */
  --bg-hover: rgba(255, 255, 255, 0.06);
  --surface: #221E1A;
  --surface-2: #2B2621;
  --border: #3A332C;
  --divider: #453D35;
  --scrollbar-hover: #4E453C;
  --text: #E9E2D6;        /* 暖白，像宣纸的暗面 */
  --text-dim: #A99C89;
  --text-faint: #7C7264;
  color-scheme: dark;
}
[data-style="shuyuan"][data-theme="light"] {
  --bg: #F7F4EE;          /* 宣纸 */
  --bg-hover: rgba(0, 0, 0, 0.04);
  --surface: #FFFDF8;     /* 压在纸上的白笺 */
  --surface-2: #F0EBE1;
  --border: #E0D8C8;
  --divider: #D6CCBB;
  --scrollbar-hover: #C4B9A6;
  --text: #1F1B16;        /* 墨 */
  --text-dim: #5C5449;
  --text-faint: #766E63;
  color-scheme: light;
}
@media (prefers-color-scheme: light) {
  [data-style="shuyuan"]:not([data-theme="dark"]) {
    --bg: #F7F4EE;  --bg-hover: rgba(0,0,0,.04);  --surface: #FFFDF8;  --surface-2: #F0EBE1;
    --border: #E0D8C8;  --divider: #D6CCBB;  --scrollbar-hover: #C4B9A6;
    --text: #1F1B16;  --text-dim: #5C5449;  --text-faint: #766E63;
    color-scheme: light;
  }
}

/* ── 精密仪器：面板的硬边 ─────────────────────────────────── */
[data-style="instrument"] {
  --r-xs: 0;  --r-sm: 0;  --r-md: 0;  --r-lg: 0;
  --bw: 1px;  --bw-accent: 2px;
  --dur: .1s;  --dur-fast: .06s;  --dur-slow: .18s;  --dur-anim: .9s;
  --ease: linear;                            /* 干脆，不带情绪 */
  --font-title: var(--font-mono);            /* 标题也用等宽 */

  --bg: #0B0D10;
  --bg-hover: rgba(255, 255, 255, 0.06);
  --surface: #12151A;
  --surface-2: #171B21;
  --border: #232932;
  --divider: #2C333D;
  --scrollbar-hover: #333B47;
  --text: #E6E9EF;
  --text-dim: #8A93A3;
  --text-faint: #6B7385;
  color-scheme: dark;
}
[data-style="instrument"][data-theme="light"] {
  --bg: #F4F6F8;
  --bg-hover: rgba(0, 0, 0, 0.04);
  --surface: #FFFFFF;
  --surface-2: #EDF0F4;
  --border: #D9DFE7;
  --divider: #CDD5DF;
  --scrollbar-hover: #AEB8C6;
  --text: #10141A;
  --text-dim: #4E5765;
  --text-faint: #6E7887;
  color-scheme: light;
}
@media (prefers-color-scheme: light) {
  [data-style="instrument"]:not([data-theme="dark"]) {
    --bg: #F4F6F8;  --bg-hover: rgba(0,0,0,.04);  --surface: #FFFFFF;  --surface-2: #EDF0F4;
    --border: #D9DFE7;  --divider: #CDD5DF;  --scrollbar-hover: #AEB8C6;
    --text: #10141A;  --text-dim: #4E5765;  --text-faint: #6E7887;
    color-scheme: light;
  }
}

/* ── 温润陪伴：柔和的圆 ───────────────────────────────────── */
[data-style="warm"] {
  --r-xs: 6px;  --r-sm: 8px;  --r-md: 12px;  --r-lg: 16px;
  --bw: 1px;  --bw-accent: 3px;
  --dur: .24s;  --dur-fast: .15s;  --dur-slow: .4s;  --dur-anim: 1.6s;
  --ease: ease-out;
  --font-title: var(--font-ui);

  --bg: #1C1916;
  --bg-hover: rgba(255, 255, 255, 0.06);
  --surface: #262220;
  --surface-2: #2E2926;
  --border: #3E3833;
  --divider: #4A433D;
  --scrollbar-hover: #554D46;
  --text: #EFE8E0;
  --text-dim: #B3A79A;
  --text-faint: #877C71;
  color-scheme: dark;
}
[data-style="warm"][data-theme="light"] {
  --bg: #FAF7F2;
  --bg-hover: rgba(0, 0, 0, 0.04);
  --surface: #FFFFFF;
  --surface-2: #F5F0E9;
  --border: #E8E0D5;
  --divider: #DED4C6;
  --scrollbar-hover: #C9BEB0;
  --text: #2C2823;
  --text-dim: #6F675D;
  --text-faint: #807870;
  color-scheme: light;
}
@media (prefers-color-scheme: light) {
  [data-style="warm"]:not([data-theme="dark"]) {
    --bg: #FAF7F2;  --bg-hover: rgba(0,0,0,.04);  --surface: #FFFFFF;  --surface-2: #F5F0E9;
    --border: #E8E0D5;  --divider: #DED4C6;  --scrollbar-hover: #C9BEB0;
    --text: #2C2823;  --text-dim: #6F675D;  --text-faint: #807870;
    color-scheme: light;
  }
}

/* ── 高对比：杂志的版式 ───────────────────────────────────── */
[data-style="contrast"] {
  --r-xs: 0;  --r-sm: 0;  --r-md: 0;  --r-lg: 0;
  --bw: 1px;  --bw-accent: 4px;
  --dur: .14s;  --dur-fast: .08s;  --dur-slow: .22s;  --dur-anim: 1s;
  --ease: cubic-bezier(.4, 0, .2, 1);
  --font-title: var(--font-ui);

  --bg: #000000;
  --bg-hover: rgba(255, 255, 255, 0.08);
  --surface: #0D0D0D;
  --surface-2: #1A1A1A;
  --border: #FFFFFF;      /* 亮线，这是这套的签名 */
  --divider: #E0E0E0;
  --scrollbar-hover: #666666;
  --text: #FFFFFF;
  --text-dim: #B8B8B8;
  --text-faint: #8A8A8A;
  color-scheme: dark;
}
[data-style="contrast"][data-theme="light"] {
  --bg: #FFFFFF;
  --bg-hover: rgba(0, 0, 0, 0.06);
  --surface: #FFFFFF;
  --surface-2: #F2F2F2;
  --border: #0A0A0A;      /* 黑线，不是浅灰 —— 这套的签名 */
  --divider: #0A0A0A;
  --scrollbar-hover: #767676;
  --text: #0A0A0A;
  --text-dim: #4A4A4A;
  --text-faint: #6E6E6E;
  color-scheme: light;
}
@media (prefers-color-scheme: light) {
  [data-style="contrast"]:not([data-theme="dark"]) {
    --bg: #FFFFFF;  --bg-hover: rgba(0,0,0,.06);  --surface: #FFFFFF;  --surface-2: #F2F2F2;
    --border: #0A0A0A;  --divider: #0A0A0A;  --scrollbar-hover: #767676;
    --text: #0A0A0A;  --text-dim: #4A4A4A;  --text-faint: #6E6E6E;
    color-scheme: light;
  }
}
