/* ============================================================
   Design Tokens — 3 层体系：Primitive（不随主题变）→ Semantic（dark/light）→ Component
   ============================================================ */
:root {
  /* === Primitive（颜色原子，不随主题变） === */
  --brand-indigo-50:  #eef2ff;
  --brand-indigo-400: #818cf8;
  --brand-indigo-500: #6366f1;
  --brand-indigo-600: #4f46e5;
  --brand-indigo-700: #4338ca;
  --brand-violet-500: #8b5cf6;
  --brand-fuchsia-500:#d946ef;
  --emerald-400: #34d399;
  --emerald-500: #10b981;
  --amber-400:   #fbbf24;
  --amber-500:   #f59e0b;
  --rose-400:    #fb7185;
  --rose-500:    #ef4444;
  --sky-400:     #38bdf8;
  --sky-500:     #0ea5e9;

  /* === Motion ===
     --ease-out: ease-out-quint, zero overshoot. Default for state transitions and hovers.
     --ease-spring: ease-out-quart, zero overshoot. Distinct curve for entrance moments
                    (drawer open, modal, toast, view-transition) — symmetric decel, no bounce. */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-spring: cubic-bezier(0.25, 1, 0.5, 1);
  --dur-fast: 150ms;
  --dur-base: 250ms;
  --dur-slow: 400ms;

  /* === Radius / Shadow === */
  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 14px;
  --radius-xl: 20px;

  /* Depth system — 6 elevation levels + 6 glow variants.
     Alpha is theme-aware: .dark uses higher alpha (more visible shadow on dark bg),
     .light uses lower alpha (shadow still visible but not muddy).
     Component spec:
       card=sm, button=xs, drawer=lg, modal/toast=xl, popover=2xl */
  --shadow-xs: 0 1px 2px rgba(0,0,0,0.20);
  --shadow-sm: 0 2px 4px rgba(0,0,0,0.24), 0 1px 2px rgba(0,0,0,0.20);
  --shadow-md: 0 4px 8px rgba(0,0,0,0.28), 0 2px 4px rgba(0,0,0,0.20);
  --shadow-lg: 0 8px 16px rgba(0,0,0,0.32), 0 4px 8px rgba(0,0,0,0.22);
  --shadow-xl: 0 16px 32px rgba(0,0,0,0.36), 0 8px 16px rgba(0,0,0,0.24);
  --shadow-2xl: 0 32px 64px rgba(0,0,0,0.40), 0 16px 32px rgba(0,0,0,0.28);
  --shadow-glow: 0 0 24px rgba(99,102,241,0.25);
  --shadow-glow-indigo: 0 0 24px rgba(99,102,241,0.35);
  --shadow-glow-emerald: 0 0 24px rgba(16,185,129,0.35);
  --shadow-glow-rose:    0 0 24px rgba(244,63,94,0.35);
  --shadow-glow-amber:   0 0 24px rgba(245,158,11,0.35);
  --shadow-glow-violet:  0 0 24px rgba(139,92,246,0.35);
  --shadow-glow-sky:     0 0 24px rgba(14,165,233,0.35);

  /* === Semantic — Dark (default) === */
  --bg:           #0b0d14;  /* 带蓝调，非纯黑 */
  /* agent 灵魂色全局变量（气泡/边框用）*/
  --agent-dorians-color: #fbbf24;
  --agent-dorians-border: rgba(251,191,36,0.4);
  --agent-ameng-color: #38bdf8;
  --agent-ameng-border: rgba(56,189,248,0.4);
  --agent-architect-color: #34d399;
  --agent-architect-border: rgba(52,211,153,0.4);
  --bg-gradient:  radial-gradient(at 0% 0%, #14172a 0%, #0b0d14 60%);
  --surface:      #11131c;
  --surface-2:    #161927;
  --surface-3:    #1d2133;
  --elevated:     #161927;
  --hover:        #161927;
  --input:        #0f111a;
  --border:        rgba(255,255,255,0.06);
  --border-2:      rgba(255,255,255,0.12);
  --border-hover:  rgba(99,102,241,0.35);

  --fg:        #f4f4f5;
  --fg-2:      #c7c9d1;
  --fg-3:      #8b8e9c;
  --fg-4:      #5a5d6e;
  --fg-on-brand: #ffffff;

  --brand: var(--brand-indigo-500);
  --brand-2: var(--brand-violet-500);
  --brand-3: var(--brand-fuchsia-500);

  --status-active-bg:    rgba(99,102,241,0.12);
  --status-active-fg:    var(--brand-indigo-400);
  --status-success-bg:   rgba(16,185,129,0.12);
  --status-success-fg:   var(--emerald-400);
  --status-warning-bg:   rgba(245,158,11,0.12);
  --status-warning-fg:   var(--amber-400);
  --status-danger-bg:    rgba(244,67,54,0.14);
  --status-danger-fg:    var(--rose-400);

  --success: var(--emerald-500);
  --warning: var(--amber-500);
  --danger:  var(--rose-500);

  --topbar-bg:        rgba(11,13,20,0.72);
  --topbar-border:    rgba(255,255,255,0.06);
  --sidebar-bg:       rgba(11,13,20,0.92);
  --sidebar-item-active-bg: rgba(99,102,241,0.15);
  --mobile-tabs-bg:   rgba(11,13,20,0.92);
  --overlay-bg:       rgba(15,15,18,0.95);

  /* Backdrop overlays — graduated opacity for modal vs drawer vs command palette */
  --backdrop-modal:   rgba(0,0,0,0.65);
  --backdrop-drawer:  rgba(0,0,0,0.55);

  /* Agent gradient endpoints — used in chat avatars + dot indicators.
     Primary color is *-color; this is the deeper shade for 2-stop gradients. */
  --agent-dorians-grad:   #f59e0b;
  --agent-ameng-grad:     #0ea5e9;
  --agent-architect-grad: #10b981;

  /* Chart palette — categorical, semantic. Each color encodes a status/category. */
  --chart-coding:     #6366f1;
  --chart-building:   #f59e0b;
  --chart-thinking:   #0ea5e9;
  --chart-done:       #10b981;
  --chart-error:      #ef4444;
  --chart-dormant:    #5a5d6e;

  /* Log console — CRT 终端质感（light 主题也保留深色，更像终端） */
  --log-bg:           #07090f;
  --log-text:         #b8baca;
  --log-accent:       var(--brand-indigo-400);
  --log-entry-bg:     rgba(255,255,255,0.02);
  --log-entry-hover:  rgba(255,255,255,0.05);

  /* Avatar ring per status */
  --ring-active:   conic-gradient(from 0deg, #6366f1, #8b5cf6, #d946ef, #6366f1);
  --ring-idle:     linear-gradient(135deg, #10b981, #34d399);
  --ring-dormant:  repeating-linear-gradient(90deg, #5a5d6e 0 4px, transparent 4px 8px);
  --ring-error:    linear-gradient(135deg, #ef4444, #dc2626);
  --ring-offline:  transparent;

  /* === Agent-town office palette (dark default) === */
  --office-panel-bg:         rgba(11,13,20,0.88);
  --office-panel-bg-strong:  rgba(11,13,20,0.96);
  --office-inline-bg:        rgba(15,17,25,0.97);
  --office-modal-bg:         #11131c;
  --office-fg:               #f3f4f6;
  --office-fg-soft:          #d1d5db;
  --office-fg-muted:         #9ca3af;
  --office-fg-faint:         #6b7280;
  --office-gold:             #ffd700;
  --office-gold-soft:        #fbbf24;
  --office-error:            #ef4444;
  --office-error-fg:         #fca5a5;
  --office-success:          #22c55e;
  --office-border:           rgba(255,255,255,0.12);
  --office-border-subtle:    rgba(255,255,255,0.06);
  --office-tint:             rgba(255,255,255,0.04);
  --office-tint-hover:       rgba(255,255,255,0.07);
  --office-tint-active:      rgba(255,255,255,0.08);

  /* === Game-feel panel palette (v5.27 — warm parchment for activity map) === */
  --game-panel-bg:           linear-gradient(160deg, rgba(62,46,28,0.97) 0%, rgba(37,34,25,0.97) 100%);
  --game-panel-bg-strong:    linear-gradient(160deg, rgba(72,54,32,0.98) 0%, rgba(45,40,28,0.98) 100%);
  --game-gold-glow:          0 0 0 2px rgba(255,215,0,0.25), 0 8px 28px rgba(0,0,0,0.55), inset 0 1px 0 rgba(255,255,255,0.08);
  --game-tooltip-bg:         rgba(40,36,28,0.6);
  --game-tooltip-glow:       0 8px 32px rgba(255,215,0,0.35), inset 0 1px 0 rgba(255,255,255,0.08);
}

html.light {
  /* === Semantic — Light（温暖米白 + 多层光晕设计感） === */
  --bg:           #fafaf7;
  --bg-gradient:
    radial-gradient(at 0% 0%, rgba(99,102,241,0.06) 0%, transparent 50%),
    radial-gradient(at 100% 0%, rgba(217,70,239,0.05) 0%, transparent 50%),
    radial-gradient(at 50% 100%, rgba(245,158,11,0.04) 0%, transparent 50%),
    linear-gradient(180deg, #fffdf5 0%, #fafaf7 100%);
  --surface:      #ffffff;
  --surface-2:    #f6f5f0;
  --surface-3:    #efeee7;
  --elevated:     #f6f5f0;
  --hover:        #f6f5f0;
  --input:        #f3f2ec;
  --border:        rgba(15,23,42,0.08);
  --border-2:      rgba(15,23,42,0.14);
  --border-hover:  rgba(99,102,241,0.4);

  --fg:        #0c0e16;
  --fg-2:      #3d4150;
  --fg-3:      #6b6e7c;
  --fg-4:      #9b9eaa;
  --fg-on-brand: #ffffff;

  /* status-fg 在 light 下用更深色保证 WCAG AA 对比度 */
  --status-active-bg:    rgba(79,70,229,0.10);
  --status-active-fg:    #4338ca;
  --status-success-bg:   rgba(5,150,105,0.10);
  --status-success-fg:   #047857;
  --status-warning-bg:   rgba(217,119,6,0.10);
  --status-warning-fg:   #b45309;
  --status-danger-bg:    rgba(220,38,38,0.10);
  --status-danger-fg:    #b91c1c;

  --success: #059669;
  --warning: #d97706;
  --danger:  #dc2626;

  --topbar-bg:        rgba(250,250,247,0.78);
  --topbar-border:    rgba(15,23,42,0.08);
  --sidebar-bg:       rgba(255,255,255,0.92);
  --sidebar-item-active-bg: rgba(99,102,241,0.10);
  --mobile-tabs-bg:   rgba(255,255,255,0.92);
  --overlay-bg:       rgba(255,255,255,0.95);

  /* Log console: light 下用渐变背景 + 深紫文字，符合主题审美 */
  --log-bg:           linear-gradient(135deg, rgba(255,253,245,0.96) 0%, rgba(243,240,250,0.96) 50%, rgba(250,247,243,0.96) 100%);
  --log-text:         #2d3142;
  --log-accent:       #4338ca;
  --log-entry-bg:     rgba(255,255,255,0.55);

  /* Light theme shadows — softer alpha (dark shadows on white = muddy) */
  --shadow-xs: 0 1px 2px rgba(15,23,42,0.04);
  --shadow-sm: 0 2px 4px rgba(15,23,42,0.06), 0 1px 2px rgba(15,23,42,0.04);
  --shadow-md: 0 4px 8px rgba(15,23,42,0.08), 0 2px 4px rgba(15,23,42,0.05);
  --shadow-lg: 0 8px 16px rgba(15,23,42,0.10), 0 4px 8px rgba(15,23,42,0.06);
  --shadow-xl: 0 16px 32px rgba(15,23,42,0.12), 0 8px 16px rgba(15,23,42,0.08);
  --shadow-2xl: 0 32px 64px rgba(15,23,42,0.14), 0 16px 32px rgba(15,23,42,0.10);
  --shadow-glow-indigo: 0 0 24px rgba(99,102,241,0.20);
  --shadow-glow-emerald: 0 0 24px rgba(16,185,129,0.20);
  --shadow-glow-rose:    0 0 24px rgba(244,63,94,0.20);
  --shadow-glow-amber:   0 0 24px rgba(245,158,11,0.22);
  --shadow-glow-violet:  0 0 24px rgba(139,92,246,0.20);
  --shadow-glow-sky:     0 0 24px rgba(14,165,233,0.20);
  --log-entry-hover:  rgba(99,102,241,0.10);

  --shadow-glow: 0 0 24px rgba(99,102,241,0.18);

  /* Agent 灵魂色 — light 主题用更深色保证对比度
     (was hardcoded in JS, now driven by these vars so avatar + log + chart
     share a single source of truth) */
  --agent-dorians-color:   #c2410c;
  --agent-dorians-border:  rgba(194,65,12,0.4);
  --agent-ameng-color:     #0369a1;
  --agent-ameng-border:    rgba(3,105,161,0.4);
  --agent-architect-color: #047857;
  --agent-architect-border:rgba(4,120,87,0.4);

  /* Light theme agent gradient endpoints — deeper for contrast on cream */
  --agent-dorians-grad:   #9a3412;
  --agent-ameng-grad:     #075985;
  --agent-architect-grad: #065f46;

  /* Light theme backdrops — warm gray instead of pure black for less muddy feel */
  --backdrop-modal:   rgba(15,23,42,0.50);
  --backdrop-drawer:  rgba(15,23,42,0.40);

  /* === Agent-town office palette (light overrides) ===
     v5.26.8: agent-town used to hardcode dark-only colors; now tokenized
     so the activity map is readable when dashboard flips to light theme. */
  --office-panel-bg:         rgba(255,255,255,0.92);
  --office-panel-bg-strong:  rgba(255,255,255,0.98);
  --office-inline-bg:        rgba(250,250,247,0.97);
  --office-modal-bg:         #ffffff;
  --office-fg:               #0c0e16;
  --office-fg-soft:          #3d4150;
  --office-fg-muted:         #6b6e7c;
  --office-fg-faint:         #9b9eaa;
  --office-gold:             #b45309;  /* amber-700 — readable on light */
  --office-gold-soft:        #d97706;
  --office-error:            #dc2626;
  --office-error-fg:         #b91c1c;
  --office-success:          #16a34a;
  --office-border:           rgba(15,23,42,0.14);
  --office-border-subtle:    rgba(15,23,42,0.08);
  --office-tint:             rgba(15,23,42,0.04);
  --office-tint-hover:       rgba(15,23,42,0.07);
  --office-tint-active:      rgba(15,23,42,0.08);

  /* === Game-feel panel palette — light overrides (warm cream parchment) === */
  --game-panel-bg:           linear-gradient(160deg, rgba(255,250,240,0.97) 0%, rgba(245,234,210,0.97) 100%);
  --game-panel-bg-strong:    linear-gradient(160deg, rgba(255,252,242,0.98) 0%, rgba(248,238,218,0.98) 100%);
  --game-gold-glow:          0 0 0 2px rgba(180,83,9,0.20), 0 8px 28px rgba(15,23,42,0.18), inset 0 1px 0 rgba(255,255,255,0.6);
  --game-tooltip-bg:         rgba(255,250,240,0.75);
  --game-tooltip-glow:       0 8px 32px rgba(180,83,9,0.18), inset 0 1px 0 rgba(255,255,255,0.5);
}

/* 触屏无 tap 高亮（保留），但不做全局 transition（性能杀手） */
* { -webkit-tap-highlight-color: transparent; box-sizing: border-box; }

/* === iOS Safari 防溢出全局规则（关键修复） === */
/* 所有 image/svg/video/canvas 强制不超出父容器（之前缺失的关键修复） */
img, svg:not([width][height]), video, canvas, iframe {
  max-width: 100%;
  height: auto;
}

/* View Transition API: 主题切换 — circular reveal from click point */
::view-transition-old(root) {
  animation: 350ms var(--ease-out) both fade-out;
}
::view-transition-new(root) {
  animation: 450ms var(--ease-spring) both circle-reveal;
}
@keyframes fade-out {
  to { opacity: 0; }
}
@keyframes circle-reveal {
  from {
    clip-path: circle(0% at var(--reveal-x, 50%) var(--reveal-y, 50%));
  }
  to {
    clip-path: circle(150% at var(--reveal-x, 50%) var(--reveal-y, 50%));
  }
}

/* Fallback for browsers without view-transition */
@media (prefers-reduced-motion: no-preference) {
  html.theme-transitioning, html.theme-transitioning * {
    transition: background-color 300ms var(--ease-out),
                color 300ms var(--ease-out),
                border-color 300ms var(--ease-out) !important;
  }
}

/* === Startup loading screen === */
#boot-loader {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg, #0b0d14);
  transition: opacity 400ms var(--ease-out);
}
#boot-loader.hide {
  opacity: 0;
  pointer-events: none;
}
.boot-mark {
  width: 56px;
  height: 56px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 16px;
  background: linear-gradient(135deg, var(--brand-indigo-500, #6366f1), var(--brand-indigo-400, #818cf8));
  animation: boot-pulse 1.4s var(--ease-spring) infinite;
}
.boot-mark svg { animation: boot-spin 2s linear infinite; }
@keyframes boot-pulse {
  0%, 100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(99,102,241,0.4); }
  50% { transform: scale(1.08); box-shadow: 0 0 0 16px rgba(99,102,241,0); }
}
@keyframes boot-spin {
  to { transform: rotate(360deg); }
}
.boot-progress {
  position: absolute;
  bottom: 30%;
  left: 50%;
  transform: translateX(-50%);
  width: 140px;
  height: 2px;
  background: var(--surface-3, #27272a);
  border-radius: 1px;
  overflow: hidden;
}
.boot-progress::after {
  content: '';
  display: block;
  width: 40%;
  height: 100%;
  background: var(--brand-indigo-400, #818cf8);
  animation: boot-progress-slide 1.2s var(--ease-out) infinite;
}
@keyframes boot-progress-slide {
  0% { transform: translateX(-100%); }
  100% { transform: translateX(350%); }
}

html, body {
  background: var(--bg);
  background-image: var(--bg-gradient);
  background-attachment: fixed;
  color: var(--fg);
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Microsoft YaHei', sans-serif;
  font-feature-settings: 'cv02','cv03','cv04','cv11','ss01';
  letter-spacing: -0.011em;
  -webkit-font-smoothing: antialiased;
  margin: 0; min-height: 100dvh;
  /* iOS Safari: 严格防止横向溢出 + "放大页面"现象 */
  width: 100%;
  max-width: 100%;
  overflow-x: hidden;
  overflow-x: clip;  /* clip 更现代，iOS Safari 16+ 不会忽略 */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  transition: background-color var(--dur-slow) var(--ease-out), color var(--dur-base) var(--ease-out);
}

/* === iOS Safari 专用强化 === */
@supports (-webkit-touch-callout: none) {
  html, body {
    width: 100% !important;
    max-width: 100% !important;
    overflow-x: hidden !important;
    position: relative;
  }
  /* iOS Safari: fixed 元素强制不超过 viewport */
  .mobile-tabs, .topbar, .sidebar, .drawer, .drawer-backdrop, .truncate-modal-backdrop {
    max-width: 100% !important;
  }
  /* iOS Safari: 防止 absolute 装饰元素溢出导致 viewport 放大 */
  .absolute.pointer-events-none { max-width: 100%; }
}
body {
  font-feature-settings: 'cv02','cv03','cv04','cv11'; letter-spacing: -0.01em;
  /* iOS Safari safe-area（刘海屏）*/
  padding-left: env(safe-area-inset-left, 0px);
  padding-right: env(safe-area-inset-right, 0px);
}

/* Scrollbars */
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.08); border-radius: 4px; }
::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.16); }

[x-cloak] { display: none !important; }

/* 加载页动画 */
@keyframes loading-pulse { 0%,100% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.1); opacity: 0.85; } }
@keyframes loading-spin { to { transform: rotate(360deg); } }
@keyframes loading-dot { 0%,100% { transform: translateY(0); opacity: 0.3; } 50% { transform: translateY(-6px); opacity: 1; } }

/* === 游戏化日志终端 — CRT 质感 + 类型化动画 + typewriter === */
.log-console {
  background: var(--log-bg);
  color: var(--log-text);
  font-family: 'JetBrains Mono', 'Fira Code', 'SF Mono', Menlo, monospace;
  border-radius: 0 0 var(--radius-lg) var(--radius-lg);
  position: relative;
  overflow: hidden;
  isolation: isolate;
}
/* CRT vignette: 四周变暗（保留，柔和） */
.log-console::before {
  content: ''; position: absolute; inset: 0; pointer-events: none; z-index: 4;
  background: radial-gradient(ellipse at center, transparent 55%, rgba(0,0,0,0.4) 100%);
}
html.light .log-console::before {
  background: radial-gradient(ellipse at center, transparent 65%, rgba(15,23,42,0.08) 100%);
}
/* 去掉横向 scanline（用户反馈难看） */
.log-console::after { content: none !important; display: none !important; }
html.light .log-console::after { content: none !important; display: none !important; }
/* 动态光带（柔和扫描，替代 scanline，更优雅） */
.log-scanbar {
  position: absolute; left: 0; right: 0; height: 60px; pointer-events: none; z-index: 6;
  background: linear-gradient(180deg,
    transparent 0%,
    rgba(129,140,248,0.06) 50%,
    transparent 100%);
  animation: log-scanbar-move 5s linear infinite;
  opacity: 0.7;
}
html.light .log-scanbar {
  background: linear-gradient(180deg,
    transparent 0%,
    rgba(99,102,241,0.05) 50%,
    transparent 100%);
  opacity: 0.5;
}
@keyframes log-scanbar-move {
  0%   { transform: translateY(-60px); }
  100% { transform: translateY(700px); }
}

/* 单条日志 — 终端风 + 3D 翻转进入 + hover 浮起 */
.log-entry {
  position: relative;
  padding: 5px 12px 5px 22px;
  border-left: 2px solid var(--log-entry-color, var(--fg-4));
  margin-bottom: 2px;
  background: var(--log-entry-bg);
  animation: log-enter-3d 0.55s var(--ease-spring) backwards;
  transition: background 250ms var(--ease-out),
              transform 250ms var(--ease-spring),
              box-shadow 250ms var(--ease-out);
  cursor: default;
  transform-origin: left center;
  border-radius: 0 6px 6px 0;
}
/* 3D Y 轴翻转进入（perspective） */
@keyframes log-enter-3d {
  0%   { opacity: 0; transform: perspective(800px) rotateY(-25deg) translateX(-12px); filter: blur(3px); }
  60%  { opacity: 1; transform: perspective(800px) rotateY(4deg) translateX(2px); filter: blur(0); }
  100% { opacity: 1; transform: perspective(800px) rotateY(0) translateX(0); filter: blur(0); }
}
/* Hover：卡片浮起 + 强 glow */
.log-entry:hover {
  background: var(--log-entry-hover);
  transform: translateX(4px) translateY(-1px) scale(1.005);
  box-shadow:
    0 4px 16px rgba(99,102,241,0.18),
    inset 0 0 0 1px rgba(99,102,241,0.2);
}
.log-entry:hover .log-entry-text {
  filter: brightness(1.15);
}

/* 类型化背景渐变（success 绿 / error 红 / warn 琥珀 微妙背景） */
.log-entry[data-level="success"] {
  background: linear-gradient(90deg, rgba(16,185,129,0.08) 0%, var(--log-entry-bg) 30%);
}
.log-entry[data-level="error"] {
  background: linear-gradient(90deg, rgba(239,68,68,0.10) 0%, var(--log-entry-bg) 30%);
}
.log-entry[data-level="warn"] {
  background: linear-gradient(90deg, rgba(245,158,11,0.08) 0%, var(--log-entry-bg) 30%);
}
.log-entry[data-level="info"] {
  background: linear-gradient(90deg, rgba(99,102,241,0.06) 0%, var(--log-entry-bg) 30%);
}
html.light .log-entry[data-level="success"] {
  background: linear-gradient(90deg, rgba(5,150,105,0.10) 0%, var(--log-entry-bg) 30%);
}
html.light .log-entry[data-level="error"] {
  background: linear-gradient(90deg, rgba(220,38,38,0.10) 0%, var(--log-entry-bg) 30%);
}
html.light .log-entry[data-level="warn"] {
  background: linear-gradient(90deg, rgba(217,119,6,0.10) 0%, var(--log-entry-bg) 30%);
}
html.light .log-entry[data-level="info"] {
  background: linear-gradient(90deg, rgba(99,102,241,0.08) 0%, var(--log-entry-bg) 30%);
}
/* 终端 prompt 符号 ▸ */
.log-entry::before {
  content: '▸';
  position: absolute;
  left: 7px; top: 5px;
  color: var(--log-entry-color, var(--fg-4));
  opacity: 0.85;
  font-weight: 700;
  font-size: 11px;
  font-family: 'JetBrains Mono', 'SF Mono', Menlo, monospace;
  text-shadow: 0 0 6px currentColor;
  animation: prompt-pulse 2.5s ease-in-out infinite;
}
@keyframes prompt-pulse {
  0%, 100% { opacity: 0.7; text-shadow: 0 0 4px currentColor; }
  50%      { opacity: 1; text-shadow: 0 0 10px currentColor, 0 0 16px currentColor; }
}
.log-entry:hover {
  background: var(--log-entry-hover);
  transform: translateX(2px);
}
.log-entry:hover::before { opacity: 1; }
.log-entry:hover .log-entry-text {
  text-shadow: 0 0 8px rgba(129,140,248,0.55);
}

/* 类型化颜色 + 左 border */
.log-entry[data-level="error"]   { --log-entry-color: var(--status-danger-fg); }
.log-entry[data-level="success"] { --log-entry-color: var(--status-success-fg); }
.log-entry[data-level="warn"]    { --log-entry-color: var(--status-warning-fg); }
.log-entry[data-level="info"]    { --log-entry-color: var(--brand-indigo-400); }

/* 差异化进入动画 */
@keyframes log-enter {
  0%   { opacity: 0; transform: translateX(-16px); filter: blur(2px); }
  100% { opacity: 1; transform: translateX(0);     filter: blur(0); }
}
.log-entry[data-level="error"] { animation: log-enter-error 0.6s var(--ease-out) backwards; }
@keyframes log-enter-error {
  0%   { opacity: 0; transform: translateX(-22px); filter: blur(4px); }
  20%  { opacity: 1; transform: translateX(3px); background: rgba(239,68,68,0.18); }
  100% { opacity: 1; transform: translateX(0); }
}
.log-entry[data-level="success"] { animation: log-enter-success 0.7s var(--ease-out) backwards; }
@keyframes log-enter-success {
  0%   { opacity: 0; transform: scale(0.97); }
  50%  { text-shadow: 0 0 14px rgba(52,211,153,0.7); }
  100% { opacity: 1; transform: scale(1); text-shadow: none; }
}

/* Glitch 故障效果（error log 文本进入时 RGB 分离） */
.log-entry[data-level="error"] .log-entry-text {
  animation: log-glitch 0.55s steps(5) 0.05s backwards;
}
@keyframes log-glitch {
  0%   { text-shadow: 2px 0 #ef4444, -2px 0 #22d3ee; transform: translateX(0); filter: hue-rotate(0); }
  20%  { text-shadow: -2px 0 #ef4444, 2px 0 #22d3ee; transform: translateX(2px); filter: hue-rotate(15deg); }
  40%  { text-shadow: 2px 0 #ef4444, -2px 0 #22d3ee; transform: translateX(-2px); filter: hue-rotate(-15deg); }
  60%  { text-shadow: -1px 0 #ef4444, 1px 0 #22d3ee; transform: translateX(1px); filter: hue-rotate(5deg); }
  100% { text-shadow: 0 0 transparent; transform: translateX(0); filter: none; }
}

/* JS typewriter 拆字符：每个字符独立 span，emerge + wave + glow（明显加强） */
.log-char {
  display: inline-block;
  animation: char-emerge 0.4s var(--ease-spring) backwards,
             char-wave 2.2s ease-in-out infinite calc(var(--ci, 0) * 0.06s),
             char-glow-pulse 2.5s ease-in-out infinite calc(var(--ci, 0) * 0.1s);
}
@keyframes char-emerge {
  from { opacity: 0; transform: translateY(8px) scale(0.5); filter: blur(4px); }
  to   { opacity: 1; transform: translateY(0) scale(1); filter: blur(0); }
}
@keyframes char-wave {
  0%, 100% { transform: translateY(0) rotate(0deg); }
  25%      { transform: translateY(-2px) rotate(-1deg); }
  50%      { transform: translateY(-3px) rotate(0deg); }
  75%      { transform: translateY(-2px) rotate(1deg); }
}
@keyframes char-glow-pulse {
  0%, 100% { text-shadow: 0 0 0 transparent; filter: brightness(1); }
  30%      { text-shadow: 0 0 8px var(--log-accent), 0 0 16px var(--log-accent); filter: brightness(1.2); }
  60%      { text-shadow: 0 0 4px var(--log-accent); filter: brightness(1.1); }
}

/* 类型化周期内容光效（所有 log 持续动） */
.log-entry[data-level="success"] .log-entry-text,
.log-entry[data-level="success"] .log-char {
  animation-timing-function: ease-in-out;
}
.log-entry[data-level="success"] .log-char {
  animation: char-emerge 0.32s var(--ease-spring) backwards,
             char-wave-success 2.8s ease-in-out infinite calc(var(--ci, 0) * 0.05s);
}
@keyframes char-wave-success {
  0%, 100% { transform: translateY(0); text-shadow: 0 0 0 transparent; color: inherit; }
  50%      { transform: translateY(-1.5px); text-shadow: 0 0 8px var(--status-success-fg); color: var(--status-success-fg); }
}
.log-entry[data-level="error"] .log-char {
  animation: char-emerge 0.32s var(--ease-spring) backwards,
             char-wave-error 2s ease-in-out infinite calc(var(--ci, 0) * 0.06s);
}
@keyframes char-wave-error {
  0%, 100% { transform: translateY(0) translateX(0); text-shadow: 0 0 0 transparent; }
  30%      { transform: translateY(-1px) translateX(-0.5px); text-shadow: 1px 0 #ef4444, -1px 0 #22d3ee; }
  60%      { transform: translateY(-2px) translateX(0.5px); text-shadow: 0 0 8px var(--status-danger-fg); }
}
.log-entry[data-level="warn"] .log-char {
  animation: char-emerge 0.32s var(--ease-spring) backwards,
             char-wave-warn 3s ease-in-out infinite calc(var(--ci, 0) * 0.05s);
}
@keyframes char-wave-warn {
  0%, 100% { transform: translateY(0); text-shadow: 0 0 0 transparent; }
  50%      { transform: translateY(-1.2px); text-shadow: 0 0 7px var(--status-warning-fg); }
}

/* 非最新 log：内容周期性 glow（不拆字符，性能友好） */
.log-entry:not(.is-latest):not(.typing) .log-entry-text {
  animation: log-content-pulse 4s ease-in-out infinite;
}
.log-entry[data-level="success"]:not(.is-latest):not(.typing) .log-entry-text {
  animation: log-pulse-success 4s ease-in-out infinite;
}
@keyframes log-pulse-success {
  0%, 100% { text-shadow: 0 0 0 transparent; }
  50%      { text-shadow: 0 0 6px rgba(52,211,153,0.4); }
}
.log-entry[data-level="error"]:not(.is-latest):not(.typing) .log-entry-text {
  animation: log-pulse-error 3s ease-in-out infinite;
}
@keyframes log-pulse-error {
  0%, 90%, 100% { text-shadow: 0 0 0 transparent; }
  92%, 94%      { text-shadow: 1px 0 #ef4444, -1px 0 #22d3ee; }
}
.log-entry[data-level="warn"]:not(.is-latest):not(.typing) .log-entry-text {
  animation: log-pulse-warn 3.5s ease-in-out infinite;
}
@keyframes log-pulse-warn {
  0%, 100% { text-shadow: 0 0 0 transparent; }
  50%      { text-shadow: 0 0 5px rgba(245,158,11,0.4); }
}
@keyframes log-content-pulse {
  0%, 100% { text-shadow: 0 0 0 transparent; }
  50%      { text-shadow: 0 0 4px rgba(129,140,248,0.3); }
}

/* JS typewriter 进行中（class .typing 由 _typewriteEntry 添加） */
.log-entry.typing::before {
  animation: prompt-flash 0.4s ease-in-out infinite;
}
@keyframes prompt-flash {
  0%,100% { opacity: 0.55; }
  50%     { opacity: 1; text-shadow: 0 0 6px var(--log-accent); }
}
.log-entry.typing .log-entry-text {
  text-shadow: 0 0 8px var(--log-accent);
}
.log-entry.typing::after {
  content: '▍';
  position: absolute;
  right: 8px; top: 4px;
  color: var(--log-accent);
  font-size: 11px;
  animation: log-cursor-blink 0.6s steps(2) infinite;
  text-shadow: 0 0 6px var(--log-accent);
}

/* === 语法高亮 token（typewriter 完成后多色显示）=== */
.log-token-url {
  color: var(--brand-indigo-400);
  text-decoration: underline dotted;
  text-decoration-color: rgba(99,102,241,0.5);
  text-underline-offset: 2px;
  transition: text-decoration-color 200ms;
}
.log-token-url:hover { text-decoration-color: var(--brand-indigo-400); }

.log-token-path {
  color: var(--brand-violet-500);
  font-style: italic;
  opacity: 0.9;
}

.log-token-num {
  color: var(--amber-400);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
}

.log-token-tool {
  color: #c4b5fd;
  background: rgba(139,92,246,0.12);
  border: 1px solid rgba(139,92,246,0.25);
  padding: 1px 5px;
  border-radius: 4px;
  font-size: 0.92em;
  display: inline-block;
  line-height: 1.2;
}

.log-token-tag {
  color: #fbbf24;
  background: rgba(251,191,36,0.10);
  border: 1px solid rgba(251,191,36,0.25);
  padding: 1px 6px;
  border-radius: 4px;
  font-size: 0.88em;
  font-weight: 600;
  letter-spacing: 0.02em;
}

.log-token-status { font-weight: 700; transition: all 200ms; }
.log-token-status[data-word*="成"],
.log-token-status[data-word*="完"],
.log-token-status[data-word="done"],
.log-token-status[data-word="success"] {
  color: var(--status-success-fg);
  text-shadow: 0 0 6px rgba(52,211,153,0.4);
}
.log-token-status[data-word*="败"],
.log-token-status[data-word*="错"],
.log-token-status[data-word="error"],
.log-token-status[data-word="failed"],
.log-token-status[data-word="fail"] {
  color: var(--status-danger-fg);
  text-shadow: 0 0 6px rgba(248,113,113,0.4);
}
.log-token-status[data-word*="警"],
.log-token-status[data-word="warn"],
.log-token-status[data-word="warning"] {
  color: var(--status-warning-fg);
  text-shadow: 0 0 6px rgba(251,191,36,0.4);
}
.log-token-status[data-word*="在"],
.log-token-status[data-word="running"] {
  color: var(--status-success-fg);
  text-shadow: 0 0 6px rgba(52,211,153,0.3);
}
.log-token-status[data-word*="离"],
.log-token-status[data-word*="休"],
.log-token-status[data-word*="空"],
.log-token-status[data-word="pending"] {
  color: var(--fg-4);
  font-weight: 500;
}
.log-token-status[data-word*="正"],
.log-token-status[data-word*="运"] {
  color: var(--brand-indigo-400);
  text-shadow: 0 0 6px rgba(129,140,248,0.4);
}

/* light 主题 token 颜色更深保证对比度 */
html.light .log-token-url { color: #4338ca; }
html.light .log-token-path { color: #6d28d9; opacity: 1; }
html.light .log-token-num { color: #b45309; }
html.light .log-token-tool {
  color: #6d28d9;
  background: rgba(139,92,246,0.10);
  border-color: rgba(139,92,246,0.25);
}
html.light .log-token-tag {
  color: #b45309;
  background: rgba(251,191,36,0.15);
  border-color: rgba(251,191,36,0.35);
}
html.light .log-token-status { text-shadow: none !important; }
html.light .log-token-status[data-word*="成"],
html.light .log-token-status[data-word*="完"],
html.light .log-token-status[data-word="done"],
html.light .log-token-status[data-word="success"] { color: #047857; }
html.light .log-token-status[data-word*="败"],
html.light .log-token-status[data-word*="错"],
html.light .log-token-status[data-word="error"],
html.light .log-token-status[data-word="failed"],
html.light .log-token-status[data-word="fail"] { color: #b91c1c; }
html.light .log-token-status[data-word*="警"],
html.light .log-token-status[data-word="warn"],
html.light .log-token-status[data-word="warning"] { color: #b45309; }
html.light .log-token-status[data-word*="在"],
html.light .log-token-status[data-word="running"] { color: #047857; }
html.light .log-token-status[data-word*="正"],
html.light .log-token-status[data-word*="运"] { color: #4338ca; }

/* === 新增 5 类 token（v3.8）=== */

/* agent 名（灵魂色 per agent）— driven by :root / :root.light CSS vars */
.log-token-agent { font-weight: 700; }
.log-token-agent[data-agent="dorians"]   { color: var(--agent-dorians-color);   text-shadow: 0 0 6px var(--agent-dorians-border); }
.log-token-agent[data-agent="ameng"]     { color: var(--agent-ameng-color);     text-shadow: 0 0 6px var(--agent-ameng-border); }
.log-token-agent[data-agent="architect"] { color: var(--agent-architect-color); text-shadow: 0 0 6px var(--agent-architect-border); }

/* 容器名（hermes-xxx 浅蓝）*/
.log-token-container {
  color: #7dd3fc;
  background: rgba(56,189,248,0.10);
  padding: 0 4px;
  border-radius: 3px;
  font-family: ui-monospace, monospace;
  font-size: 0.95em;
}

/* 错误关键字（红色加粗 + 红色 glow）*/
.log-token-error-kw {
  color: #fca5a5;
  font-weight: 700;
  text-shadow: 0 0 8px rgba(248,113,113,0.5);
}

/* 时间相对词（sky 色 + 弱 glow）*/
.log-token-time-rel {
  color: #60a5fa;
  font-style: italic;
  opacity: 0.95;
}

/* 命令行 flag（紫色斜体 chip）*/
.log-token-flag {
  color: #c4b5fd;
  background: rgba(139,92,246,0.10);
  padding: 1px 5px;
  border-radius: 3px;
  font-style: italic;
  font-size: 0.92em;
}

/* @mention 或 #channel（琥珀加粗）*/
.log-token-mention {
  color: #fbbf24;
  font-weight: 600;
  background: rgba(251,191,36,0.10);
  padding: 1px 4px;
  border-radius: 3px;
}

/* 引用 'xxx' 或 "xxx"（绿色斜体）*/
.log-token-quote {
  color: #86efac;
  font-style: italic;
  opacity: 0.95;
}

/* light 主题新增 token */
html.light .log-token-agent { text-shadow: none !important; }
html.light .log-token-agent[data-agent="dorians"]   { color: #c2410c; }
html.light .log-token-agent[data-agent="ameng"]     { color: #0369a1; }
html.light .log-token-agent[data-agent="architect"] { color: #047857; }
html.light .log-token-container {
  color: #0369a1;
  background: rgba(56,189,248,0.15);
}
html.light .log-token-error-kw {
  color: #b91c1c;
  text-shadow: none;
}
html.light .log-token-time-rel { color: #1d4ed8; }
html.light .log-token-flag {
  color: #6d28d9;
  background: rgba(139,92,246,0.12);
}
html.light .log-token-mention {
  color: #b45309;
  background: rgba(251,191,36,0.18);
}
html.light .log-token-quote { color: #047857; }
@keyframes log-cursor-blink { 50% { opacity: 0; } }

/* === 最新一条 log 文字动画（明显加强 + 持续 + 创意光带 + 游戏感）=== */
/* CSS-only 不依赖 JS typewriter，所有浏览器都能看到 */
.log-entry.is-latest:not(.typing) .log-entry-text {
  background: linear-gradient(90deg,
    var(--fg-2) 0%, var(--fg-2) 35%,
    var(--log-accent) 48%, var(--log-accent) 52%,
    var(--fg-2) 65%, var(--fg-2) 100%);
  background-size: 250% 100%;
  background-position: 250% 0;
  background-clip: text;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  color: var(--fg-2);
  animation:
    log-shine-sweep 3s linear infinite,
    log-text-position-wave 2.8s ease-in-out infinite,
    log-text-glow-pulse 2s ease-in-out infinite;
}
/* 最新一条 log 外发光呼吸（游戏感）*/
.log-entry.is-latest:not(.typing) {
  animation: log-latest-breath 3s ease-in-out infinite;
}
@keyframes log-latest-breath {
  0%, 100% { box-shadow: 0 0 0 0 transparent; }
  50%      { box-shadow: 0 0 12px 0 rgba(129,140,248,0.15); }
}

/* === 类型化持续字符效果（游戏感核心）=== */
/* success: 翠绿周期脉冲 */
.log-entry[data-level="success"]:not(.typing) .log-char {
  animation: char-emerge 0.4s var(--ease-spring) backwards,
             char-wave-success 2.8s ease-in-out infinite calc(var(--ci, 0) * 0.06s),
             char-game-success 4s ease-in-out infinite calc(var(--ci, 0) * 0.08s);
}
@keyframes char-game-success {
  0%, 100% { filter: brightness(1); }
  50%      { filter: brightness(1.2) drop-shadow(0 0 3px rgba(52,211,153,0.6)); }
}
/* error: 红色周期闪烁 + 随机微抖动 */
.log-entry[data-level="error"]:not(.typing) .log-char {
  animation: char-emerge 0.4s var(--ease-spring) backwards,
             char-wave-error 2s ease-in-out infinite calc(var(--ci, 0) * 0.06s),
             char-game-error 3s steps(2) infinite calc(var(--ci, 0) * 0.1s);
}
@keyframes char-game-error {
  0%, 90%, 100% { transform: translateX(0); filter: brightness(1); }
  92%           { transform: translateX(-0.5px); filter: brightness(1.3) drop-shadow(1px 0 #ef4444) drop-shadow(-1px 0 #22d3ee); }
  94%           { transform: translateX(0.5px); filter: brightness(1.2); }
  96%           { transform: translateX(0); filter: brightness(1); }
}
/* warn: 琥珀周期脉冲 */
.log-entry[data-level="warn"]:not(.typing) .log-char {
  animation: char-emerge 0.4s var(--ease-spring) backwards,
             char-wave-warn 3s ease-in-out infinite calc(var(--ci, 0) * 0.05s),
             char-game-warn 3.5s ease-in-out infinite calc(var(--ci, 0) * 0.07s);
}
@keyframes char-game-warn {
  0%, 100% { filter: brightness(1); }
  50%      { filter: brightness(1.15) drop-shadow(0 0 3px rgba(251,191,36,0.5)); }
}
/* info: indigo 流光 */
.log-entry[data-level="info"]:not(.typing) .log-char {
  animation: char-emerge 0.4s var(--ease-spring) backwards,
             char-wave 2.6s ease-in-out infinite calc(var(--ci, 0) * 0.06s),
             char-game-info 4s ease-in-out infinite calc(var(--ci, 0) * 0.05s);
}
@keyframes char-game-info {
  0%, 100% { filter: brightness(1); }
  30%      { filter: brightness(1.15) drop-shadow(0 0 4px rgba(129,140,248,0.5)); }
  60%      { filter: brightness(1.05); }
}

/* === CRT 闪烁（微妙 brightness 变化，老显示器质感）=== */
.log-console {
  animation: crt-flicker 8s linear infinite;
}
@keyframes crt-flicker {
  0%, 96%, 100% { filter: brightness(1); }
  97%           { filter: brightness(0.97); }
  98%           { filter: brightness(1.02); }
  99%           { filter: brightness(0.98); }
}
/* 扫描光带从左到右 */
@keyframes log-shine-sweep {
  0%   { background-position: 250% 0; }
  100% { background-position: -150% 0; }
}
/* 微小上下浮动 */
@keyframes log-text-position-wave {
  0%, 100% { transform: translateY(0); }
  25%      { transform: translateY(-1px); }
  50%      { transform: translateY(0.5px); }
  75%      { transform: translateY(-0.5px); }
}
/* glow 脉冲 */
@keyframes log-text-glow-pulse {
  0%, 100% { filter: drop-shadow(0 0 0 transparent); }
  50%      { filter: drop-shadow(0 0 4px var(--log-accent)); }
}

/* 历史 log（非最新）：更柔和的周期 glow */
.log-entry:not(.is-latest) .log-entry-text {
  animation: log-history-glow 4s ease-in-out infinite;
}
@keyframes log-history-glow {
  0%, 100% { text-shadow: 0 0 0 transparent; }
  50%      { text-shadow: 0 0 4px var(--log-accent); }
}

/* 时间戳：等宽 + 暗色，hover 亮起 */
.log-entry-time {
  color: var(--fg-4);
  margin-right: 8px;
  transition: color 200ms;
}
.log-entry:hover .log-entry-time { color: var(--fg-2); }

/* agent 名字：彩色 + 较强 glow */
.log-entry-agent {
  font-weight: 700;
  color: var(--log-entry-color, var(--fg-3));
  margin-right: 6px;
  text-shadow: 0 0 6px currentColor, 0 0 12px currentColor;
  letter-spacing: 0.02em;
}

/* 等待状态呼吸点 */
.log-waiting-dots { display: inline-flex; gap: 5px; margin-bottom: 10px; }
.log-waiting-dots span {
  display: inline-block; width: 6px; height: 6px; border-radius: 50%;
  background: var(--log-accent);
  animation: log-dot-breath 1.4s ease-in-out infinite;
}
.log-waiting-dots span:nth-child(2) { animation-delay: 0.2s; }
.log-waiting-dots span:nth-child(3) { animation-delay: 0.4s; }
@keyframes log-dot-breath {
  0%, 100% { transform: scale(0.7); opacity: 0.4; }
  50%      { transform: scale(1.2); opacity: 1; }
}

/* iOS Safari 触摸滑动修复 */
.drawer, .sheet, [class*="overflow-y-auto"], [class*="overflow-auto"], .tab-content, pre {
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  touch-action: pan-y;
}
.drawer {
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  touch-action: pan-y pan-x;
}

/* Glass card — depth system: md at rest (dark needs stronger shadow to read on near-black bg),
   lg on hover, xl on interactive hover. Inset top highlight simulates layered glass
   (Linear/Vercel-style — 1px lighter line at top edge catches ambient light). */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  position: relative;
  max-width: 100%;
  box-shadow: var(--shadow-md), inset 0 1px 0 rgba(255,255,255,0.04);
  transition: transform var(--dur-base) var(--ease-out), border-color var(--dur-base) var(--ease-out), box-shadow var(--dur-base) var(--ease-out);
}
html.dark .card {
  background: linear-gradient(180deg, rgba(255,255,255,0.05), rgba(255,255,255,0.01)), var(--surface);
  box-shadow: var(--shadow-xl), inset 0 1px 0 rgba(255,255,255,0.08), 0 0 0 1px rgba(255,255,255,0.02);
}
html.light .card {
  box-shadow: var(--shadow-sm), inset 0 1px 0 rgba(255,255,255,0.6);
}
/* F3 所有 card 都有 hover lift（之前只有 .card-interactive）*/
.card:hover {
  border-color: var(--border-2);
  transform: translateY(-2px);
  box-shadow: var(--shadow-lg), inset 0 1px 0 rgba(255,255,255,0.06);
}
html.dark .card:hover {
  box-shadow: var(--shadow-2xl), inset 0 1px 0 rgba(255,255,255,0.10), 0 0 0 1px rgba(99,102,241,0.08);
}
.card-interactive { cursor: pointer; }
.card-interactive:hover {
  transform: translateY(-3px);
  border-color: var(--border-hover);
  box-shadow: var(--shadow-xl), 0 0 0 1px rgba(99,102,241,0.25), inset 0 1px 0 rgba(255,255,255,0.08);
}

/* F3 Sparkline 迷你趋势图（SVG path）*/

/* CSS-only focus tooltip（iOS 100% 兼容，不需要 JS）*/
.info-tooltip-wrap { position: relative; outline: none; }
.info-tooltip {
  display: none;
  position: absolute;
  left: 0; right: 0;
  top: calc(100% + 4px);
  z-index: 100;
  padding: 8px 12px;
  border-radius: 10px;
  font-size: 11px;
  font-family: ui-monospace, 'SF Mono', Menlo, monospace;
  line-height: 1.5;
  background: var(--surface-3);
  border: 1px solid var(--border-hover);
  color: var(--fg);
  box-shadow: var(--shadow-xl);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  white-space: normal;
  word-break: break-all;
  animation: tooltip-in 150ms var(--ease-out);
}
@keyframes tooltip-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* HTML5 <details> tooltip（最可靠，iOS 100% 兼容）*/
.cpu-details > summary { list-style: none; }
.cpu-details > summary::-webkit-details-marker { display: none; }
.cpu-details > summary { outline: none; -webkit-tap-highlight-color: transparent; }
.cpu-details > div {
  display: none;
  animation: tooltip-in 150ms var(--ease-out);
}
.cpu-details[open] > div { display: block; }
.sparkline {
  display: inline-block;
  vertical-align: middle;
}
.sparkline path {
  fill: none;
  stroke: var(--brand-indigo-500);
  stroke-width: 1.5;
  stroke-linejoin: round;
  stroke-linecap: round;
  opacity: 0.85;
  transition: opacity 200ms;
}
.sparkline:hover path { opacity: 1; stroke-width: 2; }

/* F3 进度条 grow 动画 — 用 transform 而非 width 避免 layout reflow */
.progress-bar {
  width: 100%;
  transform-origin: left center;
  transform: scaleX(var(--p, 0));
  transition: transform 800ms var(--ease-spring);
}

/* Brand gradient — reserved for avatar ring + brand mark only (login shield, sidebar logo).
   Never as a fill on >5% of any screen per the Triad Restraint Rule. */
.brand-gradient { background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 50%, #d946ef 100%); }

/* Brand text — solid Operator Indigo. Gradient text is banned in DESIGN.md §6.
   Emphasis through weight (600) and tight tracking, never background-clip. */
.brand-text {
  color: var(--brand-indigo-400);
  font-weight: 600;
  letter-spacing: -0.015em;
}
html.light .brand-text {
  color: var(--brand-indigo-700);
}

/* Search summary — solid ink with brand-color weight cue.
   No text-shadow glow (glow is reserved for state per DESIGN.md). */
.search-summary-text {
  color: var(--fg);
  font-weight: 600;
  letter-spacing: -0.015em;
}
html.light .search-summary-text {
  color: var(--fg);
}

/* 显式给 form/title 元素颜色，防止 inherit 异常 */
input, textarea, select { color: var(--fg) !important; }
h1, h2, h3, h4, h5, h6 { color: var(--fg); }
.topbar h2 { color: var(--fg); }
.input { color: var(--fg) !important; }
input::placeholder, textarea::placeholder { color: var(--fg-3) !important; opacity: 0.7; }
/* accountName 输入框特别处理 */
input[x-model="accountName"] { color: var(--fg) !important; }

/* Sidebar */
.sidebar {
  width: 240px;
  background: var(--surface);
  border-right: 1px solid var(--border);
  position: fixed; left: 0; top: 0; bottom: 0;
  display: flex; flex-direction: column;
  z-index: 30;
}
.sidebar-item {
  display: flex; align-items: center; gap: 12px;
  padding: 9px 12px; margin: 2px 8px;
  border-radius: 8px;
  color: var(--fg-2);
  font-size: 13.5px; font-weight: 500;
  cursor: pointer;
  position: relative;
  transition: all var(--dur-fast) var(--ease-out);
}
.sidebar-item:hover { background: var(--hover); color: var(--fg); }
.sidebar-item.active {
  background: rgba(99,102,241,0.10);
  color: var(--fg);
}
.sidebar-item.active::before {
  content: ''; position: absolute; left: -8px; top: 50%; transform: translateY(-50%);
  width: 3px; height: 18px; border-radius: 2px;
  background: linear-gradient(180deg, #6366f1, #d946ef);
}
.sidebar-icon { width: 16px; height: 16px; opacity: 0.8; flex-shrink: 0; }
.sidebar-item.active .sidebar-icon { opacity: 1; color: var(--brand-2); }

/* Mobile bottom tabs — 最保守方案，保证 iOS Safari 100% 可点击 */
.mobile-tabs {
  display: none;
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(11,13,20,0.98);
  border-top: 1px solid var(--border);
  padding: 6px 0 calc(6px + env(safe-area-inset-bottom, 0px));
  z-index: 50;
  justify-content: space-around;
  align-items: flex-end;
  gap: 0;
  height: calc(58px + env(safe-area-inset-bottom, 0px));
  box-sizing: border-box;
  -webkit-transform: translateZ(0);
  transform: translateZ(0);
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}
html.light .mobile-tabs { background: rgba(255,255,255,0.98); }
.mobile-tab {
  flex: 1 1 0;
  min-width: 0;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding: 4px 1px;
  border-radius: 8px;
  color: var(--fg-3);
  font-size: 9px;
  font-weight: 500;
  cursor: pointer;
  transition: color 120ms ease-out, background-color 120ms ease-out;
  white-space: nowrap;
  overflow: hidden;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
  touch-action: manipulation;
  user-select: none;
  -webkit-user-select: none;
  -webkit-transform: translateZ(0);
  transform: translateZ(0);
  position: relative;
}

/* === Chat message animations === */
@keyframes msgEnter {
  from { opacity: 0; transform: translateY(8px) scale(0.97); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}

/* === Deploy button styling (interactive feel) === */
.deploy-btn-local {
  background: var(--brand-indigo-500, #6366f1);
  box-shadow: 0 2px 8px rgba(99,102,241,0.2);
  border: none;
  transition: all 200ms var(--ease-spring, ease);
}
.deploy-btn-local:hover:not(:disabled) {
  background: var(--brand-indigo-400, #818cf8);
  transform: translateY(-1px);
  box-shadow: 0 4px 14px rgba(99,102,241,0.3);
}
.deploy-btn-local:active:not(:disabled) {
  transform: scale(0.98);
}
.deploy-btn-remote {
  background: var(--brand-indigo-500, #6366f1);
  box-shadow: 0 2px 8px rgba(99,102,241,0.2);
  border: none;
  transition: all 200ms var(--ease-spring, ease);
}
.deploy-btn-remote:hover:not(:disabled) {
  background: var(--brand-indigo-400, #818cf8);
  transform: translateY(-1px);
  box-shadow: 0 4px 14px rgba(99,102,241,0.3);
}
.deploy-btn-remote:active:not(:disabled) {
  transform: scale(0.98);
}
.deploy-btn-failed {
  background: #e11d48 !important;
  box-shadow: 0 2px 8px rgba(225,29,72,0.2) !important;
}
.deploy-btn-running {
  cursor: wait !important;
  opacity: 0.85;
}
.deploy-btn-success {
  background: #10b981 !important;
  box-shadow: 0 2px 8px rgba(16,185,129,0.2) !important;
}

/* === Center tab — clean FAB style (not a purple blob) === */
.mobile-tab:nth-of-type(3) {
  flex: 0 0 52px;
  min-width: 52px;
  height: 52px;
  margin-top: -12px;
  padding: 0;
  border-radius: 16px;
  background: var(--surface-3, #27272a);
  border: 1px solid var(--border, #3f3f46);
  box-shadow: 0 2px 12px rgba(0,0,0,0.2);
  gap: 0;
  z-index: 1;
  position: relative;
  transition: all 0.2s cubic-bezier(0.25, 0.1, 0.25, 1);
}
.mobile-tab:nth-of-type(3) svg {
  width: 22px;
  height: 22px;
  color: var(--fg-3, #a1a1aa);
  transition: color 0.2s;
}
.mobile-tab:nth-of-type(3) > span:last-child {
  display: none;
}
.mobile-tab:nth-of-type(3).active {
  background: var(--brand-indigo-500, #6366f1);
  border-color: var(--brand-indigo-400, #818cf8);
  box-shadow: 0 4px 16px rgba(99,102,241,0.3);
  transform: translateY(-2px);
}
.mobile-tab:nth-of-type(3).active svg {
  color: white;
}
html.light .mobile-tab:nth-of-type(3) {
  background: #fff;
  border-color: #e4e4e7;
  box-shadow: 0 2px 8px rgba(0,0,0,0.08);
}
html.light .mobile-tab:nth-of-type(3).active {
  background: var(--brand-indigo-500, #6366f1);
  border-color: var(--brand-indigo-400, #818cf8);
}
.mobile-tab.active {
  color: var(--brand-indigo-400);
  background: var(--status-active-bg);
}
.mobile-tab svg { width: 19px; height: 19px; flex-shrink: 0; }
.mobile-tab span { line-height: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }

/* Top bar */
.topbar {
  height: 56px;
  border-bottom: 1px solid var(--border);
  background: var(--topbar-bg, rgba(15,15,18,0.7));
  background-size: 100% 100%;
  backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
  display: flex; align-items: center;
  padding: 0 24px;
  position: sticky; top: 0;
  z-index: 20;
}

/* Status dot with pulse */
.dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.dot-online { background: var(--success); box-shadow: 0 0 0 0 rgba(16,185,129,0.5); animation: pulse-ring 2s infinite; }
.dot-warning { background: var(--warning); box-shadow: 0 0 0 0 rgba(245,158,11,0.5); animation: pulse-ring 2s infinite; }
.dot-offline { background: var(--fg-4); }
.dot-warn { background: var(--warning); }
@keyframes pulse-ring {
  0% { box-shadow: 0 0 0 0 rgba(16,185,129,0.6); }
  70% { box-shadow: 0 0 0 6px rgba(16,185,129,0); }
  100% { box-shadow: 0 0 0 0 rgba(16,185,129,0); }
}

/* Buttons */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 8px 14px;
  border-radius: 8px;
  font-size: 13px; font-weight: 500;
  cursor: pointer;
  border: 1px solid transparent;
  transition: all var(--dur-fast) var(--ease-out);
}
.btn:active { transform: scale(0.97); }
.btn-primary {
  background: linear-gradient(135deg, #6366f1, #8b5cf6);
  color: white;
  box-shadow: var(--shadow-xs), inset 0 1px 0 rgba(255,255,255,0.15);
}
.btn-primary:hover { box-shadow: var(--shadow-glow-indigo), inset 0 1px 0 rgba(255,255,255,0.2); }
.btn-primary:disabled { opacity: 0.5; cursor: not-allowed; }
.btn-ghost {
  background: transparent; color: var(--fg-2);
  border-color: var(--border-2);
}
.btn-ghost:hover { background: var(--hover); color: var(--fg); border-color: var(--border-hover); }
.btn-danger {
  background: rgba(239,68,68,0.1); color: var(--danger);
  border-color: rgba(239,68,68,0.3);
}
.btn-danger:hover { background: rgba(239,68,68,0.2); }

/* Inputs */
.input {
  width: 100%;
  padding: 10px 12px;
  background: var(--input);
  border: 1px solid var(--border-2);
  border-radius: 8px;
  color: var(--fg);
  font-size: 14px;
  outline: none;
  transition: all var(--dur-fast);
}

/* === iOS Safari 防 input focus 自动放大 bug === */
/* iOS Safari 在 input font-size < 16px 时会自动放大页面且 blur 后不缩回 */
/* 修复：mobile 模式下所有 form 元素强制 16px（iOS 标准）*/
@media (max-width: 1023px) {
  input, textarea, select {
    font-size: 16px !important;
  }
}
.input:focus {
  border-color: var(--brand);
  box-shadow: 0 0 0 3px rgba(99,102,241,0.15);
  background: var(--elevated);
}
.input::placeholder { color: var(--fg-4); }

/* Login background — flat canvas.
   Previous version floated 3 blurred indigo/fuchsia/violet halos — the exact
   indigo→pink SaaS-template DNA that PRODUCT.md bans. The page-level
   --bg-gradient (defined in :root) already supplies a subtle brand tint. */
.login-bg {
  position: fixed; inset: 0; z-index: 0;
  background: var(--bg);
  background-image: var(--bg-gradient);
  background-attachment: fixed;
}

/* Page transitions */
.page-enter { animation: pageEnter 400ms var(--ease-out); }
@keyframes pageEnter {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: translateY(0); }
}

/* Stagger children */
.stagger > * { animation: itemEnter 500ms var(--ease-out) backwards; }
.stagger > *:nth-child(1) { animation-delay: 50ms; }
.stagger > *:nth-child(2) { animation-delay: 100ms; }
.stagger > *:nth-child(3) { animation-delay: 150ms; }
.stagger > *:nth-child(4) { animation-delay: 200ms; }
.stagger > *:nth-child(5) { animation-delay: 250ms; }
.stagger > *:nth-child(6) { animation-delay: 300ms; }
.stagger > *:nth-child(7) { animation-delay: 350ms; }
.stagger > *:nth-child(8) { animation-delay: 400ms; }
@keyframes itemEnter {
  from { opacity: 0; transform: translateY(12px); }
  to { opacity: 1; transform: translateY(0); }
}

/* Skeleton shimmer */
.skeleton {
  background: linear-gradient(90deg, var(--surface) 0%, var(--elevated) 50%, var(--surface) 100%);
  background-size: 200% 100%;
  animation: shimmer 1.5s infinite;
  border-radius: 6px;
}
@keyframes shimmer {
  from { background-position: 200% 0; }
  to { background-position: -200% 0; }
}

/* Toast stack — multiple toasts stacked vertically, max 5 */
.toast-stack {
  position: fixed; top: 20px; right: 20px;
  z-index: 100;
  display: flex; flex-direction: column; gap: 8px;
  max-width: 380px;
  pointer-events: none;
}
.toast-stack > * {
  pointer-events: auto;
  cursor: pointer;
}

/* Toast (legacy single — kept for backward compat) */
.toast {
  position: fixed; top: 20px; right: 20px;
  z-index: 100;
  animation: toastIn 350ms var(--ease-spring);
  max-width: calc(100% - 40px);
}
@media (max-width: 480px) {
  .toast { top: 12px; right: 12px; left: 12px; }
  .toast > div { min-width: 0 !important; width: 100%; }
}
.toast.leaving { animation: toastOut 200ms var(--ease-out) forwards; }
@keyframes toastIn {
  from { opacity: 0; transform: translateY(-20px) scale(0.95); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}
@keyframes toastOut {
  to { opacity: 0; transform: translateY(-20px) scale(0.95); }
}

/* Task drawer (desktop: slide from right; mobile: bottom sheet) */
.drawer-backdrop {
  position: fixed; inset: 0;
  background: rgba(0,0,0,0.6);
  backdrop-filter: blur(4px);
  z-index: 60;
  animation: fadeIn 200ms var(--ease-out);
}
.drawer {
  position: fixed; top: 0; right: 0; bottom: 0;
  width: 100%;
  background: var(--surface);
  border-left: 1px solid var(--border-2);
  box-shadow: var(--shadow-xl);
  z-index: 70;
  overflow-y: auto;
  /* iOS: 防止内部长内容（评论、URL、代码）造成横向滑动 */
  overflow-x: hidden;
  animation: drawerIn 350ms var(--ease-out);
  /* drawer 内部所有内容强制 word-break + max-width */
  word-break: break-word;
  overflow-wrap: anywhere;
}
.drawer * { max-width: 100%; }
.drawer pre, .drawer code, .drawer .text-xs, .drawer .text-sm, .drawer .font-mono {
  white-space: pre-wrap;
  word-break: break-all;
  overflow-wrap: anywhere;
  max-width: 100%;
}
@keyframes drawerIn {
  from { transform: translateX(100%); }
  to { transform: translateX(0); }
}
@media (max-width: 767px) {
  .drawer {
    top: 8dvh; left: 0; right: 0;
    width: 100%;
    /* iOS Safari: dvh 是 dynamic viewport height，会随地址栏收缩 */
    max-height: -webkit-fill-available;
    max-height: 84dvh;
    height: 84dvh;
    border-left: none;
    border-top: 1px solid var(--border-2);
    border-top-left-radius: 16px;
    border-top-right-radius: 16px;
    animation: sheetUp 350ms var(--ease-out);
    padding-bottom: calc(20px + env(safe-area-inset-bottom));
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
  }
}
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }

/* Markdown */
.md-body { color: var(--fg-2); font-size: 13.5px; line-height: 1.7; word-break: break-word; }
.md-body h1, .md-body h2, .md-body h3 { color: var(--fg); font-weight: 600; margin: 1.2em 0 0.5em; }
.md-body h1 { font-size: 1.4em; }
.md-body h2 { font-size: 1.2em; }
.md-body h3 { font-size: 1.05em; }
.md-body p { margin: 0.6em 0; }
.md-body ul, .md-body ol { padding-left: 1.5em; margin: 0.6em 0; }
.md-body li { margin: 0.2em 0; }
.md-body code { background: var(--surface-3); padding: 2px 6px; border-radius: 4px; font-family: ui-monospace, 'SF Mono', monospace; font-size: 0.9em; color: #f0abfc; }
.md-body pre { background: var(--surface-3); padding: 12px; border-radius: 8px; overflow-x: auto; margin: 0.8em 0; border: 1px solid var(--border); }
.md-body pre code { background: none; padding: 0; color: var(--fg-2); }
.md-body strong { color: var(--fg); font-weight: 600; }
.md-body a { color: var(--brand-2); text-decoration: none; }
.md-body hr { border: 0; border-top: 1px solid var(--border-2); margin: 1em 0; }
.md-body blockquote { border: 1px solid var(--border-2); background: var(--surface-2); border-radius: 8px; padding: 8px 12px; color: var(--fg-3); margin: 0.8em 0; font-style: italic; }
.md-body table { border-collapse: collapse; margin: 0.8em 0; }
.md-body th, .md-body td { border: 1px solid var(--border-2); padding: 6px 10px; }

/* Chips */
.chip {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 11px; font-weight: 500;
  background: rgba(99,102,241,0.1);
  border: 1px solid rgba(99,102,241,0.25);
  color: #c7d2fe;
}
.chip-success { background: rgba(16,185,129,0.1); border-color: rgba(16,185,129,0.3); color: #6ee7b7; }
.chip-warning { background: rgba(245,158,11,0.1); border-color: rgba(245,158,11,0.3); color: #fcd34d; }
.chip-danger { background: rgba(239,68,68,0.1); border-color: rgba(239,68,68,0.3); color: #fca5a5; }
.chip-neutral { background: rgba(161,161,170,0.08); border-color: rgba(161,161,170,0.2); color: var(--fg-2); }
/* light 主题：chip 颜色更深保证 AA 对比度 */
html.light .chip-success { background: rgba(5,150,105,0.12); border-color: rgba(5,150,105,0.3); color: #047857; }
html.light .chip-warning { background: rgba(217,119,6,0.12); border-color: rgba(217,119,6,0.3); color: #b45309; }
html.light .chip-danger { background: rgba(220,38,38,0.12); border-color: rgba(220,38,38,0.3); color: #b91c1c; }

/* Jz logo 按钮（topbar 右上角，跳转 QQ 音乐） */
.jz-logo-btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  text-decoration: none !important;
  transition: all 200ms var(--ease-out);
}
.jz-logo-btn:hover {
  transform: translateY(-1px);
  border-color: var(--brand-indigo-500) !important;
  box-shadow: var(--shadow-glow-indigo);
}
.jz-logo-btn:active { transform: scale(0.96); }
.publish-agent-btn {
  min-height: 48px;
  transition: transform 200ms var(--ease-spring), border-color 200ms, background-color 200ms, box-shadow 200ms;
}
.publish-agent-btn:active { transform: scale(0.96); }
.publish-agent-btn:hover { transform: translateY(-1px); box-shadow: var(--shadow-sm); }
html.light .publish-agent-btn { background: var(--surface) !important; border-color: var(--border-2) !important; }
html.light .publish-agent-btn:hover { background: var(--surface-2) !important; border-color: var(--border-hover) !important; }
/* light 模式下选中的主导按钮有柔和阴影 */
html.light .publish-agent-btn[class*="border-[var(--agent-color)"] {
  box-shadow: 0 4px 16px rgba(99,102,241,0.15);
}

/* 发布任务按钮 — 点击时有粒子动画 */
.publish-trigger {
  position: relative;
  overflow: visible;
}
.publish-trigger:active {
  animation: publish-burst 0.6s var(--ease-spring);
}
@keyframes publish-burst {
  0%   { transform: scale(1); box-shadow: 0 0 0 0 rgba(99,102,241,0.6); }
  30%  { transform: scale(1.08); box-shadow: 0 0 0 12px rgba(99,102,241,0); }
  100% { transform: scale(1); box-shadow: 0 0 0 0 transparent; }
}

/* Numbered metric */
.metric-num {
  font-feature-settings: 'tnum';
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  letter-spacing: -0.02em;
}

/* Responsive layout */
@media (max-width: 1023px) {
  .sidebar { display: none; }
  .main-shell { margin-left: 0 !important; }
}
@media (min-width: 1024px) {
  .tablet-tabs { display: none !important; }
}
@media (max-width: 767px) {
  /* mobile 也保留 tablet-tabs（顶部滑动 tab），底部 mobile-tabs 保留 */
  .tablet-tabs { display: flex !important; }
  .main-shell { padding-bottom: 64px; }
  .mobile-tabs { display: flex; }
  .topbar { padding: 0 16px; }
  /* 手机卡片压缩 */
  .card { padding: 14px !important; }
  .card > div > .mb-4 { margin-bottom: 10px !important; }
  .card > div > .mb-3 { margin-bottom: 8px !important; }
  .card .grid { gap: 8px !important; }
  .main-pad { padding: 12px !important; }
}

/* Spin loader */
.spinner {
  width: 16px; height: 16px;
  border: 2px solid rgba(255,255,255,0.1);
  border-top-color: var(--brand);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* Slide-up sheet for mobile modals */
.sheet {
  position: fixed; left: 0; right: 0; bottom: 0;
  max-height: 90dvh;
  background: var(--surface);
  border-top-left-radius: 20px;
  border-top-right-radius: 20px;
  border-top: 1px solid var(--border-2);
  z-index: 70;
  overflow-y: auto;
  animation: sheetUp 350ms var(--ease-out);
  padding-bottom: env(safe-area-inset-bottom);
}
@keyframes sheetUp { from { transform: translateY(100%); } to { transform: translateY(0); } }

/* Section title */
.section-title { font-size: 12px; font-weight: 600; color: var(--fg-3); text-transform: uppercase; letter-spacing: 0.08em; }

/* Subtle grid lines for backgrounds */
.grid-bg {
  background-image:
    linear-gradient(rgba(255,255,255,0.015) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,0.015) 1px, transparent 1px);
  background-size: 40px 40px;
}

/* Tab content visibility */
/* tab-content 默认隐藏,Alpine x-show 通过 inline style 覆盖.
   切换 tab 时 .active class 重新挂上,触发 fadeUp animation (200ms spring).
   :class="{'active': tab===...}" 在 index.html 每个 tab panel 上. */
.tab-content { display: none; max-width: 100%; overflow-x: hidden; }
.tab-content.active {
  display: block;
  max-width: 100%;
  animation: tabFadeUp 220ms var(--ease-out);
}
@keyframes tabFadeUp {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ============================================================
   Shimmer skeleton — Linear-style loading placeholder.
   Use: <div class="skeleton h-4 w-32"></div> (Tailwind h/w utility
   sets the box size, .skeleton provides the shimmer animation).
   Replaces spinners in overview/kanban/sandbox first-load states. */
.skeleton {
  background: linear-gradient(90deg,
    var(--surface) 0%,
    var(--surface-3) 50%,
    var(--surface) 100%);
  background-size: 200% 100%;
  animation: shimmer 1.4s var(--ease-out) infinite;
  border-radius: var(--radius-sm);
  display: inline-block;
  vertical-align: middle;
}
.skeleton-rounded { border-radius: var(--radius-md); }
.skeleton-circle { border-radius: 50%; }
@keyframes shimmer {
  0%   { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

/* ============================================================
   Empty state — Linear/Vercel 风格的"还没有"插画 + 标题 + 描述。
   用法: <div class="empty-state"><svg.../><h3>...</h3><p>...</p></div> */
.empty-state {
  text-align: center;
  padding: 2.5rem 1rem;
  color: var(--fg-3);
}
.empty-state svg {
  width: 48px; height: 48px;
  margin: 0 auto 0.75rem;
  display: block;
  opacity: 0.4;
  stroke: var(--fg-3);
}
.empty-state h3 {
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--fg-2);
  margin: 0 0 0.25rem;
}
.empty-state p {
  font-size: 0.8125rem;
  margin: 0;
}

/* ============================================================
   Agent active-card breath glow — 每个灵魂色一个呼吸光晕。
   active = 真在跑任务 (activity.status === 'active')。光晕缩放 + 透明度
   循环,3s 一次,subtle 但能感知到"这个 agent 活着"。 */
@keyframes agentBreath {
  0%, 100% { opacity: 0.55; transform: scale(0.98); }
  50%      { opacity: 1;    transform: scale(1.02); }
}
.agent-active-glow-amber   { box-shadow: 0 0 0 1px var(--agent-dorians-border),   var(--shadow-glow-amber);   animation: agentBreath 3.2s var(--ease-out) infinite; }
.agent-active-glow-sky     { box-shadow: 0 0 0 1px var(--agent-ameng-border),     var(--shadow-glow-sky);     animation: agentBreath 3.0s var(--ease-out) infinite; }
.agent-active-glow-emerald { box-shadow: 0 0 0 1px var(--agent-architect-border), var(--shadow-glow-emerald); animation: agentBreath 3.4s var(--ease-out) infinite; }

/* ============================================================
   Skip-to-content link — visible only on keyboard focus (a11y WCAG 2.4.1).
   Mouse users never see it; Tab key users get it as first focus target. */
/* Alert banner — budget/offline threshold warnings */
.alert-banner {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.75rem 1.25rem;
  font-size: 0.875rem;
  font-weight: 500;
  border-radius: 0 0 var(--radius-md) var(--radius-md);
  animation: fadeUp 300ms var(--ease-out);
}
.alert-warning {
  background: var(--status-warning-bg);
  color: var(--status-warning-fg);
  border-bottom: 1px solid var(--amber-400);
}
.alert-critical {
  background: var(--status-danger-bg);
  color: var(--status-danger-fg);
  border-bottom: 1px solid var(--rose-400);
  animation: alertPulse 2s ease-in-out infinite;
}
@keyframes alertPulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.85; }
}

.skip-link {
  position: absolute;
  top: -100px;
  left: 0;
  background: var(--brand-indigo-600);
  color: white;
  padding: 12px 24px;
  border-radius: 0 0 var(--radius-md) 0;
  z-index: 200;
  font-weight: 600;
  text-decoration: none;
  transition: top var(--dur-fast) var(--ease-out);
}
.skip-link:focus {
  top: 0;
}

/* Focus-visible — clear focus ring for keyboard nav only (not mouse click).
   Uses outline instead of box-shadow so it doesn't conflict with our
   shadow system. WCAG 2.4.7 (Focus Visible). */
:focus-visible {
  outline: 2px solid var(--brand-indigo-400);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}
/* Mouse click shouldn't show focus ring */
:focus:not(:focus-visible) {
  outline: none;
}

/* Honor reduced motion globally */
@media (prefers-reduced-motion: reduce) {
  .skeleton { animation: none; opacity: 0.6; }
  .tab-content.active { animation: none; }
  .agent-active-glow-amber, .agent-active-glow-sky, .agent-active-glow-emerald { animation: none; opacity: 0.85; }
  .fade-up, .scale-in, .slide-in-left, .slide-in-right, .blur-in { animation: none !important; opacity: 1 !important; transform: none !important; filter: none !important; }
  ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation: none !important; }
}

/* ============================================================
   Reusable animation utilities — apply via class.
   .fade-up: opacity 0→1 + translateY(8px→0), 220ms
   .scale-in: opacity 0→1 + scale(0.96→1), 200ms spring
   .slide-in-left: opacity 0→1 + translateX(-12px→0), 250ms
   .slide-in-right: opacity 0→1 + translateX(12px→0), 250ms
   .blur-in: opacity 0→1 + blur(8px→0), 300ms

   Use: <div class="card fade-up"> — element animates on first render.
   Re-trigger: remove + re-add class via JS, or toggle keyframe via :key. */
.fade-up      { animation: fadeUp 220ms var(--ease-out) backwards; }
.scale-in     { animation: scaleIn 200ms var(--ease-spring) backwards; }
.slide-in-left  { animation: slideInLeft 250ms var(--ease-out) backwards; }
.slide-in-right { animation: slideInRight 250ms var(--ease-out) backwards; }
.blur-in      { animation: blurIn 300ms var(--ease-out) backwards; }

@keyframes fadeUp      { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
@keyframes scaleIn     { from { opacity: 0; transform: scale(0.96); } to { opacity: 1; transform: scale(1); } }
@keyframes slideInLeft { from { opacity: 0; transform: translateX(-12px); } to { opacity: 1; transform: translateX(0); } }
@keyframes slideInRight{ from { opacity: 0; transform: translateX(12px); } to { opacity: 1; transform: translateX(0); } }
@keyframes blurIn      { from { opacity: 0; filter: blur(8px); } to { opacity: 1; filter: blur(0); } }

/* View Transitions API (Chrome 111+, Safari 17.4+) — document.startViewTransition().
   Default cross-fade. Customize via ::view-transition-old/new pseudo-elements. */
::view-transition-old(root), ::view-transition-new(root) {
  animation-duration: 220ms;
  animation-timing-function: var(--ease-out);
}
::view-transition-old(root) { animation-name: -vt-fade-out; }
::view-transition-new(root) { animation-name: -vt-fade-in; }
@keyframes -vt-fade-out { from { opacity: 1; } to { opacity: 0; } }
@keyframes -vt-fade-in  { from { opacity: 0; } to { opacity: 1; } }

/* Stagger helper — apply to parent, children animate with 50ms delay each */
.stagger > *:nth-child(1) { animation-delay: 0ms; }
.stagger > *:nth-child(2) { animation-delay: 50ms; }
.stagger > *:nth-child(3) { animation-delay: 100ms; }
.stagger > *:nth-child(4) { animation-delay: 150ms; }
.stagger > *:nth-child(5) { animation-delay: 200ms; }
.stagger > *:nth-child(6) { animation-delay: 250ms; }
.stagger > *:nth-child(7) { animation-delay: 300ms; }
.stagger > *:nth-child(8) { animation-delay: 350ms; }

/* ============================================================
   Agent Avatar Orb — 灵魂色 + 多层环 + 微动画
   参考 Vercel spinner + Discord dot + Notion 灵魂色
   每个 agent 一个固定品牌色（不依赖 currentColor），多层视觉
   ============================================================ */

/* 灵魂色 per agent */
.agent-orb[data-agent="dorians"] {
  --agent-light: #fde68a;
  --agent-mid:   #fbbf24;
  --agent-dark:  #f97316;
  --agent-glow:  rgba(251,146,60,0.5);
  --agent-ring-grad: conic-gradient(from 0deg, #fbbf24, #f97316, #dc2626, #fbbf24);
}
.agent-orb[data-agent="ameng"] {
  --agent-light: #bae6fd;
  --agent-mid:   #38bdf8;
  --agent-dark:  #0284c7;
  --agent-glow:  rgba(56,189,248,0.5);
  --agent-ring-grad: conic-gradient(from 0deg, #7dd3fc, #0ea5e9, #06b6d4, #7dd3fc);
}
.agent-orb[data-agent="architect"] {
  --agent-light: #a7f3d0;
  --agent-mid:   #34d399;
  --agent-dark:  #059669;
  --agent-glow:  rgba(16,185,129,0.5);
  --agent-ring-grad: conic-gradient(from 0deg, #6ee7b7, #10b981, #047857, #6ee7b7);
}

/* 主容器：圆形发光球 — 默认就有呼吸动画 */
.agent-orb {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  background:
    radial-gradient(circle at 30% 25%, var(--agent-light), var(--agent-mid) 50%, var(--agent-dark));
  box-shadow:
    inset 0 2px 6px rgba(255,255,255,0.4),
    inset 0 -3px 8px rgba(0,0,0,0.25),
    0 4px 14px var(--agent-glow),
    0 0 0 1px rgba(255,255,255,0.1);
  transition: transform 400ms var(--ease-spring),
              opacity 400ms var(--ease-out),
              filter 400ms var(--ease-out),
              box-shadow 400ms var(--ease-out);
  /* 默认所有状态都有 subtle 呼吸（除非被 status-specific 覆盖） */
  animation: agent-default-breathe 4s ease-in-out infinite;
}
@keyframes agent-default-breathe {
  0%, 100% { transform: scale(1); box-shadow:
    inset 0 2px 6px rgba(255,255,255,0.4),
    inset 0 -3px 8px rgba(0,0,0,0.25),
    0 4px 14px var(--agent-glow),
    0 0 0 1px rgba(255,255,255,0.1); }
  50%      { transform: scale(1.025); box-shadow:
    inset 0 2px 6px rgba(255,255,255,0.5),
    inset 0 -3px 8px rgba(0,0,0,0.25),
    0 6px 20px var(--agent-glow),
    0 0 0 1px rgba(255,255,255,0.15); }
}

/* 外层 ring — conic gradient + mask 做中空圈 */
.agent-orb::before {
  content: '';
  position: absolute;
  inset: -3px;
  border-radius: inherit;
  padding: 3px;
  background: var(--ring-current, transparent);
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  pointer-events: none;
  z-index: 1;
  transition: opacity 400ms var(--ease-out);
}

/* 第二层光晕（仅 active/error） */
.agent-orb::after {
  content: '';
  position: absolute;
  inset: -8px;
  border-radius: inherit;
  background: radial-gradient(circle, var(--agent-glow), transparent 65%);
  opacity: 0;
  pointer-events: none;
  transition: opacity 400ms var(--ease-out);
  z-index: 0;
}

/* 内嵌 SVG 角色（用半透明白色 stroke + fill 在彩色球上显出形状） */
.agent-orb .agent-svg {
  width: 70%;
  height: 70%;
  position: relative;
  z-index: 2;
  color: rgba(255,255,255,0.95);
  filter: drop-shadow(0 1px 2px rgba(0,0,0,0.3));
}
.agent-orb .agent-svg g {
  stroke: currentColor;
  fill: none;
}

/* === 状态视觉 === */

/* active: 旋转环 + 呼吸 + 光晕 */
.agent-orb[data-status="active"] {
  --ring-current: var(--agent-ring-grad);
  animation: agent-breathe 2.4s ease-in-out infinite;
}
.agent-orb[data-status="active"]::before {
  animation: agent-ring-spin 2.2s linear infinite;
}
.agent-orb[data-status="active"]::after {
  opacity: 0.7;
  animation: agent-glow-pulse 2s ease-in-out infinite;
}

/* idle: 静态环 + 缓慢浮动 */
.agent-orb[data-status="idle"] {
  --ring-current: linear-gradient(135deg, var(--agent-light), var(--agent-dark));
  animation: agent-float 4s ease-in-out infinite;
}
.agent-orb[data-status="idle"]::before { opacity: 0.6; }

/* thinking: 加快呼吸 + ring 加速 */
.agent-orb[data-status="thinking"] {
  --ring-current: var(--agent-ring-grad);
  animation: agent-breathe 1.2s ease-in-out infinite;
}
.agent-orb[data-status="thinking"]::before {
  animation: agent-ring-spin 1s linear infinite;
  opacity: 0.85;
}

/* dormant: 半透明 + 灰度 + dashed ring */
.agent-orb[data-status="dormant"] {
  opacity: 0.6;
  filter: grayscale(0.45) brightness(0.85);
  --ring-current: repeating-linear-gradient(90deg, var(--fg-4) 0 3px, transparent 3px 6px);
}
.agent-orb[data-status="dormant"]::before { opacity: 0.5; }

/* error: 红色 glow + 震动 + 红环 */
.agent-orb[data-status="error"] {
  --ring-current: conic-gradient(from 0deg, #ef4444, #f87171, #dc2626, #ef4444);
  box-shadow:
    inset 0 2px 6px rgba(255,255,255,0.4),
    inset 0 -3px 8px rgba(0,0,0,0.25),
    0 4px 18px rgba(239,68,68,0.55),
    0 0 0 1px rgba(239,68,68,0.3);
  animation: agent-shake 0.5s ease-in-out;
}
.agent-orb[data-status="error"]::before {
  animation: agent-ring-spin 1.4s linear infinite;
}
.agent-orb[data-status="error"]::after {
  opacity: 0.85;
  background: radial-gradient(circle, rgba(239,68,68,0.6), transparent 65%);
  animation: agent-glow-pulse 1s ease-in-out infinite;
}

/* offline: 灰度 + 30% opacity */
.agent-orb[data-status="offline"] {
  opacity: 0.35;
  filter: grayscale(1);
  --ring-current: transparent;
}

/* === 状态角标（Discord-style 描边小圆点 + 动画） === */
.agent-orb .agent-badge {
  position: absolute;
  width: 30%;
  height: 30%;
  min-width: 10px;
  min-height: 10px;
  right: -2px;
  bottom: -2px;
  border-radius: 50%;
  background: var(--badge-bg, var(--success));
  border: 2px solid var(--surface);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 9px;
  font-weight: 700;
  color: white;
  text-shadow: 0 1px 2px rgba(0,0,0,0.4);
  z-index: 3;
  box-shadow: 0 2px 4px rgba(0,0,0,0.2);
  animation: agent-badge-breathe 2.5s ease-in-out infinite;
}
@keyframes agent-badge-breathe {
  0%, 100% { transform: scale(1); box-shadow: 0 2px 4px rgba(0,0,0,0.2); }
  50%      { transform: scale(1.12); box-shadow: 0 2px 8px var(--badge-bg, var(--success)); }
}
.agent-orb[data-status="active"]   .agent-badge { --badge-bg: var(--success); animation: agent-badge-active 1.4s ease-in-out infinite; }
.agent-orb[data-status="idle"]     .agent-badge { --badge-bg: var(--success); }
.agent-orb[data-status="thinking"] .agent-badge { --badge-bg: var(--warning); animation: agent-badge-thinking 1s ease-in-out infinite; }
.agent-orb[data-status="dormant"]  .agent-badge { --badge-bg: var(--fg-4); animation: none; opacity: 0.7; }
.agent-orb[data-status="error"]    .agent-badge { --badge-bg: var(--danger); animation: agent-badge-error 0.6s ease-in-out infinite; }
.agent-orb[data-status="offline"]  .agent-badge { display: none; }

@keyframes agent-badge-active {
  0%, 100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(16,185,129,0.6); }
  50%      { transform: scale(1.15); box-shadow: 0 0 0 6px rgba(16,185,129,0); }
}
@keyframes agent-badge-thinking {
  0%, 100% { transform: scale(1) rotate(0deg); }
  50%      { transform: scale(1.15) rotate(180deg); }
}
@keyframes agent-badge-error {
  0%, 100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(239,68,68,0.7); }
  50%      { transform: scale(1.2); box-shadow: 0 0 0 8px rgba(239,68,68,0); }
}

/* === Animations === */
@keyframes agent-ring-spin {
  to { transform: rotate(360deg); }
}
@keyframes agent-breathe {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.05); }
}
@keyframes agent-float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-4px); }
}
@keyframes agent-shake {
  0%, 100% { transform: translateX(0); }
  20%      { transform: translateX(-3px) rotate(-2deg); }
  40%      { transform: translateX(3px) rotate(2deg); }
  60%      { transform: translateX(-2px) rotate(-1deg); }
  80%      { transform: translateX(2px) rotate(1deg); }
}
@keyframes agent-glow-pulse {
  0%, 100% { opacity: 0.4; transform: scale(0.95); }
  50%      { opacity: 0.85; transform: scale(1.1); }
}
@keyframes agent-badge-pulse {
  0%, 100% { transform: scale(1); box-shadow: 0 2px 4px rgba(0,0,0,0.2); }
  50%      { transform: scale(1.15); box-shadow: 0 2px 8px rgba(239,68,68,0.6); }
}

/* ============================================================
   Mobile touch target sizing — WCAG 2.5.5 (minimum 44×44px).
   Increases hit area for buttons/links/tabs on phones without
   making them visually larger. Uses min-height + padding extension
   so the visible chip stays compact but the touchable area grows.
   ============================================================ */
@media (max-width: 767px) {
  /* Top tab strip (scrollable tabs at top of every page) */
  .tablet-tabs button,
  .tablet-tabs a,
  .mobile-tabs button,
  .mobile-tabs a {
    min-height: 44px;
    min-width: 44px;
  }
  /* Generic small action buttons (icon buttons in cards, refresh, etc.) */
  .card button:not([class*="h-14"]):not([class*="h-16"]):not([class*="py-12"]):not([class*="py-8"]) {
    min-height: 36px;
  }
  /* Tiny icon-only buttons (the svg action chips on agent cards) */
  a[class*="cursor-pointer"],
  button[class*="cursor-pointer"] {
    min-height: 36px;
    min-width: 36px;
  }
  /* Nav tab buttons (text + icon) */
  nav button,
  nav a {
    min-height: 40px;
  }
  /* Form inputs (login etc.) */
  input[type="password"],
  input[type="text"],
  input[type="email"],
  button[type="submit"] {
    min-height: 44px;
  }
}

/* ============================================================
   Microinteractions polish (v3.20.6) — tactile feedback everywhere.
   - Buttons / cards press down on :active (haptic-feel without vibration)
   - focus-visible ring for keyboard nav (a11y + looks intentional)
   - Sidebar active item gets subtle inner glow (signpost)
   - Tab transition tuned (faster + spring easing)
   - Empty states get illustration + descriptive copy (not just text)
   ============================================================ */

/* Press effect — applies to anything marked .pressable or button-like.
   Scale 0.97 + slight brightness lift = "I felt that click". */
button:not(:disabled):not([aria-disabled="true"]):active,
[role="button"]:not([aria-disabled="true"]):active,
.pressable:active {
  transform: scale(0.97);
  transition-duration: 60ms;  /* snap down fast, ease up slow via transition on :hover/:default */
}

/* Cards that are clickable get stronger press feedback */
.card-interactive:active {
  transform: scale(0.985) translateY(1px);
}

/* Focus-visible ring — only shows for keyboard nav (not mouse clicks).
   2px ring offset so it doesn't clip with the element. */
*:focus-visible {
  outline: 2px solid var(--brand-indigo-500);
  outline-offset: 2px;
  border-radius: 4px;
}

/* Sidebar active gets subtle inner glow + brighter icon */
.sidebar-item.active {
  background: linear-gradient(90deg,
    var(--sidebar-item-active-bg) 0%,
    rgba(99,102,241,0.04) 100%);
  box-shadow: inset 0 0 0 1px rgba(99,102,241,0.18);
}

/* Smoother page transitions (was 400ms linear, now 280ms spring) */
.page-enter {
  animation: pageEnter 280ms var(--ease-spring);
}

/* Toast entrance snappier */
@keyframes toastIn {
  from { opacity: 0; transform: translateY(-12px) scale(0.96); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}

/* Subtle progress shimmer for skeleton bars (was static gray) */
@keyframes skeleton-shimmer {
  0%   { background-position: -200% 0; }
  100% { background-position: 200% 0; }
}
.skeleton {
  background: linear-gradient(90deg,
    var(--surface-2) 0%,
    var(--surface-3) 50%,
    var(--surface-2) 100%);
  background-size: 200% 100%;
  animation: skeleton-shimmer 1.6s linear infinite;
  border-radius: 6px;
}

/* Empty state — bigger illustration + softer colors */
.empty-state {
  padding: 3rem 1rem;
}
.empty-state svg {
  width: 56px; height: 56px;
  opacity: 0.35;
  margin-bottom: 1rem;
  animation: float 3s ease-in-out infinite;
}
@keyframes float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-4px); }
}

/* Number tick on count-up — subtle scale pulse when value changes */
[x-data] [x-count-up] {
  transition: transform 200ms var(--ease-spring);
  display: inline-block;
}

/* Drawer slide-in smoother (was 350ms, now 280ms spring) */
@keyframes drawerIn {
  from { transform: translateX(100%); opacity: 0.6; }
  to   { transform: translateX(0); opacity: 1; }
}
.drawer {
  animation: drawerIn 280ms var(--ease-spring);
}

/* Modal backdrop fade snappier */
.truncate-modal-backdrop, .drawer-backdrop {
  animation: fadeIn 180ms var(--ease-out);
}
@keyframes fadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* Reduced motion — respect user preference */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  .empty-state svg { animation: none; }
}

/* ============================================================
   Help popover — accessible inline `?` icon for form fields.
   Uses native <details>/<summary> so works without JS, keyboard-accessible,
   hover/focus opens, click also opens. Falls back to title attribute.
   ============================================================ */
.help-popover {
  display: inline-flex;
  vertical-align: middle;
  margin-left: 4px;
}
.help-popover > summary {
  list-style: none;
  cursor: help;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--surface-3);
  color: var(--fg-3);
  font-size: 10px;
  font-weight: 600;
  line-height: 1;
  transition: background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.help-popover > summary::-webkit-details-marker { display: none; }
.help-popover > summary:hover,
.help-popover[open] > summary {
  background: var(--brand-indigo-500);
  color: white;
}
.help-popover[open] > summary::after {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 40;
  /* Click-outside-to-close without JS */
}
.help-popover > .help-content {
  position: absolute;
  z-index: 50;
  margin-top: 6px;
  background: var(--elevated);
  border: 1px solid var(--border-2);
  border-radius: var(--radius-md);
  padding: 10px 12px;
  font-size: 11px;
  line-height: 1.55;
  color: var(--fg-2);
  max-width: 280px;
  box-shadow: var(--shadow-lg);
  white-space: normal;
  /* Default to below the trigger; flip via [data-position="above"] */
  transform: translateY(4px);
  animation: helpFadeIn 150ms var(--ease-out);
}
@keyframes helpFadeIn {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: translateY(4px); }
}
.help-popover[data-position="above"] > .help-content {
  transform: translateY(-100%);
  top: 0;
}
.help-content code {
  background: var(--input);
  padding: 1px 5px;
  border-radius: 3px;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 0.9em;
  color: var(--fg);
}
.help-content strong { color: var(--fg); font-weight: 600; }

/* ============================================================
   Visual polish (v3.22.4) — based on 28-screenshot full audit
   ============================================================ */

/* Card action links (查看 SOUL →, 查看全部 →) — subtle by default, bright on hover.
   MCP feedback: links competed with subheadings for visual hierarchy. */
.card a:not([class*="btn"]):not([class*="jz-logo"]) {
  opacity: 0.65;
  font-size: 0.7rem;
  font-weight: 500;
  transition: opacity var(--dur-fast) var(--ease-out);
}
.card a:not([class*="btn"]):not([class*="jz-logo"]):hover {
  opacity: 1;
}

/* Agent status badges — slightly brighter glow in dark theme.
   MCP feedback: status dots could be more immediately noticeable. */
html.dark .agent-active-glow-amber,
html.dark .agent-active-glow-sky,
html.dark .agent-active-glow-emerald {
  filter: brightness(1.15);
}

/* Host monitoring — more breathing room between metrics and process list.
   MCP feedback: add whitespace to reduce density. */
.card .host-stats-section + div,
.card .grid + .text-xs {
  margin-top: 1rem;
}

/* Dark theme: status chips with subtle glow */
html.dark [class*="bg-emerald-500/15"],
html.dark [class*="bg-amber-500/15"],
html.dark [class*="bg-indigo-500/15"] {
  box-shadow: 0 0 0 1px rgba(255,255,255,0.05);
}

/* ============================================================
   v3.23.1: Mobile tab fix — prevent overlap on narrow screens.
   MOBILE (<768px): ONLY sub-tabs at top. Categories in bottom nav.
   No category row at top → eliminates "two tab bar" confusion.
   TABLET (768-1023px): categories at top, sub-tabs below (clearly separated).
   ============================================================ */
@media (max-width: 767px) {
  /* Mobile: HIDE category row entirely (categories are in bottom nav) */
  .tablet-tabs > div:first-child {
    display: none !important;
  }
  /* Mobile: sub-tab row takes full width, single row */
  .tablet-tabs > div:nth-child(2) {
    padding: 6px 12px 8px;
  }
  /* Reduce topbar height on mobile */
  .topbar {
    padding: 0 12px;
    height: 48px;
  }
}

@media (min-width: 768px) and (max-width: 1023px) {
  /* Tablet: show category row with smaller text, sub-tab row below with separator */
  .tablet-tabs > div:first-child button svg {
    width: 14px;
    height: 14px;
  }
  .tablet-tabs > div:first-child button {
    padding: 5px 8px;
    font-size: 11px;
  }
  .tablet-tabs > div:nth-child(2) {
    border-top: 1px solid var(--border);
    background: var(--surface);
    padding-top: 4px;
  }
}


/* === Chat UI — iMessage/WeChat quality (v4.6.2 refined) === */

.chat-container {
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.06);
}

/* Messages area — clean flat background (iMessage style) */
.chat-messages {
  scroll-behavior: smooth;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-y: contain;
  background: transparent;
}

/* User bubble — iMessage blue */
.chat-bubble-user {
  background: #007AFF;
  color: white;
  border-radius: 18px 18px 4px 18px;
  padding: 9px 15px;
  font-size: 15px;
  line-height: 1.45;
  margin-right: 12px;
  position: relative;
  min-width: 48px;
  box-shadow: 0 1px 2px rgba(0,0,0,0.15);
  -webkit-tap-highlight-color: transparent;
}

/* Agent bubble — iMessage gray */
.chat-bubble-agent {
  background: var(--surface-3);
  color: var(--fg);
  border-radius: 18px 18px 18px 4px;
  padding: 9px 15px;
  font-size: 15px;
  line-height: 1.45;
  position: relative;
  min-width: 48px;
  box-shadow: 0 1px 2px rgba(0,0,0,0.1);
}

html.light .chat-bubble-agent {
  background: #E9E9EB;
  color: #000;
}
html.light .chat-bubble-user {
  background: #007AFF;
}

/* Avatar */
.chat-avatar-wrapper {
  margin-right: 6px;
  margin-bottom: 2px;
}

/* Typing dots */
.chat-typing-dot {
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--fg-3);
  animation: chatTypingPulse 1.4s infinite ease-in-out;
}
html.light .chat-typing-dot { background: #8E8E93; }

@keyframes chatTypingPulse {
  0%, 60%, 100% { transform: translateY(0); opacity: 0.3; }
  30% { transform: translateY(-5px); opacity: 1; }
}

/* Message slide-in — spring */
@keyframes chatMsgEnter {
  0% { opacity: 0; transform: translateY(12px) scale(0.95); }
  100% { opacity: 1; transform: translateY(0) scale(1); }
}

/* Welcome avatar */
@keyframes chatPulse {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.03); }
}

/* Suggestion chips */
.chat-suggestion {
  font-size: 13px;
  padding: 8px 18px;
  border-radius: 20px;
  background: var(--surface-3);
  color: var(--fg-2);
  border: 1px solid var(--border);
  transition: all 0.2s cubic-bezier(0.25, 0.1, 0.25, 1);
  cursor: pointer;
  white-space: nowrap;
  font-weight: 500;
  -webkit-tap-highlight-color: transparent;
}
.chat-suggestion:hover {
  background: var(--status-active-bg);
  color: var(--brand-indigo-400);
  border-color: var(--brand-indigo-400);
  transform: translateY(-1px);
}
.chat-suggestion:active { transform: scale(0.95); }

/* Scrollbar — minimal */
.chat-messages::-webkit-scrollbar { width: 4px; }
.chat-messages::-webkit-scrollbar-track { background: transparent; }
.chat-messages::-webkit-scrollbar-thumb { background: transparent; }
.chat-messages:hover::-webkit-scrollbar-thumb { background: var(--border); }

/* Mobile: bubble sizing only (height is set by the immersive rule below) */
@media (max-width: 640px) {
  .chat-bubble-user, .chat-bubble-agent { font-size: 14px; }
}

/* Streaming cursor (▌) — blinks while LLM is generating tokens */
.chat-stream-cursor {
  display: inline-block;
  width: 0.5em;
  color: var(--brand-indigo-400, #818cf8);
  font-weight: 100;
  margin-left: 1px;
  animation: chatCursorBlink 1s steps(2, start) infinite;
}
@keyframes chatCursorBlink {
  0%, 50% { opacity: 1; }
  50.01%, 100% { opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .chat-stream-cursor { animation: none; opacity: 0.7; }
}

/* === PWA cross-platform optimizations === */

/* iOS safe-area-inset — accounts for notch + home indicator */
@supports (padding: env(safe-area-inset-top)) {
  body {
    padding-top: env(safe-area-inset-top);
    padding-bottom: env(safe-area-inset-bottom);
  }
  .topbar, .sidebar {
    padding-top: max(env(safe-area-inset-top), 0px);
  }
  /* Bottom nav: respect home indicator */
  .mobile-tabs {
    padding-bottom: max(env(safe-area-inset-bottom), 8px);
  }
  /* Chat input: lift above home indicator */
  .chat-container > div:last-child {
    padding-bottom: max(env(safe-area-inset-bottom), 10px);
  }
}

/* macOS/Windows desktop: when installed as PWA, use proper window controls */
@media (display-mode: standalone) {
  body {
    user-select: none;
    -webkit-user-select: none;
  }
  /* Allow text selection in chat + inputs */
  .chat-messages, textarea, input {
    user-select: text;
    -webkit-user-select: text;
  }
  /* Remove tap highlight on desktop PWA */
  * {
    -webkit-tap-highlight-color: transparent;
  }
}

/* Android: disable pull-to-refresh inside PWA (conflicts with scroll) */
@media (display-mode: standalone) {
  html, body {
    overscroll-behavior-y: contain;
  }
}

/* Markdown content inside agent chat bubbles */
.chat-md-content p { margin: 0 0 8px; }
.chat-md-content p:last-child { margin-bottom: 0; }
.chat-md-content h1, .chat-md-content h2, .chat-md-content h3 {
  font-size: 15px; font-weight: 600; margin: 12px 0 6px;
}
.chat-md-content h1:first-child, .chat-md-content h2:first-child, .chat-md-content h3:first-child { margin-top: 0; }
.chat-md-content ul, .chat-md-content ol { margin: 6px 0; padding-left: 20px; }
.chat-md-content li { margin: 3px 0; }
.chat-md-content code {
  background: rgba(0,0,0,0.15); padding: 1px 5px; border-radius: 4px;
  font-size: 13px; font-family: ui-monospace, 'SF Mono', Menlo, monospace;
}
html.light .chat-md-content code { background: rgba(0,0,0,0.08); }
.chat-md-content pre {
  background: rgba(0,0,0,0.2); border-radius: 8px; padding: 10px 12px;
  overflow-x: auto; margin: 8px 0; font-size: 12px;
}
html.light .chat-md-content pre { background: rgba(0,0,0,0.05); }
.chat-md-content pre code { background: none; padding: 0; }
.chat-md-content a { color: inherit; text-decoration: underline; }
.chat-md-content strong { font-weight: 600; }
.chat-md-content blockquote {
  border: 1px solid var(--border-2); background: var(--surface-2);
  border-radius: 6px; padding: 6px 10px; margin: 6px 0;
  opacity: 0.85;
}
.chat-md-content table { border-collapse: collapse; margin: 8px 0; }
.chat-md-content th, .chat-md-content td {
  border: 1px solid var(--border); padding: 4px 8px; font-size: 13px;
}

/* === v5.29.0: body.immersive-mode removed — replaced by body.mobile-fullscreen ===
   (see new unified rules at top of v5.29.0 block below). */

/* Immersive-mode exit button — top-left floating chip */
.immersive-exit-btn {
  position: fixed;
  /* Lift above iOS notch / Dynamic Island */
  top: calc(14px + env(safe-area-inset-top, 0px));
  left: calc(14px + env(safe-area-inset-left, 0px));
  z-index: 200;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 14px;
  background: rgba(11,13,20,0.92);
  border: 1px solid rgba(255,255,255,0.18);
  color: #ffffff;
  font-size: 13px;
  font-weight: 700;
  border-radius: 8px;
  backdrop-filter: blur(10px);
  cursor: pointer;
  transition: background 200ms ease;
  /* Sprint 0 v5.25: strong text shadow for visibility on frosted glass over bright office */
  text-shadow: 0 1px 2px rgba(0,0,0,0.95), 0 0 8px rgba(0,0,0,0.6);
  /* SVG icon shadow via filter */
  filter: drop-shadow(0 1px 2px rgba(0,0,0,0.5));
  /* iOS Safari: no tap highlight, no callout, no 300ms delay */
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
  touch-action: manipulation;
  min-height: 44px;  /* WCAG 2.5.5 touch target */
  letter-spacing: 0.2px;
}
.immersive-exit-btn:hover { background: rgba(99,102,241,0.92); }
.immersive-exit-btn:active { background: rgba(99,102,241,0.95); transform: scale(0.96); }

/* Tap-to-walk ripple animation */
@keyframes bossTapRipple {
  0%   { transform: scale(0.4); opacity: 1; }
  100% { transform: scale(2.4); opacity: 0; }
}

/* Quick-jump chips (top-right floating buttons for jumping camera to each worker) */
.office-jump-bar {
  position: absolute;
  top: calc(60px + env(safe-area-inset-top, 0px));
  right: calc(12px + env(safe-area-inset-right, 0px));
  z-index: 36;
  display: flex;
  flex-direction: column;
  gap: 6px;
  pointer-events: none;
}
.office-jump-bar .jump-chip {
  pointer-events: auto;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 6px 10px;
  background: rgba(11,13,20,0.75);
  backdrop-filter: blur(8px);
  border: 1px solid rgba(255,255,255,0.1);
  color: #f3f4f6;
  font-size: 11px;
  font-weight: 600;
  border-radius: 16px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
  touch-action: manipulation;
  min-height: 32px;
  transition: transform 120ms ease, background 120ms ease;
}
.office-jump-bar .jump-chip:active { transform: scale(0.94); }
.office-jump-bar .jump-chip .dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}

/* ============================================================
   Sprint 12 v5.25.1 — Mobile top-region consolidation
   User feedback: "不符合预期" — too much UI stacked on a 390px
   viewport (exit + TopBar + HUD + 9 dock buttons + jumpBar =
   ~762px worth of UI fighting for 390px). This media query
   hides duplicates and constrains the dock so mobile gets a
   clean layout. No features removed — TopBar's agent info
   lives in BottomBar busy/connection pills + WorkerPanel
   flyout; HUD center text lives in promptEl (golden "✦" pill);
   jumpBar's camera-pan lives in WorkerPanel tap-to-pan.
   ============================================================ */
@media (max-width: 600px) {
  /* Hide TopBar (logo + agent pills) — duplicated in BottomBar */
  .office-topbar { display: none !important; }
  /* Hide HUD center text — promptEl covers interaction hint */
  .office-hud { display: none !important; }
  /* Hide quick-jump bar — camera pan via WorkerPanel tap-to-row */
  .office-jump-bar { display: none !important; }

  /* Dock: cap width + wrap so 9 buttons flow to 2 rows instead of overflowing */
  .office-hud-dock {
    max-width: calc(100vw - 80px);  /* leave room for exit button on left */
    flex-wrap: wrap;
    justify-content: flex-end;
    row-gap: 4px;
  }
  /* Dock overflow dropdown (mobile-only — shown when "更多" tapped) */
  .office-hud-dock__overflow {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    z-index: 44;
    display: none;
    flex-direction: column;
    gap: 4px;
    padding: 6px;
    background: rgba(11,13,20,0.96);
    backdrop-filter: blur(12px);
    border: 1px solid rgba(255,255,255,0.12);
    border-radius: var(--radius-md);
    box-shadow: 0 8px 24px rgba(0,0,0,0.6);
    min-width: 160px;
    pointer-events: auto;
  }
  .office-hud-dock__overflow--open { display: flex; }
  .office-hud-dock__overflow-btn {
    display: flex !important;
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: 8px 10px !important;
    background: transparent !important;
    border: 1px solid transparent !important;
    color: #f3f4f6 !important;
    font-size: 12px;
    font-weight: 600;
    border-radius: var(--radius-sm);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    -webkit-touch-callout: none;
    touch-action: manipulation;
    min-height: 40px;
    text-align: left;
  }
  .office-hud-dock__overflow-btn:active {
    background: rgba(255,255,255,0.08) !important;
    transform: scale(0.97);
  }
  .office-hud-dock__overflow-btn svg {
    flex-shrink: 0;
  }
  /* "更多" trigger button — only visible on mobile */
  .office-hud-dock__more-btn {
    display: inline-flex !important;
    order: 99;  /* always last in the dock row */
  }

  /* BottomBar: compress to fit narrow viewport */
  .office-bottombar {
    font-size: 10px !important;
    gap: 4px !important;
    padding: 4px 6px !important;
    max-width: calc(100vw - 12px) !important;
  }
  .office-bottombar > div {  /* tighten pill padding */
    padding: 2px 4px !important;
  }
  /* Hide model pill text on mobile (just keep connection + context + busy) */
  .office-bottombar > div:nth-child(2) span:last-child {
    max-width: 60px !important;
  }
}
/* Hide "更多" trigger on desktop — only needed in mobile compact mode */
@media (min-width: 601px) {
  .office-hud-dock__more-btn { display: none !important; }
}

/* === v5.27: Game-feel panel animations === */
@keyframes panelPop {
  0%   { transform: translateY(20px) scale(0.96); opacity: 0; }
  60%  { transform: translateY(-4px) scale(1.02); }
  100% { transform: none; opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .office-inline-panel { animation: none !important; }
}

/* === v5.27: Onboarding spotlight upgrades === */
@keyframes onboardingRingSpin {
  from { transform: translate(-50%, -50%) rotate(0deg); }
  to   { transform: translate(-50%, -50%) rotate(360deg); }
}
@keyframes onboardingTipPop {
  0%   { transform: translateX(-50%) translateY(8px) scale(0.95); opacity: 0; }
  100% { transform: translateX(-50%) translateY(0) scale(1); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .office-onboarding-ring { animation: none !important; }
  .office-onboarding-tip { animation: none !important; opacity: 1 !important; }
}

/* === v5.28: Tour + Onboarding premium animations === */
@keyframes tourStepSlide {
  0%   { opacity: 0; transform: translateX(12px); }
  100% { opacity: 1; transform: translateX(0); }
}
.tour-content-enter {
  animation: tourStepSlide 300ms cubic-bezier(0.22, 1, 0.36, 1);
}
@media (prefers-reduced-motion: reduce) {
  .tour-content-enter { animation: none; }
}

/* v5.28.2: light theme card border + contrast fix */
html.light .card {
  border-color: rgba(15,23,42,0.12) !important;
  box-shadow: 0 1px 3px rgba(15,23,42,0.06), 0 1px 2px rgba(15,23,42,0.04) !important;
}
html.light .text-zinc-400, html.light .text-zinc-500 {
  color: var(--fg-3) !important;
  opacity: 0.85;
}
html.light .text-zinc-300 {
  color: var(--fg-2) !important;
}

/* === v5.28.3: P2 polish fixes === */

/* Soul/chat code blocks: syntax-highlight-like coloring */
.md-body pre code, .chat-md-content pre code {
  color: var(--fg-2);
  line-height: 1.6;
}
.md-body pre, .chat-md-content pre {
  border: 1px solid var(--border-2);
}

/* Settings: unify button radius to var(--radius-sm) */
html.light .card button[class*="rounded"],
html.dark .card button[class*="rounded"] {
  border-radius: var(--radius-sm) !important;
}

/* Kanban avatar: ensure soul colors are distinct enough */
.kanban-assignee-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
  box-shadow: 0 0 0 2px rgba(0,0,0,0.15);
}

/* Tour "下一步" button: ensure ≥44px on mobile */
@media (max-width: 640px) {
  [x-show="tourActive"] button {
    min-height: 44px !important;
  }
}

/* Mobile sub-tab buttons: ≥44px touch target */
@media (max-width: 768px) {
  .tablet-tabs button,
  .mobile-tabs button {
    min-height: 44px;
    min-width: 44px;
  }
}

/* Refresh/close icon buttons: ≥44px via padding */
@media (max-width: 768px) {
  .card button[class*="p-1"],
  .card button[class*="p-1.5"],
  .card button[class*="p-0.5"] {
    min-width: 44px;
    min-height: 44px;
  }
}


/* === v5.30.6: mobile-fullscreen with tab bars preserved === */
/* User feedback: "tab 不能 hide 掉，得 AI Agent 选择 UI 在 tab 下方固定住"
 * - Keep topbar (top status, 56px) + tablet-tabs (sticky sub-tabs, 59px) visible
 * - Keep mobile-tabs (fixed bottom, 58px) visible
 * - chat-container / office-container fill the gap between top bars and bottom bar
 * - Only hide .sidebar (desktop-only, irrelevant on mobile)
 */
body.mobile-fullscreen .sidebar {
  display: none !important;
}
body.mobile-fullscreen .chat-container,
body.mobile-fullscreen #office-container {
  position: fixed !important;
  top: calc(env(safe-area-inset-top, 0px) + 56px + 59px) !important;  /* topbar + tablet-tabs */
  left: 0 !important;
  right: 0 !important;
  bottom: calc(env(safe-area-inset-bottom, 0px) + 58px + var(--kb-offset, 0px)) !important;  /* mobile-tabs + iOS keyboard */
  width: 100vw !important;
  height: auto !important;  /* let top/bottom define height */
  border-radius: 0 !important;
  border: none !important;
  z-index: 50 !important;  /* below tab bars (z:50+) so they sit on top */
  display: flex !important;
  flex-direction: column !important;
  padding-top: 8px !important;
  padding-bottom: 8px !important;
  background: var(--bg) !important;
  transition: bottom 0.15s ease-out !important;  /* v5.30.8: smooth keyboard lift */
}

/* Mobile chat internals */
@media (max-width: 1024px) {
  body.mobile-fullscreen .chat-messages {
    flex: 1 !important;
    min-height: 0 !important;
    overflow-y: auto !important;
    -webkit-overflow-scrolling: touch !important;
    overscroll-behavior-y: contain !important;
    touch-action: pan-y !important;
  }
  body.mobile-fullscreen .chat-container > div:last-child {
    flex-shrink: 0 !important;
    padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 8px) !important;
    background: var(--surface) !important;
    border-top: 1px solid var(--border) !important;
  }
  body.mobile-fullscreen .chat-container > div:first-child {
    flex-shrink: 0 !important;
    overflow-x: auto !important;
    -webkit-overflow-scrolling: touch !important;
  }
}

/* === v5.29.0 bug #1 fix: iOS Safari input focus protection === */
@media (max-width: 1024px) {
  body.mobile-fullscreen .chat-container textarea,
  body.mobile-fullscreen .chat-container input {
    font-size: 16px !important;
  }
  body.mobile-fullscreen .chat-container textarea:focus {
    /* iOS Safari toolbar (~50px) + status bar (~38px) ≈ 88px on notched devices.
     * scrollIntoView parks textarea below both, preventing the v5.28.15 "void above". */
    scroll-margin-top: calc(env(safe-area-inset-top, 0px) + 88px);
  }
}
