diff --git a/README.md b/README.md index 888b5c039dc7e290052473443e46b61baf798ba4..2660e41f7c564f60bfd5c4c555123acbc6a8d7ba 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,165 @@ --- -title: Perch Design -emoji: 🏃 -colorFrom: red -colorTo: yellow +title: 栖木 Perch · Warm Paper 设计系统 +emoji: 🎨 +colorFrom: yellow +colorTo: red sdk: static pinned: false +license: mit +short_description: 像纸一样温暖、像工具一样安静的界面语言 --- -Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference +# 🎨 perch-design + +### 一套像纸一样温暖、像工具一样安静的界面语言。 + +> 大多数 AI 应用长这样:纯白背景 + 蓝紫渐变 + 冷冰冰的圆角。 +> 那是"工具"的语言,不是"伙伴"的语言。 +> +> 栖木选了**暖纸**——纸张泛黄的白、墨水的深棕、陶土橙的强调色。 +> 用户要长时间盯着它,**暖色比冷色更不容易疲劳**。 + +[栖木 Perch](https://huggingface.co/datasets/hongcoding/perch) 的完整设计系统 · 48 个 CSS 文件 · MIT 开源 + +--- + +## ✨ 三个设计原则 + +| 原则 | 含义 | 体现 | +|---|---|---| +| **安静优先** | 界面不抢注意力 | 低饱和、少动画、无渐变噪点 | +| **内容为王** | 结构和排版服务于阅读 | 衬线标题 + 无衬线正文 | +| **物理感** | 元素像真的纸/玻璃 | 柔和阴影、毛玻璃、微圆角 | + +--- + +## 🎨 调色板(一眼看懂) + +``` +┌─────────────────────────────────────────────────────────┐ +│ 暖纸底 #faf9f5 卡片 #f0eee6 凹陷 #e8e5db │ +│ 墨水 #1f1e1b 次要 #6b6862 提示 #9c988d │ +│ 陶土橙 #d97757 ← 唯一的强调色(不滥用) │ +└─────────────────────────────────────────────────────────┘ +``` + +**只有一个强调色**。大多数界面之所以"脏",就是因为用了太多颜色。 +栖木只用一个陶土橙,其余全靠中性色的层次关系。 + +**深色模式**不是简单反色——是重新调的一套: +暖纸 `#faf9f5` → 炭黑 `#262521`,橙 `#d97757` → `#e08a6e`(深色下略提亮)。 + +--- + +## 📦 三种用法 + +### 1. 直接引入(最快) + +```html + + + +``` + +### 2. 只取令牌(最灵活) + +```css +:root { + --bg: #faf9f5; + --text: #1f1e1b; + --accent: #d97757; + /* ... */ +} +``` + +### 3. 看效果(最直观) + +打开 `preview/index.html` —— 一个零依赖的组件预览页。 + +--- + +## 🔧 主题切换 + +```html + + + + + + + + +``` + +```css +/* 令牌文件里三套定义并存: + 1) @media (prefers-color-scheme: dark) → 跟随系统 + 2) [data-theme="light"] → 显式浅色 + 3) [data-theme="dark"] → 显式深色 + 顺序保证显式覆盖能盖过系统偏好。 */ +``` + +--- + +## 📐 设计令牌速查 + +| 类别 | 令牌 | 值 | +|---|---|---| +| **圆角** | `--radius-control` | 10px | +| | `--radius-card` | 14px | +| | `--radius-float` | 16px | +| **阴影** | `--shadow-float` | `0 4px 24px rgba(31,30,27,0.08)` | +| **毛玻璃** | `--glass` / `--glass-blur` | 85% 暖纸 + 20px 模糊 | +| **动效** | `--ease` / `--dur` | 快进慢出 / 150ms | +| **字体** | `--font-serif` | Source Serif 4 | +| | `--font-sans` | Inter | +| | `--font-mono` | JetBrains Mono | + +--- + +## 🗂️ 文件地图 + +``` +perch-design/ +├── tokens/ +│ └── theme.css 全局令牌 + 三套主题 + 排版基线 +├── css/ 48 个模块样式 +│ ├── chat.css 对话区 +│ ├── composer.css 输入区(思考滑块) +│ ├── markdown.css Markdown 渲染 +│ ├── materials.css 材质 +│ ├── screensaver.css 待机屏保 +│ └── ... 各功能面板 +├── docs/ +│ └── design-system.md ★ 完整设计文档(先读这个) +└── preview/ + └── index.html 零依赖预览页 +``` + +--- + +## ♿ 可访问性 + +- 正文对背景对比度 **≥ 7:1**(WCAG AAA) +- 键盘导航有可见焦点环 +- 尊重 `prefers-reduced-motion` +- 正文字号 14.5px 起(不玩 12px 小字) + +--- + +## 🔗 相关项目 + +| 项目 | 说明 | 链接 | +|---|---|---| +| **栖木 Perch**(应用) | macOS 本地优先 AI 工作台 | https://huggingface.co/datasets/hongcoding/perch | +| **perch-ultrafast**(框架) | 混合流 + Ultrafast:首字 1s → 80ms | https://huggingface.co/hongcoding/perch-ultrafast | +| **perch-gpu**(工具) | 本机 GPU 加速:冷启动 5s → 0.08s | https://huggingface.co/hongcoding/perch-gpu | +| **perch-design**(本库) | 就是这套设计系统 | https://huggingface.co/hongcoding/perch-design | + +## 📜 许可 + +MIT —— 随便用,注明出处即可。 + +--- + +**🎨 好的界面不抢戏。它只是安静地把内容递到你面前。** diff --git a/css/App.css b/css/App.css new file mode 100644 index 0000000000000000000000000000000000000000..e4d3ed206f79971ce5f4e84767769c90da92c1e1 --- /dev/null +++ b/css/App.css @@ -0,0 +1,305 @@ +/* Warm Paper 外壳布局 + 通用按钮(颜色一律走 theme.css 令牌) */ + +.shell { + display: flex; + height: 100vh; + overflow: hidden; /* 整窗禁止滚动:只有消息流内部滚动 */ + background: var(--bg); +} + +/* ---------- 侧栏 ---------- */ +/* 顶部 40px 安全边距:主窗 titleBarStyle=overlay 后 traffic light 悬浮在内容上, + 侧栏品牌位必须让开左上角(实测遮挡区约高 20px,留 40px 余量)。 + .brand 带 data-tauri-drag-region,作为窗口拖拽区。 */ +.sidebar { + width: 232px; + flex-shrink: 0; + display: flex; + flex-direction: column; + padding: 40px 16px 20px; + border-right: 1px solid var(--border); +} + +.brand { + display: flex; + align-items: center; + gap: 10px; + padding: 0 8px 28px; + cursor: default; +} + +/* 品牌标:内联 SVG 鸟巢(Brand.tsx),陶土橙单线,不再用色块文字标 */ +.brand-mark { + display: inline-flex; + align-items: center; + color: var(--accent); +} + +.brand-name { + font-family: var(--font-serif); + font-size: 16px; + font-weight: 600; +} + +.sidebar nav { + display: flex; + flex-direction: column; + gap: 2px; + flex: 1; +} + +.nav-item { + position: relative; + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 1px; + padding: 9px 12px; + border: none; + border-radius: var(--radius-control); + background: transparent; + color: var(--text); + font-family: inherit; + font-size: 14px; + text-align: left; + cursor: pointer; + transition: background-color var(--dur) var(--ease); +} + +.nav-item:hover { + background: var(--bg-elevated); +} + +.nav-item.is-active { + background: var(--accent-soft); +} + +/* 激活态左侧 2px accent 竖条(Claude 式);非激活时淡出 */ +.nav-item::before { + content: ""; + position: absolute; + left: 0; + top: 8px; + bottom: 8px; + width: 2px; + border-radius: 1px; + background: var(--accent); + opacity: 0; + transition: opacity var(--dur) var(--ease); +} + +.nav-item.is-active::before { + opacity: 1; +} + +.nav-label { + font-weight: 500; +} + +/* 设置项:行内齿轮图标 + 文字 */ +.nav-row { + display: inline-flex; + align-items: center; + gap: 8px; + color: var(--text); +} + +.nav-row svg { + color: var(--text-secondary); +} + +.nav-hint { + font-size: 12px; + color: var(--text-tertiary); +} + +.sidebar-foot { + padding: 8px 12px; + font-size: 12px; + color: var(--text-tertiary); +} + +/* ---------- 主区 ---------- */ +.content { + flex: 1; + min-width: 0; + min-height: 0; /* 关键:允许子项收缩,消息流才能在视口内滚动 */ + display: flex; + flex-direction: column; +} + +/* ---------- 占位板块空态 ---------- */ +.placeholder { + flex: 1; + display: flex; + flex-direction: column; + justify-content: center; + align-items: flex-start; + gap: 12px; + max-width: 620px; + padding: 48px 80px; +} + +.placeholder h1 { + font-size: 32px; +} + +.placeholder-sub { + margin: 0; + font-size: 16px; + color: var(--text-secondary); +} + +.placeholder-note { + margin: 0; + font-size: 13px; + color: var(--text-tertiary); +} + +/* ---------- 按钮 ---------- */ +.btn-primary { + height: 40px; + padding: 0 22px; + border: none; + border-radius: var(--radius-control); + background: var(--accent); + color: var(--bg); + font-family: inherit; + font-size: 14px; + font-weight: 500; + cursor: pointer; + transition: background-color var(--dur) var(--ease); +} + +.btn-primary:hover { + filter: brightness(0.94); +} + +.btn-primary:disabled, +.btn-secondary:disabled { + opacity: 0.6; + cursor: default; + filter: none; +} + +.btn-secondary { + height: 36px; + padding: 0 16px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: transparent; + color: var(--text); + font-family: inherit; + font-size: 13.5px; + cursor: pointer; + transition: background-color var(--dur) var(--ease); +} + +.btn-secondary:hover { + background: var(--bg-elevated); +} + +.icon-btn { + display: inline-grid; + place-items: center; + width: 28px; + height: 28px; + border: none; + border-radius: var(--radius-control); + background: transparent; + color: var(--text-tertiary); + cursor: pointer; + transition: background-color var(--dur) var(--ease); +} + +.icon-btn:hover { + background: var(--bg-elevated); + color: var(--text); +} + +.icon-btn-danger:hover { + background: var(--accent-soft); + color: var(--danger); +} + +/* ---------- 卡片 hover 统一(design-system §6:克制的 150ms) ---------- + 描边加深 + 极轻上浮 1px;只作用于内容卡片,覆盖看板/诊断/技能/专家/表单。 */ +.metric-card, +.panel, +.diag-card, +.diag-trash, +.skill-card, +.mcp-card, +.cloud-card, +.expert-card { + transition: + border-color var(--dur) var(--ease), + transform var(--dur) var(--ease); +} + +.metric-card:hover, +.panel:hover, +.diag-card:hover, +.diag-trash:hover, +.skill-card:hover, +.mcp-card:hover, +.cloud-card:hover, +.expert-card:hover { + border-color: color-mix(in srgb, var(--border) 55%, var(--text-tertiary)); + transform: translateY(-1px); +} + +/* 选中态的专家卡保持 accent 描边,不被 hover 色盖掉 */ +.expert-card.is-active, +.expert-card.is-active:hover { + border-color: var(--accent); +} + +/* 个人账户(契约 40A) */ +.account-redeem { display: flex; gap: 6px; align-items: center; } +.account-redeem input { + padding: 6px 10px; border: 1px solid var(--line); border-radius: 8px; + background: var(--surface); color: var(--ink-1); font-size: 12px; width: 140px; + font-family: ui-monospace, monospace; +} +.account-redeem button { + padding: 6px 12px; border: 1px solid var(--accent); border-radius: 8px; + background: var(--accent-soft); color: var(--accent); font-size: 12px; cursor: pointer; +} +.account-redeem button:disabled { opacity: 0.5; cursor: default; } +.account-msg { font-size: 12px; color: var(--ink-2); margin: 6px 0; } + +/* Pro 门控(免费缩水) */ +.pro-gate { + display: flex; flex-direction: column; align-items: center; gap: 8px; + padding: 32px 20px; text-align: center; + border: 1px dashed var(--line); border-radius: 12px; + background: var(--surface-2); +} +.pro-gate-badge { + display: inline-flex; padding: 3px 12px; border-radius: 999px; + background: var(--accent-soft); color: var(--accent); font-weight: 600; font-size: 12px; +} +.pro-gate-text { font-size: 14px; color: var(--ink-1); margin: 0; } +.pro-gate-hint { font-size: 12px; color: var(--ink-3); margin: 0; } + +/* 底部状态条(契约 6E):常驻显示输出速度 + 缓存命中 */ +.stats-bar { + display: flex; align-items: center; gap: 12px; + padding: 4px 14px; border-top: 1px solid var(--line); + font-size: 11px; color: var(--ink-3); + background: var(--surface-2); + flex: 0 0 auto; +} +.stats-dot { + width: 6px; height: 6px; border-radius: 50%; + background: var(--ink-4); flex: 0 0 auto; +} +.stats-dot.is-live { + background: var(--accent); + animation: stats-pulse 1.2s ease-in-out infinite; +} +@keyframes stats-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.35; } } +.stats-item { white-space: nowrap; font-variant-numeric: tabular-nums; } +.stats-spacer { flex: 1; } +.stats-hint { color: var(--ink-4); font-size: 10px; } diff --git a/css/acceptance.css b/css/acceptance.css new file mode 100644 index 0000000000000000000000000000000000000000..bc280d4dfd50a0f77a5c06d5181e7692cdcdd716 --- /dev/null +++ b/css/acceptance.css @@ -0,0 +1,238 @@ +/* 小栖验收卡(契约 19A A2)——Warm Paper 全令牌,语义色只出现在状态语境。 + 规则来自 docs/design-system.md:1px 描边、无阴影、克制 150ms 过渡。 */ + +.acc-card { + display: flex; + flex-direction: column; + gap: 10px; + padding: 12px 14px; + border: 1px solid var(--border); + border-left-width: 3px; + border-radius: var(--radius-card); + font-size: 13px; + line-height: 1.65; + /* 液态玻璃(2026-10-23 用户点名):半透明底 + 背景模糊 + 内侧高光, + 语义色以"雾"的浓度存在而非实心块;主窗口 WebView 支持 backdrop-filter + (坑位记录里的禁令只针对透明原生窗)。 */ + background: color-mix(in srgb, var(--bg-elevated) 72%, transparent); + backdrop-filter: blur(18px) saturate(140%); + -webkit-backdrop-filter: blur(18px) saturate(140%); + box-shadow: + inset 0 1px 0 color-mix(in srgb, var(--text) 5%, transparent), + inset 0 0 0 1px color-mix(in srgb, var(--text) 4%, transparent); + transition: background var(--dur) var(--ease); +} + +/* 语义色只染左侧状态条、徽章与玻璃雾浓度(克制) */ +.acc-card.is-success { + border-left-color: var(--success); + background: color-mix( + in srgb, + var(--success) 9%, + color-mix(in srgb, var(--bg-elevated) 74%, transparent) + ); +} +.acc-card.is-warning { + border-left-color: var(--warning); + background: color-mix( + in srgb, + var(--warning) 8%, + color-mix(in srgb, var(--bg-elevated) 74%, transparent) + ); +} +.acc-card.is-danger { + border-left-color: var(--danger); + background: color-mix( + in srgb, + var(--danger) 8%, + color-mix(in srgb, var(--bg-elevated) 74%, transparent) + ); +} +.acc-card.is-tertiary { + border-left-color: var(--text-tertiary); +} + +.acc-head { + display: flex; + align-items: center; + gap: 8px; + flex-wrap: wrap; +} + +.acc-badge { + display: inline-flex; + align-items: center; + height: 20px; + padding: 0 8px; + border-radius: var(--radius-chip); + font-size: 12px; + white-space: nowrap; + background: var(--bg-sunken); + color: var(--text-secondary); + transition: background var(--dur) var(--ease), color var(--dur) var(--ease); +} + +.acc-badge.is-success { + background: color-mix(in srgb, var(--success) 16%, transparent); + color: var(--success); +} + +.acc-badge.is-warning { + background: color-mix(in srgb, var(--warning) 18%, transparent); + color: var(--warning); +} + +.acc-badge.is-danger { + background: color-mix(in srgb, var(--danger) 14%, transparent); + color: var(--danger); +} + +.acc-badge.is-tertiary { + background: var(--bg-sunken); + color: var(--text-tertiary); +} + +.acc-title { + font-family: var(--font-serif); + font-size: 14px; + font-weight: 600; + color: var(--text); +} + +.acc-meta { + margin-left: auto; + color: var(--text-tertiary); + font-size: 11.5px; +} + +.acc-degraded { + margin: 0; + padding: 8px 10px; + border-left: 3px solid var(--warning); + border-radius: 0 var(--radius-chip) var(--radius-chip) 0; + background: color-mix(in srgb, var(--warning) 10%, transparent); + color: var(--text-secondary); + font-size: 12.5px; +} + +.acc-task { + margin: 0; + color: var(--text-secondary); + font-size: 12.5px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.acc-block { + display: flex; + flex-direction: column; + gap: 6px; +} + +.acc-block-title { + margin: 0; + color: var(--text-tertiary); + font-family: inherit; + font-size: 11.5px; + font-weight: 600; + letter-spacing: 0.04em; + text-transform: none; +} + +/* 缺口清单 */ +.acc-gaps, +.acc-evidence, +.acc-plan { + margin: 0; + padding: 0; + list-style: none; + display: flex; + flex-direction: column; + gap: 4px; +} + +.acc-gaps li { + position: relative; + padding-left: 14px; + color: var(--text); +} + +.acc-gaps li::before { + content: ""; + position: absolute; + left: 2px; + top: 9px; + width: 5px; + height: 5px; + border-radius: 50%; + background: var(--warning); +} + +/* 证据行:小号等宽,单条最多三行(长片段在后端已截到 3KB) */ +.acc-evidence li { + padding: 6px 8px; + border-radius: var(--radius-chip); + background: var(--bg-sunken); + color: var(--text-secondary); + font-family: var(--font-mono); + font-size: 11.5px; + line-height: 1.6; + white-space: pre-wrap; + word-break: break-word; + max-height: 4.8em; + overflow: hidden; +} + +/* 分步方案:序号 + 工具 chip + 说明 */ +.acc-plan li { + display: flex; + align-items: baseline; + gap: 8px; + padding: 6px 8px; + border-radius: var(--radius-chip); + background: var(--bg-sunken); +} + +.acc-tool { + flex-shrink: 0; + padding: 1px 6px; + border-radius: var(--radius-chip); + background: var(--accent-soft); + color: var(--accent); + font-family: var(--font-mono); + font-size: 11px; + white-space: nowrap; +} + +.acc-step { + color: var(--text); +} + +/* 一键派发(16A 同款次按钮基调) */ +.acc-dispatch { + align-self: flex-start; + display: inline-flex; + align-items: center; + gap: 6px; + height: 30px; + padding: 0 12px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: transparent; + color: var(--text); + font-family: inherit; + font-size: 12.5px; + cursor: pointer; + transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease); +} + +.acc-dispatch:hover { + background: var(--accent-soft); + border-color: var(--accent); +} + +.acc-dispatch:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} diff --git a/css/account.css b/css/account.css new file mode 100644 index 0000000000000000000000000000000000000000..5862bc76d05cbdd257f14b8bd09ccc12f233b088 --- /dev/null +++ b/css/account.css @@ -0,0 +1,368 @@ +/* 个人账户 / 变现(契约 40A)——Warm Paper 令牌,无硬编码色,克制动效。 + 账户卡 · token 用量看板 · Alipay 解锁区 · 免费缩水「Pro 解锁」占位卡。 + 色彩全部走 theme.css 的 var(--*),深浅色两套自动跟随;不引任何硬编码色。 */ + +/* ── 通用按钮(账户区自成一体,不依赖 mcp.css 的 field/btn 类)───── */ +.account-btn { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 8px 15px; + border: 1px solid transparent; + border-radius: var(--radius-control); + background: var(--accent); + color: var(--bg); + font-family: inherit; + font-size: 13px; + font-weight: 600; + line-height: 1.2; + cursor: pointer; + transition: filter var(--dur) var(--ease), transform var(--dur) var(--ease); +} +.account-btn:hover:not(:disabled) { + filter: brightness(1.05); +} +.account-btn:active:not(:disabled) { + transform: translateY(1px); +} +.account-btn:disabled { + opacity: 0.55; + cursor: default; +} + +.account-btn-ghost { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 8px 15px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: transparent; + color: var(--text-secondary); + font-family: inherit; + font-size: 13px; + font-weight: 500; + line-height: 1.2; + cursor: pointer; + transition: border-color var(--dur) var(--ease), color var(--dur) var(--ease); +} +.account-btn-ghost:hover:not(:disabled) { + border-color: var(--text-tertiary); + color: var(--text); +} +.account-btn-ghost:disabled { + opacity: 0.55; + cursor: default; +} + +/* 载入小转圈(Loader2 用):克制、可被系统「减少动态效果」关掉。 */ +.spin { + animation: perch-spin 900ms linear infinite; +} +@keyframes perch-spin { + to { + transform: rotate(360deg); + } +} +@media (prefers-reduced-motion: reduce) { + .spin { + animation: none; + } + .account-btn, + .account-btn-ghost, + .token-bar-fill { + transition: none; + } +} + +/* ── 账户卡 ─────────────────────────────────────────────────── */ +.account-card { + border: 1px solid var(--border); + border-radius: var(--radius-card); + background: var(--bg-elevated); + padding: 16px 18px; +} +.account-card-top { + display: flex; + align-items: center; + gap: 10px; + margin-bottom: 8px; +} +.account-tier { + display: inline-flex; + align-items: center; + padding: 3px 12px; + border-radius: var(--radius-chip); + font-family: var(--font-serif); + font-size: 15px; + font-weight: 600; + letter-spacing: 0.01em; +} +.account-tier.is-free { + background: var(--bg-sunken); + color: var(--text-secondary); +} +.account-tier.is-pro { + background: var(--accent-soft); + color: var(--accent); +} +.account-admin { + padding: 2px 9px; + border: 1px solid var(--border); + border-radius: var(--radius-chip); + font-size: 11px; + color: var(--text-secondary); +} +.account-card-desc { + margin: 0; + color: var(--text); + font-size: 13.5px; + line-height: 1.6; +} +.account-card-meta { + margin: 6px 0 0; + color: var(--text-tertiary); + font-size: 12px; +} + +/* ── token 用量看板 ─────────────────────────────────────────── */ +.token-board { + margin-top: 12px; + border: 1px solid var(--border); + border-radius: var(--radius-card); + background: var(--bg); + padding: 16px 18px; +} +.token-board-head { + display: flex; + align-items: baseline; + justify-content: space-between; + gap: 12px; +} +.token-board-title { + font-family: var(--font-serif); + font-size: 15px; + font-weight: 600; + color: var(--text); +} +.token-board-total { + font-family: var(--font-mono); + font-size: 13px; + color: var(--text-secondary); +} +.token-bar { + margin: 12px 0 8px; + height: 8px; + border-radius: 999px; + background: var(--bg-sunken); + overflow: hidden; +} +.token-bar-fill { + height: 100%; + border-radius: 999px; + background: var(--accent); + transition: width var(--dur) var(--ease); +} +.token-board-caption { + margin: 0; + color: var(--text-tertiary); + font-size: 11.5px; + line-height: 1.55; +} +.token-board-caption strong { + color: var(--text-secondary); + font-weight: 600; +} +.token-grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 10px; + margin: 14px 0 0; +} +.token-cell { + border: 1px solid var(--border); + border-radius: var(--radius-chip); + background: var(--bg-elevated); + padding: 9px 11px; +} +.token-cell dt { + margin: 0; + color: var(--text-tertiary); + font-size: 11px; +} +.token-cell dd { + margin: 3px 0 0; + font-family: var(--font-mono); + font-size: 15px; + color: var(--text); +} + +/* ── Alipay 解锁区 ──────────────────────────────────────────── */ +.unlock-block { + margin-top: 12px; + border: 1px solid var(--border); + border-radius: var(--radius-card); + background: var(--bg-elevated); + padding: 16px 18px; +} +.unlock-title { + margin: 0 0 12px; + font-family: var(--font-serif); + font-size: 15px; + font-weight: 600; +} +.unlock-row { + display: flex; + gap: 18px; + align-items: flex-start; + flex-wrap: wrap; +} +.unlock-qr { + margin: 0; + display: flex; + flex-direction: column; + align-items: center; + gap: 8px; +} +.unlock-qr-img { + width: 148px; + height: 148px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: var(--bg); + padding: 6px; +} +.unlock-qr-cap { + color: var(--text-tertiary); + font-size: 11px; +} +.unlock-form { + flex: 1; + min-width: 220px; + display: flex; + flex-direction: column; + gap: 10px; +} +.unlock-price { + margin: 0; + font-family: var(--font-serif); + font-size: 14px; + font-weight: 600; + color: var(--accent); +} +.unlock-field { + display: flex; + flex-direction: column; + gap: 5px; +} +.unlock-label { + color: var(--text-secondary); + font-size: 12px; +} +.unlock-input { + padding: 9px 12px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: var(--bg); + color: var(--text); + font-family: var(--font-mono); + font-size: 13px; + letter-spacing: 0.04em; +} +.unlock-input:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 1px; +} +.unlock-input:disabled { + opacity: 0.6; + cursor: default; +} +.unlock-actions { + display: flex; + gap: 10px; + flex-wrap: wrap; +} +.unlock-honest { + margin: 14px 0 0; + padding: 11px 13px; + border-left: 3px solid var(--warning); + border-radius: var(--radius-chip); + background: var(--bg-sunken); + color: var(--text-secondary); + font-size: 11.5px; + line-height: 1.65; +} +.unlock-honest strong { + color: var(--text); + font-weight: 600; +} + +/* ── 免费缩水「Pro 解锁」占位卡(AssistantPanel / 看板等复用)── */ +.pro-lock { + display: flex; + flex-direction: column; + align-items: center; + gap: 10px; + margin: 8px; + padding: 30px 24px; + border: 1px dashed var(--border); + border-radius: var(--radius-card); + background: var(--bg-elevated); + text-align: center; +} +.pro-lock-badge { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 3px 11px; + border-radius: var(--radius-chip); + background: var(--accent-soft); + color: var(--accent); + font-size: 11.5px; + font-weight: 600; +} +.pro-lock-title { + margin: 0; + font-family: var(--font-serif); + font-size: 16px; + font-weight: 600; + color: var(--text); +} +.pro-lock-desc { + margin: 0; + max-width: 380px; + color: var(--text-secondary); + font-size: 13px; + line-height: 1.65; +} +.pro-lock-hint { + margin: 2px 0 0; + max-width: 380px; + color: var(--text-tertiary); + font-size: 11px; + line-height: 1.6; +} + +/* ── 置灰的 Pro-only 子项(自定义专家 / 看板全量项)───────────── */ +.is-pro-locked { + opacity: 0.5; + filter: grayscale(0.85); + pointer-events: none; + user-select: none; +} +.pro-gate-note { + display: inline-flex; + align-items: center; + gap: 6px; + margin: 8px 0 0; + padding: 8px 12px; + border: 1px dashed var(--border); + border-radius: var(--radius-chip); + background: var(--bg-elevated); + color: var(--text-secondary); + font-size: 12px; +} +.pro-gate-note .account-btn { + padding: 5px 11px; + font-size: 12px; +} diff --git a/css/agent.css b/css/agent.css new file mode 100644 index 0000000000000000000000000000000000000000..aaa818412f41f2ff18b937f31f6410f2f6bb0e89 --- /dev/null +++ b/css/agent.css @@ -0,0 +1,359 @@ +/* Agent 面板(Phase 5B:能操控电脑的手):Warm Paper 令牌配色,与全站一致。 + 只服务 AgentPanel.tsx;样式独立不外溢。 */ + +.agent-panel { + flex: 1; + min-width: 0; + display: flex; + flex-direction: column; + padding: 26px 32px 20px; + gap: 14px; + overflow: hidden; +} + +.agent-head h1 { + font-family: var(--font-serif); + font-size: 26px; + font-weight: 600; +} + +.agent-sub { + margin-top: 4px; + color: var(--text-secondary); + font-size: 14px; +} + +.agent-sub-dim { + color: var(--text-tertiary); +} + +/* 常驻安全说明(琥珀色细条,温和不吓人) */ +.agent-safety { + padding: 10px 14px; + border: 1px solid var(--border); + border-left: 3px solid var(--warning); + border-radius: var(--radius-card); + background: var(--bg-elevated); + color: var(--text-secondary); + font-size: 12.5px; + line-height: 1.6; +} + +/* 输入区 */ +.agent-inputs { + display: flex; + flex-direction: column; + gap: 10px; +} + +.agent-model { + align-self: flex-start; + min-width: 240px; + padding: 7px 12px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: var(--bg); + color: var(--text); + font-family: var(--font-mono); + font-size: 12.5px; +} + +.agent-task { + width: 100%; + resize: vertical; + min-height: 64px; + padding: 12px 14px; + border: 1px solid var(--border); + border-radius: var(--radius-card); + background: var(--bg); + color: var(--text); + font-family: var(--font-sans); + font-size: 14px; + line-height: 1.6; +} + +.agent-task:focus, +.agent-model:focus { + outline: none; + border-color: var(--accent); + box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent-soft) 65%, transparent); +} + +.agent-actions { + display: flex; + gap: 10px; + align-items: center; +} + +.agent-run, +.agent-cancel, +.agent-audit, +.agent-allow, +.agent-deny, +.agent-audit-close, +.agent-tool-copy { + padding: 8px 18px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: var(--bg); + color: var(--text); + font-size: 13.5px; + cursor: pointer; + transition: background-color var(--dur) var(--ease); +} + +.agent-run, +.agent-allow { + background: var(--accent); + border-color: var(--accent); + color: var(--bg); +} + +.agent-run:disabled { + opacity: 0.55; + cursor: default; +} + +.agent-run:not(:disabled):hover, +.agent-allow:hover { + filter: brightness(1.05); +} + +.agent-cancel:hover, +.agent-audit:hover, +.agent-audit-close:hover, +.agent-tool-copy:hover { + background: var(--bg-elevated); +} + +.agent-empty { + color: var(--text-secondary); + font-size: 13px; +} + +/* ── 工具调用卡片(时间线主角)───────────────────────────────────── */ + +.agent-tool-card { + border: 1px solid var(--border); + border-left: 3px solid var(--border); + border-radius: var(--radius-card); + background: var(--bg-elevated); + padding: 10px 14px; + display: flex; + flex-direction: column; + gap: 8px; +} + +/* 🟢 自动执行:绿色细条;🟡 需确认:琥珀细条 */ +.agent-tool-card.level-green { + border-left-color: var(--success); +} + +.agent-tool-card.level-yellow { + border-left-color: var(--warning); +} + +.agent-tool-card.is-pending { + background: var(--accent-soft); + border-color: var(--accent); + border-left-color: var(--accent); +} + +.agent-tool-card.is-failed { + border-left-color: var(--danger); +} + +.agent-tool-head { + display: flex; + align-items: baseline; + gap: 8px; + flex-wrap: wrap; +} + +/* 衬线小标题:「读文件」「执行命令」 */ +.agent-tool-title { + font-family: var(--font-serif); + font-size: 15px; + font-weight: 600; + color: var(--text); +} + +/* 状态徽章:与全站徽章同尺寸同字重(2px 8px / 12px / 500 / pill) */ +.agent-tool-badge { + font-size: 12px; + font-weight: 500; + padding: 2px 8px; + border-radius: 999px; + border: 1px solid var(--border); + color: var(--text-secondary); + white-space: nowrap; +} + +.agent-tool-badge.is-green { + color: var(--success); + border-color: var(--success); +} + +.agent-tool-badge.is-yellow { + color: var(--warning); + border-color: var(--warning); +} + +.agent-tool-summary { + font-size: 13px; + color: var(--text-secondary); + min-width: 0; +} + +.agent-tool-status { + margin-left: auto; + font-size: 12px; + color: var(--text-tertiary); + white-space: nowrap; +} + +/* 参数原文(mono;命令原文/文件路径都在这里看清楚) */ +.agent-tool-args { + font-family: var(--font-mono); + font-size: 12px; + line-height: 1.6; + color: var(--text-secondary); + background: var(--bg-sunken); + border: 1px solid var(--border); + border-radius: var(--radius-chip); + padding: 8px 10px; + white-space: pre-wrap; + word-break: break-all; + max-height: 180px; + overflow-y: auto; +} + +.agent-tool-actions { + display: flex; + gap: 10px; +} + +.agent-tool-running { + font-size: 12.5px; + color: var(--text-tertiary); +} + +/* 危险命令被拦:人话提示(danger 红,仅指引不代执行) */ +.agent-tool-blocked { + font-size: 13px; + color: var(--danger); + border: 1px dashed var(--danger); + border-radius: var(--radius-chip); + padding: 6px 10px; +} + +/* 结果折叠区(mono、可复制) */ +.agent-tool-result { + border-top: 1px dashed var(--border); + padding-top: 6px; +} + +.agent-tool-result summary { + cursor: pointer; + font-size: 12.5px; + color: var(--text-secondary); + user-select: none; +} + +.agent-tool-result pre { + margin-top: 6px; + font-family: var(--font-mono); + font-size: 12px; + line-height: 1.6; + color: var(--text); + background: var(--bg-sunken); + border: 1px solid var(--border); + border-radius: var(--radius-chip); + padding: 8px 10px; + white-space: pre-wrap; + word-break: break-all; + max-height: 240px; + overflow-y: auto; +} + +.agent-tool-copy { + margin-top: 6px; + padding: 4px 12px; + font-size: 12px; +} + +/* ── 时间线 ─────────────────────────────────────────────────────── */ + +.agent-timeline { + flex: 1; + min-height: 120px; + overflow-y: auto; + display: flex; + flex-direction: column; + gap: 8px; + padding: 4px 2px; +} + +.agent-timeline-empty { + color: var(--text-tertiary); + font-size: 13.5px; +} + +.agent-item { + padding: 9px 13px; + border-radius: var(--radius-card); + border: 1px solid var(--border); + font-size: 13.5px; + line-height: 1.6; +} + +.agent-item-task { + align-self: flex-end; + background: var(--accent-soft); + border-color: transparent; + max-width: 78%; +} + +.agent-item-assistant { + background: var(--bg-elevated); +} + +.agent-item-notice { + color: var(--text-secondary); + border-style: dashed; +} + +.agent-item-notice.is-danger { + color: var(--danger); + border-color: var(--danger); +} + +/* ── 审计日志查看 ───────────────────────────────────────────────── */ + +.agent-audit-view { + max-height: 220px; + overflow-y: auto; + border: 1px solid var(--border); + border-radius: var(--radius-card); + background: var(--bg-sunken); + padding: 10px 14px; +} + +.agent-audit-title { + display: flex; + justify-content: space-between; + align-items: center; + font-size: 12px; + color: var(--text-secondary); + margin-bottom: 6px; + gap: 10px; +} + +.agent-audit-view pre { + font-family: var(--font-mono); + font-size: 11px; + line-height: 1.7; + color: var(--text-secondary); + white-space: pre-wrap; + word-break: break-all; +} diff --git a/css/assistant.css b/css/assistant.css new file mode 100644 index 0000000000000000000000000000000000000000..2cf3725c58a32cb1257459c4b20610121f29cae2 --- /dev/null +++ b/css/assistant.css @@ -0,0 +1,704 @@ +/* 常驻助理(契约 11A):面板 + 页签 + 设置区(Warm Paper,全令牌配色) */ + +/* ---------- 工作台根(页签条 + 内容区的纵向骨架) ---------- */ +.wb-root { + flex: 1; + min-width: 0; + min-height: 0; + display: flex; + flex-direction: column; +} + +.wb-body { + flex: 1; + min-width: 0; + min-height: 0; + display: flex; +} + +/* ---------- 页签(对话工作台最左第一位) ---------- */ +.wb-tabs { + display: flex; + align-items: center; + gap: 4px; + padding: 10px 16px 0; + border-bottom: 1px solid var(--border); + flex-shrink: 0; +} + +.wb-tab { + position: relative; + display: inline-flex; + align-items: center; + gap: 6px; + height: 32px; + padding: 0 12px; + border: none; + border-radius: var(--radius-control) var(--radius-control) 0 0; + background: transparent; + color: var(--text-secondary); + font-family: inherit; + font-size: 13px; + cursor: pointer; + transition: background-color var(--dur) var(--ease), color var(--dur) var(--ease); +} + +.wb-tab:hover { + background: var(--bg-elevated); + color: var(--text); +} + +.wb-tab.is-active { + background: var(--accent-soft); + color: var(--text); + font-weight: 600; +} + +.wb-tab:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +/* 主动观察红点(v1 占位:有未读观察结论时亮点) */ +.wb-tab-dot { + width: 7px; + height: 7px; + border-radius: 50%; + background: var(--danger); + flex-shrink: 0; +} + +/* ---------- 面板骨架 ---------- */ +.assistant-panel { + flex: 1; + min-width: 0; + min-height: 0; + display: flex; + flex-direction: column; +} + +/* ---------- 头部:状态灯 + 人设名 + 设置 ---------- */ +.assistant-head { + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; + padding: 20px 48px 14px; + border-bottom: 1px solid var(--border); + flex-shrink: 0; +} + +.assistant-id { + display: flex; + align-items: baseline; + gap: 10px; + min-width: 0; +} + +.assistant-name { + font-size: 18px; + margin: 0; +} + +.assistant-style { + font-size: 12px; + color: var(--text-tertiary); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.assistant-head-right { + display: flex; + align-items: center; + gap: 8px; + flex-shrink: 0; +} + +/* 驻场状态灯 */ +.assistant-light { + display: inline-flex; + align-items: center; + gap: 6px; + height: 28px; + padding: 0 10px; + border: 1px solid var(--border); + border-radius: var(--radius-chip); + background: transparent; + color: var(--text-secondary); + font-family: inherit; + font-size: 12px; + cursor: pointer; + transition: background-color var(--dur) var(--ease); +} + +.assistant-light:hover { + background: var(--bg-elevated); +} + +.assistant-light-dot { + width: 8px; + height: 8px; + border-radius: 50%; + background: var(--text-tertiary); + flex-shrink: 0; +} + +.assistant-light.is-resident .assistant-light-dot { + background: var(--success); +} + +.assistant-light.is-sleeping .assistant-light-dot { + background: var(--text-tertiary); +} + +.assistant-light.is-offline .assistant-light-dot { + background: var(--warning); +} + +/* 云端在线(契约 17A:API 模型,不占本机内存)——accent 点色区分本机驻留 */ +.assistant-light.is-cloud .assistant-light-dot { + background: var(--accent); +} + +.assistant-light.is-cloud { + color: var(--text-secondary); +} + +/* 专属助理徽标(契约 17A:对话页签里的专属模式) */ +.assistant-style.is-thread { + color: var(--accent); + font-weight: 500; +} + +/* 线程下拉(契约 17A:侧栏全局模式顶部的「全局 / 某会话」切换) */ +.assistant-thread { + display: inline-flex; + align-items: center; + gap: 6px; + font-size: 12px; + color: var(--text-tertiary); + flex-shrink: 0; +} + +.assistant-thread-label { + white-space: nowrap; +} + +.assistant-thread-select { + max-width: 200px; + height: 28px; + padding: 0 8px; + border: 1px solid var(--border); + border-radius: var(--radius-chip); + background: var(--bg-elevated); + color: var(--text-secondary); + font-family: inherit; + font-size: 12px; + cursor: pointer; +} + +.assistant-thread-select:disabled { + opacity: 0.5; + cursor: default; +} + +.assistant-settings-btn { + display: inline-flex; + align-items: center; + gap: 5px; + height: 28px; + padding: 0 10px; + border: 1px solid var(--border); + border-radius: var(--radius-chip); + background: transparent; + color: var(--text-secondary); + font-family: inherit; + font-size: 12px; + cursor: pointer; + transition: background-color var(--dur) var(--ease), color var(--dur) var(--ease); +} + +.assistant-settings-btn:hover { + background: var(--bg-elevated); + color: var(--text); +} + +/* ---------- 消息流 ---------- */ +.assistant-stream { + flex: 1; + min-height: 0; + overflow-y: auto; +} + +.assistant-stream-inner { + max-width: 760px; + width: 100%; + margin: 0 auto; + padding: 32px 48px 24px; + display: flex; + flex-direction: column; + gap: 28px; +} + +.ap-msg { + display: flex; + flex-direction: column; + gap: 8px; +} + +.ap-msg.is-user { + align-items: flex-end; +} + +.ap-msg-card { + max-width: 86%; + padding: 10px 16px; + border: 1px solid color-mix(in srgb, var(--accent) 16%, transparent); + border-radius: var(--radius-card); + background: var(--accent-soft); + font-size: 15px; + line-height: 1.7; + white-space: pre-wrap; + word-break: break-word; +} + +.ap-md { + font-size: 15px; + line-height: 1.75; + color: var(--text); +} + +/* 流式呼吸光标(design-system.md:1s 呼吸闪烁) */ +.ap-caret { + display: inline-block; + width: 7px; + height: 15px; + margin-left: 2px; + vertical-align: text-bottom; + background: var(--accent); + border-radius: 1px; + animation: ap-breathe 1s ease-in-out infinite; +} + +@keyframes ap-breathe { + 0%, + 100% { + opacity: 0.15; + } + 50% { + opacity: 0.9; + } +} + +@media (prefers-reduced-motion: reduce) { + .ap-caret { + animation: none; + opacity: 0.6; + } +} + +/* 只读工具迹(模型查了什么) */ +.ap-tools { + display: flex; + flex-wrap: wrap; + gap: 6px; +} + +.ap-tool-chip { + display: inline-flex; + align-items: center; + height: 22px; + padding: 0 8px; + border: 1px solid var(--border); + border-radius: var(--radius-chip); + background: var(--bg-elevated); + color: var(--text-secondary); + font-family: var(--font-mono); + font-size: 11px; +} + +.ap-error { + margin: 0; + color: var(--danger); + font-size: 13px; + line-height: 1.6; +} + +/* ---------- 空状态 ---------- */ +.assistant-empty { + display: flex; + flex-direction: column; + gap: 12px; + padding: 40px 0; +} + +.assistant-empty-title { + margin: 0; + font-family: var(--font-serif); + font-size: 22px; + font-weight: 600; + letter-spacing: -0.01em; +} + +.assistant-empty-hint { + margin: 0; + color: var(--text-secondary); + font-size: 14px; + line-height: 1.7; +} + +.assistant-suggestions { + display: flex; + flex-wrap: wrap; + gap: 8px; + margin-top: 8px; +} + +.assistant-suggestion { + height: 32px; + padding: 0 14px; + border: 1px solid var(--border); + border-radius: var(--radius-chip); + background: transparent; + color: var(--text); + font-family: inherit; + font-size: 13px; + cursor: pointer; + transition: background-color var(--dur) var(--ease); +} + +.assistant-suggestion:hover { + background: var(--bg-elevated); +} + +/* ---------- 输入区 ---------- */ +.assistant-composer-wrap { + flex-shrink: 0; + padding: 0 48px 24px; +} + +.assistant-composer { + max-width: 760px; + margin: 0 auto; + border: 1px solid var(--border); + border-radius: var(--radius-card); + background: var(--bg-sunken); + transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease); +} + +.assistant-composer:focus-within { + border-color: var(--accent); + box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 12%, transparent); +} + +.assistant-input { + display: block; + width: 100%; + padding: 12px 16px 4px; + border: none; + background: transparent; + color: var(--text); + font-family: inherit; + font-size: 15px; + line-height: 1.6; + resize: none; + outline: none; +} + +.assistant-input::placeholder { + color: var(--text-tertiary); +} + +.assistant-input:disabled { + color: var(--text-tertiary); +} + +.assistant-composer-bar { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + padding: 6px 10px 10px 16px; +} + +.assistant-hint { + font-size: 12px; + color: var(--text-tertiary); +} + +.assistant-send { + display: inline-flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + border: none; + border-radius: var(--radius-chip); + background: var(--accent); + color: #fff; + cursor: pointer; + transition: opacity var(--dur) var(--ease); + flex-shrink: 0; +} + +.assistant-send:hover:not(:disabled) { + opacity: 0.9; +} + +.assistant-send:disabled { + opacity: 0.4; + cursor: default; +} + +.assistant-send:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +.assistant-send-spin { + width: 13px; + height: 13px; + border: 2px solid color-mix(in srgb, #fff 45%, transparent); + border-top-color: #fff; + border-radius: 50%; + animation: ap-spin 0.8s linear infinite; +} + +@keyframes ap-spin { + to { + transform: rotate(360deg); + } +} + +/* ---------- 设置区(AssistantSettings,Settings.tsx 挂载) ---------- */ +.asst-set-row { + display: flex; + flex-direction: column; + gap: 8px; + margin-bottom: 20px; +} + +.asst-set-row:last-child { + margin-bottom: 0; +} + +.asst-set-label { + font-size: 13px; + font-weight: 600; + color: var(--text); +} + +.asst-set-hint { + margin: 0; + font-size: 12px; + color: var(--text-secondary); + line-height: 1.6; +} + +/* 驻场档四选:每档一个卡片,卡下方明示内存成本 */ +.asst-residency-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); + gap: 10px; +} + +.asst-residency-card { + display: flex; + flex-direction: column; + gap: 6px; + padding: 12px 14px; + border: 1px solid var(--border); + border-radius: var(--radius-card); + background: transparent; + text-align: left; + font-family: inherit; + cursor: pointer; + transition: background-color var(--dur) var(--ease), border-color var(--dur) var(--ease); +} + +.asst-residency-card:hover { + background: var(--bg-elevated); +} + +.asst-residency-card.is-active { + border-color: var(--accent); + background: var(--accent-soft); +} + +.asst-residency-card:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +.asst-residency-name { + font-size: 13px; + font-weight: 600; + color: var(--text); +} + +.asst-residency-cost { + font-size: 12px; + color: var(--text-secondary); + line-height: 1.55; +} + +/* 人设编辑 */ +.asst-persona-fields { + display: flex; + flex-direction: column; + gap: 10px; +} + +.asst-field { + display: flex; + flex-direction: column; + gap: 4px; +} + +.asst-field-label { + font-size: 12px; + color: var(--text-secondary); +} + +.asst-input, +.asst-textarea { + width: 100%; + padding: 8px 12px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: var(--bg-sunken); + color: var(--text); + font-family: inherit; + font-size: 14px; + line-height: 1.6; + outline: none; + transition: border-color var(--dur) var(--ease); +} + +.asst-textarea { + min-height: 120px; + resize: vertical; +} + +.asst-input:focus, +.asst-textarea:focus { + border-color: var(--accent); +} + +.asst-actions { + display: flex; + align-items: center; + gap: 10px; +} + +.asst-note { + font-size: 12px; + color: var(--text-secondary); +} + +.asst-note.is-error { + color: var(--danger); +} + +.asst-note.is-ok { + color: var(--success); +} + +/* ── 「求助大脑」(契约 11B 补充二)──────────────────── */ +.assistant-brain { + height: 30px; + padding: 0 12px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: transparent; + color: var(--text-secondary); + font-family: inherit; + font-size: 12.5px; + cursor: default; + transition: background-color var(--dur) var(--ease), + border-color var(--dur) var(--ease); +} +.assistant-brain:hover:not(:disabled) { + background: var(--accent-soft); + border-color: var(--accent); + color: var(--text); +} +.assistant-brain:disabled { + opacity: 0.45; +} +.ap-msg-brain-tag { + display: inline-block; + margin-bottom: 4px; + padding: 1px 8px; + border-radius: 99px; + background: var(--accent-soft); + color: var(--accent); + font-size: 11px; + font-weight: 500; +} + +/* ── 「发给主对话」(契约 16A)────────────────────── */ +.ap-dispatch { + align-self: flex-start; + margin-top: 6px; + height: 26px; + padding: 0 10px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: transparent; + color: var(--text-tertiary); + font-family: inherit; + font-size: 12px; + cursor: default; + transition: background-color var(--dur) var(--ease), + border-color var(--dur) var(--ease), color var(--dur) var(--ease); +} +.ap-dispatch:hover { + background: var(--accent-soft); + border-color: var(--accent); + color: var(--accent); +} + +/* ──契约 22A 意图徽章 + 建议 chip ── + * 徽章:12px 衬线 tertiary 小字(不吵);chip:单个、贴在消息下方、 + * hover 说「小栖猜你想…」——一律需点击,意图只影响建议不自动执行。 */ +.ap-msg-meta { + display: flex; + align-items: center; + gap: 8px; +} + +.ap-intent-badge { + font-family: var(--font-serif); + font-size: 12px; + line-height: 1.4; + color: var(--text-tertiary); +} + +.ap-intent-chip { + display: inline-flex; + align-items: center; + height: 26px; + padding: 0 10px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: var(--bg-elevated); + color: var(--text-secondary); + font-family: inherit; + font-size: 12px; + cursor: pointer; + transition: background-color var(--dur) var(--ease), + border-color var(--dur) var(--ease), color var(--dur) var(--ease); +} + +.ap-intent-chip:hover { + background: var(--accent-soft); + border-color: var(--accent); + color: var(--accent); +} + +.ap-intent-chip:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} diff --git a/css/bench.css b/css/bench.css new file mode 100644 index 0000000000000000000000000000000000000000..7bd09090c43384874b1b15d8f4b3eea3b018413a --- /dev/null +++ b/css/bench.css @@ -0,0 +1,934 @@ +/* 批量推理台(契约 20A · 工作台第三 tab「对比」)——Warm Paper 令牌, + 零硬编码色:所有颜色走 theme.css 变量(深浅色自动跟随)。 + 布局沿用 .kb / .skills 的整页滚动容器(flex:1 + 独立滚动 + 48px 留白)。 */ + +.bench { + flex: 1; + min-width: 0; + overflow-y: auto; + padding: 36px 48px 48px; +} + +/* ── 页头 ───────────────────────────────────────────────────────── */ + +.bench-head { + display: flex; + align-items: flex-end; + justify-content: space-between; + gap: 16px; + margin-bottom: 20px; +} + +.bench-title { + font-family: var(--font-serif); + font-size: 26px; + font-weight: 600; + letter-spacing: -0.01em; + color: var(--text); +} + +.bench-head-sub { + margin: 6px 0 0; + font-size: 13.5px; + line-height: 1.6; + color: var(--text-secondary); +} + +.bench-head-actions { + display: flex; + gap: 8px; + flex-shrink: 0; +} + +.bench-muted { + font-size: 13px; + line-height: 1.6; + color: var(--text-secondary); +} + +.bench-notice { + margin: 0 0 16px; + padding: 10px 14px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: var(--bg-elevated); + font-size: 13.5px; + line-height: 1.6; + color: var(--text); +} + +/* ── 卡片与表单 ─────────────────────────────────────────────────── */ + +.bench-card { + background: var(--bg-elevated); + border: 1px solid var(--border); + border-radius: var(--radius-card); + padding: 22px 24px; + margin-bottom: 24px; +} + +.bench-card-title { + font-family: var(--font-serif); + font-size: 18px; + font-weight: 600; + color: var(--text); + margin: 0 0 18px; +} + +.bench-field { + display: flex; + flex-direction: column; + gap: 8px; + margin-bottom: 18px; +} + +.bench-field-label { + font-size: 13px; + color: var(--text-secondary); +} + +.bench-field-row { + display: flex; + flex-wrap: wrap; + gap: 24px; + align-items: flex-start; +} + +.bench-field-row .bench-field { + min-width: 240px; + flex: 1; +} + +.bench-field textarea, +.bench-field select { + width: 100%; + font-family: var(--font-sans); + font-size: 14px; + line-height: 1.65; + color: var(--text); + background: var(--bg-sunken); + border: 1px solid transparent; + border-radius: var(--radius-control); + padding: 10px 12px; + transition: border-color var(--dur) var(--ease); +} + +.bench-field textarea { + resize: vertical; + min-height: 120px; +} + +.bench-field textarea::placeholder { + color: var(--text-tertiary); +} + +.bench-field textarea:focus-visible, +.bench-field select:focus-visible { + outline: none; + border-color: var(--accent); +} + +/* ── 模型分组多选(本机 / 云 · 接口名) ───────────────────────────── */ + +.bench-groups { + display: flex; + flex-direction: column; + gap: 14px; +} + +.bench-group { + display: flex; + flex-direction: column; + gap: 8px; +} + +.bench-group-label { + font-family: var(--font-serif); + font-size: 14px; + font-weight: 600; + color: var(--text); +} + +.bench-chips { + display: flex; + flex-wrap: wrap; + gap: 8px; +} + +.bench-chip { + display: inline-flex; + align-items: center; + gap: 7px; + height: 30px; + padding: 0 11px; + border: 1px solid var(--border); + border-radius: var(--radius-chip); + background: var(--bg); + color: var(--text-secondary); + font-family: inherit; + font-size: 13px; + cursor: pointer; + transition: + background-color var(--dur) var(--ease), + border-color var(--dur) var(--ease), + color var(--dur) var(--ease); +} + +.bench-chip:hover { + background: var(--accent-soft); + color: var(--text); +} + +.bench-chip.is-on { + background: var(--accent-soft); + border-color: var(--accent); + color: var(--text); + font-weight: 600; +} + +.bench-chip:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +.bench-chip-name { + max-width: 200px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.bench-chip-badge { + font-size: 11px; + line-height: 1; + padding: 3px 6px; + border-radius: var(--radius-chip); + background: var(--bg-sunken); + color: var(--text-secondary); +} + +.bench-chip-badge.is-cloud { + background: var(--accent-soft); + color: var(--text); +} + +/* ── 评委开关 ───────────────────────────────────────────────────── */ + +.bench-field-switch { + min-width: 280px; +} + +.bench-switch-line { + display: flex; + align-items: center; + gap: 10px; +} + +.bench-switch { + position: relative; + width: 42px; + height: 24px; + flex-shrink: 0; + border: 1px solid var(--border); + border-radius: var(--radius-chip); + background: var(--bg-sunken); + cursor: pointer; + transition: background-color var(--dur) var(--ease), border-color var(--dur) var(--ease); +} + +.bench-switch.is-on { + background: var(--accent); + border-color: var(--accent); +} + +.bench-switch-knob { + position: absolute; + top: 2px; + left: 2px; + width: 18px; + height: 18px; + border-radius: 50%; + background: var(--bg); + transition: transform var(--dur) var(--ease); +} + +.bench-switch.is-on .bench-switch-knob { + transform: translateX(18px); +} + +.bench-switch:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +/* ── think 五档(整场统一一档) ──────────────────────────────────── */ + +.bench-think { + display: inline-flex; + gap: 4px; + padding: 4px; + background: var(--bg-sunken); + border-radius: var(--radius-control); +} + +.bench-think-btn { + min-width: 44px; + height: 28px; + padding: 0 10px; + border: none; + border-radius: var(--radius-control); + background: transparent; + color: var(--text-secondary); + font-family: inherit; + font-size: 12.5px; + cursor: pointer; + transition: background-color var(--dur) var(--ease), color var(--dur) var(--ease); +} + +.bench-think-btn:hover { + color: var(--text); +} + +.bench-think-btn.is-on { + background: var(--bg-elevated); + color: var(--text); + font-weight: 600; + box-shadow: inset 0 0 0 1px var(--border); +} + +.bench-think-btn.is-ultra.is-on { + background: var(--accent-soft); + box-shadow: inset 0 0 0 1px var(--accent); +} + +.bench-think-btn:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +/* ── 成本提示(契约:开跑前必须可见) ────────────────────────────── */ + +.bench-cost { + padding: 12px 14px; + margin-bottom: 18px; + background: var(--bg-sunken); + border-radius: var(--radius-control); +} + +.bench-cost-summary { + margin: 0; + font-size: 13.5px; + line-height: 1.6; + color: var(--text); +} + +.bench-cost-discipline { + display: inline-block; + margin-left: 10px; + padding: 2px 8px; + border: 1px solid var(--border); + border-radius: var(--radius-chip); + font-size: 12px; + color: var(--text-secondary); +} + +.bench-cost-lines { + display: flex; + flex-wrap: wrap; + gap: 6px 16px; + margin: 8px 0 0; + padding: 0; + list-style: none; +} + +.bench-cost-lines li { + display: inline-flex; + align-items: baseline; + gap: 6px; + font-size: 12.5px; + color: var(--text-secondary); +} + +.bench-cost-model { + font-family: var(--font-mono); + font-size: 12px; + color: var(--text); +} + +.bench-cost-lines li.is-free .bench-cost-label { + color: var(--success); +} + +.bench-cost-lines li.is-paid .bench-cost-label { + color: var(--warning); +} + +.bench-cost-lines li.is-local .bench-cost-label { + color: var(--text-secondary); +} + +/* ── 按钮 ───────────────────────────────────────────────────────── */ + +.bench-actions { + display: flex; + align-items: center; + gap: 14px; + flex-wrap: wrap; +} + +.bench-primary { + display: inline-flex; + align-items: center; + gap: 7px; + height: 38px; + padding: 0 18px; + border: none; + border-radius: var(--radius-control); + background: var(--accent); + color: var(--bg); + font-family: inherit; + font-size: 14px; + font-weight: 600; + cursor: pointer; + transition: opacity var(--dur) var(--ease); +} + +.bench-primary:hover:not(:disabled) { + opacity: 0.9; +} + +.bench-primary:disabled { + opacity: 0.45; + cursor: not-allowed; +} + +.bench-primary:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +.bench-secondary, +.bench-danger, +.bench-icon-btn { + display: inline-flex; + align-items: center; + gap: 6px; + height: 30px; + padding: 0 11px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: transparent; + color: var(--text-secondary); + font-family: inherit; + font-size: 13px; + cursor: pointer; + transition: + background-color var(--dur) var(--ease), + color var(--dur) var(--ease), + border-color var(--dur) var(--ease); +} + +.bench-secondary:hover { + background: var(--accent-soft); + color: var(--text); +} + +.bench-danger { + color: var(--danger); + border-color: var(--danger); +} + +.bench-danger:hover { + background: var(--danger); + color: var(--bg); +} + +.bench-icon-btn { + padding: 0 9px; + font-size: 16px; + line-height: 1; +} + +.bench-secondary:focus-visible, +.bench-danger:focus-visible, +.bench-icon-btn:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +/* ── 运行头 + 进度 ──────────────────────────────────────────────── */ + +.bench-run-head { + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; + flex-wrap: wrap; + margin-bottom: 14px; +} + +.bench-run-title { + display: flex; + align-items: baseline; + gap: 10px; + flex-wrap: wrap; + min-width: 0; +} + +.bench-run-title .bench-card-title { + margin: 0; +} + +.bench-toolbar { + display: flex; + gap: 8px; + flex-shrink: 0; +} + +.bench-progress { + height: 6px; + border-radius: var(--radius-chip); + background: var(--bg-sunken); + overflow: hidden; + margin-bottom: 18px; +} + +.bench-progress-fill { + height: 100%; + background: var(--accent); + border-radius: var(--radius-chip); + transition: width var(--dur) var(--ease); +} + +/* ── 状态点 / 徽章 ──────────────────────────────────────────────── */ + +.bench-dot { + width: 9px; + height: 9px; + flex-shrink: 0; + border-radius: 50%; + background: var(--text-tertiary); +} + +.bench-dot.is-running { + background: var(--accent); +} + +.bench-dot.is-done { + background: var(--success); +} + +.bench-dot.is-failed { + background: var(--danger); +} + +.bench-dot.is-stopped { + background: var(--warning); +} + +.bench-dot.is-pending { + background: var(--text-tertiary); +} + +.bench-badge { + display: inline-flex; + align-items: center; + height: 20px; + padding: 0 8px; + border-radius: var(--radius-chip); + background: var(--bg-sunken); + font-size: 11.5px; + color: var(--text-secondary); + white-space: nowrap; +} + +.bench-badge.is-running { + background: var(--accent-soft); + color: var(--text); +} + +.bench-badge.is-done { + color: var(--success); +} + +.bench-badge.is-error, +.bench-badge.is-failed { + color: var(--danger); +} + +.bench-badge.is-cancelled, +.bench-badge.is-stopped { + color: var(--warning); +} + +/* ── 评委卡(完成后置顶) ───────────────────────────────────────── */ + +.bench-judge { + border: 1px solid var(--border); + border-radius: var(--radius-card); + background: var(--bg); + padding: 18px 20px; + margin-bottom: 20px; +} + +.bench-judge-head { + display: flex; + align-items: center; + gap: 10px; + flex-wrap: wrap; + margin-bottom: 10px; +} + +.bench-judge-badge { + display: inline-flex; + align-items: center; + height: 22px; + padding: 0 9px; + border-radius: var(--radius-chip); + background: var(--accent); + color: var(--bg); + font-size: 11.5px; + font-weight: 600; +} + +.bench-judge-model { + margin: 0; + font-family: var(--font-serif); + font-size: 15px; + font-weight: 600; + color: var(--text); +} + +.bench-judge-rec { + display: inline-flex; + align-items: center; + height: 22px; + padding: 0 9px; + border: 1px solid var(--accent); + border-radius: var(--radius-chip); + background: var(--accent-soft); + font-size: 12px; + color: var(--text); + max-width: 320px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +/* ── 矩阵表(行 = prompt、列 = 模型) ────────────────────────────── */ + +.bench-table-wrap { + overflow-x: auto; + border: 1px solid var(--border); + border-radius: var(--radius-card); +} + +.bench-table { + width: 100%; + border-collapse: collapse; + font-size: 13px; +} + +.bench-table th, +.bench-table td { + border-bottom: 1px solid var(--border); + vertical-align: top; + text-align: left; +} + +.bench-table thead th { + background: var(--bg-sunken); + padding: 10px 12px; + font-weight: 600; + color: var(--text); + white-space: nowrap; +} + +.bench-col-name { + display: block; + font-family: var(--font-serif); + font-size: 13.5px; +} + +.bench-col-cost { + display: block; + margin-top: 2px; + font-size: 11.5px; + font-weight: 400; + color: var(--text-secondary); +} + +.bench-table tbody tr:last-child th, +.bench-table tbody tr:last-child td { + border-bottom: none; +} + +.bench-row-prompt { + width: 240px; + padding: 12px; + font-weight: 500; + color: var(--text); +} + +.bench-idx { + display: inline-block; + min-width: 20px; + margin-right: 6px; + font-family: var(--font-mono); + font-size: 12px; + color: var(--text-tertiary); +} + +.bench-row-text { + font-size: 13px; + line-height: 1.6; +} + +.bench-td { + position: relative; + min-width: 190px; + padding: 0; +} + +.bench-cell { + display: block; + width: 100%; + padding: 12px; + border: none; + background: transparent; + font-family: inherit; + text-align: left; + cursor: pointer; + transition: background-color var(--dur) var(--ease); +} + +.bench-cell:hover { + background: var(--accent-soft); +} + +.bench-cell:focus-visible { + outline: 2px solid var(--accent); + outline-offset: -2px; +} + +.bench-cell-top { + display: flex; + align-items: center; + gap: 7px; + margin-bottom: 5px; +} + +.bench-cell-metric { + font-family: var(--font-mono); + font-size: 11.5px; + color: var(--text-secondary); +} + +.bench-excerpt { + font-size: 12.5px; + line-height: 1.55; + color: var(--text-secondary); + overflow: hidden; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; +} + +.bench-cell-retry, +.bench-cell-stop { + position: absolute; + top: 8px; + right: 8px; + width: 22px; + height: 22px; + display: inline-flex; + align-items: center; + justify-content: center; + border: 1px solid var(--border); + border-radius: var(--radius-chip); + background: var(--bg-elevated); + color: var(--text-secondary); + cursor: pointer; + transition: + background-color var(--dur) var(--ease), + color var(--dur) var(--ease); +} + +.bench-cell-retry:hover { + background: var(--accent-soft); + color: var(--text); +} + +.bench-cell-stop:hover { + background: var(--danger); + color: var(--bg); +} + +.bench-cell-retry:focus-visible, +.bench-cell-stop:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 1px; +} + +.bench-legend { + margin: 12px 0 0; + font-size: 12.5px; + line-height: 1.6; + color: var(--text-secondary); +} + +/* ── 全文抽屉 ───────────────────────────────────────────────────── */ + +.bench-drawer-mask { + position: fixed; + inset: 0; + display: flex; + justify-content: flex-end; + background: var(--scrim); + z-index: 40; +} + +.bench-drawer { + display: flex; + flex-direction: column; + width: min(560px, 92vw); + height: 100%; + background: var(--bg-elevated); + border-left: 1px solid var(--border); + box-shadow: var(--shadow-float); + animation: bench-drawer-in 180ms var(--ease); +} + +@keyframes bench-drawer-in { + from { + opacity: 0; + transform: translateX(12px); + } + to { + opacity: 1; + transform: translateX(0); + } +} + +.bench-drawer-head { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + padding: 18px 22px; + border-bottom: 1px solid var(--border); +} + +.bench-drawer-title { + display: flex; + align-items: center; + gap: 9px; + min-width: 0; + font-family: var(--font-serif); + font-size: 15px; + font-weight: 600; + color: var(--text); +} + +.bench-drawer-actions { + display: flex; + align-items: center; + gap: 8px; + flex-shrink: 0; +} + +.bench-drawer-meta { + margin: 0; + padding: 10px 22px; + border-bottom: 1px solid var(--border); + font-family: var(--font-mono); + font-size: 12px; + color: var(--text-secondary); +} + +.bench-drawer-body { + flex: 1; + overflow-y: auto; + padding: 20px 22px; + font-size: 14.5px; + line-height: 1.7; +} + +.bench-drawer-body .md > * { + margin: 0 0 12px; +} + +/* ── 历史 ───────────────────────────────────────────────────────── */ + +.bench-history { + margin-top: 8px; +} + +.bench-history-title { + font-family: var(--font-serif); + font-size: 15px; + font-weight: 600; + color: var(--text); + margin: 0 0 10px; +} + +.bench-history-list { + list-style: none; + margin: 0; + padding: 0; + border-top: 1px solid var(--border); +} + +.bench-history-item { + display: flex; + align-items: center; + gap: 12px; + width: 100%; + padding: 11px 6px; + border: none; + border-bottom: 1px solid var(--border); + background: transparent; + font-family: inherit; + text-align: left; + cursor: pointer; + transition: background-color var(--dur) var(--ease); +} + +.bench-history-item:hover { + background: var(--accent-soft); +} + +.bench-history-item.is-active { + background: var(--accent-soft); +} + +.bench-history-item:focus-visible { + outline: 2px solid var(--accent); + outline-offset: -2px; +} + +.bench-history-name { + font-family: var(--font-serif); + font-size: 14px; + color: var(--text); + max-width: 46%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.bench-history-meta { + font-size: 12.5px; + color: var(--text-secondary); +} + +/* ── 动效克制(尊重 reduced-motion) ────────────────────────────── */ + +@media (prefers-reduced-motion: reduce) { + .bench *, + .bench *::before, + .bench *::after { + transition-duration: 0.01ms !important; + animation-duration: 0.01ms !important; + } +} diff --git a/css/board.css b/css/board.css new file mode 100644 index 0000000000000000000000000000000000000000..777202c01dd782c9f2a509c1185f2d0b83ac7b07 --- /dev/null +++ b/css/board.css @@ -0,0 +1,367 @@ +/* 系统看板:指标卡 + 进程表 + 网络简报(Warm Paper,全令牌配色)。 + 数字一律 tabular-nums 等宽对齐(design-system §4)。 */ + +.board { + flex: 1; + min-width: 0; + overflow-y: auto; + padding: 36px 48px 48px; +} + +.board-head { + margin-bottom: 28px; +} + +.board-head h1 { + font-size: 30px; +} + +.board-sub { + margin: 6px 0 0; + font-size: 13.5px; + color: var(--text-secondary); + font-variant-numeric: tabular-nums; +} + +/* ── 指标卡 ─────────────────────────────────────────────────────── */ + +.board-cards { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 16px; +} + +.metric-card { + display: flex; + flex-direction: column; + padding: 20px 22px 18px; + border: 1px solid var(--border); + border-radius: var(--radius-card); + background: var(--bg-elevated); +} + +.metric-label { + font-size: 13px; + color: var(--text-secondary); +} + +.metric-value { + margin-top: 6px; + font-family: var(--font-serif); + font-size: 40px; + font-weight: 600; + line-height: 1.15; + letter-spacing: -0.01em; + color: var(--text); + font-variant-numeric: tabular-nums; +} + +.metric-unit { + margin-left: 2px; + font-size: 20px; + color: var(--text-secondary); +} + +.metric-bar { + margin-top: 12px; + height: 6px; + border-radius: 3px; + background: var(--bg-sunken); + overflow: hidden; +} + +.metric-bar-fill { + height: 100%; + border-radius: 3px; + transition: background-color var(--dur) var(--ease); +} + +.metric-note { + margin-top: 10px; + font-size: 12.5px; + line-height: 1.5; + color: var(--text-secondary); + font-variant-numeric: tabular-nums; +} + +/* 语义色:<70% success / 70–85% warning / >85% danger + 2026-10-23 修复:必须带填充物类作用域——裸 .is-success 会匹配全 App 所有 + is-success 元素(曾把验收卡整卡刷成实心绿)。 */ +.metric-bar-fill.is-success, +.core-bar-fill.is-success { + background: var(--success); +} +.metric-bar-fill.is-warning, +.core-bar-fill.is-warning { + background: var(--warning); +} +.metric-bar-fill.is-danger, +.core-bar-fill.is-danger { + background: var(--danger); +} + +/* CPU 每核迷你竖条 */ +.core-bars { + display: flex; + align-items: flex-end; + gap: 3px; + height: 22px; + margin-top: 12px; +} + +.core-bar { + flex: 1; + min-width: 0; + height: 100%; + display: flex; + align-items: flex-end; + border-radius: 2px; + background: var(--bg-sunken); + overflow: hidden; +} + +.core-bar-fill { + width: 100%; + min-height: 2px; + border-radius: 2px; + transition: background-color var(--dur) var(--ease); +} + +/* 数值变化只做 150ms 淡入,不做数字滚动(design-system §6) */ +.board-num { + display: inline-block; + animation: board-fade var(--dur) var(--ease); +} + +@keyframes board-fade { + from { + opacity: 0.35; + } + to { + opacity: 1; + } +} + +/* ── 下方两个面板 ───────────────────────────────────────────────── */ + +.board-panels { + display: grid; + grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); + gap: 16px; + margin-top: 16px; + align-items: start; +} + +.panel { + padding: 20px 22px; + border: 1px solid var(--border); + border-radius: var(--radius-card); + background: var(--bg-elevated); +} + +.panel h2 { + font-size: 16px; + margin-bottom: 12px; +} + +.panel-note { + margin: 4px 0; + font-size: 13px; + color: var(--text-tertiary); +} + +.panel-foot { + margin: 12px 0 0; + font-size: 12px; + color: var(--text-tertiary); +} + +/* ── 进程表 ─────────────────────────────────────────────────────── */ + +.proc-table { + width: 100%; + border-collapse: collapse; + font-size: 13px; + font-variant-numeric: tabular-nums; +} + +.proc-table th { + padding: 6px 8px; + text-align: left; + font-weight: 500; + font-size: 12px; + color: var(--text-secondary); + border-bottom: 1px solid var(--border); +} + +.proc-table th.num, +.proc-table td.num { + text-align: right; +} + +.proc-table td { + padding: 7px 8px; + border-bottom: 1px solid var(--border); +} + +.proc-table tbody tr { + transition: background-color var(--dur) var(--ease); +} + +/* hover 行底色 = accent-soft 的 40%(design-system §7) */ +.proc-table tbody tr:hover { + background: color-mix(in srgb, var(--accent-soft) 40%, transparent); +} + +.proc-table tbody tr:last-child td { + border-bottom: none; +} + +.proc-name { + max-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.sort-btn { + padding: 0; + border: none; + background: transparent; + color: inherit; + font: inherit; + font-variant-numeric: tabular-nums; + cursor: pointer; +} + +.sort-btn:hover { + color: var(--text); +} + +.sort-btn.is-active { + color: var(--accent); +} + +.sort-arrow { + font-size: 10px; +} + +/* ── 网络简报 ───────────────────────────────────────────────────── */ + +.net-public { + display: flex; + align-items: baseline; + gap: 10px; + padding-bottom: 12px; + border-bottom: 1px solid var(--border); +} + +.net-public-label { + flex-shrink: 0; + font-size: 12.5px; + color: var(--text-secondary); +} + +.net-public-value { + font-family: var(--font-mono); + font-size: 15px; + color: var(--text); + font-variant-numeric: tabular-nums; + overflow-wrap: anywhere; +} + +.iface-list { + list-style: none; + margin: 10px 0 0; + padding: 0; +} + +.iface { + display: flex; + align-items: baseline; + gap: 10px; + padding: 7px 0; + font-size: 13px; +} + +.iface + .iface { + border-top: 1px solid var(--border); +} + +.iface-name { + flex-shrink: 0; + min-width: 56px; + font-family: var(--font-mono); + font-size: 12.5px; + color: var(--text); +} + +.iface-ips { + flex: 1; + min-width: 0; + color: var(--text-secondary); + font-variant-numeric: tabular-nums; + overflow-wrap: anywhere; +} + +.iface-mac { + flex-shrink: 0; + font-family: var(--font-mono); + font-size: 11.5px; + color: var(--text-tertiary); +} + +/* ── 空态(衬线大字一句话,design-system §7)─────────────────────── */ + +.board-empty { + padding: 56px 0 24px; +} + +.board-empty-title { + margin: 0; + font-family: var(--font-serif); + font-size: 24px; + font-weight: 600; + color: var(--text); +} + +.board-empty-sub { + margin: 10px 0 0; + font-size: 13.5px; + color: var(--text-secondary); +} + +/* ── CPU 异构分组(Apple Silicon 性能核/能效核)────────────── */ +.core-groups { + display: flex; + flex-direction: column; + gap: 6px; +} +.core-group-row { + display: flex; + align-items: center; + gap: 10px; +} +.core-group-label { + flex-shrink: 0; + width: 60px; + font-size: 12px; + color: var(--text-secondary); +} +.core-group-count { + font-family: var(--font-mono); + font-variant-numeric: tabular-nums; + color: var(--text-tertiary); +} +.core-group-row .core-bars { + flex: 1; +} +.core-group-avg { + flex-shrink: 0; + width: 38px; + text-align: right; + font-family: var(--font-mono); + font-size: 12px; + font-variant-numeric: tabular-nums; + color: var(--text-secondary); +} diff --git a/css/chat.css b/css/chat.css new file mode 100644 index 0000000000000000000000000000000000000000..7cfc08c9dc2d42aec6b51eec386bd4480fbced4d --- /dev/null +++ b/css/chat.css @@ -0,0 +1,489 @@ +/* 对话工作台:会话列表 + 消息流 + 输入区(Warm Paper,全令牌配色) */ + +.workbench { + flex: 1; + min-width: 0; + min-height: 0; /* flex 子项默认 min-height:auto 会拒绝收缩——必须显式置 0,否则消息一长整页跟着滚 */ + display: flex; +} + +/* ---------- 会话列表 ---------- */ +.conversations { + width: 264px; + flex-shrink: 0; + min-height: 0; + display: flex; + flex-direction: column; + border-right: 1px solid var(--border); + background: var(--bg); +} + +.conv-head { + display: flex; + align-items: center; + justify-content: space-between; + padding: 26px 16px 14px; +} + +.conv-head h2 { + font-size: 17px; +} + +.conv-new { + display: inline-flex; + align-items: center; + gap: 6px; + height: 30px; + padding: 0 12px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: transparent; + color: var(--text); + font-family: inherit; + font-size: 13px; + cursor: pointer; + transition: background-color var(--dur) var(--ease); +} + +.conv-new:hover { + background: var(--bg-elevated); +} + +.conv-scroll { + flex: 1; + overflow-y: auto; + display: flex; + flex-direction: column; + gap: 2px; + padding: 4px 12px 16px; +} + +.conv-empty { + padding: 20px 12px; + color: var(--text-tertiary); + font-size: 13px; + line-height: 1.7; +} + +.conv-empty p { + margin: 0 0 4px; +} + +.conv-empty-title { + color: var(--text-secondary); + font-size: 13.5px; + font-weight: 500; +} + +.conv-item { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 2px; + border-radius: var(--radius-control); + transition: background-color var(--dur) var(--ease); +} + +.conv-item:hover { + background: var(--bg-elevated); +} + +.conv-item.is-active { + background: var(--accent-soft); +} + +.conv-open { + flex: 1; + min-width: 0; + display: flex; + flex-direction: column; + gap: 1px; + padding: 10px 12px; + border: none; + background: transparent; + color: var(--text); + font-family: inherit; + text-align: left; + cursor: pointer; + border-radius: var(--radius-control); +} + +.conv-title { + display: block; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + font-size: 13.5px; + font-weight: 500; +} + +.conv-meta { + display: block; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + font-size: 11.5px; + color: var(--text-tertiary); + font-variant-numeric: tabular-nums; +} + +.conv-actions { + display: none; + gap: 2px; + padding-right: 6px; +} + +.conv-item:hover .conv-actions, +.conv-item:focus-within .conv-actions { + display: inline-flex; +} + +.conv-rename { + flex: 1; + min-width: 0; + margin: 6px 8px; + padding: 7px 10px; + border: 1px solid transparent; + border-radius: var(--radius-control); + background: var(--bg-sunken); + color: var(--text); + font-family: inherit; + font-size: 13px; +} + +.conv-rename:focus { + outline: none; + border-color: var(--accent); + box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent-soft) 65%, transparent); +} + +.conv-confirm { + flex-basis: 100%; + display: flex; + align-items: center; + gap: 8px; + padding: 8px 12px 10px; + font-size: 12px; + color: var(--text-secondary); +} + +.conv-confirm span { + flex: 1; +} + +.conv-confirm-yes, +.conv-confirm-no { + display: inline-flex; + align-items: center; + gap: 4px; + height: 26px; + padding: 0 10px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: transparent; + font-family: inherit; + font-size: 12px; + cursor: pointer; + transition: background-color var(--dur) var(--ease); +} + +.conv-confirm-yes { + color: var(--danger); +} + +.conv-confirm-yes:hover { + background: var(--accent-soft); +} + +.conv-confirm-no { + color: var(--text-secondary); +} + +.conv-confirm-no:hover { + background: var(--bg-elevated); +} + +.conv-error { + margin: 0; + padding: 10px 16px 14px; + color: var(--danger); + font-size: 12px; + line-height: 1.6; +} + +/* ---------- 消息区 ---------- */ +.chat-main { + flex: 1; + min-width: 0; + min-height: 0; + display: flex; + flex-direction: column; +} + +.stream { + flex: 1; + min-height: 0; + overflow-y: auto; + display: flex; + flex-direction: column; +} + +.stream-inner { + flex-shrink: 0; + max-width: 760px; + width: 100%; + margin: 0 auto; + padding: 48px 48px 24px; + display: flex; + flex-direction: column; + gap: 32px; +} + +.msg { + display: flex; + flex-direction: column; + gap: 8px; +} + +.msg-role { + font-size: 12px; + color: var(--text-tertiary); + font-variant-numeric: tabular-nums; +} + +.msg-card { + padding: 12px 16px; + border: 1px solid color-mix(in srgb, var(--accent) 16%, transparent); + border-radius: var(--radius-card); + background: var(--accent-soft); + font-size: 15px; + line-height: 1.75; + white-space: pre-wrap; + overflow-wrap: break-word; + user-select: text; +} + +.msg-body { + font-size: 15px; + user-select: text; +} + +.msg-error { + display: flex; + align-items: center; + gap: 6px; + margin: 0; + color: var(--danger); + font-size: 13px; +} + +.msg-note { + margin: 0; + color: var(--text-tertiary); + font-size: 12.5px; +} + +.msg-reasoning summary { + cursor: pointer; + color: var(--text-tertiary); + font-size: 12.5px; +} + +.msg-reasoning-body { + margin-top: 8px; + padding: 12px 14px; + border-radius: var(--radius-control); + background: var(--bg-elevated); + color: var(--text-secondary); + font-size: 13px; + line-height: 1.7; + white-space: pre-wrap; + user-select: text; +} + +/* 流式呼吸光标(1s 透明度呼吸;reduced-motion 时 theme.css 全局降级为静止) */ +@keyframes cursor-breathe { + 0%, + 100% { + opacity: 1; + } + 50% { + opacity: 0.15; + } +} + +.stream-cursor { + display: inline-block; + width: 2px; + height: 1.05em; + margin-left: 4px; + border-radius: 1px; + background: var(--accent); + vertical-align: text-bottom; + animation: cursor-breathe 1s ease-in-out infinite; +} + +/* 有内容时,光标贴在最后一个 Markdown 块的文本尾部 */ +.msg-body.is-streaming .md > :last-child::after { + content: ""; + display: inline-block; + width: 2px; + height: 1em; + margin-left: 3px; + border-radius: 1px; + background: var(--accent); + vertical-align: -0.12em; + animation: cursor-breathe 1s ease-in-out infinite; +} + +/* 代码块收尾时,光标落到代码行尾 */ +.msg-body.is-streaming .md > .code-block:last-child::after { + content: none; +} + +.msg-body.is-streaming .md > .code-block:last-child pre::after { + content: ""; + display: inline-block; + width: 2px; + height: 1em; + margin-left: 3px; + border-radius: 1px; + background: var(--accent); + vertical-align: -0.12em; + animation: cursor-breathe 1s ease-in-out infinite; +} + +/* ---------- 欢迎空态 ---------- */ +.chat-welcome { + position: relative; + flex: 1; + display: flex; + flex-direction: column; + justify-content: center; + padding: 48px 80px; + overflow: hidden; +} + +/* 极淡的径向暖光(accent-soft 的 5%,无新颜色) */ +.chat-welcome::before { + content: ""; + position: absolute; + inset: 0; + pointer-events: none; + background: radial-gradient( + 56% 48% at 28% 40%, + color-mix(in srgb, var(--accent-soft) 5%, transparent) 0%, + transparent 72% + ); +} + +/* 品牌鸟巢水印(Brand.tsx 复用,极低透明度) */ +.chat-welcome-mark { + position: absolute; + right: 72px; + top: 50%; + transform: translateY(-50%); + color: var(--accent); + opacity: 0.07; + pointer-events: none; +} + +.chat-welcome h1 { + position: relative; + margin: 0 0 12px; + font-size: 32px; +} + +.chat-welcome p { + position: relative; + margin: 0; + max-width: 520px; + font-size: 16px; + line-height: 1.8; + color: var(--text-secondary); +} + +/* ---------- 对话头部右侧动作区(ultrafast 开关 + 专家选择器) ---------- */ +.chat-header-actions { + display: flex; + align-items: center; + gap: 8px; +} + +/* ultrafast 闪电开关(dev-ultrafast):与狂暴火焰同款视觉语言(幽灵按钮 → + 金渐变徽章,warning 金 → accent 陶土走令牌,反向渐变以区分二者), + 只是图标换 Zap、语义求快(关思考 + 用最快的模型) */ +.ultrafast-toggle { + position: relative; + display: inline-flex; + align-items: center; + gap: 4px; + padding: 3px 10px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: transparent; + color: var(--text-secondary); + font-size: 12px; + font-weight: 600; + cursor: pointer; + transition: + background var(--dur) var(--ease), + color var(--dur) var(--ease), + border-color var(--dur) var(--ease); +} + +.ultrafast-toggle:hover { + color: var(--text); + border-color: var(--accent); +} + +.ultrafast-toggle.is-on { + border-color: transparent; + color: var(--bg); + background: linear-gradient(135deg, var(--accent), var(--warning)); + /* 开启瞬间的小特效①:徽章轻微弹跳("啪"地一下上档) */ + animation: ultrafast-pop 300ms var(--ease); +} + +/* 开启瞬间的小特效②:一圈金色能量环从徽章外扩淡出(像被点亮/充能)—— + 纯 ::after,只在 is-on 类加上时跑一次,不常驻不刺眼(Warm Paper 克制) */ +.ultrafast-toggle.is-on::after { + content: ""; + position: absolute; + inset: -2px; + border-radius: inherit; + border: 1px solid var(--warning); + opacity: 0; + pointer-events: none; + animation: ultrafast-ring 520ms var(--ease); +} + +@keyframes ultrafast-pop { + 0% { transform: scale(1); } + 38% { transform: scale(1.09); } + 100% { transform: scale(1); } +} + +@keyframes ultrafast-ring { + 0% { opacity: 0.85; transform: scale(0.92); } + 100% { opacity: 0; transform: scale(1.6); } +} + +/* 尊重系统减弱动效:关掉开启特效(弹跳与能量环都不跑) */ +@media (prefers-reduced-motion: reduce) { + .ultrafast-toggle.is-on, + .ultrafast-toggle.is-on::after { + animation: none; + } +} + +.ultrafast-toggle.is-on:hover { + color: var(--bg); + filter: brightness(1.04); +} + +.ultrafast-toggle:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + diff --git a/css/cloud.css b/css/cloud.css new file mode 100644 index 0000000000000000000000000000000000000000..d0eadaf426d5697b6f8535c24662f48305f4a821 --- /dev/null +++ b/css/cloud.css @@ -0,0 +1,463 @@ +/* 设置页(Phase 5A):云端 API 接入 + 关于。 + Warm Paper 全令牌配色(design-system.md),无硬编码颜色。 */ + +.settings { + flex: 1; + min-width: 0; + overflow-y: auto; + padding: 36px 48px 48px; +} + +.settings-head h1 { + font-size: 30px; +} + +.settings-head-sub { + margin: 6px 0 0; + font-size: 13.5px; + color: var(--text-secondary); +} + +.settings-section { + max-width: 760px; + margin-top: 40px; +} + +.settings-section h2 { + font-size: 21px; +} + +.settings-sub { + margin: 6px 0 0; + font-size: 13px; + color: var(--text-secondary); +} + +/* ── 云端 API 区 ────────────────────────────────────────────────── */ + +.cloud-section-head { + display: flex; + align-items: flex-end; + justify-content: space-between; + gap: 16px; + margin-bottom: 14px; + flex-wrap: wrap; +} + +.cloud-privacy { + display: flex; + align-items: center; + gap: 7px; + margin: 0 0 16px; + padding: 8px 14px; + border: 1px dashed var(--border); + border-radius: var(--radius-control); + background: var(--bg-sunken); + font-size: 13px; + color: var(--text-secondary); +} + +.cloud-muted { + margin: 0; + font-size: 13px; + color: var(--text-secondary); +} + +.cloud-error { + margin: 8px 0 0; + font-size: 13px; + color: var(--danger); +} + +.cloud-test-line { + margin: 10px 0 0; + font-size: 13px; +} + +.cloud-test-line.is-ok { + color: var(--success); +} + +/* ── 接口卡片 ───────────────────────────────────────────────────── */ + +.cloud-card { + margin-bottom: 12px; + padding: 16px 18px; + border: 1px solid var(--border); + border-radius: var(--radius-card); + background: var(--bg-elevated); +} + +.cloud-card-head { + display: flex; + align-items: center; + gap: 10px; + flex-wrap: wrap; +} + +.cloud-card-icon { + display: inline-flex; + color: var(--text-secondary); +} + +.cloud-card-title h3 { + font-size: 16px; + margin: 0; +} + +.cloud-card-url { + margin: 2px 0 0; + font-family: var(--font-mono); + font-size: 12px; + color: var(--text-secondary); + word-break: break-all; +} + +.cloud-card-count { + margin-left: auto; + font-size: 12.5px; + color: var(--text-secondary); + font-variant-numeric: tabular-nums; +} + +/* 状态徽章:与全站徽章同尺寸同字重 */ +.cloud-badge { + display: inline-flex; + align-items: center; + gap: 4px; + padding: 2px 8px; + border: 1px solid var(--border); + border-radius: 999px; + font-size: 12px; + font-weight: 500; + color: var(--text-secondary); +} + +.cloud-badge.is-ok { + color: var(--success); +} + +.cloud-badge.is-warn { + color: var(--warning); +} + +.cloud-card-actions { + display: flex; + align-items: center; + gap: 8px; + flex-wrap: wrap; + margin-top: 12px; +} + +.cloud-confirm { + display: inline-flex; + align-items: center; + gap: 8px; + font-size: 12.5px; + color: var(--text-secondary); +} + +/* ── 模型 chips ────────────────────────────────────────────────── */ + +.cloud-chips { + display: flex; + flex-wrap: wrap; + gap: 6px; + margin-top: 10px; +} + +.cloud-chip { + display: inline-flex; + align-items: center; + gap: 5px; + padding: 2px 8px; + border: 1px solid var(--border); + border-radius: 8px; + background: var(--bg-sunken); + font-family: var(--font-mono); + font-size: 12px; + color: var(--text); +} + +.cloud-chip button { + display: inline-flex; + padding: 0; + border: none; + background: transparent; + color: var(--text-tertiary); + cursor: pointer; +} + +.cloud-chip button:hover { + color: var(--danger); +} + +.cloud-model-add { + display: flex; + gap: 8px; +} + +.cloud-model-add input { + flex: 1; + min-width: 0; +} + +/* ── 按钮 / 输入 ────────────────────────────────────────────────── */ + +.cloud-btn { + display: inline-flex; + align-items: center; + gap: 5px; + height: 30px; + padding: 0 10px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: transparent; + color: var(--text); + font-family: inherit; + font-size: 12.5px; + cursor: pointer; + transition: background-color var(--dur) var(--ease); +} + +.cloud-btn:hover { + background: var(--bg-sunken); +} + +.cloud-btn:disabled { + opacity: 0.6; + cursor: default; +} + +.cloud-btn.is-danger { + color: var(--danger); + border-color: var(--danger); +} + +.cloud-btn.is-danger-quiet { + color: var(--text-secondary); +} + +.cloud-btn.is-danger-quiet:hover { + color: var(--danger); +} + +/* ── 表单 ───────────────────────────────────────────────────────── */ + +.cloud-form { + display: flex; + flex-direction: column; + gap: 14px; + margin-top: 16px; + padding: 18px 20px; + border: 1px solid var(--border); + border-radius: var(--radius-card); + background: var(--bg-elevated); +} + +.cloud-form h3 { + margin: 0; + font-size: 16px; +} + +.cloud-field { + display: flex; + flex-direction: column; + gap: 6px; +} + +.cloud-field > span { + font-size: 13px; + font-weight: 500; +} + +.cloud-field input { + height: 36px; + padding: 0 12px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: var(--bg-sunken); + color: var(--text); + font-family: inherit; + font-size: 13.5px; +} + +.cloud-field input:focus { + outline: none; + border-color: var(--accent); + box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent-soft) 65%, transparent); +} + +.cloud-field input::placeholder { + color: var(--text-tertiary); +} + +.cloud-field small { + font-size: 12px; + color: var(--text-tertiary); +} + +.cloud-test { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 8px; + padding: 8px 12px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + font-size: 13px; +} + +.cloud-test p { + margin: 0; +} + +.cloud-test.is-ok { + color: var(--success); +} + +.cloud-test.is-fail { + color: var(--danger); +} + +.cloud-form-actions { + display: flex; + gap: 10px; + margin-top: 4px; +} + +/* ── 关于 ───────────────────────────────────────────────────────── */ + +.about-list { + display: flex; + flex-direction: column; + gap: 14px; + margin: 16px 0 0; + max-width: 640px; +} + +.about-list > div { + display: flex; + flex-direction: column; + gap: 2px; +} + +.about-list dt { + font-size: 12.5px; + color: var(--text-tertiary); +} + +.about-list dd { + margin: 0; + font-size: 13.5px; +} + +.about-mono { + font-family: var(--font-mono); + font-size: 12.5px; + word-break: break-all; +} + +/* ── 小转圈(测试/保存中);prefers-reduced-motion 下会被全局关掉 ── */ + +.cloud-spin { + animation: cloud-spin 1s linear infinite; +} + +@keyframes cloud-spin { + to { + transform: rotate(360deg); + } +} + +/* ── 浏览器伴侣桥接(契约 8A)────────────────────────── */ +.bridge-desc { + margin: 0 0 14px; + color: var(--text-secondary); + font-size: 13.5px; + line-height: 1.7; +} +.bridge-status-row { + display: flex; + align-items: center; + gap: 8px; + margin-bottom: 12px; +} +.bridge-dot { + width: 9px; + height: 9px; + border-radius: 50%; + flex-shrink: 0; +} +.bridge-dot.is-on { + background: var(--success); +} +.bridge-dot.is-off { + background: var(--text-tertiary); +} +/* ── 异地访问状态灯(契约 24B):连接中 = warning、失败 = danger。 + 只用主题变量,深浅色各自成套,无硬编码色 ── */ +.bridge-dot.is-busy { + background: var(--warning); +} +.bridge-dot.is-fail { + background: var(--danger); +} +/* ── 异地访问子块(契约 24B):与上面的局域网块用虚线隔开, + 一眼看出这是两个互相独立的开关 ── */ +.remote-block { + margin-top: 18px; + padding-top: 16px; + border-top: 1px dashed var(--border); +} +.remote-privacy { + margin-top: 12px; + margin-bottom: 0; +} +/* 临时网址比局域网地址长,给它留足一行(不然省略号吃掉 .trycloudflare.com) */ +.remote-block .bridge-token { + max-width: min(560px, 100%); +} +.bridge-status-text { + font-size: 13.5px; + color: var(--text); +} +.bridge-error { + margin: 0 0 12px; + color: var(--danger); + font-size: 13px; +} +.bridge-token-row { + display: flex; + align-items: center; + gap: 8px; + flex-wrap: wrap; +} +.bridge-token { + font-family: var(--font-mono); + font-size: 12px; + background: var(--bg-sunken); + border-radius: var(--radius-chip); + padding: 4px 10px; + max-width: 380px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.bridge-path { + direction: rtl; + text-align: left; +} +.bridge-steps { + margin: 14px 0 0; + padding-left: 20px; + color: var(--text-secondary); + font-size: 13px; + line-height: 2; +} + +.about-build { + margin-left: 6px; + font-size: 11.5px; + color: var(--text-tertiary); +} diff --git a/css/composer.css b/css/composer.css new file mode 100644 index 0000000000000000000000000000000000000000..c309cb37a6be6df9a4c0a337caa19f06d805156b --- /dev/null +++ b/css/composer.css @@ -0,0 +1,488 @@ +/* 输入区(Composer)视觉层 —— 两层结构(design-system.md Warm Paper 铁律): + 上层 = textarea(呼吸空间足),下层 = 控件条: + 左组【对话|任务 分段 pill + 批准档 + 权限小字】,右组【思考滑轨 → 模型 → 发送】。 + 组内聚拢(8px)、组间留白(16px)、控件统一 32px 高、圆角按令牌; + 模型选择是窄触发器 + 向上 popover(--shadow-float 描边浮层,不用毛玻璃)。 + 窄窗时按「整组」换行,绝不把控件压扁——发送按钮永远待在右下角。 + 本文件只服务 Composer.tsx;模式切换/批准档的原始规则在 task.css, + 这里用 .composer-bar 前缀做作用域内的密度统一(不改 task.css)。 */ + +/* ---------- 外层:贴底输入区 ---------- */ +.composer-wrap { + padding: 16px 48px 24px; + border-top: 1px solid var(--border); +} + +/* ---------- 输入盒:sunken 底,聚焦 accent 描边 + 极浅外晕 ---------- */ +.composer { + max-width: 760px; + margin: 0 auto; + padding: 12px 14px; + border: 1px solid transparent; + border-radius: var(--radius-float); + background: var(--bg-sunken); + transition: border-color var(--dur) var(--ease); +} + +.composer:focus-within { + border-color: var(--accent); + box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent-soft) 65%, transparent); +} + +/* ---------- 上层:输入 textarea(不与控件抢空间) ---------- */ +.composer-input { + display: block; + width: 100%; + min-height: 44px; + max-height: 200px; + padding: 4px 2px 8px; + border: none; + background: transparent; + color: var(--text); + font-family: var(--font-sans); + font-size: 15px; + line-height: 1.65; + resize: none; + overflow-y: auto; +} + +.composer-input:focus { + outline: none; +} + +.composer-input::placeholder { + color: var(--text-tertiary); +} + +/* ---------- 下层:控件条(左右两组) ---------- */ +.composer-bar { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + gap: 8px 16px; /* 行间 8、组间 16:8px 网格 */ + margin-top: 8px; +} + +.composer-group { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 8px; + flex: 0 0 auto; /* 不缩小:放不下就整组换行,永不挤压控件 */ +} + +.composer-group-end { + margin-left: auto; +} + +/* ---------- 模式切换(契约 6D):Codex 式无边框文字切换 ---------- + 去掉容器边框与凹底(覆盖 task.css 基础款),激活档用暖陶土淡染, + 不再是实心 pill——与整条控制条的「文字优先」一致。 */ +.composer-bar .mode-switch { + gap: 2px; + padding: 0; + border: none; + background: transparent; +} + +.composer-bar .mode-pill { + height: 28px; + padding: 0 10px; + border-radius: var(--radius-chip); + font-size: 13px; + color: var(--text-tertiary); + background: transparent; +} + +.composer-bar .mode-pill:hover { + color: var(--text-secondary); + background: color-mix(in srgb, var(--accent-soft) 45%, transparent); +} + +.composer-bar .mode-pill.is-active { + background: color-mix(in srgb, var(--accent-soft) 85%, transparent); + color: var(--accent); +} + +.quick-tool-wrap{position:relative;z-index:20} +.composer-bar .quick-tool-trigger{display:inline-flex;align-items:center;gap:6px;height:27px;padding:0 8px;border:1px solid var(--border);border-radius:6px;background:transparent;color:var(--text-secondary);font:10px var(--font-sans);cursor:pointer} +.composer-bar .quick-tool-trigger:hover,.composer-bar .quick-tool-trigger[aria-expanded="true"]{color:var(--accent);background:var(--accent-soft)} +.quick-tool-menu{position:absolute;left:0;bottom:calc(100% + 9px);width:268px;padding:8px;border:1px solid var(--border);border-radius:8px;background:var(--bg-elevated);box-shadow:var(--shadow-float)} +.quick-tool-menu>strong{display:block;padding:5px 7px 8px;color:var(--text-tertiary);font-size:9px;font-weight:500} +.quick-tool-item{display:flex;align-items:center;gap:2px} +.quick-tool-item>button:first-child{display:flex;align-items:center;gap:9px;flex:1;min-width:0;height:34px;padding:0 8px;border:0;border-radius:5px;background:transparent;color:var(--text);font-size:10px;text-align:left;cursor:pointer} +.quick-tool-item>button:first-child:hover{background:var(--accent-soft)} +.quick-tool-item>button:first-child>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap} +.quick-tool-pin{display:grid;place-items:center;width:27px;height:27px;border:0;border-radius:5px;background:transparent;color:var(--text-tertiary);cursor:pointer} +.quick-tool-pin:hover,.quick-tool-pin.is-pinned{color:var(--warning);background:var(--bg-sunken)} +.quick-tool-menu>small{display:block;padding:8px 7px 3px;border-top:1px solid var(--border);color:var(--text-tertiary);font-size:9px} +.research-consent{display:flex;align-items:center;gap:12px;flex-wrap:wrap;padding:12px 14px;margin:0 8px 8px;border:1px solid color-mix(in srgb,var(--warning) 45%,var(--border));border-radius:7px;background:var(--bg-sunken)} +.research-consent>div{flex:1;min-width:220px} +.research-consent strong{font-size:11px;color:var(--text)} +.research-consent p{margin:4px 0 0;color:var(--text-secondary);font-size:10px;line-height:1.6} +.research-consent .ws-primary{padding:7px 10px} +.research-consent .ws-link{font-size:10px} + +/* ---------- 批准档(仅任务模式):彩色文字 + 安全图标,去边框下拉 ---------- + Codex 的「⚠ 完全访问」范式:select 视觉隐藏为纯文字载体,图标与文字 + 承担全部观感;全访问=陶土警示色,智能=暖中性偏正向,询问=中性。 */ +.composer-bar .perm-picker { + gap: 5px; + height: 28px; + padding: 0 6px; + border-radius: var(--radius-chip); + cursor: pointer; + transition: background-color var(--dur) var(--ease); +} + +.composer-bar .perm-picker:hover { + background: color-mix(in srgb, var(--accent-soft) 45%, transparent); +} + +.composer-bar .perm-picker select { + appearance: none; + -webkit-appearance: none; + height: 28px; + padding: 0; + border: none; + background: transparent; + color: inherit; + font-family: inherit; + font-size: 12.5px; + cursor: pointer; +} + +.composer-bar .perm-picker select:focus { + outline: none; +} + +.composer-bar .perm-picker select:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +/* 图标与文字同色:按档位着色(图标靠 color: inherit 跟随) */ +.composer-bar .perm-picker.is-full-access { + color: var(--danger); +} +.composer-bar .perm-picker.is-smart-approve { + color: var(--accent); +} +.composer-bar .perm-picker.is-always-ask { + color: var(--text-secondary); +} + +/* ---------- 权限总闸状态小字(只读,契约 13A) ---------- */ +.composer-bar .perm-gate-hint { + align-self: center; + font-size: 11.5px; + line-height: 1.2; + color: var(--text-tertiary); + white-space: nowrap; +} + +/* ---------- 模型选择:窄触发器 + 向上 popover ---------- */ +.model-menu-wrap { + position: relative; + display: inline-flex; +} + +.model-trigger { + display: inline-flex; + align-items: center; + gap: 6px; + height: 28px; + max-width: 176px; + padding: 0 6px; + border: none; + border-radius: var(--radius-chip); + background: transparent; + color: var(--text-secondary); + font-family: inherit; + font-size: 12.5px; + cursor: pointer; + transition: + color var(--dur) var(--ease), + background-color var(--dur) var(--ease); +} + +.model-trigger:hover { + color: var(--text); + background: color-mix(in srgb, var(--accent-soft) 45%, transparent); +} + +.model-trigger[aria-expanded="true"] { + color: var(--text); + background: color-mix(in srgb, var(--accent-soft) 60%, transparent); +} + +.model-trigger:focus-visible, +.model-option:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +.model-trigger-name { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.model-trigger-caret { + flex: 0 0 auto; + color: var(--text-tertiary); +} + +/* 「云」徽章:与全站徽章同尺寸同字重(同 bench 云徽章口径) */ +.model-cloud { + flex: 0 0 auto; + font-size: 11px; + line-height: 1; + padding: 3px 6px; + border-radius: var(--radius-chip); + background: var(--accent-soft); + color: var(--text); +} + +/* popover:Warm Paper 浮层(elevated 底 + 1px 描边 + --shadow-float; + 毛玻璃禁用——透明窗口上 WebKit 的 backdrop-filter 有已知坑)。 + 入场 = opacity + translateY 6px,180ms。 */ +.model-menu { + position: absolute; + right: 0; + bottom: calc(100% + 8px); + z-index: 30; + min-width: 236px; + max-width: 320px; + max-height: 264px; + overflow-y: auto; + padding: 6px; + border: 1px solid var(--border); + border-radius: var(--radius-float); + background: var(--bg-elevated); + box-shadow: var(--shadow-float); + animation: model-menu-in 180ms var(--ease); +} + +@keyframes model-menu-in { + from { + opacity: 0; + transform: translateY(6px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@media (prefers-reduced-motion: reduce) { + .model-menu { + animation: none; + } +} + +.model-option { + display: flex; + align-items: center; + gap: 8px; + width: 100%; + height: 32px; + padding: 0 10px; + border: none; + border-radius: var(--radius-control); + background: transparent; + color: var(--text); + font-family: inherit; + font-size: 12.5px; + text-align: left; + cursor: pointer; + transition: background-color var(--dur) var(--ease); +} + +.model-option:hover { + background: color-mix(in srgb, var(--accent-soft) 40%, transparent); +} + +.model-option.is-active { + background: var(--accent-soft); +} + +.model-option-name { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +/* 空态(没模型):触发器只显示短句,完整人话在浮层里 */ +.model-menu-empty { + margin: 0; + padding: 6px 8px; + max-width: 264px; + color: var(--text-tertiary); + font-size: 12px; + line-height: 1.6; +} + +/* ---------- 右组动作:快捷键提示 + 发送/停止 ---------- */ +.composer-actions { + display: inline-flex; + align-items: center; + gap: 8px; + flex: 0 0 auto; +} + +.composer-hint { + font-size: 12px; + line-height: 1; + color: var(--text-tertiary); + white-space: nowrap; +} + +/* 发送:Codex 式圆形图标按钮(暖陶土实底 + ↑),去文字。 */ +.btn-send { + display: inline-flex; + align-items: center; + justify-content: center; + flex: 0 0 auto; + width: 30px; + height: 30px; + padding: 0; + border: none; + border-radius: 50%; + background: var(--accent); + color: var(--bg); + cursor: pointer; + transition: + background-color var(--dur) var(--ease), + opacity var(--dur) var(--ease), + transform var(--dur) var(--ease); +} + +.btn-send:hover:not(:disabled) { + filter: brightness(0.94); +} + +.btn-send:active:not(:disabled) { + transform: scale(0.94); +} + +.btn-send:disabled { + opacity: 0.4; + cursor: default; +} + +.btn-send:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +/* 停止:圆形描边图标按钮(□),与发送同尺寸。 */ +.btn-stop { + display: inline-flex; + align-items: center; + justify-content: center; + flex: 0 0 auto; + width: 30px; + height: 30px; + padding: 0; + border: 1px solid var(--border); + border-radius: 50%; + background: transparent; + color: var(--text); + cursor: pointer; + transition: background-color var(--dur) var(--ease); +} + +.btn-stop:hover { + background: var(--accent-soft); +} + +.btn-stop:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +.composer-error { + max-width: 760px; + margin: 0 auto 8px; + color: var(--danger); + font-size: 12.5px; +} + +/* ---------- 思考强度胶囊滑轨(契约 6F)---------- + Warm Paper 基调:sunken 细轨 + 五个刻度点 + 圆点手柄; + 手柄 150ms transform 过渡滑动;Ultra 档手柄与轨道末端用 accent + 渐变提示「最烧脑」。不引外部滑块库。 + 收紧版:档名衬线小字(约 50px)+ 72px 轨道(五档间距 18px), + 整条约 128px;任务模式/狂暴锁 Ultra 的语义一字未改。 */ +/* ── 思考强度滑块(契约 6F)—— 对齐参考设计 ────────────────────── + 顶行「思考强度」标题 + 右侧当前档值;下方暗色渐变轨道 + 白色圆旋钮。 + 五档(关/低/中/高/炽焰)连续拖拽,松手吸附。 */ +.think-slider { + display: flex; flex-direction: column; gap: 5px; + flex: 0 0 auto; width: 220px; min-width: 0; +} +.think-slider.is-disabled { opacity: 0.45; pointer-events: none; } +.think-head { + display: flex; justify-content: space-between; align-items: baseline; gap: 6px; +} +.think-label { + font-size: 11px; color: var(--ink-3); white-space: nowrap; +} +.think-value { + font-size: 11px; color: var(--ink-1); font-weight: 600; + font-variant-numeric: tabular-nums; + transition: color var(--dur-2) var(--ease); +} +.think-slider[data-lv="4"] .think-value { color: var(--warning); } + +/* 暗色圆角轨道 + 渐变填充 + 白色圆旋钮 */ +.think-track { + position: relative; height: 16px; border-radius: 999px; + background: linear-gradient(180deg, rgba(0,0,0,0.35), rgba(0,0,0,0.15)); + box-shadow: inset 0 1px 2px rgba(0,0,0,0.35); + cursor: pointer; touch-action: none; +} +.think-fill { + position: absolute; left: 2px; top: 2px; bottom: 2px; + width: calc((var(--think-pos, 0) / 4) * (100% - 4px)); + border-radius: 999px; + background: linear-gradient(90deg, rgba(217,119,87,0.55), rgba(201,162,39,0.75)); + transition: width var(--dur-2) var(--ease); + overflow: hidden; +} +.think-knob { + position: absolute; top: 50%; + left: calc(2px + (var(--think-pos, 0) / 4) * (100% - 4px)); + width: 16px; height: 16px; transform: translate(-50%, -50%); + border-radius: 50%; background: #fff; + box-shadow: 0 1px 4px rgba(0,0,0,0.45), 0 0 0 1px rgba(0,0,0,0.08); + transition: left var(--dur-2) var(--ease); + pointer-events: none; +} +.think-slider[data-lv="4"] .think-knob { + box-shadow: 0 1px 4px rgba(0,0,0,0.45), 0 0 8px rgba(201,162,39,0.6); +} +.think-slider.is-dragging .think-knob, +.think-slider.is-dragging .think-fill { transition: none; } + +/* 星点(飞驰小点,随档位加速) */ +.think-spark { + position: absolute; top: 50%; width: 3px; height: 3px; + transform: translateY(-50%); border-radius: 50%; + background: rgba(255,255,255,0.85); opacity: 0; pointer-events: none; + animation: think-fly var(--d, 1400ms) var(--ease) infinite; + animation-delay: var(--delay, 0ms); +} +@keyframes think-fly { + 0% { left: 0; opacity: 0; } + 15% { opacity: var(--o, 0.8); } + 85% { opacity: var(--o, 0.8); } + 100% { left: 100%; opacity: 0; } +} +@media (prefers-reduced-motion: reduce) { + .think-spark { animation: none; opacity: 0; } +} diff --git a/css/computer-use.css b/css/computer-use.css new file mode 100644 index 0000000000000000000000000000000000000000..7bd8ad3cda5954d4fc40faf495c03e66b1a0db8e --- /dev/null +++ b/css/computer-use.css @@ -0,0 +1,42 @@ +.computer-use-workspace{gap:14px} +.computer-use-tabs{display:flex;gap:3px;padding:4px;width:max-content;max-width:100%;border:1px solid var(--border);border-radius:7px;background:var(--bg-sunken)} +.computer-use-tabs>button{display:flex;align-items:center;gap:7px;min-height:32px;padding:0 11px;border:0;border-radius:5px;background:transparent;color:var(--text-secondary);font-size:11px;cursor:pointer} +.computer-use-tabs>button[aria-selected="true"]{background:var(--bg-elevated);color:var(--accent);box-shadow:0 1px 3px rgba(0,0,0,.08)} +.computer-use-toolbar{display:flex;align-items:flex-end;gap:14px;padding:12px 14px} +.computer-use-toolbar>label{display:grid;gap:5px;min-width:240px;color:var(--text-tertiary);font-size:10px} +.computer-use-toolbar>label select{width:100%} +.computer-local-badge{display:flex;align-items:center;gap:6px;margin-right:auto;color:var(--success);font-size:10px} +.computer-sandbox-card{display:grid;gap:10px;padding:13px} +.computer-sandbox-card>header,.computer-action-log>header{display:flex;align-items:center;gap:10px} +.computer-sandbox-card>header>div{display:grid;gap:3px;margin-right:auto} +.computer-sandbox-card>header strong,.computer-action-log>header strong{font-size:11px;font-weight:600} +.computer-sandbox-card>header span,.computer-action-log>header span{color:var(--text-tertiary);font-size:9px} +.computer-sandbox-canvas{display:block;width:100%;height:auto;max-height:62vh;aspect-ratio:12/7;border:1px solid var(--border);border-radius:4px;background:#eef2f6;object-fit:contain;cursor:default;image-rendering:auto} +.computer-sandbox-canvas.is-agent-running{cursor:progress} +.computer-action-log{display:grid;gap:9px;padding:13px} +.computer-action-log>header{margin-bottom:2px} +.computer-action-log>header>span{margin-left:auto} +.computer-action-log>div{display:grid;grid-template-columns:28px minmax(120px,1fr) minmax(140px,2fr) 70px;align-items:center;gap:9px;padding:7px 0;border-top:1px solid var(--border)} +.computer-action-log>div>small,.computer-action-log>div>code{color:var(--text-tertiary);font:9px var(--font-mono)} +.computer-action-log>div>strong{font-size:10px;font-weight:550} +.computer-action-log>div>span{overflow:hidden;color:var(--text-secondary);font-size:9px;text-overflow:ellipsis;white-space:nowrap} +.computer-action-log .ws-empty{margin:0} +.computer-benchmark{display:grid;gap:13px} +.computer-benchmark>.feature-heading{margin:0;padding:0} +.computer-model-choices{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:7px} +.computer-model-choices>label{display:flex;align-items:center;gap:8px;min-width:0;padding:9px 10px;border:1px solid var(--border);border-radius:5px;background:var(--bg-elevated);font-size:10px} +.computer-model-choices input{accent-color:var(--accent)} +.computer-model-choices>label>span{overflow:hidden;flex:1;text-overflow:ellipsis;white-space:nowrap} +.computer-model-choices small{color:var(--text-tertiary);font:9px var(--font-mono)} +.computer-benchmark-summary{display:flex;flex-wrap:wrap;gap:16px;align-items:center;padding:10px 12px;border:1px solid var(--border);border-radius:5px;background:var(--bg-sunken);font-size:10px} +.computer-benchmark-summary strong{color:var(--accent)} +.computer-benchmark-summary span{color:var(--text-secondary)} +.computer-benchmark-rows{display:grid;gap:6px} +.computer-benchmark-row{padding:10px 12px;border:1px solid var(--border);border-radius:5px;background:var(--bg-elevated)} +.computer-benchmark-row>header{display:grid;grid-template-columns:minmax(100px,1fr) auto minmax(120px,auto);align-items:center;gap:10px} +.computer-benchmark-row>header strong{font-size:10px;font-weight:600} +.computer-benchmark-row>header>span{font-size:9px}.computer-benchmark-row .is-pass{color:var(--success)}.computer-benchmark-row .is-fail{color:var(--warning)} +.computer-benchmark-row>header small{color:var(--text-tertiary);font:9px var(--font-mono);text-align:right} +.computer-benchmark-row>p{margin:8px 0 0;color:var(--text-secondary);font-size:10px;line-height:1.65;white-space:pre-wrap;overflow-wrap:anywhere} +.computer-benchmark-row .computer-failure{display:block;margin-top:6px;color:var(--warning);font-size:9px} +@media(max-width:760px){.computer-use-toolbar{align-items:stretch;flex-direction:column}.computer-use-toolbar>label{min-width:0}.computer-local-badge{margin:0}.computer-action-log>div{grid-template-columns:25px 1fr 60px}.computer-action-log>div>span{grid-column:2/-1}.computer-model-choices{grid-template-columns:1fr}.computer-benchmark-row>header{grid-template-columns:1fr auto}.computer-benchmark-row>header small{grid-column:1/-1;text-align:left}} diff --git a/css/darkside.css b/css/darkside.css new file mode 100644 index 0000000000000000000000000000000000000000..98b53e023ac1c18f7c32005482859dcd36b1fc15 --- /dev/null +++ b/css/darkside.css @@ -0,0 +1,8 @@ +/* V5: graphite, champagne, and restrained depth. Opt-in; old themes stay intact. */ +[data-style="darkside"]{color-scheme:dark;--bg:#101317;--bg-elevated:#171b21;--bg-sunken:#0d1014;--border:#2a3038;--text:#e8eaed;--text-secondary:#9ca5b2;--text-tertiary:#7f8a99;--accent:#e7bf78;--accent-soft:#2f291e;--success:#8bbfb0;--warning:#dec077;--danger:#e79797;--glass:rgba(17,21,27,.94);--scrim:rgba(0,0,0,.6);--shadow-float:0 20px 70px rgba(0,0,0,.42);--font-serif:var(--font-sans)} +[data-style="darkside"] .shell{background:var(--bg)}[data-style="darkside"] .sidebar{background:#12161c;width:210px;border-color:#252b34;padding-left:14px;padding-right:14px}[data-style="darkside"] .brand{gap:8px;padding-bottom:24px}[data-style="darkside"] .brand-name{font-family:var(--font-sans);font-weight:550;font-size:15px;letter-spacing:-.5px}[data-style="darkside"] .brand-mark{color:var(--accent)}[data-style="darkside"] .nav-item{padding:11px 13px;gap:4px;margin-bottom:3px;border:1px solid transparent;border-radius:9px}[data-style="darkside"] .nav-item:hover{background:#1a2029}[data-style="darkside"] .nav-item.is-active{background:linear-gradient(110deg,#27261f,#211f1b);border-color:#3a3325}[data-style="darkside"] .nav-item.is-active:before{display:none}[data-style="darkside"] .nav-item.is-active .nav-row,[data-style="darkside"] .nav-item.is-active .nav-row svg{color:var(--accent)}[data-style="darkside"] .nav-row{font-size:12px;gap:9px}[data-style="darkside"] .nav-row svg{width:15px;height:15px}[data-style="darkside"] .nav-hint{font-size:10px;padding-left:24px}[data-style="darkside"] .sidebar-foot{padding:12px 9px 0;border-top:1px solid var(--border);font-size:9px;letter-spacing:.3px;line-height:2} +.release-plate{display:flex;flex-direction:column;gap:5px;padding:0 8px 22px;color:var(--text-tertiary);font:8px var(--font-mono);letter-spacing:1.5px}.release-plate strong{color:var(--text-secondary);font-size:9px;font-weight:400}.release-plate span{letter-spacing:2px} +[data-style="darkside"] .conversations{background:#12161c;border-right:1px solid var(--border)}[data-style="darkside"] .conv-item.is-active{background:#252a32}[data-style="darkside"] .conv-title{font-size:12px}[data-style="darkside"] .conv-meta{font-size:10px}[data-style="darkside"] .wb-tabs,[data-style="darkside"] .workbench-head{background:var(--bg);border-color:var(--border)}[data-style="darkside"] .composer-box{background:var(--bg-elevated);border-color:#343c47;box-shadow:0 5px 24px rgba(0,0,0,.14)}[data-style="darkside"] .msg-user .msg-card{background:#232933;border:1px solid #313946}[data-style="darkside"] .msg-assistant .msg-body{font-size:14px;line-height:1.9}[data-style="darkside"] .stats-bar{font-size:10px;border-color:var(--border)}[data-style="darkside"] button,[data-style="darkside"] input,[data-style="darkside"] select,[data-style="darkside"] textarea{transition:background-color .16s ease,border-color .16s ease,box-shadow .16s ease}[data-style="darkside"] :focus-visible{outline:2px solid var(--accent);outline-offset:3px}[data-style="darkside"] .pref-section,[data-style="darkside"] .settings-section{border-color:var(--border)}[data-style="darkside"] .style-picker{flex-wrap:wrap;justify-content:flex-end} +[data-style="darkside"][data-theme="light"]{color-scheme:light;--bg:#f5f4f0;--bg-elevated:#fff;--bg-sunken:#eeece6;--border:#d9d5cc;--text:#20252b;--text-secondary:#5b6571;--text-tertiary:#717b86;--accent:#805c29;--accent-soft:#eee4d1;--success:#356c5b;--warning:#8a6725;--danger:#a13b3b;--glass:rgba(245,244,240,.94)} +[data-style="darkside"][data-theme="light"] .sidebar,[data-style="darkside"][data-theme="light"] .conversations{background:#ebe9e2;border-color:var(--border)}[data-style="darkside"][data-theme="light"] .nav-item.is-active{background:var(--accent-soft);border-color:#d7c7a6}[data-style="darkside"][data-theme="light"] .nav-item:hover,[data-style="darkside"][data-theme="light"] .conv-item.is-active{background:#e1ddd1}[data-style="darkside"][data-theme="light"] .msg-user .msg-card{background:#ece8df;border-color:var(--border)} +@media(prefers-reduced-motion:reduce){.workspace-page *,[data-style="darkside"] *{animation:none!important;transition:none!important;scroll-behavior:auto!important}} diff --git a/css/diag.css b/css/diag.css new file mode 100644 index 0000000000000000000000000000000000000000..2202a7bd97b70d306ca447897b81c895474b09a8 --- /dev/null +++ b/css/diag.css @@ -0,0 +1,569 @@ +/* 错误诊断 · 体检报告(Warm Paper,全令牌配色,无硬编码颜色)。 + 只读呈现:没有任何「立即修复」按钮,徽章仅表达状态与修复难度。 */ + +.diag { + flex: 1; + min-width: 0; + overflow-y: auto; + padding: 36px 48px 48px; +} + +.diag-head { + margin-bottom: 24px; +} + +.diag-head-row { + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; +} + +.diag-head h1 { + font-size: 30px; +} + +.diag-refresh { + flex-shrink: 0; +} + +.diag-refresh:disabled { + opacity: 0.6; + cursor: default; +} + +.diag-sub { + margin: 6px 0 0; + font-size: 13.5px; + color: var(--text-secondary); + font-variant-numeric: tabular-nums; +} + +.diag-sub-dim { + color: var(--text-tertiary); +} + +/* ── 检查卡列表 ───────────────────────────────────────────────────── */ + +.diag-list { + display: flex; + flex-direction: column; + gap: 16px; +} + +.diag-card { + padding: 20px 22px 18px; + border: 1px solid var(--border); + border-radius: var(--radius-card); + background: var(--bg-elevated); +} + +/* 状态只用左侧一条细色带表达,克制不喧哗(design-system §2 语义色规则) */ +.diag-card.is-warn { + border-left: 3px solid var(--warning); +} + +.diag-card.is-critical { + border-left: 3px solid var(--danger); +} + +.diag-card.is-ok { + border-left: 3px solid var(--success); +} + +.diag-card-head { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + margin-bottom: 12px; +} + +.diag-card-title { + font-size: 16px; +} + +/* ── 徽章 ─────────────────────────────────────────────────────────── */ + +/* 徽章:与全站徽章同尺寸同字重(2px 8px / 12px / 500 / pill) */ +.diag-badge { + display: inline-flex; + align-items: center; + flex-shrink: 0; + padding: 2px 8px; + border-radius: 999px; + font-size: 12px; + font-weight: 500; + line-height: 1.6; +} + +.diag-badge-status.is-ok { + background: color-mix(in srgb, var(--success) 14%, transparent); + color: var(--success); +} + +.diag-badge-status.is-warn { + background: color-mix(in srgb, var(--warning) 16%, transparent); + color: var(--warning); +} + +.diag-badge-status.is-critical { + background: color-mix(in srgb, var(--danger) 14%, transparent); + color: var(--danger); +} + +.diag-badge-risk.is-green { + background: color-mix(in srgb, var(--success) 14%, transparent); + color: var(--success); +} + +.diag-badge-risk.is-yellow { + background: color-mix(in srgb, var(--warning) 16%, transparent); + color: var(--warning); +} + +.diag-badge-risk.is-red { + background: color-mix(in srgb, var(--danger) 14%, transparent); + color: var(--danger); +} + +/* ── 三段式文案 ───────────────────────────────────────────────────── */ + +.diag-card-body { + display: flex; + flex-direction: column; + gap: 8px; +} + +.diag-line { + display: flex; + align-items: baseline; + gap: 12px; +} + +.diag-line-label { + flex-shrink: 0; + width: 64px; + font-size: 12px; + color: var(--text-tertiary); +} + +.diag-line-text { + margin: 0; + font-size: 13.5px; + line-height: 1.65; + color: var(--text); +} + +.diag-fix-hint { + margin: 4px 0 0; + font-size: 12.5px; + color: var(--text-secondary); + font-family: var(--font-mono); +} + +/* ── 明细列表(崩溃报告 / Top 进程 / 端口)─────────────────────────── */ + +.diag-crash-list, +.diag-mini-list { + list-style: none; + margin: 12px 0 0; + padding: 12px 0 0; + border-top: 1px solid var(--border); +} + +.diag-crash, +.diag-mini { + display: flex; + align-items: baseline; + gap: 12px; + padding: 5px 0; + font-size: 13px; + font-variant-numeric: tabular-nums; +} + +.diag-crash-name, +.diag-mini-name { + flex-shrink: 0; + min-width: 96px; + color: var(--text); + overflow-wrap: anywhere; +} + +.diag-crash-time { + flex: 1; + min-width: 0; + color: var(--text-secondary); + overflow-wrap: anywhere; +} + +.diag-crash-kind { + flex-shrink: 0; + max-width: 220px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font-family: var(--font-mono); + font-size: 12px; + color: var(--text-tertiary); +} + +.diag-mini-value { + flex: 1; + min-width: 0; + text-align: right; + color: var(--text-secondary); + font-variant-numeric: tabular-nums; + overflow-wrap: anywhere; +} + +/* 文字按钮(查看原文):无底色,hover 才出现下划线 */ +.diag-link-btn { + flex-shrink: 0; + padding: 0; + border: none; + background: transparent; + color: var(--accent); + font-family: inherit; + font-size: 13px; + cursor: pointer; + transition: opacity var(--dur) var(--ease); +} + +.diag-link-btn:hover { + text-decoration: underline; +} + +/* ── 卡片脚注(修复难度徽章 + 温和话术)────────────────────────────── */ + +.diag-card-foot { + display: flex; + align-items: baseline; + gap: 10px; + margin-top: 12px; +} + +.diag-risk-note { + font-size: 12.5px; + color: var(--text-tertiary); +} + +.diag-foot { + margin: 8px 0 0; + font-size: 12px; + color: var(--text-tertiary); +} + +/* ── 空态 / 加载态(衬线大字一句话,design-system §7)──────────────── */ + +.diag-empty { + padding: 56px 0 24px; +} + +.diag-empty-title { + margin: 0; + font-family: var(--font-serif); + font-size: 24px; + font-weight: 600; + color: var(--text); +} + +.diag-empty-sub { + margin: 10px 0 0; + max-width: 560px; + font-size: 13.5px; + color: var(--text-secondary); +} + +/* 呼吸点加载指示:三点错峰呼吸(reduced-motion 时 theme.css 全局静止) */ +@keyframes diag-breathe { + 0%, + 100% { + opacity: 0.25; + } + 50% { + opacity: 1; + } +} + +.diag-loading-dots { + display: inline-flex; + gap: 5px; + margin-left: 10px; + vertical-align: middle; +} + +.diag-loading-dots span { + width: 6px; + height: 6px; + border-radius: 50%; + background: var(--accent); + animation: diag-breathe 1.2s var(--ease) infinite; +} + +.diag-loading-dots span:nth-child(2) { + animation-delay: 150ms; +} + +.diag-loading-dots span:nth-child(3) { + animation-delay: 300ms; +} + +/* ── 修复区(Phase 6A):🟢 直接可点 / 🟡 先确认 ────────────────────── */ + +.diag-fixes { + display: flex; + flex-direction: column; + gap: 10px; + margin-top: 14px; + padding-top: 12px; + border-top: 1px solid var(--border); +} + +.diag-fix { + display: flex; + flex-direction: column; + gap: 10px; + align-items: flex-start; +} + +/* 修复按钮:语义色只做描边与文字,底色保持纸感(design-system §2) */ +.diag-fix-btn { + height: 34px; + padding: 0 14px; + border: 1px solid transparent; + border-radius: var(--radius-control); + font-family: inherit; + font-size: 13px; + cursor: pointer; + transition: background-color var(--dur) var(--ease), opacity var(--dur) var(--ease); +} + +.diag-fix-btn.is-green { + background: color-mix(in srgb, var(--success) 14%, transparent); + border-color: color-mix(in srgb, var(--success) 32%, transparent); + color: var(--success); +} + +.diag-fix-btn.is-green:hover:not(:disabled) { + background: color-mix(in srgb, var(--success) 22%, transparent); +} + +.diag-fix-btn.is-yellow { + background: color-mix(in srgb, var(--warning) 14%, transparent); + border-color: color-mix(in srgb, var(--warning) 34%, transparent); + color: var(--warning); +} + +.diag-fix-btn.is-yellow:hover:not(:disabled) { + background: color-mix(in srgb, var(--warning) 22%, transparent); +} + +.diag-fix-btn:disabled { + opacity: 0.55; + cursor: default; +} + +/* 展开的「会发生什么」面板 */ +.diag-fix-panel { + width: 100%; + padding: 12px 14px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: var(--bg-sunken); + display: flex; + flex-direction: column; + gap: 10px; +} + +.diag-fix-detail { + margin: 0; + font-size: 13px; + line-height: 1.65; + color: var(--text); +} + +/* 候选清单:默认全不勾,一行一项 */ +.diag-candidates { + list-style: none; + margin: 0; + padding: 0; + display: flex; + flex-direction: column; + gap: 2px; +} + +.diag-candidate { + display: flex; + align-items: baseline; + gap: 10px; + padding: 5px 6px; + border-radius: var(--radius-chip); + cursor: pointer; + font-size: 13px; +} + +.diag-candidate:hover { + background: color-mix(in srgb, var(--accent-soft) 40%, transparent); +} + +.diag-candidate input { + flex-shrink: 0; + align-self: center; + accent-color: var(--accent); +} + +.diag-candidate-title { + flex-shrink: 0; + max-width: 40%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + color: var(--text); +} + +.diag-candidate-size { + flex-shrink: 0; + min-width: 72px; + text-align: right; + color: var(--text-secondary); + font-variant-numeric: tabular-nums; +} + +.diag-candidate-detail { + flex: 1; + min-width: 0; + color: var(--text-tertiary); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.diag-fix-summary { + margin: 0; + font-size: 12.5px; + color: var(--text-secondary); + font-variant-numeric: tabular-nums; +} + +.diag-fix-actions { + display: flex; + align-items: center; + gap: 10px; +} + +/* 修复结果行:人话 + 释放体积 + 可撤销说明 */ +.diag-fix-result { + display: flex; + align-items: baseline; + gap: 8px; + margin: 0; + max-width: 100%; + font-size: 13px; + line-height: 1.65; +} + +.diag-fix-result.is-ok { + color: var(--text); +} + +.diag-fix-result.is-note { + color: var(--text-secondary); +} + +.diag-fix-result-mark { + flex-shrink: 0; + font-family: var(--font-mono); +} + +.diag-fix-result.is-ok .diag-fix-result-mark { + color: var(--success); +} + +.diag-fix-undone { + color: var(--text-secondary); +} + +.diag-open-settings { + margin-top: 12px; +} + +/* ── 后悔药(隔离区清单)───────────────────────────────────────────── */ + +.diag-trash { + margin-top: 10px; + padding: 18px 22px; + border: 1px solid var(--border); + border-radius: var(--radius-card); + background: var(--bg-elevated); +} + +.diag-trash-head { + display: flex; + align-items: baseline; + gap: 14px; + flex-wrap: wrap; +} + +.diag-trash-title { + margin: 0; + font-size: 16px; +} + +.diag-trash-sub { + margin: 0; + font-size: 12.5px; + color: var(--text-secondary); +} + +.diag-trash-empty { + margin: 12px 0 0; + font-family: var(--font-serif); + font-size: 15px; + color: var(--text-tertiary); +} + +.diag-trash-list { + list-style: none; + margin: 12px 0 0; + padding: 0; + display: flex; + flex-direction: column; +} + +.diag-trash-item { + display: flex; + align-items: baseline; + gap: 12px; + padding: 7px 0; + border-top: 1px solid var(--border); + font-size: 13px; + font-variant-numeric: tabular-nums; + flex-wrap: wrap; +} + +.diag-trash-time { + flex-shrink: 0; + min-width: 168px; + color: var(--text-secondary); +} + +.diag-trash-info { + flex: 1; + min-width: 160px; + color: var(--text); +} + +.diag-trash-confirm { + display: inline-flex; + align-items: baseline; + gap: 8px; + font-size: 12.5px; + color: var(--text-secondary); +} + +.diag-trash-confirm-yes { + height: 28px; + padding: 0 10px; + font-size: 12.5px; +} diff --git a/css/discuss.css b/css/discuss.css new file mode 100644 index 0000000000000000000000000000000000000000..d3b4c7bd0d50ab78eab29b26fe2ce4e0707b80da --- /dev/null +++ b/css/discuss.css @@ -0,0 +1,566 @@ +/* 模型讨论区(契约 25A · 工作台「讨论」tab)——Warm Paper 令牌,零硬编码色: + 所有颜色走 theme.css 变量(深浅色自动跟随)。布局沿用 .bench 的整页滚动容器。 */ + +.discuss { + flex: 1; + min-width: 0; + overflow-y: auto; + padding: 36px 48px 48px; +} + +/* ── 页头 ───────────────────────────────────────────────────────── */ + +.discuss-head { + display: flex; + align-items: flex-end; + justify-content: space-between; + gap: 16px; + margin-bottom: 20px; +} + +.discuss-title { + font-family: var(--font-serif); + font-size: 26px; + font-weight: 600; + letter-spacing: -0.01em; + color: var(--text); +} + +.discuss-head-sub { + margin: 6px 0 0; + font-size: 13.5px; + line-height: 1.6; + color: var(--text-secondary); +} + +.discuss-head-actions { + display: flex; + gap: 8px; + flex-shrink: 0; +} + +.discuss-muted { + font-size: 13px; + line-height: 1.6; + color: var(--text-secondary); +} + +.discuss-notice { + margin: 0 0 16px; + padding: 10px 14px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: var(--bg-elevated); + font-size: 13.5px; + line-height: 1.6; + color: var(--text); +} + +/* ── 卡片与表单 ─────────────────────────────────────────────────── */ + +.discuss-card { + background: var(--bg-elevated); + border: 1px solid var(--border); + border-radius: var(--radius-card); + padding: 22px 24px; + margin-bottom: 24px; +} + +.discuss-card-title { + font-family: var(--font-serif); + font-size: 18px; + font-weight: 600; + color: var(--text); + margin: 0 0 18px; +} + +.discuss-field { + display: flex; + flex-direction: column; + gap: 8px; + margin-bottom: 18px; +} + +.discuss-field-label { + font-size: 13px; + color: var(--text-secondary); +} + +.discuss-field textarea { + width: 100%; + font-family: var(--font-sans); + font-size: 14px; + line-height: 1.65; + color: var(--text); + background: var(--bg-sunken); + border: 1px solid transparent; + border-radius: var(--radius-control); + padding: 10px 12px; + resize: vertical; + min-height: 72px; + transition: border-color var(--dur) var(--ease); +} + +.discuss-field textarea::placeholder { + color: var(--text-tertiary); +} + +.discuss-field textarea:focus-visible { + outline: none; + border-color: var(--accent); +} + +/* ── 模型分组多选(本机 / 云 · 接口名) ───────────────────────────── */ + +.discuss-groups { + display: flex; + flex-direction: column; + gap: 14px; +} + +.discuss-group { + display: flex; + flex-direction: column; + gap: 8px; +} + +.discuss-group-label { + font-family: var(--font-serif); + font-size: 14px; + font-weight: 600; + color: var(--text); +} + +.discuss-chips { + display: flex; + flex-wrap: wrap; + gap: 8px; +} + +.discuss-chip { + display: inline-flex; + align-items: center; + gap: 7px; + height: 30px; + padding: 0 11px; + border: 1px solid var(--border); + border-radius: var(--radius-chip); + background: var(--bg); + color: var(--text-secondary); + font-family: inherit; + font-size: 13px; + cursor: pointer; + transition: + background-color var(--dur) var(--ease), + border-color var(--dur) var(--ease), + color var(--dur) var(--ease); +} + +.discuss-chip:hover { + background: var(--accent-soft); + color: var(--text); +} + +.discuss-chip.is-on { + background: var(--accent-soft); + border-color: var(--accent); + color: var(--text); + font-weight: 600; +} + +.discuss-chip:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +.discuss-chip-name { + max-width: 200px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.discuss-chip-badge { + font-size: 11px; + line-height: 1; + padding: 3px 6px; + border-radius: var(--radius-chip); + background: var(--bg-sunken); + color: var(--text-secondary); +} + +.discuss-chip-badge.is-cloud { + background: var(--accent-soft); + color: var(--text); +} + +/* ── 轮数选择 + 预算说明 ───────────────────────────────────────── */ + +.discuss-rounds { + display: inline-flex; + gap: 4px; + padding: 4px; + background: var(--bg-sunken); + border-radius: var(--radius-control); +} + +.discuss-round-btn { + min-width: 34px; + height: 28px; + padding: 0 8px; + border: none; + border-radius: var(--radius-control); + background: transparent; + color: var(--text-secondary); + font-family: inherit; + font-size: 13px; + cursor: pointer; + transition: background-color var(--dur) var(--ease), color var(--dur) var(--ease); +} + +.discuss-round-btn:hover { + color: var(--text); +} + +.discuss-round-btn.is-on { + background: var(--bg-elevated); + color: var(--text); + font-weight: 600; + box-shadow: inset 0 0 0 1px var(--border); +} + +.discuss-round-btn:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +.discuss-budget { + margin: 4px 0 0; + font-size: 12.5px; + line-height: 1.6; + color: var(--text-secondary); +} + +/* ── 按钮 ───────────────────────────────────────────────────────── */ + +.discuss-actions { + display: flex; + align-items: center; + gap: 14px; + flex-wrap: wrap; +} + +.discuss-primary { + display: inline-flex; + align-items: center; + gap: 7px; + height: 38px; + padding: 0 18px; + border: none; + border-radius: var(--radius-control); + background: var(--accent); + color: var(--bg); + font-family: inherit; + font-size: 14px; + font-weight: 600; + cursor: pointer; + transition: opacity var(--dur) var(--ease); +} + +.discuss-primary:hover:not(:disabled) { + opacity: 0.9; +} + +.discuss-primary:disabled { + opacity: 0.45; + cursor: not-allowed; +} + +.discuss-primary:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +.discuss-secondary, +.discuss-danger { + display: inline-flex; + align-items: center; + gap: 6px; + height: 30px; + padding: 0 11px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: transparent; + color: var(--text-secondary); + font-family: inherit; + font-size: 13px; + cursor: pointer; + transition: + background-color var(--dur) var(--ease), + color var(--dur) var(--ease), + border-color var(--dur) var(--ease); +} + +.discuss-secondary:hover:not(:disabled) { + background: var(--accent-soft); + color: var(--text); +} + +.discuss-secondary:disabled { + opacity: 0.45; + cursor: not-allowed; +} + +.discuss-danger { + color: var(--danger); + border-color: var(--danger); +} + +.discuss-danger:hover { + background: var(--danger); + color: var(--bg); +} + +.discuss-secondary:focus-visible, +.discuss-danger:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +/* ── 运行头 + 进度 ──────────────────────────────────────────────── */ + +.discuss-run-head { + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; + flex-wrap: wrap; + margin-bottom: 14px; +} + +.discuss-run-title { + display: flex; + align-items: center; + gap: 10px; + flex-wrap: wrap; + min-width: 0; +} + +.discuss-run-title .discuss-card-title { + margin: 0; +} + +.discuss-toolbar { + display: flex; + gap: 8px; + flex-shrink: 0; +} + +.discuss-progress-label { + margin: 0 0 6px; + font-size: 12.5px; + color: var(--text-secondary); +} + +.discuss-progress { + height: 6px; + border-radius: var(--radius-chip); + background: var(--bg-sunken); + overflow: hidden; + margin-bottom: 16px; +} + +.discuss-progress-fill { + height: 100%; + background: var(--accent); + border-radius: var(--radius-chip); + transition: width var(--dur) var(--ease); +} + +.discuss-stop-reason { + margin: 0 0 14px; + padding: 9px 13px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: var(--bg-sunken); + font-size: 13px; + line-height: 1.6; + color: var(--text-secondary); +} + +/* ── 状态点 / 徽章 ──────────────────────────────────────────────── */ + +.discuss-dot { + width: 9px; + height: 9px; + flex-shrink: 0; + border-radius: 50%; + background: var(--text-tertiary); +} + +.discuss-dot.is-running { + background: var(--accent); +} + +.discuss-dot.is-done { + background: var(--success); +} + +.discuss-dot.is-error { + background: var(--danger); +} + +.discuss-dot.is-cancelled { + background: var(--warning); +} + +.discuss-badge { + display: inline-flex; + align-items: center; + height: 20px; + padding: 0 8px; + border-radius: var(--radius-chip); + background: var(--bg-sunken); + font-size: 11.5px; + color: var(--text-secondary); + white-space: nowrap; +} + +.discuss-badge.is-running { + background: var(--accent-soft); + color: var(--text); +} + +.discuss-badge.is-done { + color: var(--success); +} + +.discuss-badge.is-error { + color: var(--danger); +} + +.discuss-badge.is-cancelled { + color: var(--warning); +} + +/* ── 逐条发言流 ─────────────────────────────────────────────────── */ + +.discuss-thread { + display: flex; + flex-direction: column; + gap: 14px; +} + +.discuss-msg { + border: 1px solid var(--border); + border-radius: var(--radius-card); + background: var(--bg); + padding: 14px 16px; +} + +.discuss-msg.is-streaming { + border-color: var(--accent); +} + +.discuss-msg.is-failed { + background: var(--bg-sunken); +} + +.discuss-msg-head { + display: flex; + align-items: center; + gap: 10px; + flex-wrap: wrap; + margin-bottom: 8px; +} + +.discuss-msg-author { + font-family: var(--font-serif); + font-size: 14px; + font-weight: 600; + color: var(--text); +} + +.discuss-msg-round { + font-family: var(--font-mono); + font-size: 11.5px; + color: var(--text-tertiary); +} + +.discuss-msg-live { + display: inline-flex; + align-items: center; + height: 18px; + padding: 0 7px; + border-radius: var(--radius-chip); + background: var(--accent-soft); + font-size: 11px; + color: var(--text); +} + +.discuss-msg-failed { + display: inline-flex; + align-items: center; + height: 18px; + padding: 0 7px; + border-radius: var(--radius-chip); + background: var(--bg-sunken); + font-size: 11px; + color: var(--warning); +} + +.discuss-msg-body { + font-size: 14px; + line-height: 1.7; + color: var(--text); +} + +.discuss-msg-error { + margin: 0; + font-size: 13px; + line-height: 1.6; + color: var(--danger); +} + +.discuss-msg-body.md > * { + margin: 0 0 10px; +} + +.discuss-msg-body.md > *:last-child { + margin-bottom: 0; +} + +/* 流式光标(克制的闪烁点) */ +.discuss-caret { + display: inline-block; + width: 7px; + height: 15px; + margin-left: 2px; + vertical-align: text-bottom; + background: var(--accent); + border-radius: 1px; + animation: discuss-caret-blink 1s steps(2, start) infinite; +} + +@keyframes discuss-caret-blink { + to { + opacity: 0; + } +} + +.discuss-distilled { + margin: 16px 0 0; + font-size: 12.5px; + color: var(--success); +} + +/* ── 动效克制(尊重 reduced-motion) ────────────────────────────── */ + +@media (prefers-reduced-motion: reduce) { + .discuss *, + .discuss *::before, + .discuss *::after { + transition-duration: 0.01ms !important; + animation-duration: 0.01ms !important; + } +} diff --git a/css/dropzone.css b/css/dropzone.css new file mode 100644 index 0000000000000000000000000000000000000000..4b0d5c8b839fd9ec1921e6965acc4d10aa1289ab --- /dev/null +++ b/css/dropzone.css @@ -0,0 +1,102 @@ +/* 拖文件即问:Warm Paper 拖放蒙层 + 温和说明条(颜色走 theme.css 令牌) */ + +/* 全屏蒙层:半透明暖纸底,覆盖主窗口内容区之上 */ +.dropzone { + position: fixed; + inset: 0; + z-index: 60; + display: flex; + align-items: center; + justify-content: center; + background: color-mix(in srgb, var(--bg) 82%, transparent); + backdrop-filter: none; /* WebKit 透明窗口坑:不要用 backdrop-filter(坑位实测记录 #1) */ + animation: dropzone-in 150ms var(--ease); +} + +@keyframes dropzone-in { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +.dropzone-card { + display: flex; + flex-direction: column; + align-items: center; + gap: 16px; + padding: 48px 64px; + border: 1px dashed var(--border); + border-radius: var(--radius-float); + background: var(--glass); + box-shadow: var(--shadow-float); + text-align: center; +} + +.dropzone-icon { + color: var(--accent); +} + +.dropzone-title { + margin: 0; + font-family: var(--font-serif); + font-size: 30px; + font-weight: 600; + letter-spacing: -0.01em; + line-height: 1.3; + color: var(--text); +} + +.dropzone-sub { + margin: 0; + max-width: 360px; + font-size: 13.5px; + line-height: 1.65; + color: var(--text-secondary); +} + +/* 不支持文件时的温和说明条(底部浮出) */ +.dropzone-notice { + position: fixed; + left: 50%; + bottom: 28px; + z-index: 70; + transform: translateX(-50%); + display: flex; + align-items: center; + gap: 16px; + max-width: 560px; + padding: 12px 16px; + border: 1px solid var(--border); + border-radius: var(--radius-card); + background: var(--bg-elevated); + box-shadow: var(--shadow-float); + animation: dropzone-in 150ms var(--ease); +} + +.dropzone-notice-text { + font-size: 13px; + line-height: 1.6; + color: var(--text-secondary); +} + +.dropzone-notice-close { + flex-shrink: 0; + height: 28px; + padding: 0 12px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: transparent; + color: var(--text-secondary); + font-family: inherit; + font-size: 12.5px; + cursor: pointer; + transition: background-color var(--dur) var(--ease); +} + +.dropzone-notice-close:hover { + background: var(--bg-sunken); + color: var(--text); +} diff --git a/css/evolution.css b/css/evolution.css new file mode 100644 index 0000000000000000000000000000000000000000..acf4b20c717faa77a4b943196e3317a3177126d8 --- /dev/null +++ b/css/evolution.css @@ -0,0 +1,370 @@ +/* RSI 自我进化区(契约 11B-B3)——只用 theme.css 的色彩令牌,不硬编码颜色; + 风格对齐 Warm Paper(design-system.md):留白优先、克制动效、卡片 1px 描边。 */ + +/* 挂在「常驻助理」区里:视觉上是同一页的第二个子区(分隔线 + 略小的标题) */ +.rsi-section { + margin-top: 32px; + padding-top: 24px; + border-top: 1px solid var(--border); +} + +.rsi-section h2 { + font-size: 18px; +} + +.rsi-intro { + margin: 0 0 20px; + font-size: 13.5px; + line-height: 1.7; + color: var(--text-secondary); +} + +.rsi-intro strong { + color: var(--text); + font-weight: 600; +} + +/* 指令开关的红字说明(契约:这个开关要配红字提醒) */ +.rsi-danger-note { + color: var(--danger) !important; + line-height: 1.6; +} + +.rsi-select { + flex-shrink: 0; + padding: 7px 10px; + border: 1px solid var(--border); + border-radius: 10px; + background: var(--bg-sunken); + color: var(--text); + font: inherit; + font-size: 13px; +} + +/* ---------- 一眼状态 ---------- */ +.rsi-status { + margin-top: 20px; + padding: 14px 16px; + border: 1px solid var(--border); + border-radius: 14px; + background: var(--bg-elevated); +} + +.rsi-status-line { + display: flex; + flex-wrap: wrap; + gap: 6px 18px; + font-size: 13px; + color: var(--text-secondary); + font-variant-numeric: tabular-nums; +} + +.rsi-status-line strong { + color: var(--text); +} + +.rsi-gates { + display: flex; + flex-wrap: wrap; + gap: 8px; + margin: 12px 0 10px; +} + +.rsi-gate { + padding: 3px 10px; + border: 1px solid var(--border); + border-radius: 999px; + font-size: 12px; + color: var(--text-tertiary); + background: var(--bg-sunken); +} + +.rsi-gate.is-on { + border-color: var(--success); + color: var(--success); + background: transparent; +} + +/* ---------- 操作 ---------- */ +.rsi-actions { + display: flex; + flex-wrap: wrap; + gap: 10px; + margin-top: 18px; +} + +.rsi-actions button { + display: inline-flex; + align-items: center; + gap: 6px; +} + +/* ---------- 一轮结论 ---------- */ +.rsi-outcome { + display: flex; + flex-direction: column; + gap: 4px; + margin-top: 16px; + padding: 12px 14px; + border: 1px solid var(--border); + border-left-width: 3px; + border-radius: 10px; + background: var(--bg-elevated); + font-size: 13px; + line-height: 1.6; + color: var(--text); +} + +.rsi-outcome.is-promoted { + border-left-color: var(--success); +} + +.rsi-outcome.is-rejected, +.rsi-outcome.is-aborted, +.rsi-outcome.is-disabled { + border-left-color: var(--danger); +} + +.rsi-outcome-kind { + font-size: 11.5px; + letter-spacing: 0.06em; + color: var(--text-tertiary); + text-transform: uppercase; +} + +.rsi-outcome-scores { + color: var(--text-secondary); + font-variant-numeric: tabular-nums; +} + +/* ---------- 探针得分明细 ---------- */ +.rsi-details { + margin-top: 20px; + border-top: 1px solid var(--border); + padding-top: 14px; +} + +.rsi-details h3 { + display: flex; + align-items: center; + gap: 10px; + margin: 0 0 10px; + font-family: "Source Serif 4", "Songti SC", Georgia, serif; + font-size: 15px; + font-weight: 600; + color: var(--text); +} + +.rsi-probe { + padding: 10px 12px; + border: 1px solid var(--border); + border-radius: 10px; + background: var(--bg); + margin-bottom: 8px; +} + +.rsi-probe.is-failed { + border-color: var(--danger); +} + +.rsi-probe-head { + display: flex; + align-items: center; + gap: 10px; +} + +.rsi-probe-kind { + font-size: 11.5px; + color: var(--text-tertiary); +} + +.rsi-probe-id { + font-family: "JetBrains Mono", "SF Mono", Menlo, monospace; + font-size: 12px; + color: var(--text-secondary); +} + +.rsi-probe-verdict { + margin-left: auto; + font-size: 12px; + color: var(--success); +} + +.rsi-probe-verdict.is-no { + color: var(--danger); +} + +.rsi-probe-question, +.rsi-probe-answer { + margin: 6px 0 0; + font-size: 12.5px; + line-height: 1.6; +} + +.rsi-probe-question { + color: var(--text); +} + +.rsi-probe-answer { + color: var(--text-tertiary); +} + +/* ---------- 时间线 ---------- */ +.rsi-timeline-title { + margin: 26px 0 8px; + font-family: "Source Serif 4", "Songti SC", Georgia, serif; + font-size: 16px; + font-weight: 600; + color: var(--text); +} + +.rsi-timeline { + list-style: none; + margin: 0; + padding: 0; +} + +.rsi-item { + position: relative; + padding: 12px 0 12px 16px; + border-left: 2px solid var(--border); +} + +.rsi-item::before { + content: ""; + position: absolute; + left: -5px; + top: 18px; + width: 8px; + height: 8px; + border-radius: 50%; + background: var(--text-tertiary); +} + +.rsi-item.is-rejected { + border-left-color: var(--danger); +} + +.rsi-item.is-rejected::before { + background: var(--danger); +} + +.rsi-item-head { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 8px; +} + +.rsi-version { + font-family: "JetBrains Mono", "SF Mono", Menlo, monospace; + font-size: 13px; + font-weight: 600; + color: var(--text); +} + +.rsi-version.is-current { + color: var(--accent); +} + +.rsi-version.is-rejected { + display: inline-flex; + align-items: center; + gap: 4px; + color: var(--danger); +} + +.rsi-time { + font-size: 12px; + color: var(--text-tertiary); + font-variant-numeric: tabular-nums; +} + +.rsi-badge { + padding: 1px 8px; + border: 1px solid var(--accent); + border-radius: 999px; + font-size: 11px; + color: var(--accent); +} + +.rsi-badge.is-warn { + border-color: var(--warning); + color: var(--warning); +} + +.rsi-item-meta { + display: flex; + flex-wrap: wrap; + gap: 6px 14px; + margin-top: 4px; + font-size: 12.5px; + color: var(--text-secondary); + font-variant-numeric: tabular-nums; +} + +.rsi-score.is-up { + color: var(--success); +} + +.rsi-score.is-down { + color: var(--danger); +} + +.rsi-score.is-pending { + color: var(--text-tertiary); +} + +.rsi-source { + margin: 6px 0 0; + font-size: 12px; + line-height: 1.6; + color: var(--text-tertiary); +} + +.rsi-reject-reason { + margin: 6px 0 0; + font-size: 13px; + line-height: 1.6; + color: var(--danger); +} + +/* 经验卡折叠列表 */ +.rsi-cards { + margin-top: 8px; + font-size: 12.5px; +} + +.rsi-cards summary { + cursor: pointer; + color: var(--text-secondary); +} + +.rsi-cards ul { + list-style: none; + margin: 8px 0 0; + padding: 0; +} + +.rsi-cards li { + padding: 8px 10px; + margin-bottom: 6px; + border: 1px solid var(--border); + border-radius: 10px; + background: var(--bg-sunken); + line-height: 1.6; + color: var(--text-secondary); +} + +.rsi-cards strong { + color: var(--text); + font-weight: 600; +} + +@media (prefers-reduced-motion: reduce) { + .rsi-outcome, + .rsi-item, + .rsi-probe { + transition: none !important; + } +} diff --git a/css/expedition.css b/css/expedition.css new file mode 100644 index 0000000000000000000000000000000000000000..1008cfeb61b425441e74a5ce1d93e1db14602b0e --- /dev/null +++ b/css/expedition.css @@ -0,0 +1,613 @@ +/* 知识远征(契约 23A P3 · 工作台第四 tab「远征」)——Warm Paper 令牌, + 零硬编码色:所有颜色走 theme.css 变量(深浅色自动跟随)。 + 布局沿用 .bench / .kb 的整页滚动容器(flex:1 + 独立滚动 + 48px 留白)。 */ + +.xp { + flex: 1; + min-width: 0; + overflow-y: auto; + padding: 36px 48px 48px; +} + +/* ── 页头 ───────────────────────────────────────────────────────── */ + +.xp-head { + display: flex; + align-items: flex-end; + justify-content: space-between; + gap: 16px; + margin-bottom: 24px; +} + +.xp-title { + font-family: var(--font-serif); + font-size: 26px; + font-weight: 600; + letter-spacing: -0.01em; + color: var(--text); + margin: 0; +} + +.xp-head-sub { + margin: 6px 0 0; + font-size: 13.5px; + line-height: 1.6; + color: var(--text-secondary); + max-width: 60ch; +} + +.xp-notice { + margin: 0 0 16px; + padding: 10px 14px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: var(--bg-elevated); + font-size: 13.5px; + line-height: 1.6; + color: var(--text); +} + +.xp-notice.is-danger { + border-color: var(--danger); +} + +/* ── 卡片(上块 Deep Research / 下块 订阅监控)─────────────────── */ + +.xp-card { + background: var(--bg-elevated); + border: 1px solid var(--border); + border-radius: var(--radius-card); + padding: 22px 24px; + margin-bottom: 28px; +} + +.xp-card-head { + display: flex; + align-items: baseline; + justify-content: space-between; + gap: 16px; + margin-bottom: 16px; +} + +.xp-card-title { + font-family: var(--font-serif); + font-size: 18px; + font-weight: 600; + color: var(--text); + margin: 0; +} + +.xp-card-hint { + font-size: 12.5px; + line-height: 1.6; + color: var(--text-secondary); +} + +/* ── 表单 ───────────────────────────────────────────────────────── */ + +.xp-form { + display: flex; + flex-wrap: wrap; + gap: 10px; + align-items: center; +} + +.xp-input, +.xp-select { + font-family: var(--font-sans); + font-size: 14px; + line-height: 1.65; + color: var(--text); + background: var(--bg-sunken); + border: 1px solid transparent; + border-radius: var(--radius-control); + padding: 9px 12px; + transition: border-color var(--dur) var(--ease); +} + +.xp-input { + flex: 1; + min-width: 260px; +} + +.xp-input::placeholder { + color: var(--text-tertiary); +} + +.xp-input:focus-visible, +.xp-select:focus-visible { + outline: none; + border-color: var(--accent); +} + +.xp-select { + max-width: 260px; +} + +/* ── 按钮 ───────────────────────────────────────────────────────── */ + +.xp-btn { + display: inline-flex; + align-items: center; + gap: 6px; + height: 36px; + padding: 0 14px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: transparent; + color: var(--text); + font-family: inherit; + font-size: 13.5px; + cursor: pointer; + transition: + background-color var(--dur) var(--ease), + border-color var(--dur) var(--ease), + color var(--dur) var(--ease); +} + +.xp-btn:hover:not(:disabled) { + background: var(--bg); +} + +.xp-btn:disabled { + opacity: 0.55; + cursor: default; +} + +.xp-btn:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +.xp-btn-primary { + border-color: transparent; + background: var(--accent); + color: var(--bg); + font-weight: 600; +} + +.xp-btn-primary:hover:not(:disabled) { + filter: brightness(0.94); + background: var(--accent); +} + +.xp-btn-quiet { + border-color: transparent; + color: var(--text-secondary); +} + +.xp-btn-quiet:hover:not(:disabled) { + background: var(--accent-soft); + color: var(--text); +} + +.xp-icon-btn { + display: inline-flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; + border: none; + border-radius: var(--radius-control); + background: transparent; + color: var(--text-secondary); + cursor: pointer; + transition: background-color var(--dur) var(--ease), color var(--dur) var(--ease); +} + +.xp-icon-btn:hover { + background: var(--accent-soft); + color: var(--text); +} + +.xp-icon-btn:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +/* ── 进度 ───────────────────────────────────────────────────────── */ + +.xp-progress { + margin-top: 16px; + padding: 14px 16px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: var(--bg); +} + +.xp-progress-step { + display: flex; + align-items: center; + gap: 8px; + font-size: 13.5px; + line-height: 1.6; + color: var(--text); + word-break: break-all; +} + +.xp-progress-meta { + display: flex; + flex-wrap: wrap; + gap: 14px; + margin-top: 8px; + font-size: 12px; + color: var(--text-secondary); + font-variant-numeric: tabular-nums; +} + +.xp-bar { + height: 6px; + border-radius: var(--radius-chip); + background: var(--bg-sunken); + overflow: hidden; + margin-top: 12px; +} + +.xp-bar-fill { + height: 100%; + background: var(--accent); + border-radius: var(--radius-chip); + transition: width var(--dur) var(--ease); +} + +.xp-phase-dot { + width: 8px; + height: 8px; + border-radius: 50%; + background: var(--accent); + flex-shrink: 0; +} + +/* ── 报告 ───────────────────────────────────────────────────────── */ + +.xp-report { + margin-top: 18px; + padding-top: 18px; + border-top: 1px solid var(--border); +} + +.xp-report-head { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + gap: 10px; + margin-bottom: 14px; +} + +.xp-report-stats { + font-size: 12.5px; + color: var(--text-secondary); + font-variant-numeric: tabular-nums; +} + +.xp-report-actions { + display: flex; + flex-wrap: wrap; + gap: 8px; +} + +.xp-sources { + margin: 18px 0 0; + padding: 14px 16px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: var(--bg); +} + +.xp-sources-title { + font-family: var(--font-serif); + font-size: 14px; + font-weight: 600; + color: var(--text); + margin: 0 0 10px; +} + +.xp-source-list { + margin: 0; + padding-left: 18px; + display: flex; + flex-direction: column; + gap: 6px; +} + +.xp-source-list li { + font-size: 13px; + line-height: 1.6; + color: var(--text-secondary); +} + +.xp-source-list a { + color: var(--text); + text-decoration: underline; + text-underline-offset: 2px; + word-break: break-all; +} + +.xp-source-time { + color: var(--text-tertiary); + font-variant-numeric: tabular-nums; +} + +/* ── 历史报告 ───────────────────────────────────────────────────── */ + +.xp-history { + margin-top: 20px; + padding-top: 16px; + border-top: 1px solid var(--border); +} + +.xp-history-title { + font-family: var(--font-serif); + font-size: 14px; + font-weight: 600; + color: var(--text); + margin: 0 0 8px; +} + +.xp-history-list { + list-style: none; + margin: 0; + padding: 0; +} + +.xp-history-item { + display: flex; + align-items: center; + gap: 12px; + width: 100%; + padding: 10px 8px; + border: none; + border-bottom: 1px solid var(--border); + background: transparent; + color: inherit; + font-family: inherit; + font-size: 13.5px; + text-align: left; + cursor: pointer; + transition: background-color var(--dur) var(--ease); +} + +.xp-history-item:last-child { + border-bottom: none; +} + +.xp-history-item:hover { + background: var(--accent-soft); +} + +.xp-history-item:focus-visible { + outline: 2px solid var(--accent); + outline-offset: -2px; +} + +.xp-history-topic { + flex: 1; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + color: var(--text); +} + +.xp-history-meta { + flex-shrink: 0; + font-size: 12px; + color: var(--text-secondary); + font-variant-numeric: tabular-nums; +} + +/* ── 空状态 ─────────────────────────────────────────────────────── */ + +.xp-empty { + padding: 22px 4px; + font-family: var(--font-serif); + font-size: 15px; + line-height: 1.7; + color: var(--text-secondary); +} + +/* ── 订阅列表 ───────────────────────────────────────────────────── */ + +.xp-subs { + list-style: none; + margin: 16px 0 0; + padding: 0; + border-top: 1px solid var(--border); +} + +.xp-sub { + border-bottom: 1px solid var(--border); +} + +.xp-sub-row { + display: flex; + align-items: center; + gap: 12px; + padding: 12px 4px; +} + +.xp-sub.is-changed .xp-sub-name { + color: var(--accent); + font-weight: 600; +} + +.xp-sub-main { + flex: 1; + min-width: 0; +} + +.xp-sub-name { + display: flex; + align-items: center; + gap: 8px; + font-family: var(--font-serif); + font-size: 14.5px; + font-weight: 600; + color: var(--text); +} + +.xp-sub-url { + display: block; + margin-top: 2px; + font-size: 12px; + color: var(--text-tertiary); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.xp-sub-meta { + display: flex; + flex-wrap: wrap; + gap: 12px; + margin-top: 5px; + font-size: 12px; + color: var(--text-secondary); + font-variant-numeric: tabular-nums; +} + +.xp-badge { + display: inline-flex; + align-items: center; + height: 20px; + padding: 0 7px; + border-radius: var(--radius-chip); + background: var(--bg-sunken); + color: var(--text-secondary); + font-size: 11px; + font-weight: 500; + font-family: var(--font-sans); + white-space: nowrap; +} + +.xp-badge.is-changed { + background: var(--accent-soft); + color: var(--text); +} + +.xp-badge.is-error { + background: var(--bg-sunken); + color: var(--danger); +} + +.xp-sub-actions { + display: flex; + align-items: center; + gap: 6px; + flex-shrink: 0; +} + +/* 启停开关(沿用 bench-switch 的形制,颜色全走令牌) */ +.xp-switch { + position: relative; + width: 42px; + height: 24px; + flex-shrink: 0; + border: 1px solid var(--border); + border-radius: var(--radius-chip); + background: var(--bg-sunken); + cursor: pointer; + transition: background-color var(--dur) var(--ease), border-color var(--dur) var(--ease); +} + +.xp-switch.is-on { + background: var(--accent); + border-color: var(--accent); +} + +.xp-switch::after { + content: ""; + position: absolute; + top: 2px; + left: 2px; + width: 18px; + height: 18px; + border-radius: 50%; + background: var(--bg); + transition: transform var(--dur) var(--ease); +} + +.xp-switch.is-on::after { + transform: translateX(18px); +} + +.xp-switch:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +/* ── 变化历史(点开展开)───────────────────────────────────────── */ + +.xp-history-panel { + padding: 4px 4px 14px; + display: flex; + flex-direction: column; + gap: 10px; +} + +.xp-change { + padding: 10px 12px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: var(--bg); +} + +.xp-change-head { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 10px; + font-size: 12px; + color: var(--text-secondary); + font-variant-numeric: tabular-nums; +} + +.xp-change-body { + margin: 8px 0 0; + font-family: var(--font-mono); + font-size: 12.5px; + line-height: 1.6; + color: var(--text); + white-space: pre-wrap; + word-break: break-word; +} + +.xp-change-none { + font-size: 13px; + color: var(--text-secondary); + padding: 8px 4px; +} + +/* ── 小工具 ─────────────────────────────────────────────────────── */ + +.xp-inline-form { + display: flex; + flex-wrap: wrap; + gap: 10px; + align-items: flex-end; + padding-bottom: 4px; +} + +.xp-field { + display: flex; + flex-direction: column; + gap: 6px; + min-width: 0; +} + +.xp-field.grow { + flex: 1; + min-width: 240px; +} + +.xp-field-label { + font-size: 12.5px; + color: var(--text-secondary); +} + +.xp-muted { + font-size: 12.5px; + line-height: 1.6; + color: var(--text-secondary); +} diff --git a/css/flow.css b/css/flow.css new file mode 100644 index 0000000000000000000000000000000000000000..b767a269581d6918cdb765530c2cac4a4f10e95a --- /dev/null +++ b/css/flow.css @@ -0,0 +1,481 @@ +/* 栖木流(契约 25B · 工作台第五 tab「流」)——Warm Paper 令牌,零硬编码色: + 所有颜色走 theme.css 变量(深浅色自动跟随)。 + 布局沿用 .xp / .bench 整页滚动容器(flex:1 + 独立滚动 + 48px 留白)。 */ + +.flow { + flex: 1; + min-width: 0; + overflow-y: auto; + padding: 36px 48px 48px; +} + +/* ── 页头 ───────────────────────────────────────────────────────── */ + +.flow-head { + display: flex; + align-items: flex-end; + justify-content: space-between; + gap: 16px; + margin-bottom: 24px; +} + +.flow-title { + font-family: var(--font-serif); + font-size: 26px; + font-weight: 600; + letter-spacing: -0.01em; + color: var(--text); + margin: 0; +} + +.flow-head-sub { + margin: 6px 0 0; + font-size: 13.5px; + line-height: 1.6; + color: var(--text-secondary); + max-width: 62ch; +} + +/* ── 流卡片列表 ─────────────────────────────────────────────────── */ + +.flow-list { + display: flex; + flex-direction: column; + gap: 12px; +} + +.flow-item { + display: flex; + align-items: center; + gap: 14px; + padding: 14px 18px; + background: var(--bg-elevated); + border: 1px solid var(--border); + border-radius: var(--radius-card); + transition: border-color 150ms ease; +} + +.flow-item:hover { + border-color: var(--border-strong); +} + +.flow-item-main { + flex: 1; + min-width: 0; + cursor: pointer; +} + +.flow-item-name { + font-size: 15px; + font-weight: 600; + color: var(--text); + margin: 0; +} + +.flow-item-meta { + display: flex; + align-items: center; + gap: 10px; + flex-wrap: wrap; + margin-top: 4px; + font-size: 12.5px; + color: var(--text-secondary); +} + +.flow-badge { + display: inline-flex; + align-items: center; + gap: 5px; + padding: 2px 8px; + border-radius: 999px; + border: 1px solid var(--border); + font-size: 11.5px; + color: var(--text-secondary); + background: var(--bg); + white-space: nowrap; +} + +.flow-badge.is-on { + color: var(--accent); + border-color: var(--accent-soft, var(--accent)); +} + +.flow-status-dot { + width: 7px; + height: 7px; + border-radius: 50%; + background: var(--text-tertiary); + flex: none; +} + +.flow-status-dot.is-done { + background: var(--success); +} + +.flow-status-dot.is-error { + background: var(--danger); +} + +.flow-status-dot.is-running { + background: var(--warning); + animation: flow-pulse 1.2s ease-in-out infinite; +} + +@keyframes flow-pulse { + 0%, + 100% { + opacity: 1; + } + 50% { + opacity: 0.35; + } +} + +/* ── 按钮 ───────────────────────────────────────────────────────── */ + +.flow-actions { + display: flex; + align-items: center; + gap: 8px; + flex: none; +} + +.flow-btn { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 7px 14px; + border-radius: var(--radius-control); + border: 1px solid var(--border); + background: var(--bg); + color: var(--text); + font-size: 13px; + cursor: pointer; + transition: + border-color 150ms ease, + background 150ms ease; +} + +.flow-btn:hover { + border-color: var(--border-strong); +} + +.flow-btn.is-primary { + border-color: var(--accent); + color: var(--accent); +} + +.flow-btn.is-primary:hover { + background: var(--accent-soft, transparent); +} + +.flow-btn.is-ghost { + border-color: transparent; + color: var(--text-secondary); +} + +.flow-btn:disabled { + opacity: 0.45; + cursor: not-allowed; +} + +.flow-icon-btn { + display: inline-flex; + align-items: center; + justify-content: center; + width: 30px; + height: 30px; + border-radius: var(--radius-control); + border: 1px solid transparent; + background: transparent; + color: var(--text-secondary); + cursor: pointer; + transition: + color 150ms ease, + border-color 150ms ease; +} + +.flow-icon-btn:hover { + color: var(--text); + border-color: var(--border); +} + +.flow-icon-btn.is-danger:hover { + color: var(--danger); + border-color: var(--danger); +} + +/* ── 开关(沿用设置中心的形状语言)──────────────────────────────── */ + +.flow-switch { + position: relative; + width: 38px; + height: 22px; + border-radius: 999px; + border: 1px solid var(--border); + background: var(--bg); + cursor: pointer; + flex: none; + transition: background 150ms ease; + padding: 0; +} + +.flow-switch::after { + content: ""; + position: absolute; + top: 2px; + left: 2px; + width: 16px; + height: 16px; + border-radius: 50%; + background: var(--text-secondary); + transition: + transform 150ms ease, + background 150ms ease; +} + +.flow-switch.is-on { + background: var(--accent); + border-color: var(--accent); +} + +.flow-switch.is-on::after { + transform: translateX(16px); + background: var(--bg-elevated); +} + +/* ── 编辑器 ─────────────────────────────────────────────────────── */ + +.flow-editor { + max-width: 760px; +} + +.flow-field { + display: flex; + flex-direction: column; + gap: 6px; + margin-bottom: 18px; +} + +.flow-label { + font-size: 12.5px; + font-weight: 600; + color: var(--text-secondary); +} + +.flow-input, +.flow-select, +.flow-textarea { + padding: 9px 12px; + border-radius: var(--radius-control); + border: 1px solid var(--border); + background: var(--bg-elevated); + color: var(--text); + font-size: 13.5px; + font-family: inherit; + outline: none; + transition: border-color 150ms ease; +} + +.flow-input:focus, +.flow-select:focus, +.flow-textarea:focus { + border-color: var(--accent); +} + +.flow-textarea { + min-height: 72px; + resize: vertical; + line-height: 1.6; +} + +.flow-inline-row { + display: flex; + gap: 8px; + align-items: center; +} + +.flow-inline-row > .flow-input { + flex: 1; +} + +.flow-hint { + font-size: 12px; + line-height: 1.6; + color: var(--text-tertiary); +} + +/* ── 步骤列表(列表式编辑:不炫技的排序 + 参数行)────────────── */ + +.flow-steps { + display: flex; + flex-direction: column; + gap: 10px; + margin-bottom: 18px; +} + +.flow-step { + display: flex; + gap: 12px; + padding: 14px 16px; + background: var(--bg-elevated); + border: 1px solid var(--border); + border-radius: var(--radius-card); +} + +.flow-step-no { + width: 26px; + height: 26px; + border-radius: 50%; + border: 1px solid var(--border); + display: flex; + align-items: center; + justify-content: center; + font-size: 12px; + color: var(--text-secondary); + flex: none; + margin-top: 2px; +} + +.flow-step-body { + flex: 1; + min-width: 0; + display: flex; + flex-direction: column; + gap: 8px; +} + +.flow-step-kind { + display: flex; + align-items: center; + gap: 8px; + font-size: 13px; + font-weight: 600; + color: var(--text); +} + +.flow-step-ops { + display: flex; + flex-direction: column; + gap: 4px; + flex: none; +} + +/* ── 模板选择 ───────────────────────────────────────────────────── */ + +.flow-templates { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); + gap: 12px; + margin-bottom: 20px; +} + +.flow-template { + display: flex; + flex-direction: column; + gap: 6px; + padding: 16px; + text-align: left; + background: var(--bg-elevated); + border: 1px solid var(--border); + border-radius: var(--radius-card); + cursor: pointer; + transition: border-color 150ms ease; +} + +.flow-template:hover { + border-color: var(--accent); +} + +.flow-template-name { + font-size: 14px; + font-weight: 600; + color: var(--text); +} + +.flow-template-desc { + font-size: 12.5px; + line-height: 1.6; + color: var(--text-secondary); +} + +/* ── 运行记录 ───────────────────────────────────────────────────── */ + +.flow-runs { + display: flex; + flex-direction: column; + gap: 8px; +} + +.flow-run { + padding: 12px 16px; + background: var(--bg-elevated); + border: 1px solid var(--border); + border-radius: var(--radius-card); + cursor: pointer; +} + +.flow-run:hover { + border-color: var(--border-strong); +} + +.flow-run-head { + display: flex; + align-items: center; + gap: 10px; + font-size: 13px; + color: var(--text); +} + +.flow-run-steps { + display: flex; + flex-direction: column; + gap: 6px; + margin-top: 10px; +} + +.flow-run-step { + display: flex; + align-items: flex-start; + gap: 10px; + padding: 10px 12px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: var(--bg); + font-size: 12.5px; + color: var(--text); +} + +.flow-run-step-kind { + font-weight: 600; + white-space: nowrap; + color: var(--text-secondary); + flex: none; +} + +.flow-run-step-output { + flex: 1; + min-width: 0; + white-space: pre-wrap; + word-break: break-word; + line-height: 1.55; + color: var(--text); + /* 耗时毫秒等数字等宽:跳动不抖行(细节质感) */ + font-variant-numeric: tabular-nums; +} + +.flow-run-step-output.is-error { + color: var(--danger); +} + +.flow-run-step-output.is-skipped { + color: var(--text-tertiary); +} + +.flow-empty { + padding: 36px 0; + text-align: center; + color: var(--text-tertiary); + font-size: 13.5px; + line-height: 1.8; +} diff --git a/css/gemini.css b/css/gemini.css new file mode 100644 index 0000000000000000000000000000000000000000..a5155aaba42414259e468ed8efeba0da7a5783c7 --- /dev/null +++ b/css/gemini.css @@ -0,0 +1,161 @@ +/* ═══════════════════════════════════════════════════════════════════ + Gemini 皮肤 · 组件层(dev-duotheme 双外观,Warm Paper 零改动) + + 纪律(完工自检 grep): + - 本文件不出现 width / height / left / top / position —— + 只改颜色、字体、圆角、阴影、hover 这类「皮」;布局、间距、 + 宽高、位置、tab 结构一律不动(避免与 dev-composer-ui 打架)。 + - 每条覆盖规则都以 [data-style="gemini"] 打头 → Warm Paper 完全不受影响。 + - 签名渐变(--grad-start/mid/end 蓝→紫→粉)只允许三处: + ① 品牌标方标 ② 欢迎页大标题高光 ③ Ultra 档强调。 + 其余全靠黑白灰 + Google Blue 单主色(彩色 = 点缀,不铺满)。 + - 设置页「风格」预览卡是新控件:其排版样式走 Settings.tsx 内联 + 样式(本文件保持「纯覆盖」),不新增任何组件 css 文件改动。 + + 大量视觉其实由 theme.css 的 [data-style="gemini"] 令牌自动换血 + (导航激活浅蓝 #e8f0fe + Google Blue 竖条、焦点环、滚动条、选区、 + 分段控件蓝底白字、卡片灰边……),本文件只补「换骨」的几处。 + ═══════════════════════════════════════════════════════════════ */ + +/* ── ① 品牌标:签名渐变方标 + 白色线稿(渐变位 1/3) ───────────── */ +[data-style="gemini"] .brand-mark { + background: linear-gradient( + 135deg, + var(--grad-start) 0%, + var(--grad-mid) 55%, + var(--grad-end) 100% + ); + border-radius: 9px; /* 紧贴 26px 图形的圆角方标(不动其尺寸) */ + color: #ffffff; /* BrandMark 走 currentColor 描边 → 白线 */ +} + +[data-style="gemini"] .brand-name { + font-weight: 500; /* Material 标题档 500,撤掉书卷气 600 */ +} + +/* ── 标题字重:Material/Gemini 标题 400~500,不用衬线粗体气质 ──── */ +[data-style="gemini"] h1, +[data-style="gemini"] h2, +[data-style="gemini"] h3 { + font-weight: 500; +} + +[data-style="gemini"] .hub-tab.is-active, +[data-style="gemini"] .pref-subhead { + font-weight: 500; +} + +/* ── 按钮:pill 化(Google 主行动全圆角) + 蓝色态 ─────────────── */ +[data-style="gemini"] .btn-primary, +[data-style="gemini"] .btn-secondary, +[data-style="gemini"] .btn-send, +[data-style="gemini"] .btn-stop, +[data-style="gemini"] .conv-new, +[data-style="gemini"] .icon-btn { + border-radius: 999px; +} + +/* 主按钮 hover:Google 蓝变体(浅色 = Blue 700 加深,深色 = 加亮); + 令牌切换后两套深浅色自动各取各的 --accent-hover。 */ +[data-style="gemini"] .btn-primary:hover, +[data-style="gemini"] .btn-send:hover:not(:disabled) { + background: var(--accent-hover); +} + +/* 次按钮:浅灰底(elevated),hover 落到 sunken——中性灰,不用暖调 */ +[data-style="gemini"] .btn-secondary { + background: var(--bg-elevated); +} + +[data-style="gemini"] .btn-secondary:hover, +[data-style="gemini"] .btn-stop:hover, +[data-style="gemini"] .conv-new:hover { + background: var(--bg-sunken); +} + +/* 危险小按钮 hover:红色浅底(accent-soft 在本皮肤是浅蓝,语义不对) */ +[data-style="gemini"] .icon-btn-danger:hover { + background: color-mix(in srgb, var(--danger) 12%, transparent); +} + +/* ── 分段控件 / 模式切换:Google 分段 pill 形(只动圆角) ───────── */ +[data-style="gemini"] .pref-seg, +[data-style="gemini"] .pref-seg-btn, +[data-style="gemini"] .mode-switch, +[data-style="gemini"] .mode-pill { + border-radius: 999px; +} + +/* ── 卡片 hover:浅灰蓝描边(令牌已把圆角变 16、底变 #f8f9fa 灰) ── */ +[data-style="gemini"] .metric-card:hover, +[data-style="gemini"] .panel:hover, +[data-style="gemini"] .diag-card:hover, +[data-style="gemini"] .diag-trash:hover, +[data-style="gemini"] .skill-card:hover, +[data-style="gemini"] .mcp-card:hover, +[data-style="gemini"] .cloud-card:hover, +[data-style="gemini"] .expert-card:hover { + border-color: color-mix(in srgb, var(--accent) 40%, var(--border)); +} + +/* ── 消息:用户气泡中性化(Google 风更克制:浅灰底 + 发丝描边, + 圆角走 --radius-card=16;渐变不进对话流) ─────────────────── */ +[data-style="gemini"] .msg-card { + background: var(--bg-elevated); + border-color: var(--border); +} + +/* ── ② 欢迎页大标题:签名渐变高光(渐变位 2/3;整句文字渐变, + 正文与水印保持中性/单色) ─────────────────────────────────── */ +[data-style="gemini"] .chat-welcome h1 { + background: linear-gradient( + 100deg, + var(--grad-start) 0%, + var(--grad-mid) 52%, + var(--grad-end) 100% + ); + -webkit-background-clip: text; + background-clip: text; + color: transparent; + -webkit-text-fill-color: transparent; +} + +/* ── ③ Ultra 档强调:档名渐变高光(渐变位 3/3;轨道/手柄的蓝色系 + 渐变由 --accent 令牌自动中性化,不在本文件另写) ───────────── */ +[data-style="gemini"] .think-slider.is-ultra .think-name { + background: linear-gradient( + 90deg, + var(--grad-start), + var(--grad-mid), + var(--grad-end) + ); + -webkit-background-clip: text; + background-clip: text; + color: transparent; + -webkit-text-fill-color: transparent; +} + +/* ── 滚动条:全圆角细条(颜色本身已走中性令牌:#dadce0 → #80868b) ── */ +[data-style="gemini"] ::-webkit-scrollbar-thumb { + border-radius: 999px; +} + +/* ── 按图精修层(Lead,2026-10-23,依据 docs/refs 五张 Gemini 实拍)──── + ① 环境光晕:Gemini 的"彩色元素"本体——内容区背后两团大范围柔光 + (浅色=薰衣草紫、深色=蓝紫,取自 --grad-* 低透明度),只用 background-image + 不引入任何布局属性;欢迎页最明显,对话中退为氛围。 + ② 用户气泡:更圆的 18px 近胶囊,贴近 Gemini 对话态实拍。 */ +[data-style="gemini"] .content { + background-image: + radial-gradient(55% 40% at 80% 100%, color-mix(in srgb, var(--grad-mid) 14%, transparent), transparent 72%), + radial-gradient(45% 35% at 12% 100%, color-mix(in srgb, var(--grad-start) 10%, transparent), transparent 70%); + background-repeat: no-repeat; +} +[data-style="gemini"][data-theme="dark"] .content { + background-image: + radial-gradient(55% 42% at 78% 100%, color-mix(in srgb, var(--grad-mid) 20%, transparent), transparent 72%), + radial-gradient(45% 36% at 14% 100%, color-mix(in srgb, var(--grad-start) 14%, transparent), transparent 70%); +} +[data-style="gemini"] .msg-card { + border-radius: 18px; +} diff --git a/css/glance.css b/css/glance.css new file mode 100644 index 0000000000000000000000000000000000000000..50a2efcda9405cfa432b081eafc285d910dc5e1d --- /dev/null +++ b/css/glance.css @@ -0,0 +1,187 @@ +/* 每日一瞥(契约 18A A2):Warm Paper 全令牌配色,晨报式克制排版。 + 一句体检(衬线略大)→ 两行任务 → 一行数字 → 预警列表 + 巡检开关。 */ + +.glance { + flex: 1; + min-width: 0; + overflow-y: auto; + padding: 36px 48px 48px; + display: flex; + flex-direction: column; + gap: 24px; +} + +.glance-head h1 { + font-size: 30px; +} + +.glance-date { + margin: 6px 0 0; + font-size: 13.5px; + color: var(--text-secondary); +} + +/* ── 晨报主体:一句话体检 ─────────────────────────────────────── */ +.glance-card { + max-width: 760px; + padding: 24px 26px; + border: 1px solid var(--border); + border-radius: var(--radius-card); + background: var(--bg-elevated); +} + +.glance-headline { + margin: 0; + font-family: var(--font-serif); + font-size: 20px; + font-weight: 600; + line-height: 1.5; + letter-spacing: -0.01em; + color: var(--text); +} + +/* 严重度只染 headline 的小徽点(语义色仅用于状态语境) */ +.glance-headline.is-warn::before, +.glance-headline.is-critical::before { + content: ""; + display: inline-block; + width: 8px; + height: 8px; + margin-right: 10px; + border-radius: 50%; + vertical-align: 0.2em; +} + +.glance-headline.is-warn::before { + background: var(--warning); +} + +.glance-headline.is-critical::before { + background: var(--danger); +} + +.glance-lines { + margin: 16px 0 0; + padding-top: 14px; + border-top: 1px solid var(--border); + display: flex; + flex-direction: column; + gap: 6px; +} + +.glance-line { + margin: 0; + font-size: 14px; + line-height: 1.65; + color: var(--text-secondary); +} + +.glance-digits { + margin: 14px 0 0; + font-family: var(--font-mono); + font-size: 13px; + font-variant-numeric: tabular-nums; + color: var(--text-secondary); +} + +.glance-meta { + margin: 12px 0 0; + font-size: 12px; + color: var(--text-tertiary); +} + +/* ── 预警区 ───────────────────────────────────────────────────── */ +.glance-section { + max-width: 760px; +} + +.glance-section h2 { + font-size: 18px; + margin-bottom: 4px; +} + +.glance-section-sub { + margin: 0 0 10px; + font-size: 12.5px; + color: var(--text-tertiary); + line-height: 1.5; +} + +.glance-alert { + padding: 12px 14px; + border: 1px solid var(--border); + border-left: 3px solid var(--warning); + border-radius: var(--radius-chip); + background: var(--bg-elevated); + margin-bottom: 8px; +} + +.glance-alert-title { + margin: 0; + font-weight: 600; + font-size: 13.5px; + color: var(--text); +} + +.glance-alert-detail { + margin: 3px 0 0; + font-size: 13px; + line-height: 1.6; + color: var(--text-secondary); +} + +.glance-quiet { + margin: 0; + padding: 12px 14px; + border: 1px dashed var(--border); + border-radius: var(--radius-chip); + font-size: 13px; + color: var(--text-tertiary); +} + +/* 巡检开关行(复用 pref-row / pref-switch 的骨架,宽度自适应) */ +.glance-switches { + max-width: 760px; + border-top: 1px solid var(--border); + padding-top: 4px; +} + +.glance-switch-row { + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; + padding: 11px 0; + border-bottom: 1px solid var(--border); +} + +.glance-switch-row:last-child { + border-bottom: none; +} + +.glance-switch-label { + font-size: 13.5px; + color: var(--text); +} + +.glance-switch-hint { + margin: 2px 0 0; + font-size: 12px; + color: var(--text-tertiary); +} + +.glance-refresh { + align-self: flex-start; +} + +/* 空载 / 出错态(衬线一句话,不画问号机器人) */ +.glance-state { + font-family: var(--font-serif); + font-size: 17px; + color: var(--text-secondary); + line-height: 1.6; +} + +.glance-state-error { + color: var(--danger); +} diff --git a/css/hub.css b/css/hub.css new file mode 100644 index 0000000000000000000000000000000000000000..908347b49c9a7bf918dcf04aef3d8a17c5d926e9 --- /dev/null +++ b/css/hub.css @@ -0,0 +1,63 @@ +/* Hub 二级页签外壳(契约 18A A1:工作台 / 系统 / 设置并入后的子导航)。 + 视觉沿用对话工作台的 wb-tabs(同一套 Warm Paper 令牌,150ms 过渡)。 */ + +/* 纵向外壳:页签条 + 内容区(内容区仍是各组件自己的滚动容器) */ +.hub-root { + flex: 1; + min-width: 0; + min-height: 0; + display: flex; + flex-direction: column; +} + +.hub-body { + flex: 1; + min-width: 0; + min-height: 0; + display: flex; +} + +/* 页签条:贴内容区左内边距(48px),底边一条 1px 分隔线 */ +.hub-tabs { + display: flex; + align-items: center; + gap: 4px; + padding: 10px 48px 0; + border-bottom: 1px solid var(--border); + flex-shrink: 0; +} + +.hub-tab { + position: relative; + display: inline-flex; + align-items: center; + gap: 6px; + height: 32px; + padding: 0 12px; + border: none; + border-radius: var(--radius-control) var(--radius-control) 0 0; + background: transparent; + color: var(--text-secondary); + font-family: inherit; + font-size: 13px; + cursor: pointer; + transition: + background-color var(--dur) var(--ease), + color var(--dur) var(--ease); +} + +.hub-tab:hover { + background: var(--bg-elevated); + color: var(--text); +} + +.hub-tab.is-active { + background: var(--accent-soft); + color: var(--text); + font-weight: 600; +} + +.hub-tab:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} diff --git a/css/human-ui.css b/css/human-ui.css new file mode 100644 index 0000000000000000000000000000000000000000..730d66ef839d117dcdaaec5e453e78826c2c5d03 --- /dev/null +++ b/css/human-ui.css @@ -0,0 +1,174 @@ +/* V5 daily workspace: one navigation rail, one content canvas, contextual tools. */ +.studio-shell.is-daily{grid-template-columns:178px minmax(0,1fr);font-size:13px} +.is-daily .studio-topbar{padding-left:76px;background:var(--bg);border-bottom-color:var(--border);gap:12px} +.is-daily .studio-main{padding-top:0} +.is-daily .studio-breadcrumb,.is-daily .studio-document-tabs{display:none} +.is-daily .studio-activity{padding:16px 10px 12px;background:var(--bg-sunken);border-right-color:var(--border)} +.is-daily .studio-activity>button{min-height:48px;margin:2px 0;padding:9px 10px;border-radius:9px} +.is-daily .studio-activity>button>span{font-size:13px} +.is-daily .studio-activity button small{margin-top:3px;font-size:10px;line-height:1.4} +.is-daily .studio-nav-bottom{padding-top:10px} +.is-daily .studio-nav-bottom>p{margin-top:8px;padding-top:9px} +.studio-shell .wb-root{min-height:0;background:var(--bg)} +.studio-shell .wb-tabs{height:38px;min-height:38px;justify-content:flex-start;gap:18px;padding:0 22px;background:var(--bg);border-bottom:1px solid var(--border)} +.studio-shell .wb-tab{position:relative;height:38px;padding:0 2px;border:0;border-radius:0;background:transparent;color:var(--text-tertiary);font-size:11px} +.studio-shell .wb-tab.is-active{background:transparent;color:var(--text)} +.studio-shell .wb-tab.is-active:after{position:absolute;right:0;bottom:-1px;left:0;height:2px;background:var(--accent);content:""} +.studio-shell .wb-body{min-height:0;background:var(--bg)} +.studio-shell .workbench{min-height:0;gap:0;background:var(--bg)} +.studio-shell .conversations{border-right:1px solid var(--border);background:var(--bg-sunken)} +.studio-shell .conv-head{height:52px;padding:0 12px;border-bottom:1px solid var(--border)} +.studio-shell .conv-head-actions{display:flex;align-items:center;gap:5px} +.studio-shell .conv-head h2{font:550 12px var(--font-sans);color:var(--text)} +.studio-shell .conv-new{height:29px;padding:0 9px;border-radius:6px;background:var(--bg-elevated);border:1px solid var(--border);color:var(--text-secondary);font-size:10px} +.studio-shell .conv-item{margin:3px 7px;border-radius:6px} +.studio-shell .conv-item.is-active{background:var(--accent-soft)} +.studio-shell .conv-title{font-size:11px} +.studio-shell .conv-meta{font-size:9px} +.studio-shell .chat-main{min-width:0;background:var(--bg)} +.studio-shell .chat-header{min-height:54px;padding:8px 24px;border-bottom:1px solid var(--border);background:var(--bg)} +.studio-shell .chat-heading{min-width:0;display:flex;flex-direction:column;gap:3px} +.studio-shell .chat-section-label{font-size:9px;color:var(--text-tertiary)} +.studio-shell .chat-header-title{font:550 14px var(--font-sans);color:var(--text);letter-spacing:0} +.studio-shell .chat-welcome{gap:8px;justify-content:center;max-width:760px;margin:0 auto;padding:24px 32px} +.studio-shell .chat-welcome:before{display:none} +.studio-shell .chat-welcome-mark{position:relative;inset:auto;transform:none;width:26px;height:26px;opacity:.9;margin-bottom:7px} +.studio-shell .chat-welcome h1{font-size:21px;font-weight:550;margin:0 0 4px} +.studio-shell .chat-welcome p{font-size:12px;line-height:1.6} +.studio-shell.is-daily .chat-welcome h1{font-size:24px;font-weight:600} +.studio-shell.is-daily .chat-welcome p{font-size:13px;line-height:1.75} +.studio-shell .message-list{padding:24px max(24px,calc((100% - 820px)/2)) 18px} +.studio-shell .composer-wrap{z-index:3;padding:8px 22px 14px;background:linear-gradient(180deg,transparent,var(--bg) 18%)} +.studio-shell .composer{max-width:920px;margin:0 auto;border:1px solid var(--border);border-radius:9px;background:var(--bg-elevated);box-shadow:0 5px 22px rgba(15,24,26,.08)} +.studio-shell .composer:focus-within{border-color:color-mix(in srgb,var(--accent) 60%,var(--border));box-shadow:0 7px 24px rgba(15,24,26,.11)} +.studio-shell .composer-input{min-height:54px;padding:15px 16px 8px;font-size:13px;line-height:1.65} +.studio-shell .composer-bar{padding:4px 10px 9px;margin-top:2px;gap:6px 12px} +.studio-shell .composer-bar .mode-pill{height:27px;padding:0 9px;font-size:10px} +.studio-shell .model-trigger{max-width:190px} +.studio-shell .btn-send,.studio-shell .btn-stop{width:31px;height:31px;border-radius:7px} +.studio-shell .task-notice{margin:8px auto 0;max-width:920px;border-radius:7px} +.studio-shell .composer-skills{max-width:920px;margin:0 auto 5px} +.studio-shell .stats-bar{justify-content:center} +.conversation-research-status,.research-history{max-width:920px;width:calc(100% - 44px);margin:10px auto 0;border:1px solid var(--border);border-radius:7px;background:var(--bg-elevated)} +.conversation-research-status{padding:10px 13px} +.research-status-main{display:flex;align-items:center;gap:10px;min-width:0} +.research-status-mark{width:8px;height:8px;flex:none;border-radius:50%;background:var(--success)} +.conversation-research-status.is-running .research-status-mark{background:var(--info);box-shadow:0 0 0 3px color-mix(in srgb,var(--info) 18%,transparent)} +.research-status-main>div{min-width:0;flex:1} +.research-status-main strong{font-size:10px;font-weight:600} +.research-status-main p{overflow:hidden;margin:3px 0 0;color:var(--text-secondary);font-size:10px;text-overflow:ellipsis;white-space:nowrap} +.research-status-counts{color:var(--text-tertiary);font:9px var(--font-mono);white-space:nowrap} +.research-status-actions{display:flex;align-items:center;justify-content:flex-end;gap:12px;margin-top:7px;color:var(--success);font-size:9px} +.research-status-actions .ws-secondary{padding:5px 8px;font-size:9px} +.research-status-error{margin:6px 0 0;color:var(--danger);font-size:10px;line-height:1.5} +.research-history{flex:none;margin-top:7px;overflow:hidden} +.research-history>summary{display:flex;align-items:center;gap:8px;min-height:34px;padding:0 12px;color:var(--text-secondary);cursor:pointer;list-style:none} +.research-history>summary::-webkit-details-marker{display:none} +.research-history>summary:before{content:"▸";color:var(--text-tertiary)} +.research-history[open]>summary:before{content:"▾"} +.research-history>summary strong{font-size:10px;color:var(--text)} +.research-history>summary span{font-size:9px;color:var(--text-tertiary)} +.research-history>ul{max-height:190px;overflow:auto;margin:0;padding:0 12px 5px;list-style:none} +.research-history li{display:flex;align-items:center;gap:12px;padding:8px 0;border-top:1px solid var(--border)} +.research-history li>div{min-width:0;flex:1} +.research-history li strong,.research-history li small{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap} +.research-history li strong{font-size:10px;font-weight:500} +.research-history li small{margin-top:3px;color:var(--text-tertiary);font-size:9px} +.research-history-empty{margin:0;padding:8px 12px 12px;color:var(--text-tertiary);font-size:10px} +.research-history-notice{margin:5px 12px;color:var(--success);font-size:10px} +.research-preview{margin:0 12px 12px;padding:12px;border-top:1px solid var(--border);background:var(--bg-sunken)} +.research-preview>header{display:flex;align-items:center;justify-content:space-between;gap:8px;font-size:10px} +.research-preview>header strong{overflow:hidden;text-overflow:ellipsis;white-space:nowrap} +.research-preview>div{max-height:260px;overflow:auto;margin:8px 0;font-size:10px;line-height:1.7} +.studio-shell .tc-subtabs{display:flex;gap:4px;max-width:100%;overflow-x:auto;padding:8px 18px 0;background:var(--bg);} +.studio-shell .tc-subtab{flex:none;height:30px;padding:0 11px;border-radius:5px 5px 0 0;font-size:10px;white-space:nowrap} +.studio-shell .tc-body{min-width:0} +.studio-shell .ws-card,.studio-shell .studio-card{border-radius:7px} +.studio-shell :focus-visible{outline-color:var(--accent);outline-offset:2px} + +[data-style="darkside"]{--bg:#111619;--bg-sunken:#0c1114;--bg-elevated:#1a2226;--border:#2b3639;--text:#e8eeee;--text-secondary:#a1afb0;--text-tertiary:#7f9092;--accent:#e1bd79;--accent-soft:#2b2a22;--success:#85c2a7;--warning:#dfb95e;--danger:#e38e88;--info:#82b7d0;--glass:rgba(17,22,25,.96)} +[data-style="darkside"][data-theme="light"]{--bg:#f2f5f3;--bg-sunken:#e9efec;--bg-elevated:#fff;--border:#d7e0db;--text:#202a28;--text-secondary:#596a66;--text-tertiary:#788782;--accent:#28776b;--accent-soft:#deeee8;--success:#2f765b;--warning:#9a6c20;--danger:#a84442;--info:#346c8a;--glass:rgba(242,245,243,.96)} +[data-style="darkside"] .studio-activity,[data-style="darkside"] .studio-topbar,[data-style="darkside"] .conversations{background:var(--bg-sunken);border-color:var(--border)} +[data-style="darkside"] .studio-main,[data-style="darkside"] .chat-main,[data-style="darkside"] .wb-root,[data-style="darkside"] .wb-body{background:var(--bg)} +[data-style="darkside"] .conv-item.is-active{background:var(--accent-soft)} +[data-style="darkside"] .composer{background:var(--bg-elevated);border-color:var(--border);box-shadow:0 8px 28px rgba(0,0,0,.16)} +[data-style="darkside"] .task-notice{background:var(--bg-elevated);border-color:var(--border)} +[data-style="darkside"][data-theme="light"] .studio-activity,[data-style="darkside"][data-theme="light"] .studio-topbar,[data-style="darkside"][data-theme="light"] .conversations{background:#e9efec} + +@media(max-width:960px){.studio-shell.is-daily{grid-template-columns:164px minmax(0,1fr)}.is-daily .studio-activity{padding-left:7px;padding-right:7px}.studio-shell .studio-stage .conversations{width:168px;min-width:150px}.studio-shell .chat-header{padding-right:14px;padding-left:14px}.studio-shell .composer-wrap{padding-right:12px;padding-left:12px}.studio-shell .message-list{padding-right:20px;padding-left:20px}} +@media(max-width:720px){.studio-shell.is-daily{grid-template-columns:52px minmax(0,1fr)}.is-daily .studio-activity{align-items:center;padding:10px 4px}.is-daily .studio-activity>button,.is-daily .studio-nav-bottom>button{justify-content:center;width:42px;height:42px;padding:0}.is-daily .studio-activity>button>span,.is-daily .studio-nav-bottom>button>span,.is-daily .studio-nav-bottom>button>svg:last-child,.is-daily .studio-activity>button>small,.is-daily .studio-nav-bottom>p{display:none}.studio-shell .studio-stage .conversations{width:145px;min-width:130px}.studio-shell .command-search{width:32px;max-width:32px;padding:7px;justify-content:center}.studio-shell .command-search span,.studio-shell .command-search kbd{display:none}.studio-shell .studio-brand>span{display:none}.studio-shell .layout-toggle button{padding:5px 6px}} +@media(prefers-reduced-motion:reduce){.studio-shell.is-daily *{scroll-behavior:auto!important;animation:none!important;transition:none!important}} + +/* The two workspaces keep the same data and tools, but use different visual grammars. */ +.studio-shell.is-daily{--radius-control:10px;--radius-card:10px;--radius-chip:8px} +.studio-shell.is-daily .studio-resources{display:none} +.studio-shell.is-daily .studio-main{grid-column:2;padding-top:0} +.studio-shell.is-daily .studio-document-tabs{display:none} +.studio-shell.is-daily .studio-breadcrumb{display:none} +.studio-shell.is-daily .studio-nav-bottom>button[aria-label="开发者工具"], +.studio-shell.is-daily .studio-nav-bottom>button[aria-label="开发者工具"]+.nav-disclosure{display:none} +.studio-shell.is-daily .studio-nav-bottom{padding-top:12px} +.studio-shell.is-daily .studio-nav-bottom>p{max-width:140px;line-height:1.65} +.studio-shell.is-daily .studio-topbar{background:var(--bg-elevated);box-shadow:0 1px 8px color-mix(in srgb,var(--text) 4%,transparent)} +.studio-shell.is-daily .studio-brand>span{font:9px var(--font-sans);letter-spacing:.2px;color:var(--text-tertiary)} +.studio-shell.is-daily .layout-toggle{padding:3px;border-radius:9px;background:var(--bg-sunken)} +.studio-shell.is-daily .layout-toggle button{height:29px;padding:0 10px;border-radius:7px;font-size:10px} +.studio-shell.is-daily .layout-toggle button[aria-pressed="true"]{background:var(--bg-elevated);box-shadow:0 1px 5px color-mix(in srgb,var(--text) 9%,transparent)} +.studio-shell.is-daily .studio-activity>button.is-active{position:relative} +.studio-shell.is-daily .studio-activity>button.is-active:before{position:absolute;left:-1px;top:10px;bottom:10px;width:3px;border-radius:0 3px 3px 0;background:var(--accent);content:""} +.studio-shell.is-daily .overview-start{padding:25px 24px;border:1px solid var(--border);border-radius:10px;background:var(--bg-elevated)} +.studio-shell.is-daily .overview-start h2{font-size:20px} +.studio-shell.is-daily .overview-actions .ws-primary,.studio-shell.is-daily .overview-actions .ws-secondary{min-height:36px;border-radius:8px} +.studio-shell.is-daily .workspace-metrics{padding:22px 0} +.studio-shell.is-daily .ws-metric strong{font-size:24px;font-variant-numeric:tabular-nums} +.studio-shell.is-daily .ws-card,.studio-shell.is-daily .workspace-recent-list>button{border-radius:9px} +.studio-shell.is-daily .studio-inspector,.studio-shell.is-daily .run-console{display:none} +.studio-shell.is-daily .studio-statusbar.is-friendly{height:27px;font:10px var(--font-sans);background:var(--bg-elevated)} +.studio-shell.is-daily .studio-statusbar.is-friendly>.status-local-dot{width:7px;height:7px} +.studio-shell.is-daily .studio-statusbar.is-friendly>.status-spacer{flex:1} + +.studio-shell.is-developer{--radius-control:4px;--radius-card:4px;--radius-chip:3px} +.studio-shell.is-developer .studio-topbar{background:var(--bg-sunken);border-bottom-color:var(--border)} +.studio-shell.is-developer .studio-brand>span{font:8px var(--font-mono);letter-spacing:1px;color:var(--accent)} +.studio-shell.is-developer .layout-toggle{border-radius:4px} +.studio-shell.is-developer .layout-toggle button{height:25px;border-radius:2px;font:9px var(--font-mono)} +.studio-shell.is-developer .developer-rail-label{width:36px;margin:0 0 10px;text-align:center;color:var(--accent);font:8px var(--font-mono);letter-spacing:.8px} +.studio-shell.is-developer .studio-resources>header{border-bottom:1px solid var(--border)} +.studio-shell.is-developer .resource-project{font:10px var(--font-mono)} +.studio-shell.is-developer .studio-resources>button{border-radius:3px;font:10px var(--font-mono)} +.studio-shell.is-developer .studio-document-tabs{background:var(--bg-sunken);border-bottom-color:var(--border)} +.studio-shell.is-developer .studio-document-tabs>div{border-radius:0;border-right-color:var(--border)} +.studio-shell.is-developer .studio-breadcrumb{font:9px var(--font-mono);text-transform:uppercase} +.studio-shell.is-developer .studio-inspector{box-shadow:none;border-left-color:var(--border)} +.studio-shell.is-developer .studio-inspector>header strong,.studio-shell.is-developer .studio-statusbar{font-family:var(--font-mono)} +.studio-shell.is-developer .studio-statusbar{height:24px;font-size:9px} +.studio-shell.is-developer .run-console{border-radius:0} +.studio-shell.is-developer .run-console pre{font-size:10px} +.studio-shell.is-developer .studio-card,.studio-shell.is-developer .ws-card{border-radius:4px} +.studio-shell.is-developer .chat-welcome{align-items:flex-start;margin:0;max-width:100%;padding:24px 32px} +.studio-shell.is-developer .chat-welcome h1{font:550 17px var(--font-mono)} +.studio-shell.is-developer .chat-welcome-kicker{color:var(--accent);font:9px var(--font-mono);letter-spacing:.6px} +.studio-shell.is-developer .chat-starters{max-width:680px;grid-template-columns:repeat(3,minmax(0,1fr));margin-top:20px} +.studio-shell.is-developer .chat-starter{min-height:62px;border-radius:4px;background:var(--bg-sunken);font-family:var(--font-mono)} + +[data-style="darkside"] .studio-shell.is-daily{--bg:#18211f;--bg-sunken:#121a18;--bg-elevated:#202c29;--border:#354741;--text:#e8f1ed;--text-secondary:#a9bdb5;--text-tertiary:#81988e;--accent:#90d6b6;--accent-soft:#253b32;--success:#78d2a3;--warning:#e7bd74;--danger:#ed9688;--info:#85bfe2;color-scheme:dark} +[data-style="darkside"][data-theme="light"] .studio-shell.is-daily{--bg:#f3f7f4;--bg-sunken:#eaf1ec;--bg-elevated:#fff;--border:#d8e4dc;--text:#25342d;--text-secondary:#5f7167;--text-tertiary:#819087;--accent:#28775d;--accent-soft:#e0f0e6;--success:#2d805c;--warning:#a36b26;--danger:#b34843;--info:#346f9c;color-scheme:light} +[data-style="darkside"] .studio-shell.is-daily .conversations{background:var(--bg-sunken);border-right-color:var(--border)} +[data-style="darkside"] .studio-shell.is-daily .chat-welcome{color:var(--text)} +[data-style="darkside"] .studio-shell.is-daily .chat-starter{background:var(--bg-elevated);border-color:var(--border)} +[data-style="darkside"] .studio-shell.is-daily .composer{box-shadow:0 8px 28px color-mix(in srgb,var(--text) 8%,transparent)} + +[data-style="darkside"] .studio-shell.is-developer{--bg:#0c1118;--bg-sunken:#080d13;--bg-elevated:#121a24;--border:#283747;--text:#e3edf4;--text-secondary:#9bafbd;--text-tertiary:#708798;--accent:#65cde0;--accent-soft:#142c38;--success:#65d2a4;--warning:#f0bd67;--danger:#ef887f;--info:#85baf2;color-scheme:dark} +[data-style="darkside"][data-theme="light"] .studio-shell.is-developer{--bg:#eff3f8;--bg-sunken:#e5ebf2;--bg-elevated:#fff;--border:#cbd6e2;--text:#1c2a35;--text-secondary:#526879;--text-tertiary:#73899a;--accent:#087c98;--accent-soft:#d9eef2;--success:#217950;--warning:#9a681a;--danger:#b4413a;--info:#366dba;color-scheme:light} +[data-style="darkside"] .studio-shell.is-developer .studio-activity,[data-style="darkside"] .studio-shell.is-developer .studio-resources,[data-style="darkside"] .studio-shell.is-developer .run-console{background:var(--bg-sunken)} +[data-style="darkside"] .studio-shell.is-developer .studio-main,[data-style="darkside"] .studio-shell.is-developer .studio-inspector{background:var(--bg)} +[data-style="darkside"] .studio-shell.is-developer .studio-resources>button.is-selected{box-shadow:inset 2px 0 0 var(--accent)} +[data-style="darkside"] .studio-shell.is-developer .studio-document-tabs>div.is-active{background:var(--bg);border-top-color:var(--accent)} + +.studio-shell .chat-welcome-kicker{display:block;color:var(--text-tertiary);font-size:9px;letter-spacing:.7px} +.chat-starters{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;width:min(680px,100%);margin-top:16px} +.chat-starter{display:flex;align-items:center;gap:9px;min-width:0;min-height:48px;padding:9px 11px;border:1px solid var(--border);border-radius:8px;background:var(--bg-elevated);color:var(--text-secondary);font:11px var(--font-sans);text-align:left;cursor:pointer;transition:border-color .15s ease,background .15s ease,color .15s ease} +.chat-starter:hover{border-color:var(--accent);background:var(--accent-soft);color:var(--text)} +.chat-starter>svg{flex:none;color:var(--accent)} +.chat-starter>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap} +@media(max-width:760px){.chat-starters{grid-template-columns:1fr}.studio-shell.is-daily .overview-start{align-items:flex-start;flex-direction:column}.studio-shell.is-daily .overview-actions{justify-content:flex-start}} diff --git a/css/kb.css b/css/kb.css new file mode 100644 index 0000000000000000000000000000000000000000..83eb01ffc2d0610ba870c117dfe360e9620b1487 --- /dev/null +++ b/css/kb.css @@ -0,0 +1,644 @@ +/* 本地知识库(Phase 3 RAG):文档列表 + 检索测试 + 带引用问答。 + Warm Paper 全令牌配色,遵循 design-system.md。 */ + +.kb { + flex: 1; + min-width: 0; + overflow-y: auto; + padding: 36px 48px 48px; +} + +.kb-head { + display: flex; + align-items: flex-end; + justify-content: space-between; + gap: 16px; + margin-bottom: 16px; + flex-wrap: wrap; +} + +.kb-head h1 { + font-size: 30px; +} + +.kb-head-sub { + margin: 6px 0 0; + font-size: 13.5px; + color: var(--text-secondary); +} + +.kb-head-actions { + display: flex; + align-items: center; + gap: 14px; +} + +.kb-stat { + font-size: 13px; + color: var(--text-secondary); + font-variant-numeric: tabular-nums; +} + +.kb-backend-note { + margin: 0 0 16px; + padding: 8px 14px; + border: 1px dashed var(--border); + border-radius: var(--radius-control); + background: var(--bg-sunken); + font-size: 13px; + color: var(--text-secondary); +} + +.kb-notice { + margin: 0 0 16px; + padding: 8px 14px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: var(--accent-soft); + font-size: 13px; + color: var(--text); +} + +.kb-error { + margin: 8px 0 0; + font-size: 13px; + color: var(--danger); +} + +.kb-muted { + font-size: 13px; + color: var(--text-secondary); +} + +/* ── 按钮 / 输入 ────────────────────────────────────────────────── */ + +.kb-btn { + display: inline-flex; + align-items: center; + gap: 6px; + height: 36px; + padding: 0 14px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: transparent; + color: var(--text); + font-family: inherit; + font-size: 13.5px; + cursor: pointer; + transition: background-color var(--dur) var(--ease), border-color var(--dur) var(--ease); +} + +.kb-btn:hover:not(:disabled) { + background: var(--bg-elevated); +} + +.kb-btn:disabled { + opacity: 0.55; + cursor: default; +} + +.kb-btn-primary { + border-color: transparent; + background: var(--accent); + color: var(--bg); +} + +.kb-btn-primary:hover:not(:disabled) { + filter: brightness(0.94); +} + +.kb-icon-btn { + display: inline-flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; + border: none; + border-radius: var(--radius-control); + background: transparent; + color: var(--text-secondary); + cursor: pointer; + transition: background-color var(--dur) var(--ease); +} + +.kb-icon-btn:hover { + background: var(--accent-soft); + color: var(--text); +} + +.kb-input { + flex: 1; + min-width: 0; + height: 36px; + padding: 0 12px; + border: 1px solid transparent; + border-radius: var(--radius-control); + background: var(--bg-sunken); + color: var(--text); + font-family: inherit; + font-size: 14px; +} + +.kb-input::placeholder { + color: var(--text-tertiary); +} + +.kb-input:focus { + outline: none; + border-color: var(--accent); + box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent-soft) 65%, transparent); +} + +.kb-select { + height: 36px; + padding: 0 8px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: var(--bg-elevated); + color: var(--text); + font-family: inherit; + font-size: 13px; +} + +.kb-input-row { + display: flex; + align-items: center; + gap: 8px; + margin-bottom: 12px; +} + +/* ── 双栏布局 ───────────────────────────────────────────────────── */ + +.kb-columns { + display: grid; + grid-template-columns: 320px minmax(0, 1fr); + gap: 20px; + align-items: start; +} + +.kb-right { + display: flex; + flex-direction: column; + gap: 20px; + min-width: 0; +} + +.kb-panel { + padding: 20px 22px; + border: 1px solid var(--border); + border-radius: var(--radius-card); + background: var(--bg-elevated); +} + +.kb-panel-title { + margin: 0 0 14px; + font-family: var(--font-serif); + font-size: 17px; + font-weight: 600; +} + +/* ── 文档列表 ───────────────────────────────────────────────────── */ + +.kb-empty { + display: flex; + flex-direction: column; + align-items: center; + gap: 8px; + padding: 28px 12px; + text-align: center; + color: var(--text-secondary); +} + +.kb-empty p { + margin: 0; + font-family: var(--font-serif); + font-size: 15px; + color: var(--text); +} + +.kb-empty .kb-muted { + font-family: var(--font-sans); + font-size: 13px; + color: var(--text-secondary); +} + +.kb-doc-list { + list-style: none; + margin: 0; + padding: 0; +} + +.kb-doc { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + padding: 10px 4px; + border-bottom: 1px solid var(--border); +} + +.kb-doc:last-child { + border-bottom: none; +} + +.kb-doc-main { + display: flex; + flex-direction: column; + min-width: 0; +} + +.kb-doc-name { + font-size: 14px; + color: var(--text); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.kb-doc-meta { + margin-top: 2px; + font-size: 12px; + color: var(--text-secondary); + font-variant-numeric: tabular-nums; +} + +/* ── 检索命中卡片 ───────────────────────────────────────────────── */ + +.kb-hit-list { + list-style: none; + margin: 0; + padding: 0; + display: flex; + flex-direction: column; + gap: 10px; +} + +.kb-hit { + padding: 12px 14px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: var(--bg); + transition: border-color var(--dur) var(--ease); +} + +.kb-hit:hover { + border-color: var(--accent); +} + +.kb-hit-head { + display: flex; + align-items: baseline; + justify-content: space-between; + gap: 10px; + margin-bottom: 6px; +} + +.kb-hit-source { + font-size: 12.5px; + color: var(--text-secondary); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.kb-hit-score { + flex-shrink: 0; + font-family: var(--font-mono); + font-size: 12px; + color: var(--accent); + font-variant-numeric: tabular-nums; +} + +.kb-hit-excerpt { + margin: 0; + font-size: 13.5px; + line-height: 1.6; + color: var(--text); +} + +/* ── 问答结果 ───────────────────────────────────────────────────── */ + +.kb-ask-result { + margin-top: 4px; +} + +.kb-question-line { + margin: 10px 0 6px; + font-size: 13px; + color: var(--text-secondary); +} + +.kb-answer-body { + font-size: 14.5px; + line-height: 1.7; +} + +.kb-answer-body > * { + margin: 0 0 10px; +} + +.kb-cite-ref { + display: inline; + padding: 0 3px; + margin: 0 1px; + border: none; + border-radius: 4px; + background: var(--accent-soft); + color: var(--accent); + font-family: var(--font-mono); + font-size: 12px; + cursor: pointer; + vertical-align: super; + line-height: 1; + transition: background-color var(--dur) var(--ease); +} + +.kb-cite-ref:hover { + background: var(--accent); + color: var(--bg); +} + +/* ── 引用条目(可折叠) ─────────────────────────────────────────── */ + +.kb-citations { + margin: 0 0 12px; + padding: 10px 14px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: var(--bg-sunken); +} + +.kb-citations > summary { + cursor: pointer; + font-size: 13px; + color: var(--text-secondary); + list-style: none; +} + +.kb-citations > summary::-webkit-details-marker { + display: none; +} + +.kb-citation-list { + list-style: none; + margin: 10px 0 0; + padding: 0; + display: flex; + flex-direction: column; + gap: 8px; +} + +.kb-citation { + padding-top: 8px; + border-top: 1px solid var(--border); +} + +.kb-citation:first-child { + border-top: none; + padding-top: 0; +} + +.kb-citation-btn { + display: flex; + align-items: baseline; + gap: 6px; + width: 100%; + padding: 0; + border: none; + background: transparent; + text-align: left; + cursor: pointer; +} + +.kb-citation-rank { + flex-shrink: 0; + font-family: var(--font-mono); + font-size: 12px; + color: var(--accent); +} + +.kb-citation-source { + font-size: 12.5px; + color: var(--text-secondary); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.kb-citation-quote { + margin: 4px 0 0; + font-size: 13px; + line-height: 1.55; + color: var(--text); + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} + +/* ── 引用原文抽屉 ───────────────────────────────────────────────── */ + +.kb-drawer-mask { + position: fixed; + inset: 0; + display: flex; + justify-content: flex-end; + background: var(--scrim); + z-index: 40; +} + +.kb-drawer { + display: flex; + flex-direction: column; + width: min(520px, 90vw); + height: 100%; + background: var(--bg-elevated); + border-left: 1px solid var(--border); + box-shadow: var(--shadow-float); + animation: kb-drawer-in 180ms var(--ease); +} + +@keyframes kb-drawer-in { + from { + opacity: 0; + transform: translateX(12px); + } + to { + opacity: 1; + transform: translateX(0); + } +} + +.kb-drawer-head { + display: flex; + align-items: center; + justify-content: space-between; + gap: 10px; + padding: 18px 22px; + border-bottom: 1px solid var(--border); +} + +.kb-drawer-head > div { + display: flex; + align-items: baseline; + gap: 8px; + min-width: 0; +} + +.kb-drawer-source { + font-family: var(--font-serif); + font-size: 15px; + font-weight: 600; + color: var(--text); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.kb-drawer-body { + flex: 1; + overflow-y: auto; + padding: 20px 22px; + font-size: 14.5px; + line-height: 1.7; +} + +.kb-drawer-body .md > * { + margin: 0 0 12px; +} + +/* ── 拖放蒙层 ───────────────────────────────────────────────────── */ + +.kb-drag-overlay { + position: fixed; + inset: 0; + z-index: 50; + background: var(--glass); + display: flex; + align-items: center; + justify-content: center; +} + +.kb-drag-card { + display: flex; + flex-direction: column; + align-items: center; + gap: 10px; + padding: 40px 56px; + border: 1px dashed var(--accent); + border-radius: var(--radius-float); + color: var(--text); +} + +.kb-drag-title { + margin: 0; + font-family: var(--font-serif); + font-size: 24px; + font-weight: 600; +} + +.kb-drag-sub { + margin: 0; + font-size: 13.5px; + color: var(--text-secondary); +} + +/* 转圈(theme.css 的 reduced-motion 会全局关停动画) */ +.kb-spin { + animation: kb-rot 1s linear infinite; +} + +@keyframes kb-rot { + to { + transform: rotate(360deg); + } +} + +/* 窄屏:双栏折叠成单栏 */ +@media (max-width: 900px) { + .kb-columns { + grid-template-columns: minmax(0, 1fr); + } +} + +/* ── 语义检索徽章(契约 7B)────────────────────────────────────── */ + +.kb-backend { + margin-bottom: 12px; +} + +/* 徽章本体是个按钮:点开才看细节,默认视图只给结论 */ +.kb-backend-badge { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 4px 12px; + border: 1px solid var(--border); + border-radius: var(--radius-chip); + background: var(--bg-elevated); + color: var(--text-secondary); + font-size: 12px; + line-height: 1.6; + cursor: pointer; + transition: border-color var(--dur) var(--ease), color var(--dur) var(--ease); +} + +.kb-backend-badge:hover { + border-color: var(--accent); + color: var(--text); +} + +.kb-backend-badge:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +/* 状态点:启用=success,降级=warning。不用红——降级是设计内的正常状态 */ +.kb-dot { + width: 7px; + height: 7px; + border-radius: 50%; + background: var(--warning); + flex: none; +} + +.kb-backend-on .kb-dot { + background: var(--success); +} + +.kb-backend-label { + font-weight: 500; +} + +.kb-backend-on .kb-backend-label { + color: var(--text); +} + +/* 模型名片片:次要信息,弱化显示 */ +.kb-backend-model { + padding-left: 6px; + margin-left: 2px; + border-left: 1px solid var(--border); + color: var(--text-tertiary); + font-family: var(--font-mono); + font-size: 11px; +} + +.kb-backend-detail { + margin-top: 8px; +} + +.kb-backend-detail .kb-backend-note { + margin: 0; +} + +.kb-backend-meta { + margin: 4px 0 0; + color: var(--text-tertiary); + font-size: 12px; +} + +/* 导入进度:等宽数字更好读 */ +.kb-import-progress { + font-variant-numeric: tabular-nums; +} diff --git a/css/launcher.css b/css/launcher.css new file mode 100644 index 0000000000000000000000000000000000000000..b58ff1917d34e09956e451c313f55908e83a3052 --- /dev/null +++ b/css/launcher.css @@ -0,0 +1,302 @@ +/* 启动器:大输入框 + 模糊搜索结果列表(Warm Paper,颜色一律走 theme.css 令牌) */ + +/* ---------- 通用容器 ---------- */ +.launcher { + display: flex; + flex-direction: column; + min-width: 0; + overflow: hidden; +} + +/* ---------- 主窗口内嵌版:普通面板,靠左上对齐留白 ---------- */ +.launcher--page { + flex: 1; + height: 100%; + background: transparent; +} + +.launcher--page .launcher-search, +.launcher--page .launcher-body, +.launcher--page .launcher-foot { + width: min(720px, 100%); +} + +/* ---------- 浮窗版:毛玻璃 + 圆角 + 极轻阴影 ---------- */ +/* 注意:透明窗口上 WebKit 的 backdrop-filter 会把元素整个画没(macOS 已知坑), + 所以模糊交给系统的窗口特效(tauri.conf.json 的 windowEffects), + CSS 只负责 85% 暖纸底色,透出桌面就靠它本身是半透明的。 */ +.launcher--overlay { + flex: 1; + min-height: 0; + border: 1px solid var(--border); + border-radius: var(--radius-float); + background: var(--glass); + box-shadow: var(--shadow-float); + animation: launcher-in 180ms var(--ease); +} + +/* 透明窗口本体:桌面要从圆角外透出来 */ +body.launcher-surface { + background: transparent; +} + +.launcher-overlay { + height: 100%; + display: flex; + padding: 12px; + box-sizing: border-box; +} + +@keyframes launcher-in { + from { + opacity: 0; + transform: translateY(6px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +/* ---------- 输入区 ---------- */ +.launcher-search { + display: flex; + align-items: center; + gap: 12px; + margin: 16px 16px 8px; + padding: 10px 16px; + border: 1px solid transparent; + border-radius: var(--radius-card); + background: var(--bg-sunken); + transition: + border-color var(--dur) var(--ease), + background-color var(--dur) var(--ease); +} + +.launcher-search:focus-within { + border-color: var(--accent); +} + +.launcher-search-icon { + flex-shrink: 0; + color: var(--text-tertiary); +} + +.launcher-input { + flex: 1; + min-width: 0; + border: none; + background: transparent; + color: var(--text); + font-family: var(--font-serif); + font-size: 26px; + line-height: 1.4; + letter-spacing: -0.01em; + outline: none; + cursor: text; +} + +.launcher-input::placeholder { + color: var(--text-tertiary); +} + +.launcher-kbd { + flex-shrink: 0; + font-size: 12px; + color: var(--text-tertiary); + white-space: nowrap; +} + +/* ---------- 结果列表 ---------- */ +.launcher-body { + flex: 1; + min-height: 0; + overflow-y: auto; + padding: 4px 8px 8px; +} + +.launcher-list { + margin: 0; + padding: 0; + list-style: none; +} + +.launcher-item { + display: flex; + align-items: baseline; + gap: 16px; + width: 100%; + padding: 9px 14px; + border: none; + border-radius: var(--radius-control); + background: transparent; + color: var(--text); + font-family: inherit; + font-size: 14.5px; + text-align: left; + cursor: pointer; + transition: background-color var(--dur) var(--ease); +} + +.launcher-item:hover { + background: color-mix(in srgb, var(--accent-soft) 40%, transparent); +} + +.launcher-item.is-selected { + background: var(--accent-soft); +} + +.launcher-item-name { + flex: 1; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.launcher-item-name mark { + background: transparent; + color: var(--accent); + font-weight: 600; +} + +.launcher-item-meta { + flex-shrink: 0; + display: flex; + gap: 12px; + font-size: 12.5px; + color: var(--text-tertiary); + font-variant-numeric: tabular-nums; +} + +/* ---------- 空态 / 状态行 ---------- */ +.launcher-empty { + padding: 20px 16px; +} + +.launcher-empty-title { + margin: 0 0 6px; + font-family: var(--font-serif); + font-size: 20px; + color: var(--text); +} + +.launcher-empty-note { + margin: 0; + font-size: 13.5px; + color: var(--text-secondary); +} + +.launcher-note { + margin: 0; + padding: 16px; + font-size: 13.5px; + color: var(--text-secondary); +} + +.launcher-note.is-error { + color: var(--danger); +} + +/* ---------- 底栏 ---------- */ +.launcher-foot { + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; + padding: 10px 20px 14px; + border-top: 1px solid var(--border); + font-size: 12.5px; + color: var(--text-tertiary); +} + +.launcher-hint { + color: var(--text-tertiary); +} + +.launcher-settings { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 4px; + min-width: 0; +} + +.launcher-settings-row { + display: flex; + align-items: center; + gap: 10px; + min-width: 0; +} + +.launcher-settings-note { + max-width: 480px; + font-size: 12px; + line-height: 1.6; + color: var(--text-tertiary); +} + +.launcher-settings-label { + color: var(--text-secondary); + white-space: nowrap; +} + +.launcher-settings-error { + color: var(--danger); +} + +.launcher-chips { + display: flex; + gap: 6px; +} + +.launcher-chip { + height: 26px; + padding: 0 10px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: transparent; + color: var(--text-secondary); + font-family: inherit; + font-size: 12.5px; + cursor: pointer; + transition: background-color var(--dur) var(--ease); +} + +.launcher-chip:hover { + background: var(--bg-elevated); + color: var(--text); +} + +.launcher-chip.is-active { + border-color: var(--accent-soft); + background: var(--accent-soft); + color: var(--text); +} + +.launcher-foot-right { + display: flex; + align-items: center; + gap: 14px; +} + +.launcher-refresh { + display: inline-flex; + align-items: center; + gap: 6px; + height: 28px; + padding: 0 10px; + border: none; + border-radius: var(--radius-control); + background: transparent; + color: var(--text-secondary); + font-family: inherit; + font-size: 12.5px; + cursor: pointer; + transition: background-color var(--dur) var(--ease); +} + +.launcher-refresh:hover { + background: var(--bg-elevated); + color: var(--text); +} diff --git a/css/live-eye.css b/css/live-eye.css new file mode 100644 index 0000000000000000000000000000000000000000..ea81fd6d8e9ca5a7bbb085d0bbc4f9e42bafb64f --- /dev/null +++ b/css/live-eye.css @@ -0,0 +1,474 @@ +/* 实时之眼窗口:Warm Paper 卡片(颜色一律走 theme.css 令牌)。 + 与看图问答的差别:本窗带系统标题栏(兑现契约「标题栏红点」——标题由后端 + 改成「🔴 实时之眼中」),所以页面本体是不透明暖纸底,不做透明圆角悬浮。 */ + +body.live-surface { + background: var(--bg); +} + +.live-root { + height: 100%; + display: flex; + box-sizing: border-box; +} + +.live-card { + flex: 1; + min-height: 0; + display: flex; + flex-direction: column; + overflow: hidden; +} + +/* ---------- 顶栏:标题 + 录制徽章 ---------- */ +.live-head { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + padding: 18px 20px 6px; +} + +.live-head-main { + display: flex; + align-items: center; + gap: 10px; + min-width: 0; +} + +.live-title { + margin: 0; + font-family: var(--font-serif); + font-size: 20px; + font-weight: 600; + letter-spacing: -0.01em; + color: var(--text); +} + +/* 录制级指示(第二层):红点呼吸 +「实时之眼中」徽章 */ +.live-badge { + display: inline-flex; + align-items: center; + gap: 6px; + height: 22px; + padding: 0 9px; + border: 1px solid var(--border); + border-radius: var(--radius-chip); + background: var(--bg-elevated); + color: var(--text-tertiary); + font-size: 11.5px; + white-space: nowrap; +} + +.live-badge.is-rec { + border-color: var(--danger); + color: var(--danger); +} + +.live-badge-dot { + width: 7px; + height: 7px; + border-radius: 50%; + background: var(--text-tertiary); + flex-shrink: 0; +} + +.live-badge.is-rec .live-badge-dot { + background: var(--danger); + animation: live-breathe 1.6s ease-in-out infinite; +} + +@keyframes live-breathe { + 0%, + 100% { + opacity: 1; + } + 50% { + opacity: 0.25; + } +} + +.live-esc { + font-size: 12px; + color: var(--text-tertiary); + white-space: nowrap; +} + +/* ---------- 权限状态灯 ---------- */ +.live-perms { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 10px; + padding: 6px 20px 2px; +} + +.live-perm { + display: inline-flex; + align-items: center; + gap: 6px; + color: var(--text-tertiary); + font-size: 12px; +} + +.live-dot { + width: 7px; + height: 7px; + border-radius: 50%; + background: var(--text-tertiary); + flex-shrink: 0; +} + +.live-perm.is-ok { + color: var(--success); +} + +.live-perm.is-ok .live-dot { + background: var(--success); +} + +.live-perm.is-bad { + color: var(--danger); +} + +.live-perm.is-bad .live-dot { + background: var(--danger); +} + +.live-perm.is-wait { + color: var(--warning); +} + +.live-perm.is-wait .live-dot { + background: var(--warning); +} + +.live-perm-link { + padding: 0; + border: none; + background: transparent; + color: var(--accent); + font-family: inherit; + font-size: 12px; + cursor: pointer; + text-decoration: underline; + text-underline-offset: 3px; +} + +/* ---------- 引导态(没授权绝不硬开摄像头) ---------- */ +.live-guide { + flex: 1; + display: flex; + flex-direction: column; + padding: 24px 24px 20px; +} + +.live-guide-head { + display: flex; + align-items: center; + gap: 10px; + color: var(--accent); +} + +.live-guide-title { + margin: 0; + font-family: var(--font-serif); + font-size: 22px; + font-weight: 600; + letter-spacing: -0.01em; +} + +.live-lead { + margin: 12px 0 18px; + color: var(--text-secondary); + font-size: 14px; + line-height: 1.65; +} + +.live-guide-actions { + display: flex; + flex-wrap: wrap; + gap: 10px; +} + +.live-primary { + height: 40px; + padding: 0 20px; + border: none; + border-radius: var(--radius-control); + background: var(--accent); + color: var(--bg); + font-family: inherit; + font-size: 14px; + cursor: pointer; +} + +.live-primary:hover { + filter: brightness(0.94); +} + +.live-secondary { + height: 40px; + padding: 0 16px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: transparent; + color: var(--text-secondary); + font-family: inherit; + font-size: 13.5px; + cursor: pointer; +} + +.live-secondary:hover { + background: var(--bg-elevated); + color: var(--text); +} + +.live-guide-why { + margin: 16px 0 0; + color: var(--text-tertiary); + font-size: 12.5px; + line-height: 1.7; +} + +.live-guide-hint { + margin-top: auto; + padding-top: 18px; + color: var(--danger); + font-size: 12.5px; + line-height: 1.6; +} + +/* ---------- 采集控制 ---------- */ +.live-controls { + display: flex; + align-items: center; + gap: 12px; + padding: 12px 20px 0; +} + +.live-start, +.live-stop { + height: 36px; + padding: 0 16px; + border-radius: var(--radius-control); + font-family: inherit; + font-size: 13.5px; + cursor: pointer; + transition: background-color var(--dur) var(--ease), color var(--dur) var(--ease); +} + +.live-start { + border: none; + background: var(--accent); + color: var(--bg); +} + +.live-start:hover:not(:disabled) { + filter: brightness(0.94); +} + +.live-stop { + border: 1px solid var(--danger); + background: transparent; + color: var(--danger); +} + +.live-stop:hover:not(:disabled) { + background: var(--danger); + color: var(--bg); +} + +.live-start:disabled, +.live-stop:disabled { + opacity: 0.45; + cursor: default; +} + +.live-interval { + display: inline-flex; + align-items: center; + gap: 6px; + font-size: 12.5px; + color: var(--text-secondary); +} + +.live-interval-select { + height: 30px; + padding: 0 6px; + border: 1px solid var(--border); + border-radius: var(--radius-chip); + background: var(--bg-sunken); + color: var(--text); + font-family: inherit; + font-size: 12.5px; + outline: none; + cursor: pointer; +} + +.live-meta { + margin: 8px 0 0; + padding: 0 20px; + color: var(--text-tertiary); + font-size: 12px; + line-height: 1.6; + font-variant-numeric: tabular-nums; +} + +.live-error { + margin: 8px 20px 0; + color: var(--danger); + font-size: 12.5px; + line-height: 1.5; +} + +/* ---------- 提问输入 ---------- */ +.live-custom { + display: flex; + align-items: center; + gap: 8px; + margin: 12px 20px 0; + padding: 6px 6px 6px 12px; + border: 1px solid transparent; + border-radius: var(--radius-control); + background: var(--bg-sunken); + transition: border-color var(--dur) var(--ease); +} + +.live-custom:focus-within { + border-color: var(--accent); +} + +.live-input { + flex: 1; + min-width: 0; + border: none; + background: transparent; + color: var(--text); + font-family: inherit; + font-size: 13.5px; + outline: none; + cursor: text; +} + +.live-input::placeholder { + color: var(--text-tertiary); +} + +.live-input:disabled { + cursor: default; +} + +.live-send { + flex-shrink: 0; + height: 28px; + padding: 0 12px; + border: none; + border-radius: var(--radius-chip); + background: var(--accent); + color: var(--bg); + font-family: inherit; + font-size: 13px; + cursor: pointer; +} + +.live-send:disabled { + opacity: 0.4; + cursor: default; +} + +/* ---------- 模型下拉(vision-only 过滤后的清单) ---------- */ +.live-model-row { + display: flex; + align-items: center; + gap: 8px; + margin: 8px 20px 0; +} + +.live-model-label { + font-size: 12px; + color: var(--text-tertiary); + white-space: nowrap; +} + +.live-model { + flex: 1; + min-width: 0; + height: 30px; + padding: 0 8px; + border: 1px solid var(--border); + border-radius: var(--radius-chip); + background: var(--bg-sunken); + color: var(--text); + font-family: inherit; + font-size: 12.5px; + outline: none; + cursor: pointer; +} + +.live-model:disabled { + opacity: 0.6; + cursor: default; +} + +/* ---------- 回答区 ---------- */ +.live-answer { + flex: 1; + min-height: 0; + display: flex; + flex-direction: column; + margin-top: 12px; + padding: 10px 20px 14px; + border-top: 1px solid var(--border); +} + +.live-answer-body { + flex: 1; + min-height: 0; + overflow-y: auto; +} + +.live-answer-text { + margin: 0; + color: var(--text); + font-size: 13.5px; + line-height: 1.65; + white-space: pre-wrap; + word-break: break-word; + user-select: text; +} + +/* 流式呼吸光标(与看图问答同款;reduced-motion 由 theme.css 全局降级) */ +.live-cursor { + display: inline-block; + width: 2px; + height: 1.05em; + margin-left: 3px; + border-radius: 1px; + background: var(--accent); + vertical-align: text-bottom; + animation: live-cursor-breathe 1s ease-in-out infinite; +} + +@keyframes live-cursor-breathe { + 0%, + 100% { + opacity: 1; + } + 50% { + opacity: 0.15; + } +} + +.live-answer-foot { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + margin-top: 10px; +} + +.live-foot-hint { + font-size: 12px; + color: var(--text-tertiary); +} diff --git a/css/markdown.css b/css/markdown.css new file mode 100644 index 0000000000000000000000000000000000000000..03d484afc79f24ab3c1fa278005c009359774b59 --- /dev/null +++ b/css/markdown.css @@ -0,0 +1,239 @@ +/* 消息内 Markdown 排版 + 代码块(配色全部映射到 theme.css 令牌) */ + +.md { + font-family: var(--font-sans); + font-size: 15px; + line-height: 1.75; + color: var(--text); + overflow-wrap: break-word; +} + +.md > *:first-child { + margin-top: 0; +} + +.md > *:last-child { + margin-bottom: 0; +} + +.md p { + margin: 0 0 16px; +} + +.md h1, +.md h2, +.md h3, +.md h4 { + font-family: var(--font-serif); + margin: 32px 0 12px; +} + +.md h1 { + font-size: 24px; +} + +.md h2 { + font-size: 20px; +} + +.md h3 { + font-size: 17px; +} + +.md h4 { + font-size: 15px; +} + +.md ul, +.md ol { + margin: 0 0 16px; + padding-left: 24px; +} + +.md li { + margin: 4px 0; +} + +.md li > p { + margin: 0; +} + +.md a { + color: var(--accent); + text-decoration: underline; + text-decoration-thickness: 1px; + text-underline-offset: 3px; + cursor: pointer; +} + +.md blockquote { + margin: 0 0 16px; + padding: 4px 0 4px 16px; + border-left: 2px solid var(--border); + color: var(--text-secondary); +} + +.md hr { + margin: 24px 0; + border: none; + border-top: 1px solid var(--border); +} + +.md table { + width: 100%; + margin: 0 0 16px; + border-collapse: collapse; + font-size: 14px; + font-variant-numeric: tabular-nums; +} + +.md th, +.md td { + padding: 8px 12px; + border-bottom: 1px solid var(--border); + text-align: left; +} + +.md th { + font-weight: 600; + color: var(--text-secondary); +} + +.md img { + max-width: 100%; + border-radius: var(--radius-control); +} + +/* 行内代码 */ +.md code { + padding: 2px 6px; + border-radius: var(--radius-control); + background: var(--bg-sunken); + font-family: var(--font-mono); + font-size: 0.92em; +} + +/* ---------- 代码块 ---------- */ +.code-block { + margin: 0 0 16px; + border: 1px solid var(--border); + border-radius: var(--radius-card); + background: var(--bg-sunken); + overflow: hidden; +} + +.code-head { + display: flex; + align-items: center; + justify-content: space-between; + padding: 6px 10px 6px 14px; + border-bottom: 1px solid var(--border); +} + +.code-lang { + font-family: var(--font-mono); + font-size: 12px; + color: var(--text-tertiary); +} + +.code-copy { + display: inline-flex; + align-items: center; + gap: 6px; + height: 26px; + padding: 0 10px; + border: none; + border-radius: var(--radius-control); + background: transparent; + color: var(--text-secondary); + font-family: inherit; + font-size: 12px; + cursor: pointer; + transition: background-color var(--dur) var(--ease); +} + +.code-copy:hover { + background: var(--bg-elevated); + color: var(--text); +} + +.code-block pre { + margin: 0; + padding: 14px 16px; + overflow-x: auto; + font-family: var(--font-mono); + font-size: 13px; + line-height: 1.65; +} + +.code-block pre code { + padding: 0; + border-radius: 0; + background: none; + font-size: 13px; +} + +/* ---------- 语法高亮:highlight.js 语义 → 主题令牌 ---------- */ +.hljs-comment, +.hljs-quote { + color: var(--text-tertiary); + font-style: italic; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-literal, +.hljs-type, +.hljs-name, +.hljs-tag { + color: var(--accent); +} + +.hljs-string, +.hljs-regexp, +.hljs-addition { + color: var(--success); +} + +.hljs-number, +.hljs-symbol, +.hljs-bullet, +.hljs-attr, +.hljs-attribute, +.hljs-selector-attr, +.hljs-selector-class, +.hljs-selector-id, +.hljs-variable, +.hljs-template-variable, +.hljs-link { + color: var(--warning); +} + +.hljs-title, +.hljs-section, +.hljs-title.function_ { + color: var(--text); + font-weight: 600; +} + +.hljs-built_in, +.hljs-class .hljs-title, +.hljs-namespace { + color: var(--text-secondary); +} + +.hljs-meta { + color: var(--text-tertiary); +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: 600; +} + +.hljs-deletion { + color: var(--danger); +} diff --git a/css/materials.css b/css/materials.css new file mode 100644 index 0000000000000000000000000000000000000000..3ff8a469ab2662e3e995fc4dd71f2a92b62f2d05 --- /dev/null +++ b/css/materials.css @@ -0,0 +1,12 @@ +.materials-hub{height:100%;min-height:0;display:flex;flex-direction:column;color:var(--text)} +.materials-header{padding:20px 30px 14px;border-bottom:1px solid var(--border)} +.materials-header h1{margin:4px 0;font-size:21px;font-weight:600} +.materials-header p{margin:0;color:var(--text-secondary);font-size:12px;line-height:1.5} +.materials-tabs{display:flex;gap:4px;padding:8px 24px;border-bottom:1px solid var(--border);overflow-x:auto;flex:none} +.materials-tabs button{display:inline-flex;align-items:center;gap:7px;min-height:32px;padding:0 11px;border:1px solid transparent;border-radius:6px;background:transparent;color:var(--text-secondary);font:500 11px var(--font-sans);white-space:nowrap;cursor:pointer} +.materials-tabs button:hover{background:var(--bg-elevated);color:var(--text)} +.materials-tabs button.is-active{border-color:var(--border);background:var(--bg-elevated);color:var(--accent)} +.materials-content{flex:1;min-height:0;overflow:auto} +.materials-content>.studio-feature{min-height:100%;padding:18px 28px 30px} +.materials-content>.xp{padding:18px 28px 30px} +@media(max-width:760px){.materials-header{padding:16px 18px 12px}.materials-tabs{padding:7px 12px}.materials-content>.studio-feature,.materials-content>.xp{padding:14px 14px 22px}} diff --git a/css/mcp.css b/css/mcp.css new file mode 100644 index 0000000000000000000000000000000000000000..83e7135d9fb67d0d77f27bbedd4fb495a9c39ec5 --- /dev/null +++ b/css/mcp.css @@ -0,0 +1,721 @@ +/* MCP 服务器 + 专家中心(Phase 5D):Warm Paper 全令牌配色。 + 覆盖组件:McpPanel / ExpertsCenter / ExpertPicker,以及对话头部的专家入口。 + 规则来自 docs/design-system.md:留白优先、衬线标题、语义色只出现在状态语境。 */ + +/* ---------- 通用面板骨架 ---------- */ +.experts-center { + flex: 1; + min-width: 0; + overflow-y: auto; + padding: 36px 48px 48px; +} + +.mcp-panel { + min-width: 0; + display: flex; + flex-direction: column; + gap: 20px; +} + +.panel-head { + display: flex; + align-items: flex-end; + justify-content: space-between; + gap: 16px; + flex-wrap: wrap; + margin-bottom: 4px; +} + +.panel-title { + margin: 0; + font-family: var(--font-serif); + font-size: 30px; + font-weight: 600; + letter-spacing: -0.01em; + color: var(--text); +} + +.panel-desc { + margin: 8px 0 0; + max-width: 60ch; + font-size: 13.5px; + line-height: 1.7; + color: var(--text-secondary); +} + +.panel-error { + margin: 0; + padding: 10px 14px; + border: 1px solid var(--danger); + border-radius: var(--radius-control); + background: var(--bg-sunken); + color: var(--danger); + font-size: 13px; + line-height: 1.6; +} + +.panel-empty { + margin: 0; + padding: 28px 0; + font-size: 13.5px; + line-height: 1.9; + color: var(--text-tertiary); +} + +.inline-code { + padding: 1px 6px; + border-radius: 6px; + background: var(--bg-sunken); + color: var(--text-secondary); + font-family: var(--font-mono); + font-size: 12.5px; +} + +/* ---------- 按钮(补充 App.css 的 .btn-primary/.btn-secondary)---------- */ +.btn-ghost { + display: inline-flex; + align-items: center; + gap: 6px; + height: 32px; + padding: 0 12px; + border: 1px solid transparent; + border-radius: var(--radius-control); + background: transparent; + color: var(--text-secondary); + font-family: inherit; + font-size: 13px; + cursor: pointer; + transition: background-color var(--dur) var(--ease); +} + +.btn-ghost:hover:not(:disabled) { + background: var(--bg-elevated); + color: var(--text); +} + +.btn-ghost:disabled { + opacity: 0.55; + cursor: default; +} + +.btn-danger { + display: inline-flex; + align-items: center; + gap: 6px; + height: 32px; + padding: 0 12px; + border: 1px solid var(--danger); + border-radius: var(--radius-control); + background: transparent; + color: var(--danger); + font-family: inherit; + font-size: 13px; + cursor: pointer; + transition: background-color var(--dur) var(--ease); +} + +.btn-danger:hover { + background: var(--bg-elevated); +} + +.btn-icon { + display: inline-grid; + place-items: center; + width: 28px; + height: 28px; + border: 1px solid transparent; + border-radius: var(--radius-control); + background: transparent; + color: var(--text-secondary); + cursor: pointer; + transition: background-color var(--dur) var(--ease); +} + +.btn-icon:hover { + background: var(--bg-elevated); + color: var(--text); +} + +.mcp-panel .btn-primary, +.experts-center .btn-primary { + display: inline-flex; + align-items: center; + gap: 6px; + height: 36px; + padding: 0 18px; +} + +/* ---------- 表单 ---------- */ +.mcp-form, +.expert-form { + display: flex; + flex-direction: column; + gap: 16px; + padding: 20px 22px; + border: 1px solid var(--border); + border-radius: var(--radius-card); + background: var(--bg-elevated); +} + +.mcp-form-title { + margin: 0; + font-family: var(--font-serif); + font-size: 19px; + font-weight: 600; + color: var(--text); +} + +.field { + display: flex; + flex-direction: column; + gap: 6px; +} + +.field-label { + font-size: 13px; + font-weight: 500; + color: var(--text-secondary); +} + +.field-note { + margin: 0; + font-size: 12.5px; + line-height: 1.7; + color: var(--text-tertiary); +} + +.field-input { + width: 100%; + padding: 9px 12px; + border: 1px solid transparent; + border-radius: var(--radius-control); + background: var(--bg-sunken); + color: var(--text); + font-family: inherit; + font-size: 13.5px; + line-height: 1.6; + resize: vertical; + transition: border-color var(--dur) var(--ease); +} + +.field-input:focus { + outline: none; + border-color: var(--accent); +} + +.field-mono { + font-family: var(--font-mono); + font-size: 12.5px; +} + +.mcp-env-row { + display: grid; + grid-template-columns: 1fr 1fr auto; + gap: 8px; + align-items: center; +} + +.mcp-form-actions { + display: flex; + align-items: center; + gap: 10px; +} + +.expert-form-row { + display: grid; + grid-template-columns: 1fr 1.2fr; + gap: 16px; + align-items: start; +} + +.expert-emoji-grid { + display: flex; + flex-wrap: wrap; + gap: 6px; +} + +.expert-emoji { + display: inline-grid; + place-items: center; + width: 34px; + height: 34px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: var(--bg-sunken); + font-size: 17px; + cursor: pointer; + transition: border-color var(--dur) var(--ease), background-color var(--dur) var(--ease); +} + +.expert-emoji:hover { + background: var(--bg-elevated); +} + +.expert-emoji.is-active { + border-color: var(--accent); + background: var(--accent-soft); +} + +.expert-prompt { + font-family: var(--font-sans); + line-height: 1.75; +} + +/* ---------- MCP 服务器卡片 ---------- */ +.mcp-list { + display: flex; + flex-direction: column; + gap: 14px; + margin: 0; + padding: 0; + list-style: none; +} + +.mcp-card { + display: flex; + flex-direction: column; + gap: 10px; + padding: 18px 20px; + border: 1px solid var(--border); + border-radius: var(--radius-card); + background: var(--bg-elevated); +} + +.mcp-card-head { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + flex-wrap: wrap; +} + +.mcp-card-title { + display: flex; + align-items: center; + gap: 10px; + flex-wrap: wrap; +} + +.mcp-name { + font-family: var(--font-serif); + font-size: 18px; + font-weight: 600; + color: var(--text); +} + +.mcp-status { + display: inline-flex; + align-items: center; + gap: 6px; + font-size: 12.5px; + color: var(--text-secondary); +} + +.mcp-status-dot { + width: 8px; + height: 8px; + border-radius: 50%; + background: var(--text-tertiary); +} + +.mcp-status.is-connected .mcp-status-dot { + background: var(--success); +} + +.mcp-status.is-connecting .mcp-status-dot { + background: var(--warning); +} + +.mcp-status.is-error .mcp-status-dot { + background: var(--danger); +} + +.mcp-tools-count { + font-size: 12.5px; + color: var(--text-tertiary); + font-variant-numeric: tabular-nums; +} + +.mcp-card-actions { + display: flex; + align-items: center; + gap: 4px; + flex-wrap: wrap; +} + +.mcp-command { + margin: 0; + overflow-wrap: anywhere; +} + +.mcp-enabled { + display: inline-flex; + align-items: center; + gap: 8px; + font-size: 13px; + color: var(--text-secondary); + cursor: pointer; +} + +.mcp-error { + margin: 0; + font-size: 12.5px; + line-height: 1.7; + color: var(--danger); +} + +.mcp-confirm { + display: inline-flex; + align-items: center; + gap: 6px; + font-size: 12.5px; + color: var(--text-secondary); +} + +/* ---------- MCP 工具清单 ---------- */ +.mcp-tools { + border-top: 1px solid var(--border); + padding-top: 10px; +} + +.mcp-tools-toggle { + display: inline-flex; + align-items: center; + gap: 4px; + padding: 4px 6px 4px 0; + border: none; + background: transparent; + color: var(--text-secondary); + font-family: inherit; + font-size: 13px; + cursor: pointer; +} + +.mcp-tools-toggle:hover { + color: var(--text); +} + +.mcp-tool-list { + display: flex; + flex-direction: column; + margin: 8px 0 0; + padding: 0; + list-style: none; +} + +.mcp-tool { + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; + padding: 9px 0; + border-bottom: 1px solid var(--border); +} + +.mcp-tool:last-child { + border-bottom: none; +} + +.mcp-tool-info { + display: flex; + flex-direction: column; + gap: 2px; + min-width: 0; +} + +.mcp-tool-name { + font-family: var(--font-mono); + font-size: 12.5px; + color: var(--text); + overflow-wrap: anywhere; +} + +.mcp-tool-desc { + font-size: 12.5px; + line-height: 1.6; + color: var(--text-secondary); + overflow-wrap: anywhere; +} + +.mcp-tool-toggle { + display: inline-flex; + align-items: center; + gap: 6px; + flex-shrink: 0; + padding: 5px 10px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: var(--bg-sunken); + color: var(--text-secondary); + font-size: 12.5px; + cursor: pointer; + transition: border-color var(--dur) var(--ease), background-color var(--dur) var(--ease); +} + +.mcp-tool-toggle input { + accent-color: var(--accent); +} + +.mcp-tool-toggle.is-on { + border-color: var(--success); + background: var(--bg-elevated); + color: var(--text); +} + +/* ---------- 专家中心 ---------- */ +.experts-tabs { + display: inline-flex; + gap: 4px; + padding: 3px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: var(--bg-sunken); +} + +.experts-tab { + height: 30px; + padding: 0 14px; + border: none; + border-radius: calc(var(--radius-control) - 2px); + background: transparent; + color: var(--text-secondary); + font-family: inherit; + font-size: 13px; + cursor: pointer; + transition: background-color var(--dur) var(--ease); +} + +.experts-tab.is-active { + background: var(--bg-elevated); + color: var(--text); +} + +.experts-actions { + margin-bottom: 16px; +} + +.expert-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); + gap: 16px; + margin: 0; + padding: 0; + list-style: none; +} + +/* hover 统一(描边加深 + 轻上浮)在 App.css;transition 也集中在那里定义 */ +.expert-card { + display: flex; + gap: 14px; + padding: 18px 20px; + border: 1px solid var(--border); + border-radius: var(--radius-card); + background: var(--bg-elevated); +} + +.expert-card.is-active { + border-color: var(--accent); +} + +.expert-card-emoji { + font-size: 30px; + line-height: 1.2; +} + +.expert-card-body { + display: flex; + flex-direction: column; + gap: 6px; + min-width: 0; +} + +.expert-card-name { + display: flex; + align-items: center; + gap: 8px; + margin: 0; + font-family: var(--font-serif); + font-size: 18px; + font-weight: 600; + color: var(--text); +} + +.expert-card-desc { + margin: 0; + font-size: 13px; + line-height: 1.7; + color: var(--text-secondary); +} + +.expert-card-model { + margin: 0; + font-size: 12.5px; + color: var(--text-tertiary); +} + +.expert-card-actions { + display: flex; + align-items: center; + gap: 4px; + flex-wrap: wrap; + margin-top: 4px; +} + +/* 状态徽章:与全站徽章同尺寸同字重 */ +.expert-badge { + padding: 2px 8px; + border-radius: 999px; + background: var(--bg-sunken); + color: var(--text-tertiary); + font-family: var(--font-sans); + font-size: 12px; + font-weight: 500; +} + +.expert-badge.is-custom { + color: var(--text-secondary); +} + +.experts-foot { + margin: 18px 0 0; + font-size: 12.5px; + line-height: 1.7; + color: var(--text-tertiary); +} + +/* ---------- 对话头部的专家选择器 ---------- */ +.chat-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + padding: 10px 24px; + border-bottom: 1px solid var(--border); +} + +.chat-header-title { + margin: 0; + font-family: var(--font-serif); + font-size: 15px; + font-weight: 600; + color: var(--text-secondary); +} + +.expert-picker { + position: relative; +} + +.expert-picker-trigger { + display: inline-flex; + align-items: center; + gap: 7px; + height: 32px; + padding: 0 12px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: transparent; + color: var(--text); + font-family: inherit; + font-size: 13px; + cursor: pointer; + transition: background-color var(--dur) var(--ease); +} + +.expert-picker-trigger:hover { + background: var(--bg-elevated); +} + +.expert-picker-emoji { + font-size: 15px; +} + +.expert-menu { + position: absolute; + top: calc(100% + 6px); + right: 0; + z-index: 20; + width: 300px; + max-height: 360px; + overflow-y: auto; + padding: 10px; + border: 1px solid var(--border); + border-radius: var(--radius-float); + background: var(--bg-elevated); + box-shadow: var(--shadow-float); +} + +.expert-menu-title { + margin: 2px 6px 8px; + font-size: 12px; + color: var(--text-tertiary); +} + +.expert-option { + display: flex; + align-items: flex-start; + gap: 10px; + width: 100%; + padding: 8px 10px; + border: none; + border-radius: var(--radius-control); + background: transparent; + color: var(--text); + font-family: inherit; + text-align: left; + cursor: pointer; + transition: background-color var(--dur) var(--ease); +} + +.expert-option:hover { + background: var(--accent-soft); +} + +.expert-option.is-active { + background: var(--accent-soft); +} + +.expert-option-emoji { + font-size: 18px; + line-height: 1.3; +} + +.expert-option-body { + display: flex; + flex-direction: column; + gap: 2px; + min-width: 0; +} + +.expert-option-name { + display: flex; + align-items: center; + gap: 6px; + font-size: 13.5px; + font-weight: 500; +} + +.expert-option-desc { + font-size: 12px; + line-height: 1.6; + color: var(--text-secondary); +} + +.expert-menu-foot { + display: flex; + align-items: center; + gap: 6px; + margin: 8px 6px 2px; + font-size: 12px; + color: var(--text-tertiary); +} + +@media (prefers-reduced-motion: reduce) { + .mcp-card, + .expert-card, + .expert-menu, + .expert-option, + .btn-ghost, + .mcp-tool-toggle { + transition: none; + } +} diff --git a/css/memory.css b/css/memory.css new file mode 100644 index 0000000000000000000000000000000000000000..88a326bc622ff5a6d22c0ea58c9f7e3536b9e94c --- /dev/null +++ b/css/memory.css @@ -0,0 +1,212 @@ +/* 记忆板块(契约 7A):Warm Paper 全令牌配色,规则来自 docs/design-system.md。 + 覆盖组件:MemoryCenter——卡片墙 + 行内表单;语义色只用于 kind 徽章语境。 */ + +.memory-center { + flex: 1; + min-width: 0; + overflow-y: auto; + padding: 36px 48px 48px; + display: flex; + flex-direction: column; + gap: 18px; +} + +.memory-actions { + margin-bottom: 4px; +} + +/* ---------- 行内表单(新增/编辑)---------- */ +.memory-form { + display: flex; + flex-direction: column; + gap: 14px; + padding: 18px 20px; + border: 1px solid var(--border); + border-radius: var(--radius-card); + background: var(--bg-elevated); +} + +.memory-form-title { + margin: 0; + font-family: var(--font-serif); + font-size: 17px; + font-weight: 600; + color: var(--text); +} + +.memory-form-row { + display: grid; + grid-template-columns: 140px 1fr; + gap: 12px; +} + +.memory-content-input { + resize: vertical; + min-height: 84px; +} + +.memory-form-actions { + display: flex; + align-items: center; + gap: 8px; +} + +/* ---------- 卡片墙 ---------- */ +.memory-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); + gap: 16px; + margin: 0; + padding: 0; + list-style: none; +} + +.memory-card { + display: flex; + flex-direction: column; + gap: 6px; + padding: 16px 18px; + border: 1px solid var(--border); + border-radius: var(--radius-card); + background: var(--bg-elevated); +} + +.memory-card-top { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; +} + +/* kind 徽章:语义色只出现在类型语境;底色统一 sunken,深浅色主题都稳 */ +.memory-badge { + padding: 2px 10px; + border-radius: 999px; + background: var(--bg-sunken); + font-size: 12px; + font-weight: 500; +} + +.memory-badge.is-preference { + color: var(--accent); +} + +.memory-badge.is-project { + color: var(--success); +} + +.memory-badge.is-device { + color: var(--warning); +} + +.memory-badge.is-custom { + color: var(--text-secondary); +} + +.memory-pin { + display: inline-flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; + padding: 0; + border: 1px solid transparent; + border-radius: var(--radius-chip); + background: transparent; + color: var(--text-tertiary); + cursor: pointer; + transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease); +} + +.memory-pin:hover { + color: var(--text-secondary); + border-color: var(--border); +} + +.memory-pin.is-active { + color: var(--accent); +} + +.memory-card-title { + margin: 0; + font-family: var(--font-serif); + font-size: 16.5px; + font-weight: 600; + color: var(--text); + overflow-wrap: anywhere; +} + +.memory-card-content { + margin: 0; + font-size: 13px; + line-height: 1.7; + color: var(--text-secondary); + overflow: hidden; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + line-clamp: 2; + overflow-wrap: anywhere; +} + +.memory-card-actions { + display: flex; + align-items: center; + gap: 4px; + flex-wrap: wrap; + margin-top: 4px; +} + +/* 删除两段确认(与专家板块同款交互) */ +.memory-confirm { + display: inline-flex; + align-items: center; + gap: 8px; + font-size: 12.5px; + color: var(--text-secondary); +} + +/* ---------- 空态引导 ---------- */ +.memory-empty { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 8px; + padding: 32px 24px; + border: 1px dashed var(--border); + border-radius: var(--radius-card); + background: var(--bg-elevated); +} + +.memory-empty-title { + margin: 0; + font-family: var(--font-serif); + font-size: 19px; + font-weight: 600; + color: var(--text); +} + +.memory-empty-hint { + margin: 0 0 6px; + max-width: 56ch; + font-size: 13px; + line-height: 1.7; + color: var(--text-secondary); +} + +.memory-foot { + margin: 0; + font-size: 12.5px; + line-height: 1.7; + color: var(--text-tertiary); +} + +@media (max-width: 720px) { + .memory-center { + padding: 24px 20px 32px; + } + + .memory-form-row { + grid-template-columns: 1fr; + } +} diff --git a/css/msgboard.css b/css/msgboard.css new file mode 100644 index 0000000000000000000000000000000000000000..65ea7385fdec7b80e9f1cfa9fd8922def992e294 --- /dev/null +++ b/css/msgboard.css @@ -0,0 +1,464 @@ +/* 模型留言区(契约 26B · 工作台「留言板」tab)——Warm Paper 令牌,零硬编码色: + 所有颜色走 theme.css 变量(深浅色 / 双皮肤自动跟随)。kind 分色只用 + accent(发现·陶土)/ warning(问题·土金)/ success(回答·苔绿)三个语义令牌; + 动效克制:只用 --dur/--ease 的边框与背景过渡,无位移无闪烁。 */ + +.msgboard { + flex: 1; + min-width: 0; + overflow-y: auto; + padding: 36px 48px 48px; +} + +/* ── 页头 ───────────────────────────────────────────────────────── */ + +.msgboard-head { + display: flex; + align-items: flex-end; + justify-content: space-between; + gap: 16px; + margin-bottom: 20px; +} + +.msgboard-title { + font-family: var(--font-serif); + font-size: 26px; + font-weight: 600; + letter-spacing: -0.01em; + color: var(--text); + margin: 0; +} + +.msgboard-sub { + margin: 6px 0 0; + font-size: 13.5px; + line-height: 1.65; + color: var(--text-secondary); + max-width: 68ch; +} + +.msgboard-sub strong { + color: var(--text); + font-weight: 600; +} + +.msgboard-muted { + font-size: 13px; + line-height: 1.6; + color: var(--text-secondary); +} + +.msgboard-notice { + margin: 0 0 16px; + padding: 10px 14px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: var(--bg-elevated); + font-size: 13.5px; + line-height: 1.6; + color: var(--text); +} + +/* ── 按钮 ───────────────────────────────────────────────────────── */ + +.msgboard-primary, +.msgboard-secondary, +.msgboard-ghost { + display: inline-flex; + align-items: center; + gap: 7px; + font-family: var(--font-sans); + font-size: 13.5px; + font-weight: 550; + border-radius: var(--radius-control); + padding: 9px 16px; + cursor: pointer; + transition: + background var(--dur) var(--ease), + border-color var(--dur) var(--ease), + color var(--dur) var(--ease); +} + +.msgboard-primary { + color: var(--bg); + background: var(--accent); + border: 1px solid var(--accent); +} + +.msgboard-primary:hover:not(:disabled) { + background: var(--accent-hover, var(--accent)); + border-color: var(--accent-hover, var(--accent)); +} + +.msgboard-secondary { + color: var(--text); + background: var(--bg-elevated); + border: 1px solid var(--border); +} + +.msgboard-secondary:hover:not(:disabled) { + border-color: var(--accent); + color: var(--accent); +} + +.msgboard-ghost { + color: var(--text-secondary); + background: transparent; + border: 1px solid transparent; + padding: 7px 10px; + flex-shrink: 0; +} + +.msgboard-ghost:hover:not(:disabled) { + color: var(--text); + border-color: var(--border); + background: var(--bg-elevated); +} + +.msgboard-primary:disabled, +.msgboard-secondary:disabled, +.msgboard-ghost:disabled { + opacity: 0.45; + cursor: default; +} + +/* ── 工具条 ─────────────────────────────────────────────────────── */ + +.msgboard-toolbar { + background: var(--bg-elevated); + border: 1px solid var(--border); + border-radius: var(--radius-card); + padding: 18px 22px; + margin-bottom: 20px; +} + +.msgboard-toolbar-main { + display: flex; + gap: 10px; + flex-wrap: wrap; +} + +.msgboard-toolbar-hint { + margin: 12px 0 0; + font-size: 12.5px; + color: var(--text-secondary); + font-variant-numeric: tabular-nums; +} + +.msgboard-outcome { + margin: 8px 0 0; + padding: 8px 12px; + border-left: 2px solid var(--accent); + font-size: 12.5px; + line-height: 1.6; + color: var(--text-secondary); + font-variant-numeric: tabular-nums; +} + +/* ── 贴条区 ─────────────────────────────────────────────────────── */ + +.msgboard-composer { + background: var(--bg-elevated); + border: 1px solid var(--border); + border-radius: var(--radius-card); + padding: 18px 22px 20px; + margin-bottom: 24px; +} + +.msgboard-kind-row { + display: flex; + gap: 8px; + margin-bottom: 14px; +} + +.msgboard-kind { + display: inline-flex; + align-items: center; + gap: 6px; + font-family: var(--font-sans); + font-size: 12.5px; + font-weight: 550; + padding: 6px 12px; + border-radius: var(--radius-chip); + border: 1px solid var(--border); + background: var(--bg-sunken); + color: var(--text-secondary); + cursor: pointer; + transition: + border-color var(--dur) var(--ease), + color var(--dur) var(--ease), + background var(--dur) var(--ease); +} + +/* kind 三态分色:未选中只留图标色,选中加 accent 描边 + 字色 */ +.msgboard-kind.is-finding svg { + color: var(--accent); +} +.msgboard-kind.is-question svg { + color: var(--warning); +} +.msgboard-kind.is-answer svg { + color: var(--success); +} + +.msgboard-kind.is-on { + background: var(--bg-elevated); + color: var(--text); +} +.msgboard-kind.is-finding.is-on { + border-color: var(--accent); +} +.msgboard-kind.is-question.is-on { + border-color: var(--warning); +} +.msgboard-kind.is-answer.is-on { + border-color: var(--success); +} + +.msgboard-composer-row { + display: flex; + gap: 10px; + align-items: flex-start; +} + +.msgboard-author { + flex: 0 0 140px; + font-family: var(--font-sans); + font-size: 13px; + color: var(--text); + background: var(--bg-sunken); + border: 1px solid transparent; + border-radius: var(--radius-control); + padding: 10px 12px; + transition: border-color var(--dur) var(--ease); +} + +.msgboard-author:focus-visible { + outline: none; + border-color: var(--accent); +} + +.msgboard-input { + flex: 1; + min-width: 0; + font-family: var(--font-sans); + font-size: 14px; + line-height: 1.65; + color: var(--text); + background: var(--bg-sunken); + border: 1px solid transparent; + border-radius: var(--radius-control); + padding: 10px 12px; + resize: vertical; + min-height: 72px; + transition: border-color var(--dur) var(--ease); +} + +.msgboard-input::placeholder { + color: var(--text-tertiary); +} + +.msgboard-input:focus-visible { + outline: none; + border-color: var(--accent); +} + +.msgboard-answer-target { + display: flex; + align-items: center; + gap: 8px; + margin-top: 12px; + font-size: 13px; + color: var(--text-secondary); +} + +.msgboard-answer-target select { + flex: 1; + min-width: 0; + font-family: var(--font-sans); + font-size: 13px; + color: var(--text); + background: var(--bg-sunken); + border: 1px solid var(--border); + border-radius: var(--radius-control); + padding: 8px 10px; +} + +.msgboard-answer-target select:focus-visible { + outline: none; + border-color: var(--accent); +} + +.msgboard-composer-actions { + display: flex; + align-items: center; + gap: 12px; + margin-top: 14px; +} + +/* ── 留言流 ─────────────────────────────────────────────────────── */ + +.msgboard-stream { + display: flex; + flex-direction: column; + gap: 14px; +} + +.msgboard-empty { + padding: 28px 22px; + border: 1px dashed var(--border); + border-radius: var(--radius-card); + font-size: 13.5px; + line-height: 1.7; + color: var(--text-secondary); + text-align: center; +} + +.msgboard-card { + background: var(--bg-elevated); + border: 1px solid var(--border); + border-left: 3px solid var(--border); + border-radius: var(--radius-card); + padding: 14px 18px 16px; + transition: border-color var(--dur) var(--ease); +} + +/* kind 分色:只染左侧竖条(克制,不整卡染色) */ +.msgboard-card.is-finding { + border-left-color: var(--accent); +} +.msgboard-card.is-question { + border-left-color: var(--warning); +} +.msgboard-card.is-answer { + border-left-color: var(--success); +} + +.msgboard-card-head { + display: flex; + align-items: center; + gap: 8px; + margin-bottom: 8px; +} + +.msgboard-badge { + display: inline-flex; + align-items: center; + gap: 4px; + font-size: 11.5px; + font-weight: 600; + padding: 2px 8px; + border-radius: var(--radius-chip); + border: 1px solid var(--border); + color: var(--text-secondary); +} + +.msgboard-badge.is-finding { + color: var(--accent); + border-color: var(--accent-soft); + background: var(--accent-soft); +} +.msgboard-badge.is-question { + color: var(--warning); +} +.msgboard-badge.is-answer { + color: var(--success); +} + +.msgboard-author-name { + font-size: 13px; + font-weight: 600; + color: var(--text); +} + +.msgboard-time { + font-size: 12px; + color: var(--text-tertiary); + font-variant-numeric: tabular-nums; +} + +.msgboard-synced { + font-size: 11px; + padding: 1px 7px; + border-radius: var(--radius-chip); + background: var(--bg-sunken); + color: var(--text-tertiary); +} + +.msgboard-remove { + margin-left: auto; + display: inline-flex; + align-items: center; + gap: 5px; + font-family: var(--font-sans); + font-size: 12px; + color: var(--text-tertiary); + background: transparent; + border: 1px solid transparent; + border-radius: var(--radius-chip); + padding: 4px 8px; + cursor: pointer; + transition: + color var(--dur) var(--ease), + border-color var(--dur) var(--ease); +} + +.msgboard-remove:hover { + color: var(--danger); + border-color: var(--danger); +} + +.msgboard-remove.is-armed { + color: var(--danger); + border-color: var(--danger); +} + +.msgboard-card-body { + font-size: 14px; + line-height: 1.7; + color: var(--text); + white-space: pre-wrap; + word-break: break-word; +} + +/* ── 回答(缩进挂在被答问题下) ──────────────────────────────────── */ + +.msgboard-answers { + margin-top: 12px; + padding-left: 18px; + border-left: 2px solid var(--border); + display: flex; + flex-direction: column; + gap: 10px; +} + +.msgboard-answer { + background: var(--bg-sunken); + border: 1px solid transparent; + border-left: 3px solid var(--success); + border-radius: var(--radius-control); + padding: 10px 14px 12px; +} + +.msgboard-waiting { + font-size: 12.5px; + color: var(--text-tertiary); + font-style: italic; +} + +/* ── 窄屏(沿用 hub 既有滚动容器,这里只收紧内边距) ─────────────── */ + +@media (max-width: 900px) { + .msgboard { + padding: 24px 20px 32px; + } + + .msgboard-composer-row { + flex-direction: column; + } + + .msgboard-author { + flex: none; + width: 100%; + } +} diff --git a/css/onboarding.css b/css/onboarding.css new file mode 100644 index 0000000000000000000000000000000000000000..accca9e3addb818b20fb7fe7a365843e54683428 --- /dev/null +++ b/css/onboarding.css @@ -0,0 +1,391 @@ +/* 首次引导(契约 7C)——Warm Paper 全屏向导:衬线大标题 + 圆点进度 + 大量留白 */ + +.ob-overlay { + position: fixed; + inset: 0; + z-index: 80; + display: flex; + align-items: center; + justify-content: center; + padding: 48px 24px; + background: var(--bg); + animation: ob-fade 200ms var(--ease); +} + +@keyframes ob-fade { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +@keyframes ob-rise { + from { + opacity: 0; + transform: translateY(6px); + } + to { + opacity: 1; + transform: none; + } +} + +@keyframes ob-rotate { + to { + transform: rotate(360deg); + } +} + +/* 右上角「跳过引导」:文字按钮,安静但一直在 */ +.ob-skip { + position: absolute; + top: 18px; + right: 22px; + height: 30px; + padding: 0 12px; + border: none; + border-radius: var(--radius-chip); + background: transparent; + color: var(--text-tertiary); + font-family: inherit; + font-size: 12.5px; + cursor: pointer; + transition: + background-color var(--dur) var(--ease), + color var(--dur) var(--ease); +} + +.ob-skip:hover { + background: var(--bg-elevated); + color: var(--text); +} + +.ob-card { + width: min(620px, 100%); + max-height: 100%; + overflow-y: auto; + padding: 44px 48px 40px; + border: 1px solid var(--border); + border-radius: var(--radius-float); + background: var(--bg); + box-shadow: var(--shadow-float); + animation: ob-rise 220ms var(--ease); +} + +.ob-brand { + display: flex; + align-items: center; + gap: 8px; + margin-bottom: 26px; + color: var(--text-secondary); + font-size: 13px; + letter-spacing: 0.01em; +} + +/* ── 圆点进度:做完的实心浅陶土,当前的深陶土,未到的描边 ───────── */ + +.ob-dots { + display: flex; + gap: 8px; + margin-bottom: 24px; +} + +.ob-dot { + width: 7px; + height: 7px; + border-radius: 50%; + background: transparent; + border: 1px solid var(--border); + transition: + background-color var(--dur) var(--ease), + border-color var(--dur) var(--ease); +} + +.ob-dot.is-done { + background: var(--accent-soft); + border-color: var(--accent-soft); +} + +.ob-dot.is-active { + background: var(--accent); + border-color: var(--accent); +} + +/* ── 标题与正文三级字阶 ───────────────────────────────────────── */ + +.ob-title { + margin: 0 0 10px; + font-family: var(--font-serif); + font-size: 27px; + font-weight: 600; + letter-spacing: -0.01em; + line-height: 1.35; +} + +.ob-sub { + margin: 0 0 28px; + color: var(--text-secondary); + font-size: 14.5px; + line-height: 1.7; +} + +.ob-lede { + margin: 0 0 4px; + color: var(--text); + font-size: 14.5px; + line-height: 1.75; +} + +.ob-lede a { + color: var(--accent); + cursor: pointer; + text-decoration: underline; + text-underline-offset: 3px; +} + +.ob-hint { + margin: 10px 0 0; + color: var(--text-tertiary); + font-size: 12.5px; + line-height: 1.65; +} + +.ob-loading { + display: flex; + align-items: center; + gap: 10px; + margin: 0; + color: var(--text-secondary); + font-size: 14px; +} + +.ob-spin { + color: var(--accent); + animation: ob-rotate 900ms linear infinite; +} + +/* ── 第一步:已就绪 + 模型清单 ────────────────────────────────── */ + +.ob-ready { + display: flex; + align-items: center; + gap: 8px; + margin: 0 0 16px; + color: var(--success); + font-size: 14px; + font-weight: 500; +} + +.ob-models { + list-style: none; + margin: 0 0 8px; + padding: 0; + border: 1px solid var(--border); + border-radius: var(--radius-card); + background: var(--bg-elevated); + overflow: hidden; +} + +.ob-models li { + display: flex; + align-items: baseline; + justify-content: space-between; + gap: 16px; + padding: 11px 18px; +} + +.ob-models li + li { + border-top: 1px solid var(--border); +} + +.ob-model-name { + font-family: var(--font-mono); + font-size: 13px; + color: var(--text); +} + +.ob-model-meta { + color: var(--text-tertiary); + font-size: 12.5px; + font-variant-numeric: tabular-nums; + white-space: nowrap; +} + +/* ── 第二步:两个大选择 ───────────────────────────────────────── */ + +.ob-choices { + display: flex; + flex-direction: column; + gap: 12px; +} + +.ob-choice { + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; + width: 100%; + padding: 18px 20px; + border: 1px solid var(--border); + border-radius: var(--radius-card); + background: var(--bg-elevated); + color: var(--text); + font-family: inherit; + text-align: left; + cursor: pointer; + transition: + border-color var(--dur) var(--ease), + background-color var(--dur) var(--ease), + transform var(--dur) var(--ease); +} + +.ob-choice:hover { + border-color: var(--accent); + background: var(--accent-soft); + transform: translateY(-1px); +} + +.ob-choice-text { + display: flex; + flex-direction: column; + gap: 4px; +} + +.ob-choice-title { + font-family: var(--font-serif); + font-size: 16px; + font-weight: 600; +} + +.ob-choice-desc { + color: var(--text-secondary); + font-size: 13px; + line-height: 1.6; +} + +.ob-choice svg { + flex: none; + color: var(--text-tertiary); +} + +/* ── 第三步:模型下拉 + 输入 + 回显 ───────────────────────────── */ + +.ob-field { + display: flex; + flex-direction: column; + gap: 6px; + margin-bottom: 14px; +} + +.ob-field > span { + color: var(--text-tertiary); + font-size: 12.5px; +} + +.ob-select { + height: 38px; + padding: 0 12px; + border: none; + border-radius: var(--radius-control); + background: var(--bg-sunken); + color: var(--text); + font-family: inherit; + font-size: 13.5px; + cursor: pointer; + transition: box-shadow var(--dur) var(--ease); +} + +.ob-select:focus { + outline: none; + box-shadow: 0 0 0 1px var(--accent); +} + +.ob-textarea { + width: 100%; + padding: 12px 14px; + border: none; + border-radius: var(--radius-control); + background: var(--bg-sunken); + color: var(--text); + font-family: inherit; + font-size: 14.5px; + line-height: 1.7; + resize: none; + user-select: text; + cursor: text; + transition: box-shadow var(--dur) var(--ease); +} + +.ob-textarea:focus { + outline: none; + box-shadow: 0 0 0 1px var(--accent); +} + +.ob-transcript { + display: flex; + flex-direction: column; + gap: 10px; + margin-top: 20px; +} + +.ob-bubble { + margin: 0; + padding: 12px 16px; + border-radius: var(--radius-card); + font-size: 14px; + line-height: 1.7; + white-space: pre-wrap; + word-break: break-word; + user-select: text; + animation: ob-rise 200ms var(--ease); +} + +.ob-bubble.is-user { + align-self: flex-end; + max-width: 85%; + background: var(--accent-soft); +} + +.ob-bubble.is-assistant { + align-self: flex-start; + max-width: 92%; + background: var(--bg-elevated); + border: 1px solid var(--border); +} + +/* ── 完成页与公共动作行 ───────────────────────────────────────── */ + +.ob-done { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 4px; + color: var(--accent); +} + +.ob-done .ob-title { + margin-top: 14px; + color: var(--text); +} + +.ob-actions { + display: flex; + align-items: center; + gap: 12px; + margin-top: 28px; + flex-wrap: wrap; +} + +.ob-actions .btn-primary { + display: inline-flex; + align-items: center; + gap: 8px; +} + +.ob-actions .btn-secondary { + display: inline-flex; + align-items: center; + gap: 7px; +} diff --git a/css/overlay.css b/css/overlay.css new file mode 100644 index 0000000000000000000000000000000000000000..d8d3c4ce3ddd6df17b881eefce027dac79bea06b --- /dev/null +++ b/css/overlay.css @@ -0,0 +1,346 @@ +/* 划词浮层:Warm Paper 毛玻璃卡片(颜色一律走 theme.css 令牌)。 + 注意:透明原生窗口上 WebKit 的 backdrop-filter 会把元素整个画没(坑位实测记录 #1), + 所以模糊交给 macOS 窗口特效,CSS 只保留 85% 暖纸半透明底色。 */ + +/* 透明窗口本体:桌面要从圆角外透出来 */ +body.overlay-surface { + background: transparent; +} + +.overlay-root { + height: 100%; + display: flex; + padding: 12px; + box-sizing: border-box; +} + +/* ---------- 卡片容器 ---------- */ +.overlay-card { + flex: 1; + min-height: 0; + display: flex; + flex-direction: column; + overflow: hidden; + border: 1px solid var(--border); + border-radius: var(--radius-float); + background: var(--glass); + box-shadow: var(--shadow-float); + animation: overlay-in 180ms var(--ease); +} + +@keyframes overlay-in { + from { + opacity: 0; + transform: translateY(6px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +/* ---------- 顶栏 ---------- */ +.overlay-head { + display: flex; + align-items: baseline; + justify-content: space-between; + gap: 12px; + padding: 16px 20px 8px; +} + +.overlay-title { + margin: 0; + font-family: var(--font-serif); + font-size: 20px; + font-weight: 600; + letter-spacing: -0.01em; + color: var(--text); +} + +.overlay-esc { + font-size: 12px; + color: var(--text-tertiary); + white-space: nowrap; +} + +/* ---------- 空态 / 提示 ---------- */ +.overlay-note { + margin: 0; + padding: 12px 20px 20px; + font-size: 13.5px; + line-height: 1.6; + color: var(--text-secondary); +} + +.overlay-note.is-warn { + color: var(--warning); +} + +/* ---------- 选中文字预览 ---------- */ +.overlay-quote { + margin: 4px 20px 0; + padding: 10px 14px; + max-height: 120px; + overflow-y: auto; + border-left: 2px solid var(--accent-soft); + border-radius: 0 var(--radius-control) var(--radius-control) 0; + background: var(--bg-sunken); + color: var(--text); + font-size: 13.5px; + line-height: 1.6; + user-select: text; + white-space: pre-wrap; + word-break: break-word; +} + +/* ---------- 动作 chips ---------- */ +.overlay-chips { + display: flex; + flex-wrap: wrap; + gap: 8px; + padding: 12px 20px 4px; +} + +.overlay-chip { + height: 30px; + padding: 0 14px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: transparent; + color: var(--text-secondary); + font-family: inherit; + font-size: 13px; + cursor: pointer; + transition: + background-color var(--dur) var(--ease), + border-color var(--dur) var(--ease); +} + +.overlay-chip:hover:not(:disabled) { + background: var(--accent-soft); + border-color: var(--accent-soft); + color: var(--text); +} + +.overlay-chip:disabled { + opacity: 0.5; + cursor: default; +} + +/* ---------- 自定义输入 ---------- */ +.overlay-custom { + display: flex; + align-items: center; + gap: 8px; + margin: 8px 20px 0; + padding: 6px 6px 6px 12px; + border: 1px solid transparent; + border-radius: var(--radius-control); + background: var(--bg-sunken); + transition: border-color var(--dur) var(--ease); +} + +.overlay-custom:focus-within { + border-color: var(--accent); +} + +.overlay-input { + flex: 1; + min-width: 0; + border: none; + background: transparent; + color: var(--text); + font-family: inherit; + font-size: 13.5px; + outline: none; + cursor: text; +} + +.overlay-input::placeholder { + color: var(--text-tertiary); +} + +.overlay-send { + flex-shrink: 0; + height: 28px; + padding: 0 12px; + border: none; + border-radius: var(--radius-chip); + background: var(--accent); + color: var(--bg); + font-family: inherit; + font-size: 13px; + cursor: pointer; + transition: opacity var(--dur) var(--ease); +} + +.overlay-send:disabled { + opacity: 0.4; + cursor: default; +} + +/* ---------- 回答区 ---------- */ +.overlay-answer { + flex: 1; + min-height: 0; + display: flex; + flex-direction: column; + margin-top: 12px; + padding: 12px 20px 16px; + border-top: 1px solid var(--border); +} + +.overlay-answer-body { + flex: 1; + min-height: 0; + overflow-y: auto; +} + +.overlay-answer-text { + margin: 0; + color: var(--text); + font-size: 13.5px; + line-height: 1.65; + white-space: pre-wrap; + word-break: break-word; + user-select: text; +} + +/* 流式呼吸光标(1s 透明度呼吸;reduced-motion 时 theme.css 全局降级为静止) */ +.overlay-cursor { + display: inline-block; + width: 2px; + height: 1.05em; + margin-left: 3px; + border-radius: 1px; + background: var(--accent); + vertical-align: text-bottom; + animation: overlay-cursor-breathe 1s ease-in-out infinite; +} + +@keyframes overlay-cursor-breathe { + 0%, + 100% { + opacity: 1; + } + 50% { + opacity: 0.15; + } +} + +.overlay-error { + margin: 8px 0 0; + color: var(--danger); + font-size: 12.5px; +} + +.overlay-answer-foot { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + margin-top: 12px; +} + +.overlay-copy { + display: inline-flex; + align-items: center; + gap: 6px; + height: 30px; + padding: 0 12px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: transparent; + color: var(--text-secondary); + font-family: inherit; + font-size: 12.5px; + cursor: pointer; + transition: background-color var(--dur) var(--ease); +} + +.overlay-copy:hover:not(:disabled) { + background: var(--bg-elevated); + color: var(--text); +} + +.overlay-copy:disabled { + opacity: 0.5; + cursor: default; +} + +.overlay-foot-hint { + font-size: 12px; + color: var(--text-tertiary); +} + +/* ---------- 授权引导态 ---------- */ +.overlay-guide { + flex: 1; + display: flex; + flex-direction: column; + padding: 24px 24px 20px; +} + +.overlay-guide-head { + display: flex; + align-items: center; + gap: 10px; + color: var(--accent); +} + +.overlay-guide .overlay-title { + font-size: 22px; +} + +.overlay-lead { + margin: 12px 0 20px; + color: var(--text-secondary); + font-size: 14px; + line-height: 1.65; +} + +.overlay-primary { + align-self: flex-start; + height: 40px; + padding: 0 20px; + border: none; + border-radius: var(--radius-control); + background: var(--accent); + color: var(--bg); + font-family: inherit; + font-size: 14px; + cursor: pointer; +} + +.overlay-primary:hover { + filter: brightness(0.94); +} + +.overlay-why-toggle { + align-self: flex-start; + margin-top: 18px; + padding: 0; + border: none; + background: transparent; + color: var(--text-secondary); + font-family: inherit; + font-size: 13px; + text-decoration: underline; + text-underline-offset: 3px; + cursor: pointer; +} + +.overlay-why-body { + margin: 10px 0 0; + color: var(--text-tertiary); + font-size: 12.5px; + line-height: 1.7; +} + +.overlay-guide-hint { + margin-top: auto; + padding-top: 20px; + color: var(--text-tertiary); + font-size: 12.5px; + line-height: 1.6; +} diff --git a/css/palette.css b/css/palette.css new file mode 100644 index 0000000000000000000000000000000000000000..f927a508cab1d5ba15518af8aa9b5326300208b9 --- /dev/null +++ b/css/palette.css @@ -0,0 +1,323 @@ +/* ⌘K 统一浮窗(契约 19A-A1):大输入框 + 模式 chips + 结果区。 + Warm Paper 浮窗样式,颜色一律走 theme.css 令牌。 + 注意(design-system §7 + 坑位记录):透明窗口上 WebKit 的 backdrop-filter + 会把元素整个画没,所以**不写 backdrop-filter**,直接用 85% 暖纸半透明底(--glass)。 */ + +/* ---------- 容器 ---------- */ +body.palette-surface { + background: transparent; +} + +.palette-overlay { + height: 100%; + display: flex; + padding: 12px; + box-sizing: border-box; +} + +.palette-card { + display: flex; + flex-direction: column; + flex: 1; + min-height: 0; + border: 1px solid var(--border); + border-radius: var(--radius-float); + background: var(--glass); + box-shadow: var(--shadow-float); + overflow: hidden; + animation: palette-in 180ms var(--ease); +} + +@keyframes palette-in { + from { + opacity: 0; + transform: translateY(6px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +/* ---------- 输入区 ---------- */ +.palette-search { + display: flex; + align-items: center; + gap: 12px; + margin: 14px 14px 8px; + padding: 10px 16px; + border: 1px solid transparent; + border-radius: var(--radius-card); + background: var(--bg-sunken); + transition: border-color var(--dur) var(--ease); +} + +.palette-search:focus-within { + border-color: var(--accent); +} + +.palette-search-icon { + flex-shrink: 0; + color: var(--text-tertiary); +} + +.palette-input { + flex: 1; + min-width: 0; + border: none; + background: transparent; + color: var(--text); + font-family: var(--font-serif); + font-size: 24px; + line-height: 1.4; + letter-spacing: -0.01em; + outline: none; + cursor: text; +} + +.palette-input::placeholder { + color: var(--text-tertiary); +} + +.palette-kbd { + flex-shrink: 0; + font-size: 12px; + color: var(--text-tertiary); + white-space: nowrap; +} + +/* ---------- 模式 chips ---------- */ +.palette-chips { + display: flex; + gap: 6px; + padding: 0 14px 8px; +} + +.palette-chip { + display: inline-flex; + align-items: baseline; + gap: 6px; + height: 28px; + padding: 0 10px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: transparent; + color: var(--text-secondary); + font-family: inherit; + font-size: 12.5px; + cursor: pointer; + transition: + background-color var(--dur) var(--ease), + border-color var(--dur) var(--ease); +} + +.palette-chip:hover { + background: var(--bg-elevated); + color: var(--text); +} + +.palette-chip.is-active { + border-color: var(--accent-soft); + background: var(--accent-soft); + color: var(--text); +} + +.palette-chip-slash { + font-family: var(--font-mono); + font-size: 11px; + color: var(--text-tertiary); +} + +/* ---------- 结果区 ---------- */ +.palette-body { + flex: 1; + min-height: 0; + overflow-y: auto; + padding: 2px 8px 8px; +} + +.palette-list { + margin: 0; + padding: 0; + list-style: none; +} + +.palette-item { + display: flex; + align-items: baseline; + gap: 16px; + width: 100%; + padding: 9px 14px; + border: none; + border-radius: var(--radius-control); + background: transparent; + color: var(--text); + font-family: inherit; + font-size: 14.5px; + text-align: left; + cursor: pointer; + transition: background-color var(--dur) var(--ease); +} + +.palette-item:hover { + background: color-mix(in srgb, var(--accent-soft) 40%, transparent); +} + +.palette-item.is-selected { + background: var(--accent-soft); +} + +.palette-item-name { + flex: 1; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.palette-item-name mark { + background: transparent; + color: var(--accent); + font-weight: 600; +} + +.palette-item-meta { + flex-shrink: 0; + display: flex; + gap: 12px; + font-size: 12.5px; + color: var(--text-tertiary); + font-variant-numeric: tabular-nums; +} + +/* ---------- 空态 / 状态行 ---------- */ +.palette-empty { + padding: 18px 14px; +} + +.palette-empty-title { + margin: 0 0 6px; + font-family: var(--font-serif); + font-size: 19px; + color: var(--text); +} + +.palette-empty-note { + margin: 0; + font-size: 13.5px; + color: var(--text-secondary); +} + +.palette-note { + margin: 0; + padding: 14px; + font-size: 13.5px; + color: var(--text-secondary); +} + +.palette-note.is-error { + color: var(--danger); +} + +.palette-task { + margin: 6px 6px 0; + padding: 12px 14px; + font-family: var(--font-serif); + font-size: 17px; + line-height: 1.6; + color: var(--text); +} + +.palette-error { + margin: 8px 8px 0; + color: var(--danger); + font-size: 12.5px; +} + +/* ---------- 闲时提示 ---------- */ +.palette-hints { + padding: 12px 14px; + display: flex; + flex-direction: column; + gap: 6px; +} + +.palette-hint-line { + margin: 0; + font-size: 13px; + color: var(--text-secondary); +} + +.palette-hint-line.is-quiet { + color: var(--text-tertiary); +} + +.palette-hint-line kbd, +.palette-foot kbd { + padding: 1px 5px; + border: 1px solid var(--border); + border-radius: var(--radius-chip); + background: var(--bg-sunken); + font-family: var(--font-mono); + font-size: 11.5px; + color: var(--text); +} + +/* ---------- 回答(复用 Markdown;呼吸光标同划词浮层) ---------- */ +.palette-answer { + margin: 4px 6px 0; +} + +.palette-answer-body { + max-height: 320px; + overflow-y: auto; + font-size: 14.5px; + line-height: 1.7; + color: var(--text); +} + +.palette-answer-body > :first-child { + margin-top: 0; +} + +.palette-cursor { + display: inline-block; + width: 2px; + height: 1.05em; + margin-left: 3px; + border-radius: 1px; + background: var(--accent); + vertical-align: text-bottom; + animation: palette-cursor-breathe 1s ease-in-out infinite; +} + +@keyframes palette-cursor-breathe { + 0%, + 100% { + opacity: 1; + } + 50% { + opacity: 0.15; + } +} + +/* ---------- 底栏 ---------- */ +.palette-foot { + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; + padding: 9px 18px 12px; + border-top: 1px solid var(--border); + font-size: 12.5px; + color: var(--text-tertiary); +} + +.palette-hint { + color: var(--text-tertiary); +} + +.palette-hint.is-quiet { + color: var(--text-tertiary); + opacity: 0.85; +} diff --git a/css/perch-home.css b/css/perch-home.css new file mode 100644 index 0000000000000000000000000000000000000000..a057fe45f288c424caa2560e7df52b0ecf02d4f5 --- /dev/null +++ b/css/perch-home.css @@ -0,0 +1,105 @@ +/* Gravity Core shares the product's theme tokens; no new appearance preference. */ +.perch-home { --home-metal: var(--accent); padding: 0 0 24px; color: var(--text); } +[data-style="darkside"] .perch-home { --home-metal: #d5b580; } +[data-style="darkside"][data-theme="light"] .perch-home { --home-metal: #866330; } +.home-pagebar { display:flex; align-items:center; justify-content:space-between; gap:16px; color:var(--text-secondary); font-size:11px; } +.home-layout-label { display:flex; align-items:center; gap:7px; flex:none; color:var(--home-metal); font-size:10px; } +.home-layout-label::before { content:""; width:5px; height:5px; border-radius:50%; background:var(--home-metal); } +.home-cover { display:grid; grid-template-columns:1fr 1fr; align-items:center; min-height:284px; position:relative; isolation:isolate; } +.home-cover-copy { position:relative; z-index:1; pointer-events:none; } +.home-eyebrow { margin:0 0 15px; color:var(--home-metal); font:10px/1.7 var(--font-mono); letter-spacing:2px; } +.home-cover h2 { margin:0; font:500 clamp(28px,3.4vw,45px)/1.28 var(--font-sans); letter-spacing:-1px; } +.home-cover h2 em { color:var(--home-metal); font-style:normal; } +.home-description { margin:15px 0 0; color:var(--text-secondary); font-size:12px; line-height:1.9; } +.home-core-art { position:relative; min-width:0; height:290px; margin:0 0 0 -26px; overflow:clip; touch-action:pan-y; color:var(--home-metal); } +.home-core-art canvas { display:block; width:100%; height:100%; pointer-events:none; } +.home-core-caption { position:absolute; bottom:17px; right:14px; color:var(--text-secondary); font:9px var(--font-mono); letter-spacing:1px; pointer-events:none; } +.home-core-caption::before { content:""; display:inline-block; width:20px; height:1px; vertical-align:middle; margin-right:7px; background:var(--home-metal); } +.home-core-coordinates { position:absolute; bottom:14px; left:0; color:var(--text-secondary); font:9px/1.9 var(--font-mono); pointer-events:none; } +.home-goal-editor { background:var(--bg-elevated); border:1px solid color-mix(in srgb,var(--home-metal) 24%,var(--border)); border-radius:12px; overflow:hidden; box-shadow:0 12px 30px color-mix(in srgb,var(--bg-sunken) 38%,transparent); } +.home-goal-editor:focus-within { border-color:var(--home-metal); } +.home-goal-editor textarea { display:block; resize:vertical; width:100%; min-height:72px; max-height:340px; padding:18px 18px 8px; background:transparent; border:0; color:var(--text); font:13px/1.8 var(--font-sans); user-select:text; } +.home-goal-editor textarea::placeholder { color:var(--text-secondary); opacity:1; } +.home-goal-editor textarea:focus-visible { outline:none; } +.home-composer-foot { display:flex; align-items:center; justify-content:space-between; gap:12px; padding:9px 11px 11px; } +.home-work-modes { display:flex; flex-wrap:wrap; gap:2px; min-width:0; } +.home-work-modes button { display:flex; align-items:center; justify-content:center; gap:6px; min-height:31px; padding:7px 9px; border:1px solid transparent; border-radius:6px; background:transparent; color:var(--text-secondary); font:11px var(--font-sans); cursor:pointer; } +.home-work-modes button[aria-pressed="true"] { background:color-mix(in srgb,var(--text) 5%,var(--bg-elevated)); border-color:var(--border); color:var(--text); } +.home-work-modes button:hover { background:color-mix(in srgb,var(--text) 6%,var(--bg-elevated)); color:var(--text); } +.home-start { display:flex; align-items:center; justify-content:center; gap:9px; min-height:34px; padding:7px 12px; border:1px solid color-mix(in srgb,var(--home-metal) 86%,var(--text)); border-radius:7px; background:var(--home-metal); color:#1c1a15; font:500 11px var(--font-sans); white-space:nowrap; cursor:pointer; } +[data-style="darkside"] .home-start { color:#1c1a15; } +[data-style="darkside"][data-theme="light"] .home-start { color:#fffdf8; } +.home-start kbd { color:inherit; background:none; border:0; padding:0; font:10px var(--font-mono); opacity:.7; } +.home-start:hover { filter:brightness(1.07); } +.home-goal-help { display:flex; align-items:flex-start; gap:6px; margin-top:10px; color:var(--text-secondary); font-size:10px; line-height:1.7; overflow-wrap:anywhere; } +.home-goal-help svg { flex:none; margin-top:2px; } +.home-goal-error { color:var(--danger); border-left:2px solid var(--danger); margin:13px 0 0; padding:4px 10px; font-size:12px; line-height:1.8; } +.home-sr-only { position:absolute; width:1px; height:1px; overflow:hidden; clip-path:inset(50%); white-space:nowrap; } +.home-command-grid { display:grid; grid-template-columns:minmax(0,.94fr) minmax(0,1fr); gap:26px; align-items:center; margin-top:23px; } +.home-command-core { min-width:0; } +.home-core-top { display:flex; align-items:center; justify-content:space-between; color:var(--text-secondary); font:9px var(--font-mono); letter-spacing:1px; } +.is-professional .home-core-art { margin:0; height:286px; } +.is-professional .home-pagebar,.is-professional .home-layout-label { font-family:var(--font-mono); font-size:10px; letter-spacing:.6px; } +.home-mission { min-width:0; } +.home-mission .home-eyebrow { color:var(--text-secondary); margin-bottom:10px; } +.home-mission h2 { margin:0; font:500 26px/1.4 var(--font-sans); letter-spacing:-.7px; } +.home-mission .home-description { margin-top:8px; font-size:11px; } +.home-mission .home-goal-editor { margin-top:17px; border-color:var(--border); border-radius:6px; box-shadow:none; } +.home-editor-head { display:flex; align-items:center; gap:7px; padding:8px 12px; border-bottom:1px solid var(--border); color:var(--text-secondary); font:10px var(--font-mono); } +.home-editor-head>span:last-child { margin-left:auto; color:var(--home-metal); } +.home-mission textarea { min-height:148px; padding:12px; font:11px/1.9 var(--font-mono); } +.home-mission .home-composer-foot { padding:7px 9px; border-top:1px solid var(--border); } +.home-mission .home-work-modes button { min-height:28px; padding:5px 7px; font:9px var(--font-mono); } +.home-mission .home-work-modes svg { display:none; } +.home-mission .home-start { min-height:30px; padding:5px 9px; border-radius:4px; font:10px var(--font-mono); } +.home-mission .home-start kbd { display:none; } +.home-mission .home-goal-help { font-size:9px; } +.workspace-page.has-gravity-home .workspace-header { padding:18px 40px 7px; } +.workspace-page.has-gravity-home .workspace-header .ws-eyebrow { display:none; } +.workspace-page.has-gravity-home .workspace-header h1 { margin:0; font:500 11px var(--font-sans); letter-spacing:0; color:var(--text-secondary); } +.workspace-page.has-gravity-home .workspace-header-actions .local-pill { font-size:9px; } +.workspace-page.has-gravity-home .workspace-header .ws-icon { width:25px; height:25px; border:0; } +.workspace-page.has-gravity-home .workspace-scroll { padding-top:12px; } +.workspace-page.has-gravity-home .workspace-metrics { padding:20px 0 25px; } +.workspace-page.has-gravity-home .ws-metric strong { font-size:25px; } +.workspace-page.has-gravity-home .workspace-recent { display:block; padding:0 0 22px; border:0; } +.workspace-page.has-gravity-home .workspace-recent>div:first-child { display:flex; align-items:center; justify-content:space-between; gap:15px; margin-bottom:10px; } +.workspace-page.has-gravity-home .workspace-recent h2 { font-size:11px; font-weight:500; margin:0; } +.workspace-page.has-gravity-home .workspace-recent-list { display:block; } +.workspace-page.has-gravity-home .workspace-recent-list>button { width:100%; display:flex; align-items:center; gap:10px; padding:12px 1px; background:none; border:0; border-bottom:1px solid var(--border); border-radius:0; } +.workspace-page.has-gravity-home .workspace-recent-list>button:first-child { border-top:1px solid var(--border); } +.workspace-page.has-gravity-home .workspace-recent-list>button>span { flex:1; text-align:left; font-size:11px; } +.workspace-page.has-gravity-home .workspace-recent-list>button>small { font-size:10px; } +.workspace-home-details { margin:3px 0 0; border-top:1px solid var(--border); } +.workspace-home-details>summary { display:flex; justify-content:space-between; align-items:center; gap:15px; list-style:none; cursor:pointer; padding:16px 0; font-size:11px; color:var(--text-secondary); } +.workspace-home-details>summary::-webkit-details-marker { display:none; } +.workspace-home-details>summary::after { content:"+"; color:var(--text-secondary); margin-left:auto; } +.workspace-home-details[open]>summary::after { content:"−"; } +.workspace-home-details>summary>small { font-size:10px; color:var(--text-secondary); } +@media(max-width:1080px) { + .workspace-page.has-gravity-home .workspace-header { padding-left:25px; padding-right:25px; } + .home-command-grid { gap:17px; grid-template-columns:minmax(0,.85fr) minmax(0,1fr); } + .home-mission h2 { font-size:23px; } +} +@container perch-cover (max-width:650px) { + .home-cover h2 { font-size:32px; } + .home-command-grid { grid-template-columns:1fr; gap:18px; } + .is-professional .home-core-art { height:230px; } + .home-mission h2 br { display:none; } + .home-mission h2 { font-size:24px; } +} +.perch-home { container-type:inline-size; container-name:perch-cover; } +@container perch-cover (max-width:500px) { + .home-cover { grid-template-columns:1fr; min-height:0; } + .home-cover-copy { padding-top:25px; } + .home-cover h2 { font-size:30px; } + .home-core-art { height:230px; margin:-8px 0 0; } + .home-eyebrow { font-size:9px; letter-spacing:1.4px; } + .home-composer-foot { align-items:stretch; flex-direction:column; gap:8px; } + .home-work-modes button { flex:1; } + .home-work-modes { flex-wrap:nowrap; } + .home-start { width:100%; } + .home-goal-help { font-size:10px; } + .home-mission .home-goal-help { font-size:10px; } +} +@media(prefers-reduced-motion:reduce) { .home-core-art canvas { transform:none!important; } } diff --git a/css/permissions.css b/css/permissions.css new file mode 100644 index 0000000000000000000000000000000000000000..61163c1a46f7104436f66d9139d385b8907d3952 --- /dev/null +++ b/css/permissions.css @@ -0,0 +1,238 @@ +/* 设置 → 权限(契约 13A 自主授权模式)——只用 theme.css 的色彩令牌, + 不硬编码任何颜色;危险授权卡「红但不恐吓」(design-system.md:danger + 只做指引,不用高饱和大面积红)。 */ + +/* 危险操作授权状态卡:未授权=灰(安全态),已授权=danger 描边 + 极淡底 */ +.perm-card { + margin: 14px 0 0; + padding: 14px 16px; + border: 1px solid var(--border); + border-radius: var(--radius-card, 12px); + background: var(--bg-sunken); + transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease); +} +.perm-card.is-authorized { + border-color: var(--danger); + background: color-mix(in srgb, var(--danger) 6%, var(--bg)); +} +.perm-card-head { + display: flex; + gap: 12px; + align-items: flex-start; +} +.perm-card-icon { + display: inline-flex; + align-items: center; + justify-content: center; + width: 30px; + height: 30px; + border-radius: 50%; + border: 1px solid var(--border); + background: var(--bg); + color: var(--text-secondary); + flex-shrink: 0; +} +.perm-card.is-authorized .perm-card-icon { + color: var(--danger); + border-color: color-mix(in srgb, var(--danger) 40%, var(--border)); +} +.perm-card-text { + min-width: 0; +} +.perm-card-title { + display: flex; + align-items: center; + gap: 10px; + flex-wrap: wrap; + font-weight: 500; + color: var(--text); +} +.perm-card-desc { + margin: 4px 0 0; + font-size: 12.5px; + line-height: 1.6; + color: var(--text-secondary); +} + +/* 状态徽章:未授权=灰点,已授权=danger 点 */ +.perm-status-badge { + display: inline-flex; + align-items: center; + gap: 6px; + font-size: 11.5px; + font-weight: 500; + padding: 3px 9px; + border-radius: 999px; + border: 1px solid var(--border); + color: var(--text-secondary); + background: var(--bg); +} +.perm-status-badge.is-on { + color: var(--danger); + border-color: color-mix(in srgb, var(--danger) 45%, var(--border)); +} +.perm-status-dot { + width: 7px; + height: 7px; + border-radius: 50%; + background: var(--text-tertiary); +} +.perm-status-badge.is-on .perm-status-dot { + background: var(--danger); +} + +/* 卡内操作行 */ +.perm-card-actions { + margin-top: 12px; + display: flex; + gap: 8px; +} + +/* 一次性授权面板(输入确认词) */ +.perm-grant-panel { + margin-top: 12px; + padding: 12px 14px; + border: 1px solid color-mix(in srgb, var(--danger) 35%, var(--border)); + border-radius: var(--radius-control, 9px); + background: var(--bg); +} +.perm-grant-risk { + margin: 0; + font-size: 13px; + font-weight: 500; + color: var(--danger); + line-height: 1.6; +} +.perm-grant-note { + margin: 4px 0 0; + font-size: 12.5px; + color: var(--text-secondary); + line-height: 1.6; +} +.perm-grant-row { + margin-top: 10px; + display: flex; + gap: 8px; + align-items: center; + flex-wrap: wrap; +} +.perm-grant-input { + font: inherit; + font-size: 13px; + color: var(--text); + background: var(--bg-sunken); + border: 1px solid var(--border); + border-radius: var(--radius-control); + padding: 8px 10px; + min-width: 180px; +} +.perm-grant-input:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 1px; +} + +/* 按钮三态:危险红底(有分量不刺眼)/ 危险描边(安静入口)/ 中性 */ +.perm-btn-danger, +.perm-btn-danger-quiet, +.perm-btn-quiet { + appearance: none; + font: inherit; + font-size: 13px; + line-height: 1; + padding: 9px 14px; + border-radius: var(--radius-control); + cursor: pointer; + transition: background var(--dur) var(--ease), color var(--dur) var(--ease), + border-color var(--dur) var(--ease), opacity var(--dur) var(--ease); +} +.perm-btn-danger { + border: 1px solid var(--danger); + background: var(--danger); + color: var(--bg); +} +.perm-btn-danger:hover:not(:disabled) { + background: color-mix(in srgb, var(--danger) 88%, var(--text)); +} +.perm-btn-danger:disabled { + opacity: 0.45; + cursor: not-allowed; +} +.perm-btn-danger-quiet { + border: 1px solid color-mix(in srgb, var(--danger) 45%, var(--border)); + background: transparent; + color: var(--danger); +} +.perm-btn-danger-quiet:hover:not(:disabled) { + background: color-mix(in srgb, var(--danger) 10%, transparent); +} +.perm-btn-quiet { + border: 1px solid var(--border); + background: transparent; + color: var(--text-secondary); +} +.perm-btn-quiet:hover:not(:disabled) { + color: var(--text); + background: var(--bg-elevated); +} +.perm-btn-danger:focus-visible, +.perm-btn-danger-quiet:focus-visible, +.perm-btn-quiet:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 1px; +} + +/* sudo 固定说明行(不可更改):中性底 + 锁形小图标 */ +.perm-fixed-row { + margin-top: 14px; + display: flex; + gap: 10px; + align-items: flex-start; + padding: 11px 14px; + border: 1px solid var(--border); + border-radius: var(--radius-control, 9px); + background: var(--bg-sunken); + font-size: 12.5px; + line-height: 1.6; + color: var(--text-secondary); +} +.perm-fixed-row strong { + color: var(--text); + font-weight: 500; + margin-right: 4px; +} +.perm-fixed-icon { + display: inline-flex; + align-items: center; + color: var(--text-tertiary); + margin-top: 2px; + flex-shrink: 0; +} + +/* 底部常驻审计承诺行 */ +.perm-audit-pledge { + margin: 14px 0 0; + padding-top: 12px; + border-top: 1px solid var(--border); + font-size: 12px; + line-height: 1.6; + color: var(--text-tertiary); +} + +/* Composer 任务模式的总闸状态小字(只读展示,改动去设置) */ +.perm-gate-hint { + font-size: 11px; + line-height: 1; + color: var(--text-tertiary); + white-space: nowrap; + align-self: center; + cursor: default; +} + +/* 实时之眼摄像头状态徽章(契约 12B):授权=绿(与危险授权的红语义区分) */ +.perm-status-badge.is-good { + color: var(--success); + border-color: color-mix(in srgb, var(--success) 45%, var(--border)); +} +.perm-status-badge.is-good .perm-status-dot { + background: var(--success); +} diff --git a/css/plugins.css b/css/plugins.css new file mode 100644 index 0000000000000000000000000000000000000000..c80c3bda0824574d3dc4f3ce2ae68cb4b37aa6be --- /dev/null +++ b/css/plugins.css @@ -0,0 +1,93 @@ +/* 插件面板(契约 30A/30B · 工作台第六 tab「插件」)——复用 flow/xp 的 + 令牌与容器口径(整页滚动 + 48px 留白 + Warm Paper 变量),零硬编码色。 */ + +/* 运行面板容器 */ +.plugin-runner { + margin-top: 28px; + padding: 20px 22px; + background: var(--bg-elevated); + border: 1px solid var(--border); + border-radius: var(--radius-card); + max-width: 560px; +} + +.plugin-runner-title { + font-family: var(--font-serif); + font-size: 17px; + font-weight: 600; + color: var(--text); + margin: 0 0 16px; +} + +/* 结果:等宽 + 可横向滚(JSON 美化输出) */ +.plugin-result { + margin: 12px 0 0; + padding: 12px 14px; + background: var(--bg-sunken); + border: 1px solid var(--border); + border-radius: var(--radius-control); + font-family: var(--font-mono); + font-size: 12.5px; + line-height: 1.6; + color: var(--text); + white-space: pre-wrap; + word-break: break-word; + overflow-x: auto; + font-variant-numeric: tabular-nums; +} + +/* 选中态(卡片主区点击选中,运行面板跟着切) */ +.flow-item.is-selected { + border-color: var(--accent); +} + +.flow-item.is-selected .flow-item-name { + color: var(--accent); +} + +/* 卡片里的一句描述(100 件库没有描述会难挑) */ +.flow-item-desc { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + max-width: 40ch; +} + +/* 分类筛选行(全部/文本/编码/…) */ +.plugin-categories { + display: flex; + flex-wrap: wrap; + gap: 6px; + margin-bottom: 14px; +} + +.plugin-cat { + padding: 4px 12px; + border: 1px solid var(--border); + border-radius: 999px; + background: var(--bg); + color: var(--text-secondary); + font-size: 12px; + cursor: pointer; + transition: + border-color 150ms ease, + color 150ms ease, + background 150ms ease; +} + +.plugin-cat:hover { + border-color: var(--border-strong); + color: var(--text); +} + +.plugin-cat.is-active { + border-color: var(--accent); + color: var(--accent); + background: var(--accent-soft); +} + +/* 分类徽章(卡片上,主色化) */ +.flow-badge.is-on { + color: var(--accent); + border-color: color-mix(in srgb, var(--accent) 40%, var(--border)); +} diff --git a/css/prefs-ui.css b/css/prefs-ui.css new file mode 100644 index 0000000000000000000000000000000000000000..9363372d49ea8b2476e4011ff0e6ae7ccd77e5a0 --- /dev/null +++ b/css/prefs-ui.css @@ -0,0 +1,166 @@ +/* 模型偏好分组(契约 14A)的控件样式——只用 theme.css 的色彩令牌, + 不硬编码任何颜色;风格对齐设置页其余分组(Warm Paper)。 */ + +/* 顶部「MiMo 预置建议」一键应用条 */ +.mp-preset { + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; + padding: 12px 0; + border-top: 1px solid var(--border); +} +.mp-preset-text { + min-width: 0; +} +.mp-preset-label { + font-weight: 500; + color: var(--text); +} +.mp-preset-hint { + margin: 2px 0 0; + font-size: 12.5px; + color: var(--text-tertiary); + line-height: 1.5; +} +.mp-preset-btn { + appearance: none; + border: 1px solid var(--accent); + background: var(--accent); + color: var(--bg); + font: inherit; + font-size: 13px; + line-height: 1; + padding: 8px 14px; + border-radius: var(--radius-control); + cursor: pointer; + flex-shrink: 0; + transition: opacity var(--dur) var(--ease); +} +.mp-preset-btn:hover { + opacity: 0.9; +} +.mp-preset-btn:disabled { + opacity: 0.5; + cursor: not-allowed; +} +.mp-preset-btn:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 1px; +} + +/* 模型行列表 */ +.mp-list { + margin-top: 4px; +} +.mp-row { + display: flex; + align-items: center; + gap: 16px; + padding: 12px 0; + border-top: 1px solid var(--border); + flex-wrap: wrap; +} +.mp-row:first-child { + border-top: none; +} +.mp-row-text { + min-width: 0; + flex: 1 1 180px; +} +.mp-row-name { + display: flex; + align-items: center; + gap: 8px; + font-weight: 500; + color: var(--text); +} +.mp-row-id { + margin: 2px 0 0; + font-size: 12px; + color: var(--text-tertiary); + font-family: var(--font-mono); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +/* 云 / 本机 徽章 */ +.mp-badge { + font-size: 11px; + line-height: 1; + padding: 3px 7px; + border-radius: var(--radius-chip); + flex-shrink: 0; +} +.mp-badge.is-cloud { + background: var(--accent-soft); + color: var(--accent); +} +.mp-badge.is-local { + background: var(--bg-sunken); + color: var(--text-secondary); + border: 1px solid var(--border); +} + +/* 单个控件(思考档下拉 / 最大回复长度输入) */ +.mp-field { + display: flex; + flex-direction: column; + gap: 4px; + flex-shrink: 0; +} +.mp-field-label { + font-size: 12px; + color: var(--text-secondary); +} +.mp-select { + appearance: none; + border: 1px solid var(--border); + background: var(--bg); + color: var(--text); + font: inherit; + font-size: 13px; + padding: 7px 10px; + border-radius: var(--radius-control); + min-width: 92px; + cursor: pointer; +} +.mp-select:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 1px; +} +.mp-number { + border: 1px solid var(--border); + background: var(--bg); + color: var(--text); + font: inherit; + font-size: 13px; + padding: 7px 10px; + border-radius: var(--radius-control); + width: 130px; +} +.mp-number.is-invalid { + border-color: var(--danger); +} +.mp-number:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 1px; +} +.mp-number.is-invalid:focus-visible { + outline-color: var(--danger); +} +.mp-field-error { + margin: 0; + font-size: 12px; + color: var(--danger); + line-height: 1.4; + max-width: 220px; +} + +/* 操作反馈(一键应用结果) */ +.mp-notice { + margin: 8px 0 0; + font-size: 12.5px; + color: var(--text-secondary); +} diff --git a/css/prefs.css b/css/prefs.css new file mode 100644 index 0000000000000000000000000000000000000000..22cef33dac66fd6b2ebfa921eb5ea8e6ae96b544 --- /dev/null +++ b/css/prefs.css @@ -0,0 +1,220 @@ +/* 设置页「可调控项」新分组的控件(契约 10A)——只用 theme.css 的色彩令牌, + 不硬编码任何颜色;风格对齐 Warm Paper(design-system.md)。 */ + +/* 分组内的一行:左侧说明,右侧控件 */ +.pref-row { + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; + padding: 12px 0; + border-top: 1px solid var(--border); +} +.pref-row:first-of-type { + border-top: none; +} +.pref-row-text { + min-width: 0; +} +.pref-row-label { + font-weight: 500; + color: var(--text); +} +.pref-row-hint { + margin: 2px 0 0; + font-size: 12.5px; + color: var(--text-tertiary); + line-height: 1.5; +} + +/* 分组内的子标题(把一行行控件分段) */ +.pref-subhead { + margin: 20px 0 4px; + font-size: 12px; + font-weight: 600; + letter-spacing: 0.02em; + color: var(--text-secondary); +} +.pref-subhead:first-of-type { + margin-top: 8px; +} + +/* 分段控件(三选/五选 pill):一排等宽小按钮,选中用 accent 底 */ +.pref-seg { + display: inline-flex; + gap: 4px; + padding: 3px; + background: var(--bg-sunken); + border: 1px solid var(--border); + border-radius: var(--radius-control); + flex-shrink: 0; +} +.pref-seg-btn { + appearance: none; + border: none; + background: transparent; + color: var(--text-secondary); + font: inherit; + font-size: 13px; + line-height: 1; + padding: 7px 12px; + border-radius: var(--radius-chip); + cursor: pointer; + transition: background var(--dur) var(--ease), color var(--dur) var(--ease); + white-space: nowrap; +} +.pref-seg-btn:hover { + color: var(--text); + background: var(--bg-elevated); +} +.pref-seg-btn.is-active { + background: var(--accent); + color: var(--bg); +} +.pref-seg-btn:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 1px; +} + +/* 下拉(模型/轮询等):与设置页其它输入框同款 */ +.pref-select { + font: inherit; + font-size: 13px; + color: var(--text); + background: var(--bg-sunken); + border: 1px solid var(--border); + border-radius: var(--radius-control); + padding: 8px 10px; + min-width: 200px; + cursor: pointer; +} +.pref-select:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 1px; +} + +/* 开关(记忆/语义检索):胶囊滑块,选中=accent */ +.pref-switch { + appearance: none; + border: 1px solid var(--border); + background: var(--bg-sunken); + position: relative; + width: 42px; + height: 24px; + border-radius: 12px; + cursor: pointer; + flex-shrink: 0; + transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease); +} +.pref-switch::after { + content: ""; + position: absolute; + top: 2px; + left: 2px; + width: 18px; + height: 18px; + border-radius: 50%; + background: var(--bg-elevated); + border: 1px solid var(--border); + transition: transform var(--dur) var(--ease); +} +.pref-switch[aria-checked="true"] { + background: var(--accent); + border-color: var(--accent); +} +.pref-switch[aria-checked="true"]::after { + transform: translateX(18px); + background: var(--bg); + border-color: transparent; +} +.pref-switch:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +/* 保存/失败的一句人话提示(成功淡出、失败用 danger) */ +.pref-notice { + margin: 10px 0 0; + font-size: 12.5px; + line-height: 1.5; +} +.pref-notice.is-ok { + color: var(--success); +} +.pref-notice.is-error { + color: var(--danger); +} + +/* 「关于」里的审计日志按钮行 */ +.pref-audit-row { + display: flex; + gap: 8px; + align-items: center; + flex-wrap: wrap; +} +.pref-confirm { + display: inline-flex; + gap: 8px; + align-items: center; + font-size: 12.5px; + color: var(--text-secondary); +} + +.gpu-accel-actions { + display: flex; + flex-wrap: wrap; + gap: 8px; + padding: 12px 0; + border-top: 1px solid var(--border); +} +.gpu-accel-actions button { + display: inline-flex; + align-items: center; + gap: 7px; +} +.gpu-accel-message { + margin: 4px 0 10px; + color: var(--success); + font-size: 12.5px; + line-height: 1.5; +} +.gpu-accel-message.is-error { + color: var(--danger); +} +.gpu-accel-status { + padding-top: 12px; + border-top: 1px solid var(--border); + color: var(--text-secondary); + font-size: 12.5px; +} +.gpu-accel-status > strong { + display: block; + margin-bottom: 8px; + color: var(--text); + font-weight: 550; +} +.gpu-accel-status > p { + margin: 0; + color: var(--text-tertiary); +} +.gpu-accel-model { + display: grid; + grid-template-columns: minmax(120px, 1fr) auto auto; + gap: 12px; + padding: 7px 0; + border-top: 1px solid var(--border-subtle, var(--border)); + font-variant-numeric: tabular-nums; +} +.gpu-accel-model span:first-child { + min-width: 0; + overflow-wrap: anywhere; + color: var(--text); +} +@media (max-width: 620px) { + .gpu-accel-model { + grid-template-columns: 1fr auto; + } + .gpu-accel-model span:first-child { + grid-column: 1 / -1; + } +} diff --git a/css/screensaver.css b/css/screensaver.css new file mode 100644 index 0000000000000000000000000000000000000000..6dd2d27b8259439ffe387afc182f69f021b27adb --- /dev/null +++ b/css/screensaver.css @@ -0,0 +1,196 @@ +/* 待机显示 · 涅槃屏保 b2(对齐参考:Google 新标签页风格)—— + 明亮浅蓝渐变底 + 斜向柔光带流动 + 中央磨砂玻璃卡四色星 + 极简时钟。 + 纯 CSS(三层大渐变缓动,GPU 合成、零 WebGL),颜色锚 Google 四色系。 */ + +.saver-root { + position: fixed; + inset: 0; + overflow: hidden; + /* 明亮浅蓝基底(参考图主调):上浅白 → 下饱和蓝 */ + background: linear-gradient(180deg, #eaf3fc 0%, #cfe6fb 38%, #9fcbf5 78%, #7fb5ee 100%); + cursor: none; +} + +/* ── 三层柔光带:斜向大渐变,缓慢漂移(生命力的来源)──────────── */ +.saver-glow { + position: absolute; + inset: -30%; + pointer-events: none; +} + +/* 光带 A:左上斜白光(参考图里的斜向光束) */ +.saver-glow-a { + background: linear-gradient( + 118deg, + transparent 12%, + rgba(255, 255, 255, 0.75) 26%, + rgba(255, 255, 255, 0.15) 34%, + transparent 46% + ); + animation: saver-drift-a 26s ease-in-out infinite alternate; +} + +/* 光带 B:右侧青蓝柔光团 */ +.saver-glow-b { + background: radial-gradient( + 55% 70% at 78% 30%, + rgba(120, 200, 255, 0.55), + transparent 70% + ); + animation: saver-drift-b 34s ease-in-out infinite alternate; +} + +/* 光带 C:底部深蓝晕(压出层次与纵深) */ +.saver-glow-c { + background: radial-gradient( + 80% 60% at 30% 110%, + rgba(35, 90, 200, 0.4), + transparent 65% + ); + animation: saver-drift-c 42s ease-in-out infinite alternate; +} + +@keyframes saver-drift-a { + from { transform: translateX(-8%) rotate(-2deg); } + to { transform: translateX(10%) rotate(3deg); } +} +@keyframes saver-drift-b { + from { transform: translate(0, 0) scale(1); } + to { transform: translate(-6%, 8%) scale(1.15); } +} +@keyframes saver-drift-c { + from { transform: translate(0, 0); } + to { transform: translate(8%, -4%) scale(1.1); } +} + +/* ── 中央磨砂玻璃卡 + 四色星(参考图主体)──────────────────────── */ +.saver-card { + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -52%); + width: min(34vmin, 300px); + aspect-ratio: 1; + border-radius: 15%; /* 参考图的大圆角方卡 */ + background: linear-gradient(155deg, rgba(255, 255, 255, 0.92), rgba(240, 248, 255, 0.78)); + backdrop-filter: blur(18px) saturate(1.15); + -webkit-backdrop-filter: blur(18px) saturate(1.15); + box-shadow: + 0 24px 70px rgba(30, 80, 160, 0.28), + 0 4px 18px rgba(30, 80, 160, 0.14), + inset 0 1px 0 rgba(255, 255, 255, 0.9); + display: flex; + align-items: center; + justify-content: center; + /* 卡整体极缓呼吸(5% 缩放,22 秒一拍——「活着」但不抢戏) */ + animation: saver-card-breathe 22s ease-in-out infinite; +} + +@keyframes saver-card-breathe { + 0%, 100% { transform: translate(-50%, -52%) scale(1); } + 50% { transform: translate(-50%, -52%) scale(1.045); } +} + +/* 四色四角星:conic 渐变 + clip-path(与品牌标同形状语言), + 极慢自转(60 秒一圈——看得见在转,不引人焦躁) */ +.saver-star { + width: 52%; + aspect-ratio: 1; + background: conic-gradient( + from 200deg, + #4285f4, + #9b72cb, + #ea4335, + #fbbc04, + #34a853, + #4285f4 + ); + clip-path: polygon( + 50% 0%, 61% 39%, 100% 50%, 61% 61%, + 50% 100%, 39% 61%, 0% 50%, 39% 39% + ); + filter: blur(0.3px) saturate(1.08); + animation: saver-star-spin 60s linear infinite; +} + +@keyframes saver-star-spin { + from { transform: rotate(0deg); } + to { transform: rotate(360deg); } +} + +/* ── 时钟:卡下极简一行,浅色系深灰细字 ────────────────────────── */ +.saver-clock { + position: absolute; + left: 50%; + bottom: 12%; + transform: translateX(-50%); + display: flex; + align-items: baseline; + gap: 14px; + color: rgba(20, 50, 95, 0.72); + font-family: "Source Serif 4", "Songti SC", Georgia, serif; + text-shadow: 0 1px 12px rgba(255, 255, 255, 0.6); + user-select: none; + pointer-events: none; +} + +.saver-time { + font-size: clamp(34px, 5.6vw, 64px); + font-weight: 600; + letter-spacing: 0.03em; + line-height: 1; + font-variant-numeric: tabular-nums; +} + +.saver-date { + font-size: clamp(15px, 2vw, 22px); + font-weight: 400; + letter-spacing: 0.18em; + opacity: 0.85; +} + +/* ── 形态一:苹果航拍视频层(全屏 object-fit cover)────────────── */ +.saver-video { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + object-fit: cover; + display: block; +} + +/* 航拍态时钟:浅白字(视频上) */ +.saver-clock.on-video { + color: rgba(255, 255, 255, 0.9); + text-shadow: 0 1px 18px rgba(0, 0, 0, 0.45); +} + +/* ── 回来提示(首次进入 5 秒淡出)──────────────────────────────── */ +.saver-hint { + position: absolute; + bottom: 34px; + right: 40px; + margin: 0; + color: rgba(20, 50, 95, 0.45); + font-size: 12.5px; + letter-spacing: 0.2em; + pointer-events: none; + user-select: none; + animation: saver-hint-fade 5s ease forwards; +} + +@keyframes saver-hint-fade { + 0%, 60% { opacity: 1; } + 100% { opacity: 0; } +} + +/* 减弱动效:全部光层静止(星也停转),只留静帧构图 */ +@media (prefers-reduced-motion: reduce) { + .saver-glow-a, + .saver-glow-b, + .saver-glow-c, + .saver-star, + .saver-card { + animation: none; + } +} diff --git a/css/sight.css b/css/sight.css new file mode 100644 index 0000000000000000000000000000000000000000..9cb55164a3674df4ce6d770aab6a01f85dd27986 --- /dev/null +++ b/css/sight.css @@ -0,0 +1,447 @@ +/* 看图问答浮窗:与划词浮层同款 Warm Paper 毛玻璃卡片(颜色一律走 theme.css 令牌)。 + 透明原生窗口上不用 backdrop-filter(坑位实测记录 #1),模糊交给 macOS 窗口特效, + CSS 只保留 85% 暖纸半透明底色。 */ + +/* 透明窗口本体:桌面要从圆角外透出来 */ +body.sight-surface { + background: transparent; +} + +.sight-root { + height: 100%; + display: flex; + padding: 12px; + box-sizing: border-box; +} + +/* ---------- 卡片容器 ---------- */ +.sight-card { + flex: 1; + min-height: 0; + display: flex; + flex-direction: column; + overflow: hidden; + border: 1px solid var(--border); + border-radius: var(--radius-float); + background: var(--glass); + box-shadow: var(--shadow-float); + animation: sight-in 180ms var(--ease); +} + +@keyframes sight-in { + from { + opacity: 0; + transform: translateY(6px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +/* ---------- 顶栏 ---------- */ +.sight-head { + display: flex; + align-items: baseline; + justify-content: space-between; + gap: 12px; + padding: 16px 20px 4px; +} + +.sight-title { + margin: 0; + font-family: var(--font-serif); + font-size: 20px; + font-weight: 600; + letter-spacing: -0.01em; + color: var(--text); +} + +.sight-esc { + font-size: 12px; + color: var(--text-tertiary); + white-space: nowrap; +} + +/* ---------- 权限状态灯 ---------- */ +.sight-perms { + display: flex; + flex-wrap: wrap; + gap: 10px; + padding: 6px 20px 2px; +} + +.sight-perm { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 0; + border: none; + background: transparent; + color: var(--text-secondary); + font-family: inherit; + font-size: 12px; + cursor: default; + text-align: left; +} + +button.sight-perm.is-bad { + cursor: pointer; + text-decoration: underline; + text-underline-offset: 3px; +} + +.sight-dot { + width: 7px; + height: 7px; + border-radius: 50%; + background: var(--text-tertiary); + flex-shrink: 0; +} + +.sight-perm.is-ok { + color: var(--success); +} + +.sight-perm.is-ok .sight-dot { + background: var(--success); +} + +.sight-perm.is-bad { + color: var(--warning); +} + +.sight-perm.is-bad .sight-dot { + background: var(--warning); +} + +.sight-perm.is-mute { + color: var(--text-tertiary); +} + +/* ---------- 空态 / 提示 ---------- */ +.sight-note { + margin: 0; + padding: 16px 20px 20px; + font-size: 13.5px; + line-height: 1.6; + color: var(--text-secondary); +} + +.sight-note.is-warn { + color: var(--warning); +} + +/* ---------- 图片预览 ---------- */ +.sight-preview { + margin: 10px 20px 0; + padding: 0; + display: flex; + flex-direction: column; + gap: 6px; +} + +.sight-preview img { + display: block; + max-width: 100%; + max-height: 170px; + object-fit: contain; + object-position: left top; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: var(--bg-sunken); +} + +.sight-preview-meta { + font-size: 11.5px; + color: var(--text-tertiary); + font-variant-numeric: tabular-nums; +} + +/* ---------- 提问输入 ---------- */ +.sight-custom { + display: flex; + align-items: center; + gap: 8px; + margin: 10px 20px 0; + padding: 6px 6px 6px 12px; + border: 1px solid transparent; + border-radius: var(--radius-control); + background: var(--bg-sunken); + transition: border-color var(--dur) var(--ease); +} + +.sight-custom:focus-within { + border-color: var(--accent); +} + +.sight-input { + flex: 1; + min-width: 0; + border: none; + background: transparent; + color: var(--text); + font-family: inherit; + font-size: 13.5px; + outline: none; + cursor: text; +} + +.sight-input::placeholder { + color: var(--text-tertiary); +} + +.sight-send { + flex-shrink: 0; + height: 28px; + padding: 0 12px; + border: none; + border-radius: var(--radius-chip); + background: var(--accent); + color: var(--bg); + font-family: inherit; + font-size: 13px; + cursor: pointer; + transition: opacity var(--dur) var(--ease); +} + +.sight-send:disabled { + opacity: 0.4; + cursor: default; +} + +/* ---------- 模型下拉(vision-only 过滤后的清单) ---------- */ +.sight-model-row { + display: flex; + align-items: center; + gap: 8px; + margin: 8px 20px 0; +} + +.sight-model-label { + font-size: 12px; + color: var(--text-tertiary); + white-space: nowrap; +} + +.sight-model { + flex: 1; + min-width: 0; + height: 30px; + padding: 0 8px; + border: 1px solid var(--border); + border-radius: var(--radius-chip); + background: var(--bg-sunken); + color: var(--text); + font-family: inherit; + font-size: 12.5px; + outline: none; + cursor: pointer; +} + +.sight-model:disabled { + opacity: 0.6; + cursor: default; +} + +/* ---------- 回答区 ---------- */ +.sight-answer { + flex: 1; + min-height: 0; + display: flex; + flex-direction: column; + margin-top: 10px; + padding: 10px 20px 14px; + border-top: 1px solid var(--border); +} + +.sight-answer-body { + flex: 1; + min-height: 0; + overflow-y: auto; +} + +.sight-answer-text { + margin: 0; + color: var(--text); + font-size: 13.5px; + line-height: 1.65; + white-space: pre-wrap; + word-break: break-word; + user-select: text; +} + +/* 流式呼吸光标(与划词浮层同款;reduced-motion 时 theme.css 全局降级) */ +.sight-cursor { + display: inline-block; + width: 2px; + height: 1.05em; + margin-left: 3px; + border-radius: 1px; + background: var(--accent); + vertical-align: text-bottom; + animation: sight-cursor-breathe 1s ease-in-out infinite; +} + +@keyframes sight-cursor-breathe { + 0%, + 100% { + opacity: 1; + } + 50% { + opacity: 0.15; + } +} + +.sight-error { + margin: 8px 0 0; + color: var(--danger); + font-size: 12.5px; + line-height: 1.5; +} + +.sight-answer-foot { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + margin-top: 12px; +} + +.sight-save { + display: inline-flex; + align-items: center; + gap: 6px; + height: 30px; + padding: 0 12px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: transparent; + color: var(--text-secondary); + font-family: inherit; + font-size: 12.5px; + cursor: pointer; + transition: background-color var(--dur) var(--ease); +} + +.sight-save:hover:not(:disabled) { + background: var(--accent-soft); + color: var(--text); +} + +.sight-save:disabled { + opacity: 0.5; + cursor: default; +} + +.sight-foot-hint { + font-size: 12px; + color: var(--text-tertiary); +} + +/* ---------- 授权引导态(与划词浮层同款骨架) ---------- */ +.sight-guide { + flex: 1; + display: flex; + flex-direction: column; + padding: 24px 24px 20px; +} + +.sight-guide-head { + display: flex; + align-items: center; + gap: 10px; + color: var(--accent); +} + +.sight-guide .sight-title { + font-size: 22px; +} + +.sight-lead { + margin: 12px 0 18px; + color: var(--text-secondary); + font-size: 14px; + line-height: 1.65; +} + +.sight-guide-actions { + display: flex; + flex-wrap: wrap; + gap: 10px; +} + +.sight-primary { + height: 40px; + padding: 0 20px; + border: none; + border-radius: var(--radius-control); + background: var(--accent); + color: var(--bg); + font-family: inherit; + font-size: 14px; + cursor: pointer; +} + +.sight-primary:hover { + filter: brightness(0.94); +} + +.sight-secondary { + height: 40px; + padding: 0 16px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: transparent; + color: var(--text-secondary); + font-family: inherit; + font-size: 13.5px; + cursor: pointer; +} + +.sight-secondary:hover { + background: var(--bg-elevated); + color: var(--text); +} + +.sight-guide-why { + margin: 16px 0 0; + color: var(--text-tertiary); + font-size: 12.5px; + line-height: 1.7; +} + +.sight-guide-hint { + margin-top: auto; + padding-top: 18px; + color: var(--text-tertiary); + font-size: 12.5px; + line-height: 1.6; +} + +/* ---------- 实时之眼入口(契约 12B):摄像头状态点 + 打开 ---------- */ +.sight-perm.is-wait { + color: var(--warning); +} + +.sight-perm.is-wait .sight-dot { + background: var(--warning); +} + +button.sight-perm.is-live { + cursor: pointer; + color: var(--accent); +} + +button.sight-perm.is-live:hover { + text-decoration: underline; + text-underline-offset: 3px; +} + +button.sight-perm.is-live.is-ok { + color: var(--success); +} + +button.sight-perm.is-live.is-bad { + color: var(--danger); +} diff --git a/css/skills.css b/css/skills.css new file mode 100644 index 0000000000000000000000000000000000000000..99a72901728c0d0e71e3cd45e31284357d460b48 --- /dev/null +++ b/css/skills.css @@ -0,0 +1,424 @@ +/* Skill 技能系统(Phase 5C):技能中心页 + Composer 技能选择条。 + Warm Paper 全令牌配色,遵循 design-system.md;无硬编码颜色。 */ + +/* ── Composer 技能选择条(输入框上方,可横向滚动) ─────────────────── */ + +.composer-skills { + display: flex; + gap: 8px; + max-width: 760px; + margin: 0 auto 10px; + padding-bottom: 2px; + overflow-x: auto; + scrollbar-width: none; +} + +.composer-skills::-webkit-scrollbar { + display: none; +} + +.skill-chip { + display: inline-flex; + align-items: center; + gap: 6px; + flex: 0 0 auto; + height: 28px; + padding: 0 12px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: var(--bg); + color: var(--text-secondary); + font-family: var(--font-sans); + font-size: 12.5px; + line-height: 1; + cursor: pointer; + transition: + background-color var(--dur) var(--ease), + border-color var(--dur) var(--ease); +} + +.skill-chip:hover { + border-color: var(--accent); + color: var(--text); +} + +.skill-chip:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +.skill-chip.is-selected { + background: var(--accent-soft); + border-color: var(--accent); + color: var(--text); +} + +/* 脚本技能置灰不可选:执行属于 Agent 面板的确认流程 */ +.skill-chip.is-script { + opacity: 0.55; + cursor: not-allowed; +} + +.skill-chip.is-script:hover { + border-color: var(--border); + color: var(--text-secondary); +} + +/* ── 技能中心页 ───────────────────────────────────────────────────── */ + +.skills { + flex: 1; + min-width: 0; + overflow-y: auto; + padding: 36px 48px 48px; +} + +.skills-head { + display: flex; + align-items: flex-end; + justify-content: space-between; + gap: 16px; + margin-bottom: 20px; + flex-wrap: wrap; +} + +.skills-head h1 { + font-size: 30px; +} + +.skills-head-sub { + max-width: 560px; + margin: 6px 0 0; + font-size: 13.5px; + line-height: 1.7; + color: var(--text-secondary); +} + +.skills-import-btn { + display: inline-flex; + align-items: center; + gap: 8px; + height: 40px; + padding: 0 18px; + border: none; + border-radius: var(--radius-control); + background: var(--accent); + color: var(--bg); + font-family: var(--font-sans); + font-size: 14px; + cursor: pointer; + transition: opacity var(--dur) var(--ease); +} + +.skills-import-btn:hover { + opacity: 0.9; +} + +.skills-import-btn:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +.skills-import-btn:disabled { + opacity: 0.6; + cursor: default; +} + +.skills-spin { + animation: skills-rotate 1s linear infinite; +} + +@keyframes skills-rotate { + to { + transform: rotate(360deg); + } +} + +@media (prefers-reduced-motion: reduce) { + .skills-spin { + animation: none; + } +} + +.skills-notice { + margin: 0 0 20px; + padding: 10px 14px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: var(--accent-soft); + font-size: 13px; + line-height: 1.7; + color: var(--text); +} + +.skills-error { + margin: 0 0 20px; + font-size: 13px; + color: var(--danger); +} + +.skills-muted { + margin: 24px 0 0; + font-size: 13px; + color: var(--text-secondary); +} + +.skills-empty { + margin: 56px 0; + text-align: center; +} + +.skills-empty-title { + margin: 0; + font-family: var(--font-serif); + font-size: 24px; + font-weight: 600; + color: var(--text); +} + +.skills-empty-sub { + max-width: 420px; + margin: 12px auto 0; + font-size: 13.5px; + line-height: 1.8; + color: var(--text-secondary); +} + +.skills-group { + margin-bottom: 40px; +} + +.skills-group-title { + margin: 0; + font-size: 19px; +} + +.skills-group-hint { + margin: 4px 0 16px; + font-size: 13px; + color: var(--text-secondary); +} + +.skills-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); + gap: 16px; +} + +/* ── 技能卡片 ───────────────────────────────────────────────────── */ + +.skill-card { + display: flex; + flex-direction: column; + gap: 8px; + padding: 16px; + border: 1px solid var(--border); + border-radius: var(--radius-card); + background: var(--bg-elevated); +} + +.skill-card-head { + display: flex; + align-items: baseline; + justify-content: space-between; + gap: 10px; +} + +.skill-name { + margin: 0; + font-family: var(--font-serif); + font-size: 17px; + font-weight: 600; + letter-spacing: -0.01em; + color: var(--text); +} + +/* 状态徽章:与全站徽章同尺寸同字重(2px 8px / 12px / 500 / pill) */ +.skill-badge { + display: inline-flex; + align-items: center; + gap: 4px; + flex: 0 0 auto; + padding: 2px 8px; + border-radius: 999px; + font-size: 12px; + font-weight: 500; + line-height: 1.5; + white-space: nowrap; +} + +/* 提示词 = 绿色(安全);脚本 = 黄色(确认级) */ +.skill-badge.is-prompt { + background: color-mix(in srgb, var(--success) 16%, transparent); + color: var(--success); +} + +.skill-badge.is-script { + background: color-mix(in srgb, var(--warning) 18%, transparent); + color: var(--warning); +} + +.skill-desc { + margin: 0; + font-size: 13px; + line-height: 1.7; + color: var(--text-secondary); +} + +.skill-script-note { + margin: 0; + font-size: 12px; + line-height: 1.7; + color: var(--text-tertiary); +} + +.skill-card-foot { + display: flex; + gap: 8px; + margin-top: auto; + padding-top: 4px; +} + +.skill-btn { + display: inline-flex; + align-items: center; + gap: 5px; + height: 28px; + padding: 0 10px; + border: 1px solid var(--border); + border-radius: var(--radius-chip); + background: transparent; + color: var(--text-secondary); + font-family: var(--font-sans); + font-size: 12.5px; + cursor: pointer; + transition: + border-color var(--dur) var(--ease), + background-color var(--dur) var(--ease); +} + +.skill-btn:hover { + color: var(--text); + border-color: var(--accent); +} + +.skill-btn:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +.skill-btn:disabled { + opacity: 0.5; + cursor: default; +} + +.skill-btn:disabled:hover { + color: var(--text-secondary); + border-color: var(--border); +} + +.skill-btn.is-primary { + background: var(--accent); + border-color: var(--accent); + color: var(--bg); +} + +.skill-btn.is-primary:hover { + color: var(--bg); + opacity: 0.9; +} + +.skill-btn.is-danger:hover { + color: var(--danger); + border-color: var(--danger); +} + +/* 删除的两段确认:armed 状态用危险色提醒「再点一次」 */ +.skill-btn.is-danger.is-armed { + color: var(--danger); + border-color: var(--danger); + background: color-mix(in srgb, var(--danger) 10%, transparent); +} + +.skill-edit { + display: flex; + flex-direction: column; + gap: 8px; +} + +.skill-edit-input { + width: 100%; + padding: 8px 10px; + border: 1px solid transparent; + border-radius: var(--radius-control); + background: var(--bg-sunken); + color: var(--text); + font-family: var(--font-sans); + font-size: 13px; + line-height: 1.7; + resize: vertical; +} + +.skill-edit-input:focus { + outline: none; + border-color: var(--accent); + box-shadow: 0 0 0 3px var(--accent-soft); +} + +.skill-edit-actions { + display: flex; + justify-content: flex-end; + gap: 8px; +} + +/* ── 拖拽导入蒙层 ───────────────────────────────────────────────── */ + +.skills-drag-overlay { + position: fixed; + inset: 0; + z-index: 40; + display: flex; + align-items: center; + justify-content: center; + background: var(--glass); +} + +.skills-drag-card { + display: flex; + flex-direction: column; + align-items: center; + gap: 8px; + padding: 40px 56px; + border: 1px dashed var(--border); + border-radius: var(--radius-float); + background: var(--bg-elevated); + color: var(--text-secondary); +} + +.skills-drag-title { + margin: 8px 0 0; + font-family: var(--font-serif); + font-size: 22px; + font-weight: 600; + color: var(--text); +} + +.skills-drag-sub { + margin: 0; + font-size: 13px; + color: var(--text-secondary); +} + +@media (prefers-color-scheme: dark) { + .skill-badge.is-prompt { + background: color-mix(in srgb, var(--success) 22%, transparent); + } + + .skill-badge.is-script { + background: color-mix(in srgb, var(--warning) 22%, transparent); + } + + .skills-import-btn { + color: var(--bg); + } +} diff --git a/css/studio.css b/css/studio.css new file mode 100644 index 0000000000000000000000000000000000000000..b8ccc12fa6baa216a16fecd3069283d4217928ff --- /dev/null +++ b/css/studio.css @@ -0,0 +1,17 @@ +/* A shared shell, two densities. No duplicated business UI. */ +.studio-shell{--resource-width:224px;display:grid;grid-template-rows:52px minmax(0,1fr) 26px;grid-template-columns:194px minmax(0,1fr);height:100dvh;background:var(--bg);color:var(--text);overflow:hidden;font-size:13px} +.studio-shell button,.studio-shell input,.studio-shell select,.studio-shell textarea{font-family:var(--font-sans)}.studio-topbar{grid-column:1/-1;display:flex;align-items:center;gap:14px;padding:0 15px 0 80px;border-bottom:1px solid var(--border);background:var(--bg-sunken);min-width:0}.studio-brand{display:flex;align-items:center;gap:7px;white-space:nowrap}.studio-brand>svg{color:var(--accent)}.studio-brand strong{font-size:14px;letter-spacing:-.4px}.studio-brand>span{font:7px var(--font-mono);letter-spacing:1px;color:var(--text-tertiary);margin-left:7px}.project-switch{display:flex;align-items:center;gap:6px;min-width:120px;max-width:240px}.project-switch select{border:0;background:transparent;color:var(--text);max-width:190px;min-width:70px;font-size:11px;outline-offset:2px}.project-switch .ws-icon{width:25px;height:25px}.command-search{margin-left:auto;display:flex;align-items:center;gap:9px;width:240px;max-width:28%;padding:6px 10px;background:var(--bg-elevated);border:1px solid var(--border);color:var(--text-secondary);border-radius:6px;font-size:10px;cursor:pointer}.command-search kbd{font-size:8px;color:var(--text-tertiary);margin-left:auto}.layout-toggle{display:flex;gap:2px;background:var(--bg-elevated);padding:3px;border:1px solid var(--border);border-radius:6px}.layout-toggle button{display:flex;align-items:center;gap:5px;padding:4px 9px;border:0;border-radius:4px;background:transparent;color:var(--text-secondary);font-size:10px;cursor:pointer}.layout-toggle button[aria-pressed="true"]{background:var(--bg-sunken);color:var(--accent);box-shadow:0 1px 3px rgba(0,0,0,.15)} +.studio-activity{grid-column:1;grid-row:2;display:flex;flex-direction:column;min-height:0;overflow-y:auto;overflow-x:hidden;padding:22px 10px 12px;border-right:1px solid var(--border);background:var(--bg-sunken)}.studio-activity>button,.studio-nav-bottom>button{display:flex;align-items:center;gap:10px;width:100%;border:1px solid transparent;background:transparent;color:var(--text-secondary);border-radius:8px;text-align:left;padding:11px 12px;margin-bottom:5px;cursor:pointer;flex-shrink:0}.studio-activity>button>svg,.studio-nav-bottom>button>svg{flex-shrink:0}.studio-activity button>span{min-width:0;font-size:12px;font-weight:500}.studio-activity button small{display:block;font-size:9px;font-weight:400;color:var(--text-tertiary);line-height:1.8;margin-top:4px}.studio-activity>button:hover,.studio-nav-bottom>button:hover{background:var(--bg-elevated);color:var(--text)}.studio-activity>button.is-active,.studio-nav-bottom>button.is-active{background:var(--accent-soft);border-color:color-mix(in srgb,var(--accent) 23%,transparent);color:var(--accent)}.studio-nav-bottom{margin-top:auto;padding-top:18px;flex-shrink:0}.studio-nav-bottom>button{font-size:11px}.studio-nav-bottom>button>span{flex:1}.studio-nav-bottom>p{font-size:9px;color:var(--text-tertiary);line-height:1.8;margin:15px 12px 0;padding-top:12px;border-top:1px solid var(--border)}.nav-disclosure{padding:0 0 7px 30px}.nav-disclosure button{display:block;width:100%;padding:6px 4px;border:0;background:none;color:var(--text-secondary);font-size:10px;text-align:left;cursor:pointer}.nav-disclosure button:hover{color:var(--accent)} +.studio-main{grid-column:2;grid-row:2;display:flex;flex-direction:column;min-width:0;min-height:0;position:relative;padding-top:42px}.studio-document-tabs{display:none}.studio-breadcrumb{display:flex;align-items:center;gap:8px;padding:0 24px;height:34px;min-height:34px;border-bottom:1px solid var(--border);font-size:10px;color:var(--text-tertiary);overflow:hidden}.studio-breadcrumb>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.studio-breadcrumb>strong{font-weight:400;color:var(--text-secondary);white-space:nowrap}.studio-breadcrumb>.ws-link{margin-left:auto;flex-shrink:0;font-size:10px}.studio-stage{display:flex;flex-direction:column;flex:1;min-height:0;min-width:0;overflow:hidden;position:relative}.studio-stage>.studio-feature,.studio-stage>.workspace-page,.studio-stage>.wb-root,.studio-stage>.hub-root{flex:1;min-height:0;min-width:0}.studio-stage>.settings,.studio-stage>.settings-root{overflow:auto;min-height:0}.studio-resources{position:absolute;left:194px;right:0;top:52px;height:42px;z-index:3;display:flex;align-items:center;gap:20px;overflow:auto;padding:0 24px;border-bottom:1px solid var(--border);background:var(--bg);white-space:nowrap}.studio-resources>header,.resource-project,.resource-caption,.resource-empty,.resource-resizer{display:none}.studio-resources>button{position:relative;display:inline-flex;align-items:center;gap:6px;padding:11px 0;border:0;border-radius:0;background:transparent;color:var(--text-secondary);font-size:11px;cursor:pointer;flex-shrink:0}.studio-resources>button.is-selected{color:var(--text)}.studio-resources>button.is-selected:after{position:absolute;content:"";left:0;right:0;bottom:0;height:2px;background:var(--accent)}.studio-resources>button small{margin-left:auto;font:8px var(--font-mono);color:var(--text-tertiary)} +.studio-shell.is-developer{grid-template-columns:48px var(--resource-width) minmax(0,1fr)}.is-developer .studio-activity{padding:10px 5px 8px;align-items:center}.is-developer .studio-activity>button,.is-developer .studio-nav-bottom>button{justify-content:center;gap:0;padding:10px 0;width:36px;height:37px;border-radius:6px;margin-bottom:5px}.is-developer .studio-activity button>span,.is-developer .studio-nav-bottom>button>svg:last-child,.is-developer .studio-nav-bottom>p,.is-developer .nav-disclosure{display:none}.is-developer .studio-nav-bottom{width:36px;padding-top:12px}.is-developer .studio-resources{grid-column:2;grid-row:2;position:relative;left:auto;right:auto;top:auto;height:auto;display:block;padding:0 8px 16px;overflow:auto;border-right:1px solid var(--border);border-bottom:0;background:var(--bg-sunken);white-space:normal;z-index:2;min-width:0;min-height:0}.is-developer .studio-resources>header{display:flex;align-items:center;justify-content:space-between;height:40px;padding:0 4px;color:var(--text-tertiary);font:8px var(--font-mono);letter-spacing:1.2px}.is-developer .studio-resources>header .ws-icon{width:24px;height:24px;border:0}.is-developer .resource-project{display:flex;align-items:center;gap:7px;padding:9px 3px 12px;font-size:11px;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.is-developer .studio-resources>button{display:flex;align-items:center;gap:8px;width:100%;padding:8px;border:1px solid transparent;border-radius:5px;color:var(--text-secondary);font-size:11px;white-space:nowrap;min-width:0}.is-developer .studio-resources>button>span{overflow:hidden;text-overflow:ellipsis;min-width:0}.is-developer .studio-resources>button>svg{flex-shrink:0}.is-developer .studio-resources>button:hover{background:var(--bg-elevated);color:var(--text)}.is-developer .studio-resources>button.is-selected{background:var(--bg-elevated);border-color:var(--border);color:var(--accent)}.is-developer .studio-resources>button.is-selected:after{display:none}.is-developer .resource-caption{display:block;font:8px var(--font-mono);letter-spacing:1.2px;color:var(--text-tertiary);margin:25px 8px 10px}.is-developer .resource-empty{display:block;font-size:10px;color:var(--text-tertiary);line-height:1.9;padding:0 8px}.is-developer .resource-resizer{display:block;position:absolute;right:0;top:40px;bottom:0;width:5px;cursor:col-resize;touch-action:none}.is-developer .resource-resizer:hover,.is-developer .resource-resizer:focus-visible{background:var(--accent);opacity:.55}.is-developer .studio-main{grid-column:3;padding-top:0}.is-developer .studio-document-tabs{display:flex;align-items:center;gap:0;min-height:36px;height:36px;border-bottom:1px solid var(--border);background:var(--bg-sunken);overflow-x:auto;overflow-y:hidden;flex-shrink:0}.studio-document-tabs>div{display:flex;align-items:center;gap:7px;height:100%;border-right:1px solid var(--border);border-top:2px solid transparent;padding:0 9px 0 13px;flex-shrink:0}.studio-document-tabs>div.is-active{border-top-color:var(--accent);background:var(--bg)}.studio-document-tabs>div>button{border:0;background:transparent;color:var(--text-secondary);font-size:10px;cursor:pointer;padding:6px 0;white-space:nowrap}.studio-document-tabs>div.is-active>button:first-child{color:var(--text)}.studio-document-tabs .close-doc{opacity:.55;display:flex;align-items:center}.studio-document-tabs .close-doc:hover{opacity:1;color:var(--danger)}.studio-document-tabs>span{flex:1;min-width:8px}.studio-document-tabs>.ws-icon{height:25px;width:25px;margin:0 4px;border:0;flex-shrink:0}.is-developer .studio-breadcrumb{height:28px;min-height:28px;padding:0 18px;font-size:9px}.is-developer.resources-hidden{grid-template-columns:48px minmax(0,1fr)}.is-developer.resources-hidden .studio-resources{display:none}.is-developer.resources-hidden .studio-main{grid-column:2} +.studio-inspector{position:absolute;top:52px;bottom:26px;right:0;width:300px;z-index:12;background:var(--bg-elevated);border-left:1px solid var(--border);padding:18px;box-shadow:-15px 0 35px rgba(0,0,0,.18);overflow:auto}.studio-inspector>header{display:flex;align-items:center;justify-content:space-between;margin-bottom:25px}.studio-inspector>header strong{font-size:12px;font-weight:500}.studio-inspector>.ws-link{display:flex;margin:14px 0}.inspector-values{display:flex;flex-direction:column;gap:15px;margin:16px 0 25px;font-size:11px}.inspector-values>div{display:flex;justify-content:space-between;gap:15px}.inspector-values dt{color:var(--text-secondary);flex-shrink:0}.inspector-values dd{margin:0;text-align:right;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}.studio-statusbar{grid-column:1/-1;grid-row:3;display:flex;align-items:center;gap:10px;padding:0 13px;height:26px;min-width:0;overflow:hidden;white-space:nowrap;border-top:1px solid var(--border);background:var(--bg-sunken);font:9px var(--font-mono);color:var(--text-secondary);z-index:14}.status-local-dot{width:4px;height:4px;border-radius:50%;background:var(--success);flex-shrink:0}.status-divider{width:1px;height:10px;background:var(--border);flex-shrink:0}.status-spacer{flex:1}.speed-select{display:flex;align-items:center;gap:5px;color:var(--accent);font-size:9px}.speed-select select{font:9px var(--font-sans);color:var(--text);background:transparent;border:0;outline-offset:1px;max-width:70px}.run-console{height:190px;min-height:95px;max-height:38%;border-top:1px solid var(--border);flex-shrink:0;display:flex;flex-direction:column;background:var(--bg-sunken);overflow:hidden}.run-console>header{display:flex;align-items:center;height:33px;min-height:33px;gap:20px;padding:0 15px;border-bottom:1px solid var(--border)}.run-console>header>span{flex:1}.run-console>header>button:not(.ws-icon){height:100%;padding:0;border:0;border-bottom:1px solid transparent;background:none;color:var(--text-secondary);font-size:10px;cursor:pointer}.run-console>header>button.is-active{border-bottom-color:var(--accent);color:var(--text)}.run-console>header>.ws-icon{height:23px;width:23px;border:0}.run-console>div{flex:1;min-height:0;overflow:auto;padding:8px 15px}.run-console pre{margin:0 0 5px;white-space:pre-wrap;overflow-wrap:anywhere;color:var(--text-secondary);font:10px/1.7 var(--font-mono);user-select:text}.run-console p{font-size:10px;color:var(--text-tertiary)} +/* The main feature is shared in both shells; only framing and density change. */ +.studio-feature{height:100%;min-height:0;min-width:0;overflow:auto;padding:26px 30px 38px;display:flex;flex-direction:column;gap:18px}.is-developer .studio-feature{padding:22px 24px 30px}.feature-heading{display:flex;align-items:flex-start;justify-content:space-between;gap:18px;flex-shrink:0}.feature-heading h1{font:550 24px/1.4 var(--font-sans);letter-spacing:-.6px;margin:8px 0 0}.feature-heading p{font-size:11px;line-height:1.8;color:var(--text-secondary);margin:8px 0 0;max-width:680px}.feature-actions{display:flex;gap:8px;align-items:center;flex-shrink:0;padding-top:20px}.document-dirty{display:inline-block;margin-left:12px;font:9px var(--font-mono);letter-spacing:0;color:var(--text-tertiary);vertical-align:middle}.studio-card{min-width:0;background:var(--bg-elevated);border:1px solid var(--border);border-radius:10px;padding:19px}.studio-card h2{display:flex;align-items:center;gap:7px;font:550 13px var(--font-sans);margin:0 0 15px}.studio-card h3{font:500 12px var(--font-sans)}.studio-shell input:not([type="checkbox"]):not([type="range"]),.studio-shell select,.studio-shell textarea{color:var(--text);background:var(--bg-sunken);border:1px solid var(--border);border-radius:6px;font-size:11px;padding:9px;min-width:0}.studio-shell input[type="checkbox"]{accent-color:var(--accent)}.studio-shell textarea{font:11px/1.8 var(--font-mono);resize:vertical;user-select:text}.studio-shell input:focus-visible,.studio-shell textarea:focus-visible,.studio-shell select:focus-visible{outline:1px solid var(--accent);outline-offset:1px}.studio-shell button:disabled{opacity:.4;cursor:not-allowed}.developer-toolbar{display:grid;grid-template-columns:1fr 1fr 1.1fr auto;gap:12px;align-items:end;flex-shrink:0}.developer-toolbar>label,.intelligence-controls>label,.artifact-library>label{display:flex;flex-direction:column;gap:6px;font-size:9px;color:var(--text-secondary)}.developer-toolbar>label input,.developer-toolbar>label select{width:100%;height:34px}.developer-toolbar>.ws-icon{height:34px;width:34px}.developer-edit-grid{display:grid;grid-template-columns:minmax(0,1fr);gap:16px;flex-shrink:0}.developer-edit-grid.has-diff{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}.editor-card{padding:0;overflow:hidden}.editor-caption{display:flex;align-items:center;justify-content:space-between;gap:10px;height:37px;padding:0 13px;border-bottom:1px solid var(--border);font:8px var(--font-mono);letter-spacing:1px;color:var(--text-tertiary)}.editor-caption>label{font:9px var(--font-sans);letter-spacing:0;display:flex;align-items:center;gap:5px}.code-editor{height:300px;max-height:48vh;min-height:180px;overflow:hidden}.code-editor .cm-editor{height:100%}.code-editor .cm-scroller{overscroll-behavior:contain}.code-editor .cm-lineNumbers .cm-gutterElement{min-width:28px}.code-editor .cm-selectionBackground{background:var(--accent-soft)!important}.code-editor .cm-panel input{font-size:10px}.line-diff{max-height:310px;overflow:auto;user-select:text}.line-diff pre{margin:0;padding:2px 6px;font:10px/1.7 var(--font-mono);white-space:pre-wrap;overflow-wrap:anywhere;color:var(--text-secondary)}.line-diff pre.is-added{background:color-mix(in srgb,var(--success) 12%,transparent);color:var(--success)}.line-diff pre.is-removed{background:color-mix(in srgb,var(--danger) 10%,transparent);color:var(--danger)}.prompt-tools{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:16px;flex-shrink:0}.prompt-tools textarea{width:100%}.version-row{display:flex;align-items:center;gap:8px;padding:10px 0;border:0;border-bottom:1px solid var(--border);background:transparent;color:var(--accent);width:100%;font:11px var(--font-mono);text-align:left;cursor:pointer}.version-row small{font:9px var(--font-sans);color:var(--text-secondary);margin-left:auto}.run-confirm{background:color-mix(in srgb,var(--warning) 7%,var(--bg));border:1px solid color-mix(in srgb,var(--warning) 65%,transparent);border-radius:8px;padding:15px;flex-shrink:0}.run-confirm strong{font-size:12px;font-weight:550}.run-confirm p{font-size:11px;line-height:1.8;color:var(--text-secondary);margin:8px 0 13px}.run-confirm>.ws-primary{margin-right:14px}.studio-notice{display:flex;align-items:center;gap:7px;font-size:11px;color:var(--success);margin:0;flex-shrink:0}.request-output{flex-shrink:0}.request-output pre{max-height:450px;overflow:auto;white-space:pre-wrap;overflow-wrap:anywhere;font:12px/1.9 var(--font-sans);user-select:text}.evaluation-row{padding:14px 0;border-top:1px solid var(--border)}.evaluation-row>strong{font-size:12px}.evaluation-row>span{margin-left:12px;font:9px var(--font-mono);color:var(--text-tertiary)}.evaluation-row>p{font-size:10px;color:var(--danger)}.evaluation-row pre{font:11px/1.8 var(--font-mono);white-space:pre-wrap;overflow-wrap:anywhere;max-height:260px;overflow:auto;user-select:text}.trace-grid{display:grid;grid-template-columns:230px minmax(0,1fr);gap:16px;align-items:start}.trace-index{padding:8px;max-height:650px;overflow:auto}.trace-index>button{display:flex;flex-direction:column;gap:5px;text-align:left;width:100%;padding:12px 9px;border:1px solid transparent;border-radius:6px;background:transparent;color:var(--text);cursor:pointer}.trace-index>button strong{font-size:11px;font-weight:500}.trace-index>button small{font:9px var(--font-mono);color:var(--text-tertiary);overflow-wrap:anywhere}.trace-index>button.is-selected{background:var(--bg-sunken);border-color:var(--border)}.trace-json{max-height:450px;overflow:auto;white-space:pre-wrap;overflow-wrap:anywhere;font:10px/1.8 var(--font-mono);user-select:text}.studio-label{display:flex;flex-direction:column;gap:7px;font-size:11px;color:var(--text-secondary)}.studio-label textarea{width:100%}.intelligence-controls{display:flex;align-items:end;gap:12px;margin-top:15px;flex-wrap:wrap}.intelligence-controls>label{flex:1;min-width:130px}.intelligence-controls select{width:100%;height:34px}.intelligence-controls>.ws-primary,.intelligence-controls>.ws-secondary{min-height:34px}.intelligence-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:16px;align-items:start;flex-shrink:0}.source-option{display:flex;align-items:flex-start;gap:8px;font-size:11px;padding:12px 0;border-bottom:1px solid var(--border);cursor:pointer}.source-option>span{overflow-wrap:anywhere}.source-option small{display:block;font:9px var(--font-mono);color:var(--text-tertiary);margin-top:5px}.context-preview,.source-fulltext{white-space:pre-wrap;overflow-wrap:anywhere;font:11px/1.9 var(--font-mono);max-height:420px;overflow:auto;user-select:text}.artifact-library{max-width:420px}.artifact-editor{flex-shrink:0}.artifact-editor>.ws-card-top>input{flex:1;font-weight:500}.artifact-split{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:18px}.artifact-split textarea{width:100%;min-height:240px}.artifact-preview{max-height:500px;overflow:auto;font-size:12px;line-height:1.9;user-select:text;overflow-wrap:anywhere}.artifact-preview pre{overflow:auto;max-width:100%}.evidence-hit{padding:12px 0;border-top:1px solid var(--border)}.evidence-hit strong{font-size:11px;font-weight:500}.evidence-hit p{font-size:11px;color:var(--text-secondary);line-height:1.8;overflow-wrap:anywhere}.intelligence-grid details{border-top:1px solid var(--border);padding:12px 0}.intelligence-grid summary{font-size:11px;cursor:pointer;overflow-wrap:anywhere}.intelligence-grid summary>button{margin-left:12px}.collaboration-results{display:flex;flex-direction:column;gap:12px}.collaboration-results summary{display:flex;align-items:center;justify-content:space-between;font-size:13px;font-weight:500;cursor:pointer}.collaboration-results .studio-card[open]>summary{margin-bottom:15px}.collaboration-results details>div{font-size:12px;overflow-wrap:anywhere}.checkpoint-file{display:flex;align-items:center;justify-content:space-between;gap:12px;border-bottom:1px solid var(--border);padding:15px 0}.checkpoint-file>div{min-width:0}.checkpoint-file strong{display:block;font:10px var(--font-mono);overflow-wrap:anywhere;font-weight:400}.checkpoint-file small{display:block;font:8px var(--font-mono);color:var(--text-tertiary);margin-top:6px}.checkpoint-file>div>span{font-size:10px;color:var(--warning);display:block;margin-bottom:8px}.shell-notice{display:flex;align-items:center;justify-content:space-between;gap:15px;background:var(--accent-soft);padding:8px 20px;font-size:10px;flex-shrink:0;color:var(--text-secondary)}.studio-stage .ultrafast-toggle{display:none}.studio-stage .tc-subtabs{display:none}.studio-stage .workspace-header{padding-top:25px}.studio-stage .workspace-header h1{font-size:23px}.studio-stage .workspace-scroll{padding-top:18px}.studio-stage .workspace-foot{font-size:7px}.studio-stage .chat-header-title{font-size:17px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.studio-stage .conversations{min-width:170px;width:210px}.studio-stage .conv-meta{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block;max-width:170px}.studio-stage .wb-tabs{height:40px;min-height:40px;padding-left:20px}.studio-stage .wb-tab{font-size:11px}.studio-stage .stats-bar{font-size:9px}.studio-stage .workbench,.studio-stage .chat-main{min-width:0} +/* Shared primitives must exist even when Overview has never been loaded. */ +.studio-shell .ws-icon{width:29px;height:29px;display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--border);border-radius:6px;background:transparent;color:var(--text-secondary);cursor:pointer;flex-shrink:0}.studio-shell .ws-icon:hover{background:var(--bg-elevated);color:var(--text)}.studio-shell .ws-primary,.studio-shell .ws-secondary{display:inline-flex;align-items:center;justify-content:center;gap:7px;padding:9px 13px;border:1px solid var(--border);border-radius:7px;font-size:11px;font-weight:500;cursor:pointer;white-space:nowrap}.studio-shell .ws-primary{background:var(--text);color:var(--bg)}.studio-shell .ws-secondary{background:transparent;color:var(--text-secondary)}.studio-shell .ws-primary:hover{filter:brightness(1.06)}.studio-shell .ws-secondary:hover{background:var(--bg-sunken);color:var(--text)}.studio-shell .ws-link{display:inline-flex;align-items:center;gap:5px;background:none;border:0;padding:4px 0;color:var(--accent);font-size:10px;cursor:pointer}.studio-shell .ws-muted{font-size:11px;color:var(--text-secondary);line-height:1.8}.studio-shell .ws-label{font:8px/1.6 var(--font-mono);letter-spacing:.6px;color:var(--text-tertiary)}.studio-shell .ws-eyebrow{display:inline-flex;align-items:center;gap:8px;font:8px/1.8 var(--font-mono);letter-spacing:1.6px;color:var(--text-secondary)}.studio-shell .ws-empty{padding:22px 0;font-size:11px;line-height:1.9;color:var(--text-secondary)}.studio-shell .ws-error{padding:12px 14px;border:1px solid var(--danger);border-radius:7px;color:var(--danger);font-size:11px;line-height:1.8;overflow-wrap:anywhere;white-space:pre-wrap;flex-shrink:0;margin:0}.studio-shell .ws-card-top{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:15px} +.studio-modal-scrim{position:fixed;inset:0;z-index:150;background:var(--scrim);display:flex;align-items:center;justify-content:center;padding:30px}.studio-modal{width:440px;max-width:100%;max-height:85vh;overflow:auto;background:var(--bg-elevated);border:1px solid var(--border);border-radius:12px;padding:25px;box-shadow:var(--shadow-float)}.studio-modal h2{font:550 19px var(--font-sans);letter-spacing:-.4px}.studio-modal>p{font-size:11px;line-height:1.8;color:var(--text-secondary);margin:12px 0 18px}.studio-modal>input{width:100%;margin:0 0 20px}.studio-modal>div:last-child:not(:first-child){display:flex;gap:10px;justify-content:flex-end}.studio-modal.command-menu{width:530px;padding:0;overflow:hidden}.command-menu>label{display:flex;align-items:center;gap:10px;padding:14px 16px;border-bottom:1px solid var(--border);color:var(--text-secondary)}.studio-shell .command-menu>label>input{flex:1;background:transparent;border:0;border-radius:0;padding:3px 0;font-size:13px;outline:none}.command-menu>label>.ws-icon{border:0;width:22px;height:22px}.studio-modal.command-menu>div{display:block;max-height:420px;overflow:auto;padding:7px}.command-menu>div>button{display:flex;align-items:center;gap:10px;padding:11px;width:100%;border:0;border-radius:6px;background:transparent;color:var(--text);text-align:left;cursor:pointer}.command-menu>div>button:hover,.command-menu>div>button:focus-visible{background:var(--accent-soft);outline:none}.command-menu>div>button>span{font-size:12px;flex:1}.command-menu>div>button>small{font:8px var(--font-mono);color:var(--text-tertiary)}.command-menu>div>button>svg{color:var(--text-secondary)} +@media(min-width:1280px){.studio-shell.is-developer:has(.studio-inspector){grid-template-columns:48px var(--resource-width) minmax(0,1fr) 300px}.is-developer:has(.studio-inspector) .studio-inspector{grid-column:4;grid-row:2;position:relative;top:auto;bottom:auto;right:auto;width:auto;box-shadow:none;min-height:0;z-index:4}.studio-shell.is-developer.resources-hidden:has(.studio-inspector){grid-template-columns:48px minmax(0,1fr) 300px}.is-developer.resources-hidden:has(.studio-inspector) .studio-inspector{grid-column:3}} +@media(max-width:1100px){.studio-brand>span{display:none}.studio-topbar{gap:10px}.command-search{width:200px}.studio-feature,.is-developer .studio-feature{padding:22px 20px 28px}.feature-heading h1{font-size:21px}.feature-heading{gap:12px}.feature-heading p{font-size:10px}.feature-actions{padding-top:15px}.developer-toolbar{grid-template-columns:1fr 1fr auto}.developer-toolbar>label:first-child{grid-column:1/-1}.trace-grid{grid-template-columns:180px minmax(0,1fr)}.intelligence-grid{gap:12px}.studio-stage .conversations{width:185px}.studio-statusbar>.status-spacer+span{display:none}.studio-document-tabs>div{padding-left:9px;gap:5px}.developer-edit-grid.has-diff{grid-template-columns:minmax(0,1fr)}.studio-stage .workspace-header{padding-left:24px;padding-right:24px}.studio-stage .workspace-scroll{padding-left:24px;padding-right:24px}} +@media(max-width:960px){.studio-shell.is-developer{--resource-width:200px!important}.studio-shell.is-daily{grid-template-columns:170px minmax(0,1fr)}.is-daily .studio-resources{left:170px;gap:17px;padding:0 20px}.studio-activity{padding-left:8px;padding-right:8px}.studio-activity>button,.studio-nav-bottom>button{padding-left:10px;padding-right:8px}.studio-activity button small{font-size:8px}.studio-topbar{padding-right:9px;gap:9px}.project-switch{min-width:100px;max-width:180px}.project-switch select{max-width:135px}.command-search{width:150px;max-width:23%;padding:6px 8px}.command-search kbd{display:none}.command-search span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.studio-brand strong{font-size:13px}.layout-toggle button{font-size:9px;padding:4px 7px}.developer-edit-grid.has-diff,.prompt-tools,.artifact-split,.intelligence-grid{grid-template-columns:minmax(0,1fr)}.feature-heading{flex-wrap:wrap}.feature-actions{padding-top:0;margin-left:auto}.trace-grid{grid-template-columns:minmax(0,1fr)}.trace-index{max-height:170px}.artifact-preview{max-height:300px}.studio-statusbar{gap:7px;padding-left:9px;font-size:8px}.speed-select{font-size:8px}.studio-statusbar>span:last-child{max-width:150px;overflow:hidden;text-overflow:ellipsis}.studio-stage .conversations{width:172px;min-width:150px}.studio-stage .conv-meta{max-width:140px}.studio-stage .composer{padding-left:15px;padding-right:15px}.studio-stage .chat-header{padding-left:18px;padding-right:18px}.studio-stage .workspace-header h1{font-size:20px}} +@media(max-height:680px){.run-console{height:160px;max-height:180px}.studio-activity{padding-top:12px}.studio-activity>button{padding-top:8px;padding-bottom:8px}.studio-nav-bottom{padding-top:10px}.studio-nav-bottom>p{margin-top:8px;padding-top:8px}.feature-heading h1{font-size:20px}.code-editor{height:240px}.studio-feature,.is-developer .studio-feature{padding-top:18px;gap:14px}.studio-stage .workspace-header{padding-top:18px;padding-bottom:15px}.studio-stage .darkside-hero{min-height:220px}.studio-stage .hero-copy{padding-top:24px;padding-bottom:24px}} +@media(prefers-reduced-motion:reduce){.studio-shell *{animation:none!important;transition:none!important;scroll-behavior:auto!important}} diff --git a/css/task-center.css b/css/task-center.css new file mode 100644 index 0000000000000000000000000000000000000000..767f4fb86bd28abc7a83188b28ca2131eaa5365d --- /dev/null +++ b/css/task-center.css @@ -0,0 +1,958 @@ +/* 任务中心(契约 15A):任务页签三子区(任务 / 定时 / 批处理)。 + Warm Paper 全令牌配色,规则来自 docs/design-system.md: + 衬线标题 / 语义色只出现在状态语境 / 1px 分隔 / 克制动效。 */ + +.tc-root { + flex: 1; + min-width: 0; + min-height: 0; + display: flex; + flex-direction: column; +} + +/* ---------- 子区页签(任务页签内部) ---------- */ +.tc-subtabs { + display: flex; + align-items: center; + gap: 4px; + padding: 12px 24px 0; + border-bottom: 1px solid var(--border); + flex-shrink: 0; +} + +.tc-subtab { + position: relative; + height: 30px; + padding: 0 12px; + border: none; + border-radius: var(--radius-control) var(--radius-control) 0 0; + background: transparent; + color: var(--text-secondary); + font-family: inherit; + font-size: 13.5px; + cursor: pointer; + transition: background var(--dur) var(--ease), color var(--dur) var(--ease); +} + +.tc-subtab:hover { + background: var(--accent-soft); + color: var(--text); +} + +.tc-subtab.is-active { + color: var(--text); + font-weight: 600; +} + +.tc-subtab.is-active::after { + content: ""; + position: absolute; + left: 10px; + right: 10px; + bottom: -1px; + height: 2px; + border-radius: 1px; + background: var(--accent); +} + +.tc-subtab:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +/* ---------- 子区内容滚动区 ---------- */ +.tc-body { + flex: 1; + min-height: 0; + overflow-y: auto; +} + +.tc-sub { + max-width: 880px; + margin: 0 auto; + padding: 28px 32px 48px; + display: flex; + flex-direction: column; + gap: 16px; +} + +.tc-sub-head { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; +} + +.tc-sub-head-right { + display: flex; + align-items: center; + gap: 12px; +} + +.tc-sub-title { + margin: 0; + font-family: var(--font-serif); + font-size: 19px; + font-weight: 600; + color: var(--text); +} + +.tc-history-title { + margin-top: 12px; +} + +/* ---------- 通用小料 ---------- */ +.tc-empty { + margin: 8px 0; + color: var(--text-tertiary); + font-size: 14px; + line-height: 1.7; +} + +.tc-error { + margin: 0; + color: var(--danger); + font-size: 13.5px; +} + +.tc-notice { + margin: 0; + padding: 10px 14px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: var(--bg-elevated); + color: var(--text-secondary); + font-size: 13.5px; + line-height: 1.6; +} + +.tc-hint { + color: var(--text-tertiary); + font-size: 12.5px; +} + +.tc-redline { + margin: 0; + padding: 10px 14px; + border-left: 3px solid var(--warning); + border-radius: 0 var(--radius-chip) var(--radius-chip) 0; + background: var(--bg-elevated); + color: var(--text-secondary); + font-size: 13px; + line-height: 1.65; +} + +.tc-redline strong { + color: var(--text); +} + +/* 状态徽章(语义色只在状态语境) */ +.tc-badge { + display: inline-flex; + align-items: center; + height: 20px; + padding: 0 8px; + border-radius: var(--radius-chip); + font-size: 12px; + white-space: nowrap; + background: var(--bg-sunken); + color: var(--text-secondary); +} + +.tc-badge.is-running { + background: var(--accent-soft); + color: var(--accent); +} + +.tc-badge.is-done { + background: color-mix(in srgb, var(--success) 16%, transparent); + color: var(--success); +} + +.tc-badge.is-error { + background: color-mix(in srgb, var(--danger) 14%, transparent); + color: var(--danger); +} + +.tc-badge.is-cancelled, +.tc-badge.is-stopped { + background: var(--bg-sunken); + color: var(--text-tertiary); +} + +/* 验收结论徽章(契约 19A A2:done=success / partial=warning / failed=danger / + undecided=tertiary;语义色只出现在状态语境) */ +.tc-badge.is-success { + background: color-mix(in srgb, var(--success) 16%, transparent); + color: var(--success); +} + +.tc-badge.is-warning { + background: color-mix(in srgb, var(--warning) 18%, transparent); + color: var(--warning); +} + +.tc-badge.is-danger { + background: color-mix(in srgb, var(--danger) 14%, transparent); + color: var(--danger); +} + +.tc-badge.is-tertiary { + background: var(--bg-sunken); + color: var(--text-tertiary); +} + +/* 徽章本身是按钮(点开看验收报告):把按钮默认样式抹平 */ +.tc-verify-badge { + border: none; + font-family: inherit; + cursor: pointer; + gap: 5px; + transition: filter var(--dur) var(--ease); +} + +.tc-verify-badge:hover:not(:disabled) { + filter: brightness(0.97); +} + +.tc-verify-badge:disabled { + opacity: 0.7; +} + +.tc-verify-badge:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +/* 验收中转圈(按钮内 12px 细环) */ +.tc-verify-spin { + width: 11px; + height: 11px; + border: 1.5px solid var(--border); + border-top-color: var(--accent); + border-radius: 50%; + animation: tc-spin 0.8s linear infinite; +} + +@keyframes tc-spin { + to { + transform: rotate(360deg); + } +} + +@media (prefers-reduced-motion: reduce) { + .tc-verify-spin { + animation: none; + } +} + +/* ---------- 按钮 ---------- */ +.tc-primary { + display: inline-flex; + align-items: center; + gap: 6px; + height: 34px; + padding: 0 16px; + border: none; + border-radius: var(--radius-control); + background: var(--accent); + color: #fff; + font-family: inherit; + font-size: 13.5px; + cursor: pointer; + transition: filter var(--dur) var(--ease); +} + +.tc-primary:hover:not(:disabled) { + filter: brightness(1.06); +} + +.tc-primary:disabled { + opacity: 0.5; + cursor: default; +} + +.tc-primary:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +.tc-ghost { + height: 34px; + padding: 0 14px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: transparent; + color: var(--text-secondary); + font-family: inherit; + font-size: 13.5px; + cursor: pointer; + transition: background var(--dur) var(--ease); +} + +.tc-ghost:hover { + background: var(--bg-elevated); +} + +.tc-icon-btn { + display: inline-flex; + align-items: center; + gap: 4px; + height: 28px; + padding: 0 8px; + border: 1px solid var(--border); + border-radius: var(--radius-chip); + background: transparent; + color: var(--text-secondary); + font-family: inherit; + font-size: 12.5px; + cursor: pointer; + transition: background var(--dur) var(--ease), color var(--dur) var(--ease); +} + +.tc-icon-btn:hover:not(:disabled) { + background: var(--bg-elevated); + color: var(--text); +} + +.tc-icon-btn.is-danger:hover:not(:disabled) { + color: var(--danger); + border-color: var(--danger); +} + +.tc-icon-btn.is-confirm { + color: var(--danger); + border-color: var(--danger); +} + +.tc-refresh { + display: inline-flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; + border: 1px solid var(--border); + border-radius: var(--radius-chip); + background: transparent; + color: var(--text-secondary); + cursor: pointer; + transition: background var(--dur) var(--ease); +} + +.tc-refresh:hover { + background: var(--bg-elevated); +} + +/* ---------- 通知开关 ---------- */ +.tc-notify-switch { + display: inline-flex; + align-items: center; + gap: 6px; + color: var(--text-secondary); + font-size: 13px; + cursor: pointer; + user-select: none; +} + +.tc-notify-switch input { + accent-color: var(--accent); +} + +/* ---------- 进行中卡片 ---------- */ +.tc-running-card { + display: flex; + flex-direction: column; + gap: 8px; + padding: 16px 18px; + border: 1px solid var(--border); + border-radius: var(--radius-card); + background: var(--bg-elevated); +} + +.tc-running-head { + display: flex; + align-items: center; + gap: 10px; +} + +.tc-running-pulse { + width: 8px; + height: 8px; + border-radius: 50%; + background: var(--accent); + animation: tc-pulse 1.6s var(--ease) infinite; +} + +@keyframes tc-pulse { + 0%, + 100% { + opacity: 1; + } + 50% { + opacity: 0.3; + } +} + +@media (prefers-reduced-motion: reduce) { + .tc-running-pulse { + animation: none; + } +} + +.tc-running-task { + margin: 0; + font-family: var(--font-serif); + font-size: 16px; + font-weight: 600; + color: var(--text); + line-height: 1.5; +} + +.tc-running-meta { + display: flex; + flex-wrap: wrap; + gap: 12px; + color: var(--text-tertiary); + font-size: 12.5px; +} + +.tc-running-event { + margin: 0; + color: var(--text-secondary); + font-size: 13px; +} + +/* ---------- 历史列表 ---------- */ +.tc-history { + list-style: none; + margin: 0; + padding: 0; + border: 1px solid var(--border); + border-radius: var(--radius-card); + background: var(--bg-elevated); + overflow: hidden; +} + +.tc-history-item + .tc-history-item { + border-top: 1px solid var(--border); +} + +/* 行容器:左边主按钮(标题 + 状态 + 时间)+ 右边动作区(验收 / 徽章) */ +.tc-history-row { + display: flex; + align-items: center; + gap: 8px; +} + +.tc-history-main { + display: flex; + align-items: center; + gap: 10px; + flex: 1; + min-width: 0; + padding: 12px 16px; + border: none; + background: transparent; + color: var(--text); + font-family: inherit; + font-size: 13.5px; + text-align: left; + cursor: pointer; + transition: background var(--dur) var(--ease); +} + +.tc-history-actions { + display: flex; + align-items: center; + gap: 6px; + flex-shrink: 0; + padding-right: 14px; +} + +.tc-history-main:hover { + background: color-mix(in srgb, var(--accent-soft) 40%, transparent); +} + +.tc-history-task { + flex: 1; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.tc-history-meta { + color: var(--text-tertiary); + font-size: 12.5px; + white-space: nowrap; +} + +.tc-history-detail { + padding: 4px 16px 16px; + border-top: 1px dashed var(--border); +} + +.tc-history-summary { + margin: 10px 0 0; + color: var(--text-secondary); + font-size: 13px; + line-height: 1.65; + white-space: pre-wrap; +} + +/* ---------- 事件时间线 ---------- */ +.tc-timeline { + list-style: none; + margin: 12px 0 0; + padding: 0; + display: flex; + flex-direction: column; + gap: 6px; +} + +.tc-timeline-item { + display: flex; + align-items: baseline; + gap: 10px; + padding: 6px 10px; + border-radius: var(--radius-chip); + background: var(--bg-sunken); + font-size: 12.5px; +} + +.tc-timeline-item.is-green { + border-left: 3px solid var(--success); +} + +.tc-timeline-item.is-yellow { + border-left: 3px solid var(--warning); +} + +.tc-timeline-item.is-red { + border-left: 3px solid var(--danger); +} + +.tc-timeline-ts { + color: var(--text-tertiary); + font-family: var(--font-mono); + font-size: 11.5px; + white-space: nowrap; +} + +.tc-timeline-text { + color: var(--text); + white-space: nowrap; +} + +.tc-timeline-summary { + flex: 1; + min-width: 0; + color: var(--text-secondary); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.tc-timeline-hint, +.tc-timeline-error { + margin: 10px 0 0; + color: var(--text-tertiary); + font-size: 13px; +} + +.tc-timeline-error { + color: var(--danger); +} + +/* ---------- 表单(新建定时任务 / 批处理模板) ---------- */ +.tc-form { + display: flex; + flex-direction: column; + gap: 14px; + padding: 18px 20px; + border: 1px solid var(--border); + border-radius: var(--radius-card); + background: var(--bg-elevated); +} + +.tc-field { + display: flex; + flex-direction: column; + gap: 6px; + flex: 1; + min-width: 0; +} + +.tc-field > span { + color: var(--text-secondary); + font-size: 12.5px; +} + +.tc-field > input, +.tc-field > select, +.tc-field > textarea { + height: 34px; + padding: 0 12px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: var(--bg-sunken); + color: var(--text); + font-family: inherit; + font-size: 13.5px; +} + +.tc-field > textarea { + height: auto; + padding: 10px 12px; + line-height: 1.6; + resize: vertical; + font-family: inherit; +} + +.tc-field > input:focus, +.tc-field > select:focus, +.tc-field > textarea:focus { + outline: none; + border-color: var(--accent); +} + +.tc-field-row { + display: flex; + gap: 14px; +} + +.tc-form-actions { + display: flex; + align-items: center; + gap: 10px; +} + +/* 分段控件(三选) */ +.tc-seg { + display: inline-flex; + gap: 4px; + padding: 3px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: var(--bg-sunken); + width: fit-content; +} + +.tc-seg-btn { + height: 28px; + padding: 0 14px; + border: none; + border-radius: var(--radius-chip); + background: transparent; + color: var(--text-secondary); + font-family: inherit; + font-size: 13px; + cursor: pointer; + transition: background var(--dur) var(--ease), color var(--dur) var(--ease); +} + +.tc-seg-btn.is-active { + background: var(--bg-elevated); + color: var(--text); + font-weight: 600; + box-shadow: 0 1px 3px rgba(31, 30, 27, 0.08); +} + +/* 周几多选 */ +.tc-weekdays { + display: flex; + align-items: center; + gap: 6px; + flex-wrap: wrap; +} + +.tc-weekday { + width: 30px; + height: 30px; + border: 1px solid var(--border); + border-radius: var(--radius-chip); + background: transparent; + color: var(--text-secondary); + font-family: inherit; + font-size: 13px; + cursor: pointer; + transition: background var(--dur) var(--ease), color var(--dur) var(--ease); +} + +.tc-weekday.is-on { + background: var(--accent); + border-color: var(--accent); + color: #fff; +} + +.tc-weekdays input[type="time"] { + height: 30px; + padding: 0 8px; + border: 1px solid var(--border); + border-radius: var(--radius-chip); + background: var(--bg-sunken); + color: var(--text); + font-family: inherit; + font-size: 13px; +} + +/* ---------- 定时任务列表 ---------- */ +.tc-schedule-list { + list-style: none; + margin: 0; + padding: 0; + display: flex; + flex-direction: column; + gap: 10px; +} + +.tc-schedule-item { + display: flex; + align-items: center; + justify-content: space-between; + gap: 14px; + padding: 14px 16px; + border: 1px solid var(--border); + border-radius: var(--radius-card); + background: var(--bg-elevated); +} + +.tc-schedule-item.is-off { + opacity: 0.62; +} + +.tc-schedule-info { + min-width: 0; +} + +.tc-schedule-name { + display: flex; + align-items: center; + gap: 8px; + color: var(--text); + font-size: 14px; + font-weight: 600; +} + +.tc-schedule-cadence { + padding: 1px 8px; + border-radius: var(--radius-chip); + background: var(--accent-soft); + color: var(--accent); + font-size: 12px; + font-weight: 400; +} + +.tc-schedule-meta { + margin: 4px 0 0; + color: var(--text-tertiary); + font-size: 12.5px; +} + +.tc-schedule-actions { + display: flex; + align-items: center; + gap: 8px; + flex-shrink: 0; +} + +.tc-toggle input { + accent-color: var(--accent); +} + +/* ---------- 批处理:拖放区 / 文件 chips ---------- */ +.tc-dropzone { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 8px; + min-height: 92px; + padding: 18px; + border: 1.5px dashed var(--border); + border-radius: var(--radius-card); + background: var(--bg-elevated); + color: var(--text-tertiary); + font-size: 13.5px; + text-align: center; + cursor: pointer; + transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease); +} + +.tc-dropzone:hover { + border-color: var(--accent); +} + +.tc-dropzone.is-over { + border-color: var(--accent); + background: var(--accent-soft); + color: var(--accent); +} + +.tc-dropzone p { + margin: 0; +} + +.tc-file-chips { + list-style: none; + margin: 0; + padding: 0; + display: flex; + flex-wrap: wrap; + gap: 8px; +} + +.tc-file-chip { + display: inline-flex; + align-items: center; + gap: 6px; + height: 28px; + padding: 0 6px 0 10px; + border: 1px solid var(--border); + border-radius: var(--radius-chip); + background: var(--bg-elevated); + color: var(--text); + font-size: 12.5px; +} + +.tc-chip-x { + display: inline-flex; + align-items: center; + justify-content: center; + width: 18px; + height: 18px; + border: none; + border-radius: 4px; + background: transparent; + color: var(--text-tertiary); + cursor: pointer; +} + +.tc-chip-x:hover { + background: var(--bg-sunken); + color: var(--danger); +} + +/* ---------- 批处理:进度 / 结果 ---------- */ +.tc-batch-running, +.tc-batch-card { + display: flex; + flex-direction: column; + gap: 10px; + padding: 16px 18px; + border: 1px solid var(--border); + border-radius: var(--radius-card); + background: var(--bg-elevated); +} + +.tc-batch-running-head, +.tc-batch-card-head { + display: flex; + align-items: center; + gap: 10px; +} + +.tc-batch-running-head h3, +.tc-batch-card-head h3 { + margin: 0; + font-family: var(--font-serif); + font-size: 15.5px; + font-weight: 600; + color: var(--text); +} + +.tc-batch-card-actions { + margin-left: auto; + display: flex; + gap: 6px; +} + +.tc-progress { + height: 6px; + border-radius: 3px; + background: var(--bg-sunken); + overflow: hidden; +} + +.tc-progress-fill { + height: 100%; + border-radius: 3px; + background: var(--accent); + transition: width 240ms var(--ease); +} + +@media (prefers-reduced-motion: reduce) { + .tc-progress-fill { + transition: none; + } +} + +.tc-result-grid { + list-style: none; + margin: 0; + padding: 0; + border-top: 1px solid var(--border); +} + +.tc-result-item { + display: flex; + align-items: center; + gap: 8px; + border-bottom: 1px solid var(--border); +} + +.tc-result-main { + flex: 1; + min-width: 0; + display: flex; + align-items: center; + gap: 10px; + padding: 10px 4px; + border: none; + background: transparent; + color: var(--text); + font-family: inherit; + font-size: 13px; + text-align: left; + cursor: pointer; + transition: background var(--dur) var(--ease); +} + +.tc-result-main:hover { + background: color-mix(in srgb, var(--accent-soft) 40%, transparent); +} + +.tc-result-name { + width: 180px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font-weight: 500; +} + +.tc-result-excerpt { + flex: 1; + min-width: 0; + color: var(--text-secondary); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.tc-result-full { + flex-basis: 100%; + padding: 4px 0 12px; +} + +.tc-result-full pre { + margin: 6px 0 0; + padding: 12px 14px; + border-radius: var(--radius-chip); + background: var(--bg-sunken); + color: var(--text); + font-family: var(--font-mono); + font-size: 12.5px; + line-height: 1.65; + white-space: pre-wrap; + word-break: break-word; +} diff --git a/css/task.css b/css/task.css new file mode 100644 index 0000000000000000000000000000000000000000..de149992b7eb911a1bc5889dbabfd4008977ae36 --- /dev/null +++ b/css/task.css @@ -0,0 +1,301 @@ +/* 任务模式(契约 6D:对话/任务切换 + 三档批准)。 + 只服务 Composer 的模式切换、ChatWorkbench 的任务提示条;Warm Paper 令牌配色。 */ + +/* 模式切换 pill(对话 | 任务):任务选中时用 accent 底 */ +.mode-switch { + display: inline-flex; + align-items: center; + gap: 2px; + padding: 2px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: var(--bg-sunken); +} + +.mode-pill { + padding: 4px 12px; + border: none; + border-radius: calc(var(--radius-control) - 2px); + background: transparent; + color: var(--text-secondary); + font-size: 12.5px; + cursor: pointer; + transition: background-color var(--dur) var(--ease); +} + +.mode-pill:hover { + color: var(--text); +} + +.mode-pill.is-active { + background: var(--accent); + color: var(--bg); +} + +/* 权限档三选(下拉) */ +.perm-picker { + display: inline-flex; + align-items: center; + gap: 6px; +} + +.perm-label { + font-size: 11.5px; + color: var(--text-tertiary); + white-space: nowrap; +} + +.perm-picker select { + padding: 4px 8px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: var(--bg); + color: var(--text); + font-size: 12.5px; + cursor: pointer; +} + +.perm-picker select:focus { + border-color: var(--accent); +} + +/* 任务模式头部提示条(琥珀细条,温和不吓人) */ +.task-notice { + margin: 0 32px; + padding: 8px 14px; + border: 1px solid var(--border); + border-left: 3px solid var(--warning); + border-radius: var(--radius-card); + background: var(--bg-elevated); + color: var(--text-secondary); + font-size: 12.5px; + line-height: 1.6; +} + +.task-notice strong { + color: var(--text); + font-weight: 600; +} + +.task-notice-mode { + color: var(--accent); + font-weight: 600; +} + +/* ── 狂暴模式(契约 9A):提示条左上的火焰开关 + 进行中状态 ──────────── */ + +.task-notice-head { + display: flex; + align-items: center; + gap: 8px; + margin-bottom: 2px; +} + +/* 火焰开关:关闭=幽灵按钮;开启=金渐变徽章(warning 金 → accent 陶土,走令牌) */ +.frenzy-toggle { + display: inline-flex; + align-items: center; + gap: 4px; + padding: 3px 10px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: transparent; + color: var(--text-secondary); + font-size: 12px; + font-weight: 600; + cursor: pointer; + transition: + background var(--dur) var(--ease), + color var(--dur) var(--ease), + border-color var(--dur) var(--ease); +} + +.frenzy-toggle:hover { + color: var(--text); + border-color: var(--warning); +} + +.frenzy-toggle.is-on { + border-color: transparent; + color: var(--bg); + background: linear-gradient(135deg, var(--warning), var(--accent)); +} + +.frenzy-toggle.is-on:hover { + color: var(--bg); + filter: brightness(1.04); +} + +.frenzy-toggle:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +/* 自查 / 站岗进行中状态小签(契约 9A:「自查第 N 轮」「站岗质询」) */ +.task-notice-status { + display: inline-flex; + align-items: center; + padding: 2px 8px; + border-radius: var(--radius-chip); + font-size: 11.5px; + font-weight: 600; + background: var(--bg-sunken); + color: var(--text-secondary); + animation: task-status-pulse 1.6s var(--ease) infinite; +} + +.task-notice-status.is-sentry { + color: var(--warning); + background: color-mix(in srgb, var(--warning) 12%, var(--bg)); +} + +.task-notice-status.is-check { + color: var(--accent); + background: var(--accent-soft); +} + +@keyframes task-status-pulse { + 0%, + 100% { + opacity: 1; + } + 50% { + opacity: 0.55; + } +} + +/* 狂暴开启时的一句话说明 */ +.task-notice-frenzy-note { + font-size: 11.5px; + color: var(--text-tertiary); +} + +/* 提示条正文段落(配合上面的 head 行,去掉默认段距) */ +.task-notice-body { + margin: 0; +} + +/* 消息流里的工具卡容器(卡片视觉复用 agent.css 的 .agent-tool-card) */ +.msg-task-cards { + display: flex; + flex-direction: column; + gap: 8px; + margin: 4px 0 8px; +} + +/* 「本会话自动允许」勾选框 */ +.task-always { + display: inline-flex; + align-items: center; + gap: 6px; + font-size: 12px; + color: var(--text-secondary); + cursor: pointer; + user-select: none; +} + +.task-always input { + accent-color: var(--accent); + cursor: pointer; +} + +/* ── edit_file 改动预览(契约 6H):旧文 / 新文两栏 mono 对照 ────────── */ + +.edit-diff { + border: 1px solid var(--border); + border-radius: var(--radius-chip); + overflow: hidden; + margin-top: 6px; +} + +.edit-diff-label { + font-size: 11px; + color: var(--text-tertiary); + padding: 4px 10px; + background: var(--bg-sunken); + border-bottom: 1px solid var(--border); +} + +.edit-diff-cols { + display: grid; + grid-template-columns: 1fr 1fr; +} + +.edit-diff-col { + min-width: 0; +} + +.edit-diff-col + .edit-diff-col { + border-left: 1px solid var(--border); +} + +.edit-diff-col-head { + font-size: 11px; + padding: 3px 10px; + font-family: var(--font-mono); + border-bottom: 1px solid var(--border); +} + +/* 旧文淡红底 / 新文淡绿底(语义色 danger/success 的淡底,深浅色都成立) */ +.edit-diff-col.is-removed .edit-diff-col-head { + color: var(--danger); + background: color-mix(in srgb, var(--danger) 12%, var(--bg)); +} + +.edit-diff-col.is-added .edit-diff-col-head { + color: var(--success); + background: color-mix(in srgb, var(--success) 12%, var(--bg)); +} + +.edit-diff-col pre { + margin: 0; + padding: 6px 0; + font-family: var(--font-mono); + font-size: 12px; + line-height: 1.55; + overflow-x: auto; +} + +.edit-diff-col.is-removed pre { + background: color-mix(in srgb, var(--danger) 6%, var(--bg)); +} + +.edit-diff-col.is-added pre { + background: color-mix(in srgb, var(--success) 6%, var(--bg)); +} + +.edit-diff-line { + padding: 0 10px; + white-space: pre-wrap; + word-break: break-all; +} + +/* 窄屏两栏改上下叠放,避免挤成一条 */ +@media (max-width: 640px) { + .edit-diff-cols { + grid-template-columns: 1fr; + } + + .edit-diff-col + .edit-diff-col { + border-left: none; + border-top: 1px solid var(--border); + } +} + +/* 超过 40 行的折叠开关 */ +.edit-diff-toggle { + display: block; + width: 100%; + padding: 5px 10px; + font-size: 11px; + color: var(--text-secondary); + background: var(--bg-sunken); + border: none; + border-top: 1px solid var(--border); + cursor: pointer; + text-align: center; +} + +.edit-diff-toggle:hover { + color: var(--text); +} diff --git a/css/terminal.css b/css/terminal.css new file mode 100644 index 0000000000000000000000000000000000000000..60e5ac30a2b0fd2da212e627a0ce5adb2629dc15 --- /dev/null +++ b/css/terminal.css @@ -0,0 +1,29 @@ +.terminal-workspace{height:100%;min-height:0;overflow:auto} +.terminal-heading{align-items:flex-start} +.terminal-heading .feature-actions{padding-top:0} +.terminal-session-tabs{display:flex;align-items:center;gap:5px;min-height:34px;overflow-x:auto} +.terminal-session-tabs>button{display:flex;align-items:center;gap:7px;max-width:220px;min-height:30px;padding:0 9px;border:1px solid var(--border);border-radius:4px;background:var(--bg-elevated);color:var(--text-secondary);font:9px var(--font-mono);cursor:pointer} +.terminal-session-tabs>button[aria-selected="true"]{border-color:var(--accent);color:var(--text)} +.terminal-session-tabs>button>small{color:var(--text-tertiary);font:8px var(--font-sans)} +.terminal-cwd{display:flex;align-items:center;gap:9px;color:var(--text-tertiary);font-size:9px} +.terminal-cwd>input{width:min(420px,100%);height:28px;padding:4px 8px;border:1px solid var(--border);border-radius:4px;background:var(--bg-elevated);color:var(--text);font:10px var(--font-mono)} +.terminal-status-dot{width:6px;height:6px;flex:none;border-radius:50%;background:var(--text-tertiary)} +.terminal-status-dot.is-running{background:var(--success)}.terminal-status-dot.is-stopping{background:var(--warning)} +.terminal-frame{display:grid;grid-template-rows:32px minmax(220px,1fr);min-height:320px;height:min(58vh,560px);overflow:hidden;border:1px solid #293746;border-radius:4px;background:#080d13} +.terminal-frame>header{display:flex;align-items:center;gap:8px;padding:0 10px;border-bottom:1px solid #263340;background:#0d141c;color:#aebdc7;font:9px var(--font-mono)} +.terminal-frame>header>span:first-of-type{overflow:hidden;text-overflow:ellipsis;white-space:nowrap} +.terminal-frame>header>code{color:#6f8899;font:9px var(--font-mono)} +.terminal-header-spacer{flex:1} +.terminal-screen{min-height:0;padding:7px 9px} +.terminal-screen .xterm{height:100%;} +.terminal-screen .xterm-viewport{overflow-y:auto!important} +.terminal-approval{display:grid;grid-template-columns:24px minmax(0,1fr) auto;align-items:start;gap:11px;padding:12px;border:1px solid var(--warning);border-radius:5px;background:color-mix(in srgb,var(--warning) 6%,var(--bg-elevated))} +.terminal-approval-icon{color:var(--warning)} +.terminal-approval-copy{min-width:0} +.terminal-approval-copy>strong{font-size:11px} +.terminal-approval-copy>pre{max-height:110px;overflow:auto;margin:6px 0;padding:8px;border:1px solid var(--border);border-radius:3px;background:var(--bg-sunken);color:var(--text);font:10px/1.55 var(--font-mono);white-space:pre-wrap;overflow-wrap:anywhere} +.terminal-approval-copy>p{margin:0;color:var(--text-secondary);font-size:9px;line-height:1.55} +.terminal-approval-actions{display:flex;gap:6px} +.terminal-approval-actions button{white-space:nowrap} +.terminal-buffer-note{margin:0;color:var(--warning);font-size:9px} +@media(max-width:760px){.terminal-approval{grid-template-columns:20px minmax(0,1fr)}.terminal-approval-actions{grid-column:2;justify-content:flex-end}.terminal-heading{gap:8px}} diff --git a/css/theme.css b/css/theme.css new file mode 100644 index 0000000000000000000000000000000000000000..913bacd3a3786bf9a5f23687fe1ed8cab9e3dc43 --- /dev/null +++ b/css/theme.css @@ -0,0 +1,238 @@ +/* Perch · Warm Paper 主题(Claude 式设计语言,详见 docs/design-system.md) */ + +:root { + --bg: #faf9f5; + --bg-elevated: #f0eee6; + --bg-sunken: #e8e5db; + --border: #e3dfd3; + --text: #1f1e1b; + --text-secondary: #6b6862; + --text-tertiary: #9c988d; + --accent: #d97757; + --accent-soft: #f4e3dc; + --success: #7a9b76; + --warning: #c9a227; + --danger: #c05b4d; + + --font-serif: "Source Serif 4", "Songti SC", Georgia, serif; + --font-sans: "Inter", "PingFang SC", system-ui, -apple-system, sans-serif; + --font-mono: "JetBrains Mono", "SF Mono", Menlo, monospace; + + --radius-control: 10px; + --radius-card: 14px; + --radius-float: 16px; + --radius-chip: 8px; /* 小按钮/内嵌标签的次级圆角(控件 10px 之下的一档) */ + --ease: cubic-bezier(0.2, 0, 0, 1); + --dur: 150ms; + --shadow-float: 0 4px 24px rgba(31, 30, 27, 0.08); + + /* 模态遮罩(抽屉/浮层后面的那层暗纱),深浅色各自取值 */ + --scrim: rgba(31, 30, 27, 0.28); + + /* 浮窗毛玻璃(design-system §7:85% 暖纸底 + 20px 背景模糊) */ + --glass: rgba(250, 249, 245, 0.85); + --glass-blur: blur(20px); +} + +@media (prefers-color-scheme: dark) { + :root { + --bg: #262521; + --bg-elevated: #2f2e29; + --bg-sunken: #1e1d1a; + --border: #3b3a34; + --text: #edeae0; + --text-secondary: #a8a49a; + --text-tertiary: #79766d; + --accent: #e08a6e; + --accent-soft: #45342d; + --shadow-float: 0 4px 24px rgba(0, 0, 0, 0.35); + --glass: rgba(38, 37, 33, 0.85); + --scrim: rgba(0, 0, 0, 0.4); + } +} + +/* 契约 10A 外观:`data-theme` 显式覆盖段(设置里选「浅色/深色」时由 App 挂到 + 上)。`system` 不设属性 → 上面的 matchMedia 继续生效;这里的显式段 + 写在 matchMedia 之后,同特异性下后写者赢,因此能盖过系统偏好。 */ +[data-theme="light"] { + --bg: #faf9f5; + --bg-elevated: #f0eee6; + --bg-sunken: #e8e5db; + --border: #e3dfd3; + --text: #1f1e1b; + --text-secondary: #6b6862; + --text-tertiary: #9c988d; + --accent: #d97757; + --accent-soft: #f4e3dc; + --shadow-float: 0 4px 24px rgba(31, 30, 27, 0.08); + --glass: rgba(250, 249, 245, 0.85); + --scrim: rgba(31, 30, 27, 0.28); +} + +[data-theme="dark"] { + --bg: #262521; + --bg-elevated: #2f2e29; + --bg-sunken: #1e1d1a; + --border: #3b3a34; + --text: #edeae0; + --text-secondary: #a8a49a; + --text-tertiary: #79766d; + --accent: #e08a6e; + --accent-soft: #45342d; + --shadow-float: 0 4px 24px rgba(0, 0, 0, 0.35); + --glass: rgba(38, 37, 33, 0.85); + --scrim: rgba(0, 0, 0, 0.4); +} + +* { + box-sizing: border-box; +} + +html, +body, +#root { + height: 100%; + margin: 0; +} + +body { + background: var(--bg); + color: var(--text); + font-family: var(--font-sans); + font-size: 14.5px; + line-height: 1.65; + -webkit-font-smoothing: antialiased; + user-select: none; + cursor: default; +} + +h1, +h2, +h3 { + font-family: var(--font-serif); + font-weight: 600; + letter-spacing: -0.01em; + line-height: 1.3; + margin: 0; +} + +::selection { + background: var(--accent-soft); +} + +:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +/* 滚动条:细、暖、低调 */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} +::-webkit-scrollbar-thumb { + background: var(--border); + border-radius: 4px; +} +::-webkit-scrollbar-thumb:hover { + background: var(--text-tertiary); +} + +@media (prefers-reduced-motion: reduce) { + * { + transition: none !important; + animation: none !important; + } +} + +/* ═══════════════════════════════════════════════════════════════════ + Gemini 外观(dev-duotheme · 双皮肤)——`[data-style="gemini"]` 覆盖段。 + 与 `data-theme` 两轴正交(照 dev-tidy 的显式覆盖模式,追加在末尾): + 本段每条选择器都要求 data-style="gemini",Warm Paper(无该属性 / + ="warm")零影响。段内顺序即层叠顺序: + 1) Gemini 浅色默认(data-theme 缺省且系统浅色,或 data-theme="light") + 2) 系统深色(media 内 :not([data-theme="light"]),特异性 0,2,0 盖过 1) + 3) 显式 data-theme="dark"(与 2 同特异性、写在其后 → 后写者赢; + 系统浅色时 2 不命中,由它兜底) + 配色取自 Google/Material(见回复《Gemini 风格规范》):白底 + + #dadce0 发丝线 + Google Blue 单主色 + 蓝→紫→粉签名渐变三令牌。 + ═══════════════════════════════════════════════════════════════ */ + +/* 1) Gemini 浅色(纯白底 · Material 中性灰阶 · Google Blue) */ +[data-style="gemini"] { + --bg: #ffffff; + --bg-elevated: #f8f9fa; + --bg-sunken: #f1f3f4; + --border: #dadce0; + --text: #1f1f1f; + --text-secondary: #5f6368; + --text-tertiary: #80868b; + --accent: #1a73e8; + --accent-hover: #1967d2; /* 按钮 hover:Google Blue 700 */ + --accent-soft: #e8f0fe; /* 蓝 50:激活态浅蓝底/选区 */ + --success: #188038; + --warning: #e37400; + --danger: #d93025; + + /* Gemini 全 sans(「极简」的关键一刀):所有衬线位换 Google Sans 展示栈, + 正文同栈换 Text 字身;macOS 无 Google Sans → SF Pro Display/Text 接住。 */ + --font-serif: "Google Sans Display", "Google Sans", "SF Pro Display", + -apple-system, BlinkMacSystemFont, "PingFang SC", system-ui, sans-serif; + --font-sans: "Google Sans Text", "Google Sans", "SF Pro Text", -apple-system, + BlinkMacSystemFont, "PingFang SC", system-ui, sans-serif; + /* --font-mono 不动:代码永远等宽 */ + + /* 签名渐变三令牌(蓝 → 紫 → 珊瑚粉)。使用纪律:只允许 + 品牌标 / 欢迎页大标题高光 / Ultra 档强调 三处,其余黑白灰 + 单主色。 */ + --grad-start: #4285f4; + --grad-mid: #9b72cb; + --grad-end: #d96570; + + --radius-card: 16px; /* Material 大圆角档(8/12/16/28);控件/浮层令牌不动 */ + + --shadow-float: 0 1px 2px rgba(60, 64, 67, 0.1), 0 1px 3px rgba(60, 64, 67, 0.14); + --glass: rgba(255, 255, 255, 0.85); + --scrim: rgba(32, 33, 36, 0.32); +} + +/* 2) Gemini 深色(跟随系统:Google dark gray #1e1f20 系) */ +@media (prefers-color-scheme: dark) { + [data-style="gemini"]:not([data-theme="light"]) { + --bg: #1e1f20; + --bg-elevated: #282a2c; + --bg-sunken: #131314; + --border: #3c4043; + --text: #e3e3e3; + --text-secondary: #9aa0a6; + --text-tertiary: #80868b; + --accent: #8ab4f8; + --accent-hover: #a8c7fa; /* 深色 hover 走「浅变体」(Google 深色态加亮) */ + --accent-soft: #1e3a5f; + --success: #81c995; + --warning: #fdd663; + --danger: #f28b82; + --shadow-float: 0 1px 3px rgba(0, 0, 0, 0.55); + --glass: rgba(30, 31, 32, 0.85); + --scrim: rgba(0, 0, 0, 0.5); + } +} + +/* 3) Gemini 显式深色(设置里选「深色」→ data-theme="dark";与 2 同款取值) */ +[data-style="gemini"][data-theme="dark"] { + --bg: #1e1f20; + --bg-elevated: #282a2c; + --bg-sunken: #131314; + --border: #3c4043; + --text: #e3e3e3; + --text-secondary: #9aa0a6; + --text-tertiary: #80868b; + --accent: #8ab4f8; + --accent-hover: #a8c7fa; + --accent-soft: #1e3a5f; + --success: #81c995; + --warning: #fdd663; + --danger: #f28b82; + --shadow-float: 0 1px 3px rgba(0, 0, 0, 0.55); + --glass: rgba(30, 31, 32, 0.85); + --scrim: rgba(0, 0, 0, 0.5); +} diff --git a/css/vendor-picker.css b/css/vendor-picker.css new file mode 100644 index 0000000000000000000000000000000000000000..615f3ae4e179b52c2bb3fe5be6e6ecb3e7788225 --- /dev/null +++ b/css/vendor-picker.css @@ -0,0 +1,211 @@ +/* 选择服务商(Phase 6B):搜索 + 厂商 chips + 预置表单。 + Warm Paper 全令牌配色(design-system.md),无硬编码颜色。 */ + +.vp-wrap { + margin-bottom: 18px; + padding: 16px 18px; + border: 1px solid var(--border); + border-radius: var(--radius-card); + background: var(--bg-elevated); +} + +.vp-head { + margin-bottom: 12px; +} + +.vp-head h3 { + margin: 0; + font-size: 16px; +} + +.vp-head p { + margin: 4px 0 0; + font-size: 12.5px; + color: var(--text-secondary); +} + +/* ── 搜索框 ────────────────────────────────────────────────────── */ + +.vp-search { + width: 100%; + height: 36px; + margin-bottom: 12px; + padding: 0 14px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: var(--bg-sunken); + color: var(--text); + font-family: inherit; + font-size: 13.5px; +} + +.vp-search::placeholder { + color: var(--text-tertiary); +} + +.vp-search:focus-visible { + outline: none; + border-color: var(--accent); + box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent-soft) 65%, transparent); +} + +/* ── 厂商 chips 网格 ───────────────────────────────────────────── */ + +.vp-grid { + display: flex; + flex-wrap: wrap; + gap: 8px; +} + +.vp-chip { + display: inline-flex; + align-items: center; + gap: 9px; + padding: 7px 12px 7px 9px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: var(--bg); + color: var(--text); + font-family: inherit; + text-align: left; + cursor: pointer; + transition: background-color var(--dur) var(--ease), border-color var(--dur) var(--ease); +} + +.vp-chip:hover { + background: var(--accent-soft); +} + +.vp-chip.is-active { + border-color: var(--accent); + background: var(--accent-soft); +} + +.vp-chip.is-custom { + border-style: dashed; +} + +/* 衬线首字母圆标(logo 位) */ +.vp-avatar { + display: inline-flex; + align-items: center; + justify-content: center; + width: 26px; + height: 26px; + flex: none; + border: 1px solid var(--border); + border-radius: 50%; + background: var(--bg-sunken); + font-family: var(--font-serif); + font-size: 13px; + font-weight: 600; + color: var(--text-secondary); +} + +.vp-chip.is-active .vp-avatar { + color: var(--accent); +} + +.vp-chip-text { + display: flex; + flex-direction: column; + gap: 1px; + min-width: 0; +} + +.vp-chip-name { + font-size: 13px; + font-weight: 500; + line-height: 1.3; +} + +.vp-chip-alias { + font-size: 11.5px; + color: var(--text-tertiary); + line-height: 1.3; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 150px; +} + +/* ── 没搜到 ────────────────────────────────────────────────────── */ + +.vp-empty { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + flex-wrap: wrap; + padding: 10px 12px; + border: 1px dashed var(--border); + border-radius: var(--radius-control); + background: var(--bg-sunken); +} + +.vp-empty p { + margin: 0; + font-size: 13px; + color: var(--text-secondary); +} + +/* ── 选中后的预置表单 ──────────────────────────────────────────── */ + +.vp-form { + display: flex; + flex-direction: column; + gap: 14px; + margin-top: 14px; + padding-top: 14px; + border-top: 1px solid var(--border); +} + +.vp-form-head { + display: flex; + align-items: center; + gap: 12px; +} + +.vp-avatar.is-big { + width: 36px; + height: 36px; + font-size: 16px; +} + +.vp-form-head h4 { + margin: 0; + font-size: 15.5px; +} + +.vp-form-head p { + margin: 3px 0 0; + font-size: 12.5px; + color: var(--text-secondary); +} + +.vp-form-head a { + color: var(--accent); + text-decoration: underline; + text-underline-offset: 2px; + cursor: pointer; +} + +/* Base URL 预置展示:只读一行 + 「改」按钮解锁 */ +.vp-baseurl { + display: flex; + align-items: center; + gap: 8px; +} + +.vp-baseurl code { + flex: 1; + min-width: 0; + padding: 8px 12px; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: var(--bg-sunken); + font-family: var(--font-mono); + font-size: 12.5px; + color: var(--text-secondary); + word-break: break-all; +} diff --git a/css/workspace.css b/css/workspace.css new file mode 100644 index 0000000000000000000000000000000000000000..44d63fdbf6402ff797a4208282994c292b28e985 --- /dev/null +++ b/css/workspace.css @@ -0,0 +1,25 @@ +.workspace-page{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--bg);color:var(--text)} +.workspace-header{display:flex;align-items:center;justify-content:space-between;padding:37px 40px 22px;gap:16px;flex-shrink:0} +.ws-eyebrow{display:inline-flex;align-items:center;gap:9px;font-family:var(--font-mono);font-size:10px;letter-spacing:2px;color:var(--text-secondary);line-height:1.6} +.ws-eyebrow>span{width:5px;height:5px;border-radius:50%;background:var(--accent)} +.workspace-header h1{display:flex;align-items:center;gap:12px;margin-top:9px;font-family:var(--font-sans);font-size:24px;font-weight:550;letter-spacing:-.7px} +.ws-version{font:9px var(--font-mono);letter-spacing:1px;padding:4px 6px;border:1px solid var(--border);border-radius:4px;color:var(--text-secondary)} +.workspace-header-actions{display:flex;align-items:center;gap:12px}.local-pill{display:inline-flex;align-items:center;gap:6px;font:9px var(--font-mono);letter-spacing:1px;color:var(--text-secondary)} +.workspace-tabs{display:flex;gap:28px;padding:0 40px;border-bottom:1px solid var(--border);flex-shrink:0}.workspace-tabs button{display:flex;align-items:center;gap:7px;position:relative;padding:12px 0 14px;border:0;background:none;font:12px var(--font-sans);color:var(--text-secondary);cursor:pointer}.workspace-tabs button.is-active{color:var(--text)}.workspace-tabs button.is-active:after{content:"";position:absolute;bottom:-1px;left:0;right:0;height:2px;background:var(--accent)} +.workspace-scroll{overflow:auto;min-height:0;flex:1;padding:28px 40px 20px}.ws-muted{font-size:12px;line-height:1.7;color:var(--text-secondary)}.ws-label{font:9px var(--font-mono);letter-spacing:.8px;color:var(--text-tertiary);line-height:1.6}.ws-card{border:1px solid var(--border);border-radius:14px;background:var(--bg-elevated);padding:22px;min-width:0}.ws-card h2{font:550 14px var(--font-sans);letter-spacing:-.2px;display:flex;align-items:center;gap:8px}.ws-card-top{display:flex;justify-content:space-between;align-items:center;gap:12px;margin-bottom:15px}.ws-card-top svg{color:var(--text-secondary)} +.ws-icon{width:30px;height:30px;display:inline-flex;justify-content:center;align-items:center;background:none;color:var(--text-secondary);border:1px solid var(--border);border-radius:7px;cursor:pointer;flex-shrink:0}.ws-icon:hover{color:var(--text);background:var(--bg-sunken)}.workspace-page button:disabled{opacity:.4;cursor:not-allowed}.ws-primary,.ws-secondary{display:inline-flex;justify-content:center;align-items:center;gap:8px;cursor:pointer;font:500 12px var(--font-sans);padding:10px 15px;border-radius:8px;border:1px solid var(--border)}.ws-primary{background:var(--text);color:var(--bg)}.ws-secondary{background:transparent;color:var(--text)}.ws-primary:hover{filter:brightness(1.08)}.ws-link{display:inline-flex;align-items:center;gap:6px;border:none;padding:4px 0;color:var(--accent);font:11px var(--font-sans);background:none;cursor:pointer}.ws-error{border:1px solid var(--danger);border-radius:8px;padding:12px;color:var(--danger);font-size:12px;white-space:pre-wrap;overflow-wrap:anywhere}.ws-empty{padding:24px 0;font-size:12px;color:var(--text-secondary);line-height:1.8} +.darkside-hero{position:relative;display:flex;overflow:hidden;min-height:265px;border:1px solid var(--border);border-radius:16px;background:linear-gradient(118deg,var(--bg-elevated),var(--bg-sunken));isolation:isolate}.hero-copy{z-index:1;position:relative;padding:30px 32px;flex:1}.hero-copy .ws-eyebrow{font-size:8px;letter-spacing:2.1px}.hero-copy h2{font-family:var(--font-sans);font-weight:450;font-size:35px;letter-spacing:-1.4px;line-height:1.35;margin-top:14px}.hero-copy p{font-size:12px;color:var(--text-secondary);line-height:1.8;margin:12px 0 20px}.hero-orbit{position:relative;width:45%;min-width:220px;flex-shrink:0}.orbit-sphere{position:absolute;top:34px;right:55px;width:178px;height:178px;border-radius:50%;background:radial-gradient(circle at 32% 27%,#47505a 0%,#232a34 22%,#10151c 50%,#090b10 69%,#080a0d 73%);box-shadow:-8px -3px 22px rgba(217,190,143,.1),inset -15px -12px 25px #050608,1px 1px 0 rgba(229,193,131,.3)}.orbit-sphere:after{content:"";position:absolute;inset:-1px;border-radius:50%;border:1px solid rgba(219,190,137,.14);border-right-color:transparent;border-bottom-color:transparent;transform:rotate(-25deg)}.orbit-line{position:absolute;top:28px;right:20px;width:256px;height:212px;transform:rotate(-32deg);border:1px solid rgba(149,157,168,.17);border-radius:50%}.orbit-two{width:320px;height:154px;top:60px;right:-10px;transform:rotate(-32deg);border-color:rgba(149,157,168,.1)}.orbit-caption{position:absolute;bottom:24px;right:31px;font:9px var(--font-mono);color:var(--text-secondary);letter-spacing:3px;line-height:2}.orbit-caption b{font-size:6px;font-weight:400;letter-spacing:2px;color:var(--text-tertiary)} +.workspace-metrics{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));padding:25px 0;gap:12px}.ws-metric{padding:0 20px;border-right:1px solid var(--border);display:flex;flex-direction:column;gap:5px}.ws-metric:first-child{padding-left:0}.ws-metric:last-child{border:0;padding-right:0}.ws-metric strong{font:400 30px var(--font-sans);letter-spacing:-1px;font-variant-numeric:tabular-nums}.ws-metric>.ws-muted{font-size:11px}.ws-metric .ws-label{font-family:var(--font-sans);letter-spacing:0;font-size:10px}.workspace-bottom{display:grid;grid-template-columns:1.15fr 1fr;gap:16px}.runs-empty{display:flex;align-items:center;gap:14px;min-height:155px}.empty-signal{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:48px;height:48px;border:1px solid var(--border);border-radius:50%;color:var(--text-tertiary)}.runs-empty strong{font-size:12px;font-weight:500}.runs-empty p{font-size:11px;color:var(--text-tertiary);line-height:1.9;margin:8px 0}.health-card dl{margin:0;display:flex;flex-direction:column;gap:13px}.health-card dl>div{display:flex;justify-content:space-between;font-size:10px;gap:12px}.health-card dt{color:var(--text-secondary)}.health-card dd{margin:0;text-align:right}.health-card>.ws-muted{font-size:10px;margin:17px 0 9px}.health-pill{font-size:9px;padding:3px 7px;border:1px solid var(--border);border-radius:4px;color:var(--text-secondary)}.health-pill.is-ok{color:var(--success);border-color:color-mix(in srgb,var(--success) 30%,transparent)}.workspace-foot{display:flex;justify-content:space-between;gap:12px;margin-top:24px;padding-top:16px;border-top:1px solid var(--border);color:var(--text-tertiary);font:8px var(--font-mono);letter-spacing:1px}.workspace-foot span:last-child{font-family:var(--font-sans);letter-spacing:.3px}.live-run{display:flex;align-items:center;gap:10px;padding:14px 0;border-top:1px solid var(--border)}.live-run>div{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}.live-run strong{font-size:11px;font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.live-run .ws-muted{font-size:10px}.live-indicator,.run-state.is-live:before{width:5px;height:5px;border-radius:50%;background:var(--success)} +.history-grid{display:grid;grid-template-columns:minmax(230px,.8fr) minmax(280px,1.2fr);gap:18px;align-items:start}.ws-search{display:flex;align-items:center;gap:8px;padding:10px 12px;background:var(--bg-sunken);border:1px solid var(--border);border-radius:8px}.ws-search svg{color:var(--text-secondary);flex-shrink:0}.ws-search input{min-width:0;width:100%;border:0;background:none;color:var(--text);font:12px var(--font-sans);outline:none}.ws-search:focus-within{border-color:var(--accent)}.history-search>.ws-muted{font-size:10px}.ws-results{max-height:550px;overflow:auto;margin-top:16px}.ws-result{width:100%;display:flex;flex-direction:column;gap:9px;padding:15px 10px;border:0;border-bottom:1px solid var(--border);border-radius:6px;background:none;color:var(--text);text-align:left;cursor:pointer}.ws-result.is-active,.ws-result:hover{background:var(--bg-sunken)}.ws-result-title{display:flex;justify-content:space-between;width:100%;align-items:center;font-size:12px;gap:8px;overflow-wrap:anywhere}.ws-result-snippet{font-size:10px;color:var(--text-secondary);line-height:1.8;overflow-wrap:anywhere}.checkpoint-list{list-style:none;margin:22px 0 0;padding:0 0 0 15px;max-height:530px;overflow:auto}.checkpoint-list>li{position:relative;border-left:1px solid var(--border);padding:0 0 22px 20px}.checkpoint-list>li:last-child{border-left-color:transparent}.checkpoint-node{position:absolute;left:-4px;top:3px;width:7px;height:7px;border:1px solid var(--accent);background:var(--bg-elevated);border-radius:50%}.checkpoint-head{display:flex;justify-content:space-between;gap:8px}.checkpoint-list p{font-size:12px;line-height:1.8;color:var(--text-secondary);white-space:pre-wrap;overflow-wrap:anywhere;margin:9px 0 6px}.history-timeline>.ws-muted{font-size:11px;margin-top:0} +.lab-form{max-width:100%}.lab-models{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin:20px 0 15px}.lab-models label{display:flex;flex-direction:column;gap:7px}.lab-models select,.lab-run-picker select{color:var(--text);background:var(--bg-sunken);border:1px solid var(--border);border-radius:7px;padding:10px;font:12px var(--font-sans);min-width:0;width:100%}.lab-form textarea{resize:vertical;min-height:110px;width:100%;background:var(--bg-sunken);border:1px solid var(--border);border-radius:8px;color:var(--text);font:12px/1.8 var(--font-sans);padding:14px;user-select:text}.lab-submit{display:flex;justify-content:space-between;align-items:center;gap:12px;margin-top:12px}.lab-consent{border:1px solid var(--warning);border-radius:9px;padding:15px;margin-top:18px;font-size:12px}.lab-consent p{font-size:11px;color:var(--text-secondary);line-height:1.8}.lab-consent>div{display:flex;gap:10px}.lab-comparison{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-top:18px}.lab-placeholder{grid-column:1/-1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:14px;padding:50px 20px;color:var(--text-tertiary)}.lab-placeholder h3{font:400 18px var(--font-sans);color:var(--text-secondary)}.lab-placeholder p{font-size:11px;margin:0}.lab-letter{font:20px var(--font-mono);color:var(--accent)}.lab-answer h3{font:500 11px var(--font-sans);overflow-wrap:anywhere;flex:1}.run-state{font-size:9px;white-space:nowrap;color:var(--text-secondary);display:flex;align-items:center;gap:5px}.run-state.is-live:before{content:""}.lab-answer pre{white-space:pre-wrap;overflow-wrap:anywhere;max-height:450px;overflow:auto;font:12px/1.9 var(--font-sans);user-select:text}.lab-answer footer{display:flex;justify-content:space-between;gap:10px;border-top:1px solid var(--border);padding-top:12px}.lab-run-picker{display:flex;justify-content:flex-end;align-items:center;gap:12px;margin:15px 0}.lab-run-picker select{width:auto;max-width:220px}.is-spinning{animation:ws-spin 1s linear infinite}.ui-recovery{max-width:560px;margin:10vh auto;padding:32px;display:flex;flex-direction:column;align-items:flex-start;gap:18px}.ui-recovery p{color:var(--text-secondary);line-height:1.9}.section-loading{display:flex;align-items:center;justify-content:center;flex:1;min-height:120px;color:var(--text-secondary);font-size:12px}@keyframes ws-spin{to{transform:rotate(360deg)}} +@media(max-width:1080px){.workspace-header{padding:34px 25px 20px}.workspace-tabs{padding:0 25px}.workspace-scroll{padding:24px 25px 18px}.hero-copy{padding:26px}.hero-copy h2{font-size:30px}.hero-orbit{min-width:190px}.orbit-sphere{right:30px;width:160px;height:160px}.orbit-line{right:0;width:225px}.orbit-two{right:-30px;width:270px}.ws-card{padding:18px}.workspace-metrics{gap:6px}.ws-metric{padding:0 12px}.history-grid{grid-template-columns:1fr}.workspace-bottom{grid-template-columns:1fr 1fr}} +@media(max-width:800px){.workspace-bottom{grid-template-columns:1fr}.workspace-metrics{grid-template-columns:1fr 1fr;gap:20px}.ws-metric:nth-child(2){border:0}.ws-metric:nth-child(3){padding-left:0}.hero-orbit{display:none}.local-pill{display:none}.lab-comparison{grid-template-columns:1fr}.workspace-foot{flex-direction:column}.workspace-header h1{font-size:21px}.lab-models{grid-template-columns:1fr}} + +.ws-safety-note{display:flex;align-items:flex-start;gap:10px;border:1px solid var(--warning);border-radius:9px;padding:12px 14px;margin-bottom:18px;color:var(--warning);font-size:11px;line-height:1.8}.ws-safety-note svg{flex-shrink:0;margin-top:2px} + +.legacy-linker{margin-top:14px;border-top:1px solid var(--border);padding:12px 4px}.legacy-linker summary{font-size:10px;color:var(--text-secondary);cursor:pointer;list-style:none;display:flex;justify-content:space-between;gap:8px}.legacy-linker summary span{font-size:9px;color:var(--text-tertiary)}.legacy-linker>div{display:flex;justify-content:space-between;gap:8px;padding:10px 2px;border-top:1px solid var(--border);font-size:10px}.legacy-linker>div>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap} + +.workspace-recent{display:grid;grid-template-columns:170px 1fr;gap:18px;align-items:start;padding:0 0 21px;border-bottom:1px solid var(--border)}.workspace-recent h2{font:550 12px var(--font-sans);margin:2px 0 5px}.workspace-recent .ws-muted{font-size:10px}.workspace-recent-list{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:8px}.workspace-recent-list>button{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:5px 8px;align-items:center;text-align:left;padding:10px 11px;border:1px solid var(--border);border-radius:7px;background:var(--bg-elevated);color:var(--text);cursor:pointer;min-width:0}.workspace-recent-list>button:hover{border-color:var(--accent)}.workspace-recent-list>button>span{font-size:10px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.workspace-recent-list>button>small{font:8px var(--font-mono);color:var(--text-tertiary)}.workspace-recent-list>button>svg{grid-column:2;grid-row:1 / span 2;color:var(--text-tertiary)} +.overview-start{display:flex;align-items:center;justify-content:space-between;gap:24px;padding:22px 0 20px;border-bottom:1px solid var(--border)}.overview-start h2{margin:5px 0;font-size:19px;font-weight:550}.overview-start p{margin:0;color:var(--text-secondary);font-size:11px;line-height:1.6}.overview-actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:7px}.overview-actions .ws-primary,.overview-actions .ws-secondary{padding:7px 10px;font-size:10px} +@media(max-width:960px){.workspace-recent{grid-template-columns:1fr;gap:10px}.workspace-recent-list{grid-template-columns:repeat(2,minmax(0,1fr))}} +@media(max-width:760px){.overview-start{align-items:flex-start;flex-direction:column}.overview-actions{justify-content:flex-start}} diff --git a/docs/design-system.md b/docs/design-system.md new file mode 100644 index 0000000000000000000000000000000000000000..96f6598e8f6e7842d2b6e20fe7374731cf2a7d9b --- /dev/null +++ b/docs/design-system.md @@ -0,0 +1,159 @@ +# 栖木 Perch · 设计系统(Warm Paper) + +> 一套"像纸一样温暖、像工具一样安静"的界面语言。 +> 目标是让 AI 应用**不像一个聊天机器人**,而像你桌上一本笔记本。 + +--- + +## 1. 设计哲学 + +### 1.1 为什么是"暖纸" + +大多数 AI 应用用的是**冷色科技感**:纯白/纯黑背景 + 蓝紫渐变。 +那是"工具"的语言,不是"伙伴"的语言。 + +栖木选了**暖纸**: + +- 背景 `#faf9f5`——不是纯白,是纸张微微泛黄的白 +- 文字 `#1f1e1b`——不是纯黑,是墨水的深棕 +- 强调色 `#d97757`——陶土橙,温暖但不刺眼 + +**用户长时间盯着它**,暖色比冷色更不容易疲劳。 + +### 1.2 三条原则 + +| 原则 | 含义 | 体现 | +|---|---|---| +| **安静优先** | 界面不抢注意力 | 低饱和、少动画、无渐变噪点 | +| **内容为王** | 结构和排版服务于阅读 | 衬线标题 + 无衬线正文 | +| **物理感** | 元素像真的纸/玻璃 | 柔和阴影、毛玻璃、微圆角 | + +--- + +## 2. 色彩令牌 + +所有颜色都是 CSS 变量(`tokens/theme.css`),三套主题自动切换: + +| 令牌 | 浅色(Warm Paper) | 深色(Dark Side) | 用途 | +|---|---|---|---| +| `--bg` | `#faf9f5` | `#262521` | 页面底色 | +| `--bg-elevated` | `#f0eee6` | `#2f2e29` | 卡片/浮层 | +| `--bg-sunken` | `#e8e5db` | `#1e1d1a` | 凹陷区/代码块 | +| `--border` | `#e3dfd3` | `#3b3a34` | 分隔线/描边 | +| `--text` | `#1f1e1b` | `#edeae0` | 主文字 | +| `--text-secondary` | `#6b6862` | `#a8a49a` | 次要文字 | +| `--text-tertiary` | `#9c988d` | `#79766d` | 提示/占位 | +| `--accent` | `#d97757` | `#e08a6e` | 强调/主按钮 | +| `--accent-soft` | `#f4e3dc` | `#45342d` | 强调背景 | +| `--success` | `#7a9b76` | — | 成功 | +| `--warning` | `#c9a227` | — | 警告 | +| `--danger` | `#c05b4d` | — | 危险 | + +### 主题切换机制 + +```css +/* 1) 默认跟随系统 */ +@media (prefers-color-scheme: dark) { :root { ... } } + +/* 2) 显式覆盖(设置里选浅色/深色时挂到 ) */ +[data-theme="light"] { ... } +[data-theme="dark"] { ... } +``` + +**顺序很重要**:显式段写在 `matchMedia` 之后,同特异性下后写者赢 → 能覆盖系统偏好。 + +--- + +## 3. 字体 + +| 用途 | 令牌 | 字体栈 | +|---|---|---| +| 标题 | `--font-serif` | Source Serif 4 / Songti SC / Georgia | +| 正文 | `--font-sans` | Inter / PingFang SC / system-ui | +| 代码 | `--font-mono` | JetBrains Mono / SF Mono / Menlo | + +**为什么标题用衬线**:衬线有"书"的质感,让长文阅读更舒服,也拉开与"聊天机器人"的距离。 + +正文 `14.5px` / 行高 `1.65`——比常规 UI 略大,因为 AI 应用的主要行为是**读**。 + +--- + +## 4. 圆角与阴影 + +```css +--radius-control: 10px; /* 按钮/输入框 */ +--radius-card: 14px; /* 卡片 */ +--radius-float: 16px; /* 浮层/弹窗 */ +--radius-chip: 8px; /* 小标签 */ +--shadow-float: 0 4px 24px rgba(31,30,27,0.08); /* 浮起 */ +``` + +**原则**:圆角随"层级"递增——控件 < 卡片 < 浮层。 +阴影很淡(8% 透明度),只用来暗示层级,不制造视觉噪音。 + +--- + +## 5. 毛玻璃(Glass) + +```css +--glass: rgba(250, 249, 245, 0.85); +--glass-blur: blur(20px); +``` + +用于浮窗、命令面板、侧边抽屉——**85% 暖纸底 + 20px 模糊**。 +既保持内容可读,又透出底层氛围。 + +--- + +## 6. 动效 + +```css +--ease: cubic-bezier(0.2, 0, 0, 1); /* 快进慢出 */ +--dur: 150ms; +``` + +**原则**: +- 只用 `opacity` / `transform`(GPU 友好) +- 时长 150ms——快到不打断,慢到可感知 +- 缓动是"快进慢出",模拟物理惯性 + +--- + +## 7. 组件样式地图 + +48 个 CSS 文件按模块拆分(见 `css/`),核心几个: + +| 文件 | 模块 | +|---|---| +| `theme.css` | 全局令牌、清空、排版基线 | +| `chat.css` | 对话区(消息气泡、流式光标) | +| `composer.css` | 输入区(思考强度滑块、ultrafast 徽章) | +| `markdown.css` | Markdown 渲染(代码块/表格/引用) | +| `materials.css` | 材质(毛玻璃/纸张/凹陷) | +| `screensaver.css` | 待机屏保(四色流体 + 视频) | + +其余是各功能面板(知识库、任务、启动器、讨论区…)。 + +--- + +## 8. 可访问性 + +- **对比度**:正文对背景 ≥ 7:1(AAA) +- **焦点环**:键盘导航有可见焦点(不靠颜色单独传达状态) +- **动效偏好**:尊重 `prefers-reduced-motion` +- **字号**:正文 14.5px 起(不玩 12px 小字) + +--- + +## 9. 怎么用这套设计 + +1. 引入 `tokens/theme.css`(令牌层) +2. 按需引入 `css/*.css`(组件层) +3. 主题切换:给 `` 加 `data-theme="light" | "dark"`,或不加(跟随系统) +4. 所有自定义样式都用 `var(--token)`,不要写死颜色 + +详见 `preview/index.html`(一个可直接打开的效果预览)。 + +--- + +MIT License · 来自 [栖木 Perch](https://huggingface.co/datasets/hongcoding/perch) diff --git a/index.html b/index.html index b0c4b3666032a737f3903db53e6a8a9272483e28..aedc936ff4db3188636fa1ccf1e261a01ef1b104 100644 --- a/index.html +++ b/index.html @@ -1,19 +1,241 @@ - - - - - My static Space - - - -
-

Welcome to your static Space!

-

You can modify this app directly by editing index.html in the Files and versions tab.

-

- Also don't forget to check the - Spaces documentation. -

-
- + + + + +栖木 Perch · Warm Paper 设计系统预览 + + + +
+ +
+
+

Warm Paper

+

栖木 Perch 设计系统 · 零依赖预览(点击右上角切换深浅色)

+
+ +
+ +

① 色板 · 只有一个强调色

+
+ +

② 字体 · 衬线标题 + 无衬线正文

+

这是一段衬线标题

+

+ 正文用无衬线字体(Inter / PingFang SC),行高 1.65。比常规 UI 略大,因为 AI 应用的主要行为是阅读。 +

+

代码用等宽字体:const perch = await run_hybrid(...)

+ +

③ 按钮

+
+ + + + + +
+ +

④ 卡片

+
+
+

混合流

+

本机先答 0.08s,云端无缝接棒。

+
+
+

GPU 加速

+

热驻留让首 token 从 3s 降到 0.08s。

+
+
+

隐私优先

+

数据默认全在本地,云端只见密文。

+
+
+ +

⑤ 徽章与输入

+
+ ⚡ ultrafast + 🟢 就绪 + 🔥 狂暴模式 +
+ + +

⑥ 毛玻璃浮窗

+
+ 85% 暖纸底 + 20px 背景模糊 +

+ 用于命令面板、侧边抽屉、浮层——既保持可读,又透出底层氛围。 +

+
+ +

⑦ 圆角层级

+
+
chip 8px
+
control 10px
+
card 14px
+
float 16px
+
+ + +
+ + + diff --git a/tokens/theme.css b/tokens/theme.css new file mode 100644 index 0000000000000000000000000000000000000000..913bacd3a3786bf9a5f23687fe1ed8cab9e3dc43 --- /dev/null +++ b/tokens/theme.css @@ -0,0 +1,238 @@ +/* Perch · Warm Paper 主题(Claude 式设计语言,详见 docs/design-system.md) */ + +:root { + --bg: #faf9f5; + --bg-elevated: #f0eee6; + --bg-sunken: #e8e5db; + --border: #e3dfd3; + --text: #1f1e1b; + --text-secondary: #6b6862; + --text-tertiary: #9c988d; + --accent: #d97757; + --accent-soft: #f4e3dc; + --success: #7a9b76; + --warning: #c9a227; + --danger: #c05b4d; + + --font-serif: "Source Serif 4", "Songti SC", Georgia, serif; + --font-sans: "Inter", "PingFang SC", system-ui, -apple-system, sans-serif; + --font-mono: "JetBrains Mono", "SF Mono", Menlo, monospace; + + --radius-control: 10px; + --radius-card: 14px; + --radius-float: 16px; + --radius-chip: 8px; /* 小按钮/内嵌标签的次级圆角(控件 10px 之下的一档) */ + --ease: cubic-bezier(0.2, 0, 0, 1); + --dur: 150ms; + --shadow-float: 0 4px 24px rgba(31, 30, 27, 0.08); + + /* 模态遮罩(抽屉/浮层后面的那层暗纱),深浅色各自取值 */ + --scrim: rgba(31, 30, 27, 0.28); + + /* 浮窗毛玻璃(design-system §7:85% 暖纸底 + 20px 背景模糊) */ + --glass: rgba(250, 249, 245, 0.85); + --glass-blur: blur(20px); +} + +@media (prefers-color-scheme: dark) { + :root { + --bg: #262521; + --bg-elevated: #2f2e29; + --bg-sunken: #1e1d1a; + --border: #3b3a34; + --text: #edeae0; + --text-secondary: #a8a49a; + --text-tertiary: #79766d; + --accent: #e08a6e; + --accent-soft: #45342d; + --shadow-float: 0 4px 24px rgba(0, 0, 0, 0.35); + --glass: rgba(38, 37, 33, 0.85); + --scrim: rgba(0, 0, 0, 0.4); + } +} + +/* 契约 10A 外观:`data-theme` 显式覆盖段(设置里选「浅色/深色」时由 App 挂到 + 上)。`system` 不设属性 → 上面的 matchMedia 继续生效;这里的显式段 + 写在 matchMedia 之后,同特异性下后写者赢,因此能盖过系统偏好。 */ +[data-theme="light"] { + --bg: #faf9f5; + --bg-elevated: #f0eee6; + --bg-sunken: #e8e5db; + --border: #e3dfd3; + --text: #1f1e1b; + --text-secondary: #6b6862; + --text-tertiary: #9c988d; + --accent: #d97757; + --accent-soft: #f4e3dc; + --shadow-float: 0 4px 24px rgba(31, 30, 27, 0.08); + --glass: rgba(250, 249, 245, 0.85); + --scrim: rgba(31, 30, 27, 0.28); +} + +[data-theme="dark"] { + --bg: #262521; + --bg-elevated: #2f2e29; + --bg-sunken: #1e1d1a; + --border: #3b3a34; + --text: #edeae0; + --text-secondary: #a8a49a; + --text-tertiary: #79766d; + --accent: #e08a6e; + --accent-soft: #45342d; + --shadow-float: 0 4px 24px rgba(0, 0, 0, 0.35); + --glass: rgba(38, 37, 33, 0.85); + --scrim: rgba(0, 0, 0, 0.4); +} + +* { + box-sizing: border-box; +} + +html, +body, +#root { + height: 100%; + margin: 0; +} + +body { + background: var(--bg); + color: var(--text); + font-family: var(--font-sans); + font-size: 14.5px; + line-height: 1.65; + -webkit-font-smoothing: antialiased; + user-select: none; + cursor: default; +} + +h1, +h2, +h3 { + font-family: var(--font-serif); + font-weight: 600; + letter-spacing: -0.01em; + line-height: 1.3; + margin: 0; +} + +::selection { + background: var(--accent-soft); +} + +:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +/* 滚动条:细、暖、低调 */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} +::-webkit-scrollbar-thumb { + background: var(--border); + border-radius: 4px; +} +::-webkit-scrollbar-thumb:hover { + background: var(--text-tertiary); +} + +@media (prefers-reduced-motion: reduce) { + * { + transition: none !important; + animation: none !important; + } +} + +/* ═══════════════════════════════════════════════════════════════════ + Gemini 外观(dev-duotheme · 双皮肤)——`[data-style="gemini"]` 覆盖段。 + 与 `data-theme` 两轴正交(照 dev-tidy 的显式覆盖模式,追加在末尾): + 本段每条选择器都要求 data-style="gemini",Warm Paper(无该属性 / + ="warm")零影响。段内顺序即层叠顺序: + 1) Gemini 浅色默认(data-theme 缺省且系统浅色,或 data-theme="light") + 2) 系统深色(media 内 :not([data-theme="light"]),特异性 0,2,0 盖过 1) + 3) 显式 data-theme="dark"(与 2 同特异性、写在其后 → 后写者赢; + 系统浅色时 2 不命中,由它兜底) + 配色取自 Google/Material(见回复《Gemini 风格规范》):白底 + + #dadce0 发丝线 + Google Blue 单主色 + 蓝→紫→粉签名渐变三令牌。 + ═══════════════════════════════════════════════════════════════ */ + +/* 1) Gemini 浅色(纯白底 · Material 中性灰阶 · Google Blue) */ +[data-style="gemini"] { + --bg: #ffffff; + --bg-elevated: #f8f9fa; + --bg-sunken: #f1f3f4; + --border: #dadce0; + --text: #1f1f1f; + --text-secondary: #5f6368; + --text-tertiary: #80868b; + --accent: #1a73e8; + --accent-hover: #1967d2; /* 按钮 hover:Google Blue 700 */ + --accent-soft: #e8f0fe; /* 蓝 50:激活态浅蓝底/选区 */ + --success: #188038; + --warning: #e37400; + --danger: #d93025; + + /* Gemini 全 sans(「极简」的关键一刀):所有衬线位换 Google Sans 展示栈, + 正文同栈换 Text 字身;macOS 无 Google Sans → SF Pro Display/Text 接住。 */ + --font-serif: "Google Sans Display", "Google Sans", "SF Pro Display", + -apple-system, BlinkMacSystemFont, "PingFang SC", system-ui, sans-serif; + --font-sans: "Google Sans Text", "Google Sans", "SF Pro Text", -apple-system, + BlinkMacSystemFont, "PingFang SC", system-ui, sans-serif; + /* --font-mono 不动:代码永远等宽 */ + + /* 签名渐变三令牌(蓝 → 紫 → 珊瑚粉)。使用纪律:只允许 + 品牌标 / 欢迎页大标题高光 / Ultra 档强调 三处,其余黑白灰 + 单主色。 */ + --grad-start: #4285f4; + --grad-mid: #9b72cb; + --grad-end: #d96570; + + --radius-card: 16px; /* Material 大圆角档(8/12/16/28);控件/浮层令牌不动 */ + + --shadow-float: 0 1px 2px rgba(60, 64, 67, 0.1), 0 1px 3px rgba(60, 64, 67, 0.14); + --glass: rgba(255, 255, 255, 0.85); + --scrim: rgba(32, 33, 36, 0.32); +} + +/* 2) Gemini 深色(跟随系统:Google dark gray #1e1f20 系) */ +@media (prefers-color-scheme: dark) { + [data-style="gemini"]:not([data-theme="light"]) { + --bg: #1e1f20; + --bg-elevated: #282a2c; + --bg-sunken: #131314; + --border: #3c4043; + --text: #e3e3e3; + --text-secondary: #9aa0a6; + --text-tertiary: #80868b; + --accent: #8ab4f8; + --accent-hover: #a8c7fa; /* 深色 hover 走「浅变体」(Google 深色态加亮) */ + --accent-soft: #1e3a5f; + --success: #81c995; + --warning: #fdd663; + --danger: #f28b82; + --shadow-float: 0 1px 3px rgba(0, 0, 0, 0.55); + --glass: rgba(30, 31, 32, 0.85); + --scrim: rgba(0, 0, 0, 0.5); + } +} + +/* 3) Gemini 显式深色(设置里选「深色」→ data-theme="dark";与 2 同款取值) */ +[data-style="gemini"][data-theme="dark"] { + --bg: #1e1f20; + --bg-elevated: #282a2c; + --bg-sunken: #131314; + --border: #3c4043; + --text: #e3e3e3; + --text-secondary: #9aa0a6; + --text-tertiary: #80868b; + --accent: #8ab4f8; + --accent-hover: #a8c7fa; + --accent-soft: #1e3a5f; + --success: #81c995; + --warning: #fdd663; + --danger: #f28b82; + --shadow-float: 0 1px 3px rgba(0, 0, 0, 0.55); + --glass: rgba(30, 31, 32, 0.85); + --scrim: rgba(0, 0, 0, 0.5); +}